Skip to content

Commit

Permalink
Merge pull request #54 from engagingnewsproject/feature-help-requests…
Browse files Browse the repository at this point in the history
…-view

Admin Page Help Requests View
  • Loading branch information
luukee authored Oct 23, 2024
2 parents 846e532 + 0e6aa05 commit efbd7fe
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 9 deletions.
192 changes: 192 additions & 0 deletions components/HelpRequests.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<div className={style.section_container}>
<div className={style.section_wrapper}>
<div className={style.section_header}>
<div className={style.section_title}>Help Requests</div>
</div>
<table className={style.table_main}>
<thead className={style.table_thead}>
<tr>
<th className={style.table_th}>Subject</th>
<th className={style.table_th}>Message</th>
<th className={style.table_th}>Email</th>
<th className={style.table_th}>Created Date</th>
<th className={`${style.table_th} text-center`}>
Delete Request
</th>
</tr>
</thead>
<tbody>
{loading && (
<tr>
<td colSpan="5" className={`${style.table_td} text-center`}>
Loading...
</td>
</tr>
)}

{!loading && helpRequests.length == 0 && (
<tr>
<td colSpan="5" className={`${style.table_td} text-center`}>
No help requests found
</td>
</tr>
)}

{helpRequests.length > 0 &&
helpRequests.map((request) => (
<tr
onClick={() => {
const { id, ...data } = request
handleRequestModalShow(data)
}}
key={request.id}
className={style.table_tr}>
<td className={style.table_td}>{request.subject}</td>
<td className={style.table_td}>{request.message}</td>
<td className={style.table_td}>
<Link
onClick={(e) => {
e.stopPropagation()
}}
className="underline"
href={`mailto:${request.email}`}
target="_blank">
{request.email}
</Link>
</td>
<td className={style.table_td}>{request.createdDate}</td>
<td
className={`${style.table_td} text-center`}
onClick={(e) => e.stopPropagation()}>
<button
onClick={async () => {
await handleDeleteRequest(request.id)
}}
className={`${style.icon} tooltip-delete-user`}>
<IoTrash
size={20}
className="fill-gray-400 hover:fill-red-600"
/>
<Tooltip
anchorSelect=".tooltip-delete-user"
place="top"
delayShow={500}>
Delete Request
</Tooltip>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>

{showHelpRequestModal && selectedHelpRequest && (
<HelpRequestsModal
helpRequestInfo={selectedHelpRequest}
handleClose={handleRequestModalClose}
/>
)}
</>
)
}

export default HelpRequests
19 changes: 19 additions & 0 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
IoClose,
IoMenu,
IoChatboxEllipsesOutline,
IoDocumentTextOutline,
} from 'react-icons/io5'
import { HiOutlineDocumentPlus } from 'react-icons/hi2'
import { Tooltip } from 'react-tooltip'
Expand Down Expand Up @@ -203,6 +204,24 @@ const Navbar = ({
</Tooltip>
</button>
)}
{customClaims.admin && (
<button // Help Requests
onClick={() => {
setTab(5)
closeDrawer()
}}
className={`${basicStyle} ${
tab === 5 ? ' text-indigo-500 bg-indigo-100' : ''
} tooltip-help-requests`}>
<IoDocumentTextOutline size={30} />
<Tooltip
anchorSelect=".tooltip-help-requests"
place="bottom"
delayShow={500}>
Help Requests
</Tooltip>
</button>
)}
</div>
<div className="self-end">
{(customClaims.admin || customClaims.agency) && (
Expand Down
104 changes: 104 additions & 0 deletions components/modals/HelpRequestsModal.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className={style.modal_background} onClick={handleClose}>
<div className={style.modal_container}>
<div
className={style.modal_wrapper}
onClick={(e) => e.stopPropagation()}>
<div className={style.modal_header_container}>
<div className={style.modal_header_wrapper}>
<div className={style.modal_header}>Help Request Info</div>
<button onClick={handleClose} className={style.modal_close}>
<IoClose size={25} />
</button>
</div>
</div>

<div>
<form>
<div className={style.modal_form_container}>
{Object.entries(helpRequestInfo).map(([key, value], index) => (
<Fragment key={key}>
<div className={style.modal_form_label}>
{formatLabel(key)}
</div>
<div className={style.modal_form_data}>
{key === 'images' ? (
<div className="grid grid-cols-1 gap-y-4">
{(Array.isArray(value) ? value : [value]).map(
(image, imgIndex) => (
<Link
key={imgIndex}
href={image}
passHref={true}
target="_blank">
<Image
src={`${image}`}
width={100}
height={100}
className="w-auto"
alt={`image-${imgIndex}`}
/>
</Link>
),
)}
</div>
) : key === 'email' ? (
<Link
href={`mailto:${value}`}
target="_blank"
className="underline">
{value}
</Link>
) : (
<span>{value}</span>
)}
</div>
</Fragment>
))}
</div>
</form>
</div>
</div>
</div>
</div>
)
}

export default HelpRequestsModal
20 changes: 11 additions & 9 deletions pages/dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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)
Expand Down Expand Up @@ -108,6 +109,7 @@ const Dashboard = () => {
{tab == 4 && customClaims.admin && (
<Agencies handleAgencyUpdateSubmit={handleAgencyUpdateSubmit} />
)}
{tab == 5 && customClaims.admin && <HelpRequests />}
</div>
{/* Render the NewReportModal */}
{newReportModal && (
Expand Down

0 comments on commit efbd7fe

Please sign in to comment.