diff --git a/components/Card/StudyGroup/index.js b/components/Card/StudyGroup/index.js index 705c5283..fa98eb1b 100644 --- a/components/Card/StudyGroup/index.js +++ b/components/Card/StudyGroup/index.js @@ -7,6 +7,8 @@ import { useTranslation } from 'react-i18next' import RenderField from '../../RenderField' export function StudyGroupCard({ studyGroup }) { + if (!studyGroup.active) return null + const [showMore, setShowMore] = useState(false) const { t } = useTranslation() @@ -88,6 +90,3 @@ export function StudyGroupCard({ studyGroup }) { ) } - - - \ No newline at end of file diff --git a/firebase.json b/firebase.json index 358bd433..d3d42763 100644 --- a/firebase.json +++ b/firebase.json @@ -17,10 +17,16 @@ }, "auth": { "enabled": true + }, + "storage": { + "port": 9199 } }, "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json" + }, + "storage": { + "rules": "storage.rules" } } diff --git a/next.config.js b/next.config.js index c0a49133..40444d6f 100644 --- a/next.config.js +++ b/next.config.js @@ -5,6 +5,11 @@ module.exports = { localeDetection: true, // Turn off automatic locale detection }, images: { - domains: ['assets.zipschool.com', 'cdn.buildspace.so', 'firebasestorage.googleapis.com'], + domains: [ + 'assets.zipschool.com', + 'cdn.buildspace.so', + 'firebasestorage.googleapis.com', + 'localhost', + ], }, } diff --git a/pages/admin/editGroup.js b/pages/admin/editGroup.js new file mode 100644 index 00000000..e7f9aefd --- /dev/null +++ b/pages/admin/editGroup.js @@ -0,0 +1,336 @@ +import React, { useState, useEffect } from 'react' +import { withProtected } from '../../hooks/route' +import { useRouter } from 'next/router' +import { db, storage } from '../../firebase/initFirebase' +import { collection, getDocs, doc, updateDoc, Timestamp } from 'firebase/firestore' +import { useTranslation } from 'react-i18next' +import Head from 'next/head' +import { ref, uploadBytes, getDownloadURL } from 'firebase/storage' + +// Add this helper function at the top of your component +const convertTimestampToDateTimeLocal = (timestamp) => { + if (!timestamp) return '' + const date = + timestamp instanceof Timestamp ? timestamp.toDate() : new Date(timestamp.seconds * 1000) + + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + + return `${year}-${month}-${day}T${hours}:${minutes}` +} + +function EditStudyGroup({ user }) { + const [groups, setGroups] = useState([]) + const [selectedGroup, setSelectedGroup] = useState(null) + const [formData, setFormData] = useState({}) + + const router = useRouter() + const { t } = useTranslation() + + useEffect(() => { + fetchGroups() + }, []) + + const fetchGroups = async () => { + const querySnapshot = await getDocs(collection(db, 'study_groups')) + const groupsData = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() })) + + // Sort groups: active groups by index, then inactive groups + const sortedGroups = groupsData.sort((a, b) => { + if (a.active && !b.active) return -1 + if (!a.active && b.active) return 1 + if (a.active === b.active) return (a.index || 0) - (b.index || 0) + return 0 + }) + + setGroups(sortedGroups) + } + + const handleGroupSelect = (e) => { + const selectedGroupId = e.target.value + const group = groups.find((g) => g.id === selectedGroupId) + setSelectedGroup(group) + if (group) { + const newFormData = {} + Object.entries(group).forEach(([key, value]) => { + if (value instanceof Timestamp) { + newFormData[key] = value.toDate().toISOString().slice(0, 16) + } else { + newFormData[key] = value + } + }) + setFormData(newFormData) + } + } + + // Modify handleChange to correctly handle the scheduled_at field + const handleChange = (e) => { + const { name, value } = e.target + setFormData((prevData) => { + let newData = { ...prevData } + + if (name === 'scheduled_at') { + newData[name] = value ? Timestamp.fromDate(new Date(value)) : null + } else if (name.startsWith('metadata.')) { + const [, lang, field] = name.split('.') + newData.metadata = { + ...newData.metadata, + [lang]: { + ...newData.metadata[lang], + [field]: value, + }, + } + // Also update the main field if it's title or description + if (field === 'title' || field === 'description') { + newData[field] = value + } + } else { + newData[name] = value + // Also update the metadata if it's title or description + if (name === 'title' || name === 'description') { + Object.keys(newData.metadata).forEach((lang) => { + newData.metadata[lang][name] = value + }) + } + } + + return newData + }) + } + + const handleImageUpload = async (e) => { + const file = e.target.files[0] + if (file) { + const storageRef = ref(storage, `study_groups/${file.name}`) + try { + await uploadBytes(storageRef, file) + const url = await getDownloadURL(storageRef) + setFormData((prevData) => ({ + ...prevData, + image_url: url, + })) + alert(t('imageUploadedSuccessfully')) + } catch (error) { + console.error('Error uploading image: ', error) + alert(t('errorUploadingImage')) + } + } + } + + const handleSubmit = async (e) => { + e.preventDefault() + + try { + // Start with the original data of the selected group + const updatedData = { ...selectedGroup } + + // Iterate over the fields in formData + Object.keys(formData).forEach((key) => { + // If the value in formData is different from the original value, update it + if (JSON.stringify(formData[key]) !== JSON.stringify(selectedGroup[key])) { + updatedData[key] = formData[key] + } + }) + + // Handle scheduled_at as Timestamp + if (updatedData.scheduled_at && !(updatedData.scheduled_at instanceof Timestamp)) { + updatedData.scheduled_at = Timestamp.fromDate(new Date(updatedData.scheduled_at)) + } + + // Ensure that title and description are updated in metadata + if (updatedData.metadata) { + Object.keys(updatedData.metadata).forEach((lang) => { + updatedData.metadata[lang].title = updatedData.title + updatedData.metadata[lang].description = updatedData.description + }) + } + + // Remove fields that should not be updated + delete updatedData.id + delete updatedData.analytics + + await updateDoc(doc(db, 'study_groups', selectedGroup.id), updatedData) + console.log('Study group updated successfully') + alert(t('studyGroupUpdatedSuccessfully')) + router.push(`/study-groups/${updatedData.slug || selectedGroup.id}`) + } catch (error) { + console.error('Error updating study group: ', error) + alert(t('errorUpdatingStudyGroup')) + } + } + + const renderFormField = (key, value) => { + if (key === 'id' || key === 'analytics') return null + + if (key === 'active') { + return ( +
+ + +
+ ) + } + + if (key === 'index') { + return ( +
+ + +
+ ) + } + + if (key === 'scheduled_at') { + return ( +
+ + +
+ ) + } + + if (key === 'metadata') { + return ( +
+ + {Object.keys(value).map((lang) => ( +
+

{lang}

+ +