From a608d83a7227241a29eed379e1a30385e5f5403a Mon Sep 17 00:00:00 2001 From: Ethan Lanting Date: Wed, 23 Oct 2024 10:51:26 -0500 Subject: [PATCH 1/2] Add HelpRequests and HelpRequestModal component for managing help requests --- components/HelpRequests.jsx | 192 ++++++++++++++++++++++++ components/modals/HelpRequestsModal.jsx | 104 +++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 components/HelpRequests.jsx create mode 100644 components/modals/HelpRequestsModal.jsx diff --git a/components/HelpRequests.jsx b/components/HelpRequests.jsx new file mode 100644 index 0000000..a064b09 --- /dev/null +++ b/components/HelpRequests.jsx @@ -0,0 +1,192 @@ +import React, { useEffect, useState } from 'react' +import { + collection, + deleteDoc, + doc, + getDocs, + Timestamp, +} from 'firebase/firestore' +import { db } from '../config/firebase' +import { IoTrash } from 'react-icons/io5' +import { Tooltip } from 'react-tooltip' +import HelpRequestsModal from './modals/HelpRequestsModal' +import Link from 'next/link' + +// Styles +const style = { + section_container: + 'w-full h-full flex flex-col px-3 md:px-12 py-5 mb-5 overflow-y-auto', + section_wrapper: 'flex flex-col h-full', + section_header: 'flex justify-between ml-10 md:mx-0 py-5', + section_title: 'text-xl font-extrabold text-blue-600 tracking-wider', + section_filters: '', + section_filtersWrap: 'p-0 px-4 md:p-4 md:py-0 md:px-4 flex items-center', + table_main: 'min-w-full bg-white rounded-xl p-1', + table_thead: 'border-b dark:border-indigo-100 bg-slate-100', + table_th: 'px-3 p-3 text-sm font-semibold text-left tracking-wide', + table_tr: + 'border-b transition duration-300 ease-in-out hover:bg-indigo-50 dark:border-indigo-100 dark:hover:bg-indigo-100', + table_td: 'whitespace-normal text-sm px-3 p-2 cursor-pointer', + table_button: 'hover:fill-cyan-700', + table_icon: 'ml-4 fill-gray-400 hover:fill-red-600', + button: + 'flex items-center shadow ml-auto bg-white hover:bg-gray-100 text-sm py-2 px-4 rounded-lg focus:outline-none focus:shadow-outline', +} + +const HelpRequests = () => { + const [helpRequests, setHelpRequests] = useState([]) + const [showHelpRequestModal, setShowHelpRequestModal] = useState(false) + const [selectedHelpRequest, setSelectedHelpRequest] = useState(null) + const [loading, setLoading] = useState(true) + + const getData = async () => { + const helpRequestsCollection = collection(db, 'helpRequests') + const helpRequestsSnapshot = await getDocs(helpRequestsCollection) + + const helpRequestsList = helpRequestsSnapshot.docs.map((doc) => { + const { createdDate, ...data } = doc.data() + return { + id: doc.id, + ...data, + createdDate: formatDate(createdDate), + } + }) + + setHelpRequests(helpRequestsList) + setLoading(false) + } + + const formatDate = (timestamp) => { + if (timestamp instanceof Timestamp) { + const date = timestamp.toDate() + return date.toLocaleDateString() + ' ' + date.toLocaleTimeString() + } + return '' + } + + const handleRequestModalShow = (data) => { + // Open the modal when the button is clicked + setSelectedHelpRequest(data) + setShowHelpRequestModal(true) + } + + const handleRequestModalClose = () => { + // Close the modal when the close button is clicked + setShowHelpRequestModal(false) + setSelectedHelpRequest(null) + } + + const handleDeleteRequest = async (id) => { + try { + console.log('Deleting help request:', id) + const helpRequestDoc = doc(db, 'helpRequests', id) + await deleteDoc(helpRequestDoc) + setHelpRequests(helpRequests.filter((request) => request.id !== id)) + getData() + } catch (error) { + console.error('Error deleting help request:', error) + } + } + + // Fetch data from Firestore + useEffect(() => { + getData() + }, []) + + return ( + <> +
+
+
+
Help Requests
+
+ + + + + + + + + + + + {loading && ( + + + + )} + + {!loading && helpRequests.length == 0 && ( + + + + )} + + {helpRequests.length > 0 && + helpRequests.map((request) => ( + { + const { id, ...data } = request + handleRequestModalShow(data) + }} + key={request.id} + className={style.table_tr}> + + + + + + + ))} + +
SubjectMessageEmailCreated Date + Delete Request +
+ Loading... +
+ No help requests found +
{request.subject}{request.message} + { + e.stopPropagation() + }} + className="underline" + href={`mailto:${request.email}`} + target="_blank"> + {request.email} + + {request.createdDate} e.stopPropagation()}> + +
+
+
+ + {showHelpRequestModal && selectedHelpRequest && ( + + )} + + ) +} + +export default HelpRequests diff --git a/components/modals/HelpRequestsModal.jsx b/components/modals/HelpRequestsModal.jsx new file mode 100644 index 0000000..00a4ef3 --- /dev/null +++ b/components/modals/HelpRequestsModal.jsx @@ -0,0 +1,104 @@ +import Image from 'next/image' +import Link from 'next/link' +import React, { Fragment } from 'react' +import { IoClose } from 'react-icons/io5' + +const style = { + modal_background: + 'fixed z-[9998] top-0 left-0 w-full h-full bg-black bg-opacity-50 overflow-auto', + modal_container: + 'absolute inset-0 flex justify-center items-center z-[9999] sm:overflow-y-scroll', + modal_wrapper: + 'flex-col justify-center items-center w-10/12 md:w-8/12 rounded-2xl py-10 px-10 bg-sky-100 sm:overflow-visible', + modal_header_container: 'grid md:gap-5 lg:gap-5 auto-cols-auto mb-6', + modal_header_wrapper: 'flex w-full items-baseline justify-between', + modal_header: 'text-lg font-bold text-blue-600 tracking-wider', + modal_close: 'text-gray-800', + modal_form_container: + 'grid justify-center md:gap-5 lg:gap-5 grid-cols-2 auto-cols-auto', + modal_form_label: + 'text-lg font-bold text-black tracking-wider mb-4 capitalize', + modal_form_switch: 'flex mb-4 col-span-2', + modal_form_upload_image: + 'block w-full text-sm text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-sky-100 file:text-blue-500 hover:file:bg-blue-100 file:cursor-pointer', + modal_form_radio_container: 'flex gap-2 col-span-2', + modal_form_radio: 'mr-1', + modal_form_input: + 'shadow border-none rounded-xl min-w-full col-span-2 p-3 text-sm text-gray-700 leading-tight focus:outline-none focus:shadow-outline', + modal_form_button: + 'bg-blue-600 self-end hover:bg-blue-700 text-sm text-white font-semibold py-2 px-6 rounded-md focus:outline-none focus:shadow-outline', +} + +// Function to format camelCase or PascalCase labels by adding spaces between words +const formatLabel = (label) => { + return label.replace(/([a-z])([A-Z])/g, '$1 $2') +} + +const HelpRequestsModal = ({ helpRequestInfo, handleClose }) => { + return ( +
+
+
e.stopPropagation()}> +
+
+
Help Request Info
+ +
+
+ +
+
+
+ {Object.entries(helpRequestInfo).map(([key, value], index) => ( + +
+ {formatLabel(key)} +
+
+ {key === 'images' ? ( +
+ {(Array.isArray(value) ? value : [value]).map( + (image, imgIndex) => ( + + {`image-${imgIndex}`} + + ), + )} +
+ ) : key === 'email' ? ( + + {value} + + ) : ( + {value} + )} +
+
+ ))} +
+
+
+
+
+
+ ) +} + +export default HelpRequestsModal From 0e6aa0555008dad206cc7eb1afddf4b4b7bb367c Mon Sep 17 00:00:00 2001 From: Ethan Lanting Date: Wed, 23 Oct 2024 10:54:05 -0500 Subject: [PATCH 2/2] Add navigation for HelpRequests page --- components/Navbar.jsx | 19 +++++++++++++++++++ pages/dashboard.jsx | 20 +++++++++++--------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/components/Navbar.jsx b/components/Navbar.jsx index c268629..64694c3 100644 --- a/components/Navbar.jsx +++ b/components/Navbar.jsx @@ -14,6 +14,7 @@ import { IoClose, IoMenu, IoChatboxEllipsesOutline, + IoDocumentTextOutline, } from 'react-icons/io5' import { HiOutlineDocumentPlus } from 'react-icons/hi2' import { Tooltip } from 'react-tooltip' @@ -203,6 +204,24 @@ const Navbar = ({ )} + {customClaims.admin && ( + + )}
{(customClaims.admin || customClaims.agency) && ( diff --git a/pages/dashboard.jsx b/pages/dashboard.jsx index a7884b2..866999b 100644 --- a/pages/dashboard.jsx +++ b/pages/dashboard.jsx @@ -13,6 +13,7 @@ import { db, auth } from '../config/firebase' import LanguageSwitcher from '../components/LanguageSwitcher' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import Head from 'next/head' +import HelpRequests from '../components/HelpRequests' const tabList = [ 'Home', 'Profile', @@ -38,20 +39,20 @@ const Dashboard = () => { const router = useRouter() const [agencyUpdateSubmitted, setAgencyUpdateSubmitted] = useState(0) - - const [newReportModal,setNewReportModal] = useState(false) - const [newReportSubmitted,setNewReportSubmitted] = useState(0) + + const [newReportModal,setNewReportModal] = useState(false) + const [newReportSubmitted,setNewReportSubmitted] = useState(0) const handleNewReportSubmit = () => { // increment the newReportSubmitted - setNewReportSubmitted((prevState) => prevState + 1) - setNewReportModal(false) + setNewReportSubmitted((prevState) => prevState + 1) + setNewReportModal(false) + } + + const handleNewReportClick = () => { + setNewReportModal(true) // Open the modal when the button is clicked } - const handleNewReportClick = () => { - setNewReportModal(true) // Open the modal when the button is clicked - } - const handleAgencyUpdateSubmit = () => { // increment the agencyUpdateSubmitted setAgencyUpdateSubmitted((prevState) => prevState + 1) @@ -108,6 +109,7 @@ const Dashboard = () => { {tab == 4 && customClaims.admin && ( )} + {tab == 5 && customClaims.admin && }
{/* Render the NewReportModal */} {newReportModal && (