diff --git a/src/components/Accounts/ApprovedAccounts.jsx b/src/components/Accounts/ApprovedAccounts.jsx index 927c1b4..d2de376 100644 --- a/src/components/Accounts/ApprovedAccounts.jsx +++ b/src/components/Accounts/ApprovedAccounts.jsx @@ -1,67 +1,177 @@ import { NPOBackend } from '../../utils/auth_utils.js'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, useCallback } from 'react'; import { Box, Table, Thead, Tbody, Tr, Th, Td, TableContainer, Button, Checkbox, useDisclosure } from '@chakra-ui/react' import { CloseIcon } from '@chakra-ui/icons' import DeleteAccountModal from './DeleteAccountModal.jsx'; import PropTypes from 'prop-types'; +import PaginationFooter from "../../components/Catalog/PaginationFooter/PaginationFooter"; +import { usePagination } from '@ajna/pagination'; -const ApprovedAccounts = ( {accountType} ) => { +const ApprovedAccounts = ( {accountType, searchQuery} ) => { const [approvedAccounts, setApprovedAccounts] = useState([]); const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onClose: onDeleteClose } = useDisclosure(); - const [deleteItemId, setDeleteItemId] = useState(""); + const [deleteItemId, setDeleteItemId] = useState([]); + const [totalRowCount, setTotalRowCount] = useState(0); + const { currentPage, setCurrentPage, pagesCount, offset, pageSize, setPageSize} = usePagination({ + initialState: { currentPage: 1, pageSize: 10 }, + total: totalRowCount, + }); + const [individualChecked, setIndividualChecked] = useState(new Array(approvedAccounts.length).fill(false)); + const [checkedAccountIds, setCheckedAccountIds] = useState([]); + const [dataShouldRevalidate, setDataShouldRevalidate] = useState(false); + + const fetchTableData = useCallback(async () => { + try { + const { data } = await NPOBackend.get(`/users/approved-accounts`, { + params: { + keyword: (searchQuery && searchQuery.length) && searchQuery, + page: currentPage, + limit: pageSize, + accountType: accountType} + }); + setApprovedAccounts(data.accounts); + setTotalRowCount(Number(data.count[0].count)); + } catch (error) { + console.error('Error fetching data:', error); + } + }, [searchQuery, currentPage, pageSize, accountType]); + + useEffect(() => { + fetchTableData(); + }, [fetchTableData]); + + useEffect(() => { + if (dataShouldRevalidate) { + fetchTableData(); + setDataShouldRevalidate(false); + setIndividualChecked(new Array(totalRowCount).fill(false)); + setCheckedAccountIds([]); + } + }, [dataShouldRevalidate, fetchTableData, totalRowCount]); + + useEffect(() => { + setCurrentPage(1); + }, [searchQuery, setCurrentPage, pageSize]); useEffect(() => { - const renderTable = async () => { - const { data } = await NPOBackend.get('/users/approved-accounts'); - setApprovedAccounts(data); - }; - renderTable(); - }, [approvedAccounts]) + setIndividualChecked(new Array(totalRowCount).fill(false)); + setCheckedAccountIds([]); + }, [searchQuery, currentPage, totalRowCount]); const handleDeleteClick = id => { setDeleteItemId(id); onDeleteOpen(); } + const updateAllCheckedAccountIds = (e) => { + setIndividualChecked(new Array(approvedAccounts.length).fill(e.target.checked)); + if (e.target.checked) { + let allIds = []; + for (let i = 0; i < approvedAccounts.length; i++) { + allIds.push(approvedAccounts[i].id) + } + setCheckedAccountIds(allIds); + } else { + setCheckedAccountIds([]); + } + } + + const updateIndividualCheckedAccountIds = (e, id, index) => { + const newIndividualChecked = [...individualChecked]; + newIndividualChecked[index] = e.target.checked; + setIndividualChecked(newIndividualChecked); + let newCheckedAccountIds = [... checkedAccountIds]; + if (e.target.checked) { + newCheckedAccountIds.push(id); + setCheckedAccountIds(newCheckedAccountIds); + } else { + let index = newCheckedAccountIds.indexOf(id); + newCheckedAccountIds.splice(index, 1); + setCheckedAccountIds(newCheckedAccountIds); + } + } + return ( - - - - - - - - - - - - { - approvedAccounts.map((account, i) => ( - accountType === account.type ? ( - - - - - - - ) : ( - <> - ) - )) + +
NameEmailDeactivate
{account.firstName} {account.lastName}{account.email} - -
+ + + + + + + {checkedAccountIds.length > 0 && + + } + + + + { + approvedAccounts.map((account, i) => ( + + + + + {checkedAccountIds.length > 0 && + } - -
{ updateAllCheckedAccountIds(e) }}/>NameEmailDeactivate + +
+ { updateIndividualCheckedAccountIds(e, account.id, i)}}> + + {account.firstName} {account.lastName}{account.email}
-
- + + + + + )) + } + + + + +
) } ApprovedAccounts.propTypes = { accountType: PropTypes.string.isRequired, + searchQuery: PropTypes.string }; -export default ApprovedAccounts; \ No newline at end of file +export default ApprovedAccounts; diff --git a/src/components/Accounts/DeleteAccountModal.jsx b/src/components/Accounts/DeleteAccountModal.jsx index 040ef34..dc15679 100644 --- a/src/components/Accounts/DeleteAccountModal.jsx +++ b/src/components/Accounts/DeleteAccountModal.jsx @@ -11,11 +11,14 @@ import { } from '@chakra-ui/react'; import { NPOBackend } from '../../utils/auth_utils.js'; -const DeleteAccountModal = ({ isOpen, onClose, deleteItemId}) => { +const DeleteAccountModal = ({ isOpen, onClose, deleteItemId, setDataShouldRevalidate}) => { const handleConfirmDelete = async idToDelete => { try { - await NPOBackend.delete(`/users/${idToDelete}`); + for (let i = 0; i < idToDelete.length; i++) { + await NPOBackend.delete(`/users/${idToDelete[i]}`); + } onClose(); + setDataShouldRevalidate(true); } catch (error) { console.error(error); } @@ -30,7 +33,7 @@ const DeleteAccountModal = ({ isOpen, onClose, deleteItemId}) => { Are you sure? You cannot undo this action afterwards. - + @@ -40,7 +43,8 @@ const DeleteAccountModal = ({ isOpen, onClose, deleteItemId}) => { DeleteAccountModal.propTypes = { isOpen: PropTypes.bool.isRequired, onClose: PropTypes.func.isRequired, - deleteItemId: PropTypes.string.isRequired, + deleteItemId: PropTypes.array.isRequired, + setDataShouldRevalidate: PropTypes.func.isRequired }; export default DeleteAccountModal; diff --git a/src/components/Accounts/PendingAccounts.jsx b/src/components/Accounts/PendingAccounts.jsx index bd775ae..52e71c8 100644 --- a/src/components/Accounts/PendingAccounts.jsx +++ b/src/components/Accounts/PendingAccounts.jsx @@ -4,60 +4,182 @@ import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Button } from '@chakra import { Checkbox } from '@chakra-ui/react' import PropTypes from 'prop-types'; -const PendingAccounts = ( {accountType} ) => { +const PendingAccounts = ( {accountType, setHasPendingAccounts} ) => { const [pendingAccounts, setPendingAccounts] = useState([]); + const [individualChecked, setIndividualChecked] = useState(new Array(pendingAccounts.length).fill(false)); + const [checkedAccountIds, setCheckedAccountIds] = useState([]); + const [accountStatus, setAccountStatus] = useState({}); + useEffect(() => { const renderTable = async () => { - const { data } = await NPOBackend.get('/users/pending-accounts'); + const { data } = await NPOBackend.get('/users/pending-accounts', {params: {accountType: accountType}}); setPendingAccounts(data); + setHasPendingAccounts(data.length !== 0); }; renderTable(); + }, [accountType, setHasPendingAccounts]) + + useEffect(() => { + const newAccountStatus = {} + for (let i = 0; i < pendingAccounts.length; i++) { + newAccountStatus[pendingAccounts[i]["id"]] = "pending"; + } + setAccountStatus(newAccountStatus); }, [pendingAccounts]) - const handleApproveUser = async (id) => { + const changeStatus = ((accountid, status) => { + let newAccountStatus = {...accountStatus}; + newAccountStatus[accountid] = status; + setAccountStatus(newAccountStatus); + }); + + const handleApproveDeclineUser = async (ids, option) => { try { - await NPOBackend.put(`/users/approve/${id}`); + for (let i = 0; i < ids.length; i++) { + if (option === "approve-option") { + await NPOBackend.put(`/users/approve/${ids[i]}`); + } + else if (option === "decline-option") { + await NPOBackend.delete(`/users/${ids[i]}`); + } + } + setIndividualChecked(new Array(pendingAccounts.length).fill(false)); } catch (error) { console.log(error); } } - const handleDeleteUser = async (id) => { - try { - await NPOBackend.delete(`/users/${id}`); - } catch (error) { - console.log(error); + const updateAllIndividualChecked = (e) => { + let newIndividualChecked = []; + for (let i = 0; i < pendingAccounts.length; i++) { + if (accountStatus[pendingAccounts[i].id] === "pending") { + newIndividualChecked.push(e.target.checked); + } + else { + newIndividualChecked.push(false); + } + } + setIndividualChecked(newIndividualChecked); + } + + const updateAllCheckedAccountIds = (e) => { + if (e.target.checked) { + let allIds = []; + for (let i = 0; i < pendingAccounts.length; i++) { + if (accountStatus[pendingAccounts[i].id] === "pending") { + allIds.push(pendingAccounts[i].id); + } + } + setCheckedAccountIds(allIds); + } else { + setCheckedAccountIds([]); + } + } + + const updateIndividualCheckedAccountIds = (e, id, index) => { + const newIndividualChecked = [...individualChecked]; + newIndividualChecked[index] = e.target.checked; + setIndividualChecked(newIndividualChecked); + let newCheckedAccountIds = [... checkedAccountIds]; + if (e.target.checked) { + newCheckedAccountIds.push(id); + setCheckedAccountIds(newCheckedAccountIds); + } else { + let index = newCheckedAccountIds.indexOf(id); + newCheckedAccountIds.splice(index, 1); + setCheckedAccountIds(newCheckedAccountIds); + } + } + + const acceptDeclineAllClick = (option) => { + handleApproveDeclineUser(checkedAccountIds, option); + const newAccountStatus = {... accountStatus}; + for (let i = 0; i < checkedAccountIds.length; i++) { + newAccountStatus[checkedAccountIds[i]] = option === "approve-option" ? "approved" : "declined"; } + setAccountStatus(newAccountStatus); + setCheckedAccountIds([]); } return ( - + - - - - + + + + + {checkedAccountIds.length > 0 && + + } { pendingAccounts.map((account, i) => ( - accountType === account.type ? ( - - - - - + + + + {checkedAccountIds.length > 0 && + + } + { + accountStatus[account.id] === "pending" ? ( + - - ) : ( - <> - ) + ) : accountStatus[account.id] === "approved" ? ( + + ) : ( + + ) + } + ) ) } @@ -69,6 +191,7 @@ const PendingAccounts = ( {accountType} ) => { PendingAccounts.propTypes = { accountType: PropTypes.string.isRequired, + setHasPendingAccounts: PropTypes.func.isRequired }; -export default PendingAccounts; \ No newline at end of file +export default PendingAccounts; diff --git a/src/components/AddDayForm/AddDayForm.jsx b/src/components/AddDayForm/AddDayForm.jsx index 1313b4a..c9d88f4 100644 --- a/src/components/AddDayForm/AddDayForm.jsx +++ b/src/components/AddDayForm/AddDayForm.jsx @@ -19,10 +19,10 @@ import { NPOBackend } from '../../utils/auth_utils'; const schema = yup.object({ date: yup.date().nullable().transform((curr, orig) => orig === '' ? null : curr).required('Date required'), - location: yup.string().required('Location required').max(50, 'Location exceeds 50 character limit'), + location: yup.string().required('Location required').max(100, 'Location exceeds 100 character limit'), details: yup .string() - .max(50, 'Details exceeds 50 character limit'), + .max(200, 'Details exceeds 200 character limit'), }); const AddDayForm = ({ onClose, onOpen, setDayId, dayData, setShouldDataRevalidate }) => { diff --git a/src/components/AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm.jsx b/src/components/AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm.jsx index 35b3ab7..4f875f4 100644 --- a/src/components/AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm.jsx +++ b/src/components/AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm.jsx @@ -12,7 +12,9 @@ import { Heading, Flex, Text, - Stack + HStack, + useDisclosure, + Spacer } from '@chakra-ui/react'; import { yupResolver } from '@hookform/resolvers/yup'; import { useForm } from 'react-hook-form'; @@ -30,14 +32,19 @@ import Dropdown from '../Dropdown/Dropdown'; import PropTypes from 'prop-types'; import { PlannerContext } from '../Planner/PlannerContext'; import PlannedEvent, { convertTimeToMinutes } from '../Planner/PlannedEvent'; +import RemoveTimelineEventModal from '../Planner/RemoveTimelineEventModal'; const schema = yup.object({ - startTime: yup.string().required('Start time is required'), + startTime: yup.string().required('Start time is required').test('is-after-7-am', 'Start time cannot be earlier than 7 AM', function(startTime) { + return startTime && startTime >= "07:00"; + }), endTime: yup.string() .required('End time is required') .test('is-after', 'End time must be after start time', function(endTime) { const startTime = this.parent.startTime; return startTime && endTime && startTime < endTime; + }).test('is-before-11-pm', 'End time must be earlier than 11 PM', function(endTime) { + return endTime && endTime <= "23:00"; }), host: yup.string().max(50, 'Host exceeds 50 character limit').default('').nullable(), title: yup.string().required('Title Required').max(50, 'Title exceeds 50 character limit'), @@ -58,6 +65,7 @@ const AddEventToPublishedScheduleForm = ({ closeForm }) => { const [seasonFilter, yearFilter, subjectFilter, eventFilter] = filters; const [checkboxVal, setCheckboxVal] = useState(undefined); const [formData, setFormData] = useState({...eventData}); + const { isOpen: isRemoveOpen, onOpen: onRemoveOpen, onClose: onRemoveClose } = useDisclosure(); useEffect(() => { if (Object.keys(eventData).length === 0) { @@ -85,7 +93,7 @@ const AddEventToPublishedScheduleForm = ({ closeForm }) => { }, [eventData]); useEffect(() => { - if (formData.startTime && formData.endTime && formData.startTime < formData.endTime) { + if (formData.startTime && formData.endTime && formData.startTime < formData.endTime && formData.startTime >= "07:00" && formData.endTime <= "23:00") { // if (isEdit) { // // setPlannedEvents([...plannedEvents.filter(e => e.id != -1 && e.id != eventData.id)]); // } @@ -265,7 +273,7 @@ const AddEventToPublishedScheduleForm = ({ closeForm }) => { return ( -
+ Event Information @@ -431,11 +439,16 @@ const AddEventToPublishedScheduleForm = ({ closeForm }) => {
- - - - + + {isEdit && + + } + + + + + ); }; diff --git a/src/components/Authentication/SignUp.jsx b/src/components/Authentication/SignUp.jsx index 95a1c98..5b9168c 100644 --- a/src/components/Authentication/SignUp.jsx +++ b/src/components/Authentication/SignUp.jsx @@ -6,7 +6,7 @@ import emailtemplate from '../EmailTemplates/emailtemplate'; import { Box, Heading, Text, FormControl, Button, Center, Link, Input, Alert, AlertDescription } from '@chakra-ui/react'; import AUTH_ROLES from '../../utils/auth_config'; -const { USER_ROLE } = AUTH_ROLES.AUTH_ROLES; +const { ADMIN_ROLE, USER_ROLE } = AUTH_ROLES.AUTH_ROLES; const SignUp = () => { const [firstName, setFirstName] = useState(); @@ -45,7 +45,7 @@ const SignUp = () => { } // register email and password - await registerWithEmailAndPassword(email, password, USER_ROLE, navigate, '/awaitConfirmation', firstName, lastName); + await registerWithEmailAndPassword(email, password, userType, navigate, '/awaitConfirmation', firstName, lastName); // send email to Debbie const subject = "New User Created Account"; @@ -86,7 +86,7 @@ const SignUp = () => { }} > - - - )} + {!confirmEvent && ( + + +
+
+ +
+
+ )} @@ -138,13 +135,7 @@ const DailyEvent = ({ id, startTime, endTime, eventTitle, confirmed, description }; DailyEvent.propTypes = { - id: PropTypes.number.isRequired, - startTime: PropTypes.string.isRequired, - endTime: PropTypes.string.isRequired, - eventTitle: PropTypes.string.isRequired, - description: PropTypes.string, - confirmed: PropTypes.bool.isRequired, - eventId: PropTypes.number.isRequired, + event: PropTypes.object.isRequired, }; export default DailyEvent; diff --git a/src/components/Events/Events.jsx b/src/components/Events/Events.jsx index 56da337..e4975b5 100644 --- a/src/components/Events/Events.jsx +++ b/src/components/Events/Events.jsx @@ -2,21 +2,8 @@ import DailyEvent from './DailyEvent.jsx'; import PropTypes from 'prop-types'; import { Grid } from '@chakra-ui/react'; - const Events = ({ eventData }) => { - // console.log("Event Data", eventData); - - const formatDate = (date) => { - let time = date.split(":"); - let hours = time[0]; - let mins = time[1]; - let ampm = hours >= 12 ? 'pm' : 'am'; - hours = hours % 12; - hours = hours ? hours : 12; - return `${hours}:${mins} ${ampm}`; - } - let maxId = eventData.reduce((maxVal, event) => Math.max(maxVal, event.id), -Infinity)+1; eventData.sort((a, b) => { @@ -62,19 +49,13 @@ const Events = ({ eventData }) => { if (eventData.length > 1) { eventDataWithBreaks.push(eventData[eventData.length - 1]); } - // console.log(eventDataWithBreaks); + return ( {eventDataWithBreaks.map(item => ( ))} diff --git a/src/components/Events/PublishedScheduleTable.jsx b/src/components/Events/PublishedScheduleTable.jsx index f6ec432..bc82adf 100644 --- a/src/components/Events/PublishedScheduleTable.jsx +++ b/src/components/Events/PublishedScheduleTable.jsx @@ -38,7 +38,7 @@ const PublishedScheduleTable = ({ season, allSeasons }) => { renderTable(); setShouldDataRevalidate(false); } - }, [dataShouldRevalidate]) + }, [dataShouldRevalidate, renderTable]) const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index d53032a..b14f347 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -34,7 +34,7 @@ const Navbar = ({ hasLoaded, isAdmin }) => { ); }; - if (!hasLoaded) { + if (!hasLoaded || location.pathname == '/login') { return null; } diff --git a/src/components/Planner/EmptyDayModal.jsx b/src/components/Planner/EmptyDayModal.jsx new file mode 100644 index 0000000..60a48f4 --- /dev/null +++ b/src/components/Planner/EmptyDayModal.jsx @@ -0,0 +1,51 @@ +import PropTypes from 'prop-types'; +import { + Button, + Modal, + ModalBody, + ModalContent, + ModalOverlay, + ModalHeader, + ModalCloseButton, + ModalFooter, +} from '@chakra-ui/react'; +import { NPOBackend } from '../../utils/auth_utils'; +import { useContext } from 'react'; +import { PlannerContext } from './PlannerContext'; + +const EmptyDayModal = ({ isOpen, onClose, onClosePlanner }) => { + const { dayId } = useContext(PlannerContext); + + const handleConfirmDelete = async () => { + try { + await NPOBackend.delete(`/day/${dayId}`); + onClose(); + onClosePlanner(); + } catch (error) { + console.error(error); + } + }; + + return ( + + + + Warning + + No events have been added, this day will not be saved. + + + + + + + ); +}; + +EmptyDayModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + onClosePlanner: PropTypes.func.isRequired, +}; + +export default EmptyDayModal; diff --git a/src/components/Planner/PlannedEvent.js b/src/components/Planner/PlannedEvent.js index e69d2be..966307b 100644 --- a/src/components/Planner/PlannedEvent.js +++ b/src/components/Planner/PlannedEvent.js @@ -1,7 +1,7 @@ import { MINUTES_PER_HOUR } from './chrono'; export default class PlannedEvent { - static EARLIEST_HOUR = 6; // 6:00 AM (6:00 military) + static EARLIEST_HOUR = 7; // 7:00 AM (7:00 military) static LATEST_HOUR = 22; // 10:00 PM (22:00 military time) id; // string name; // string diff --git a/src/components/Planner/PlannerEvents/PlannerEvents.jsx b/src/components/Planner/PlannerEvents/PlannerEvents.jsx index b38a511..f2048f5 100644 --- a/src/components/Planner/PlannerEvents/PlannerEvents.jsx +++ b/src/components/Planner/PlannerEvents/PlannerEvents.jsx @@ -6,8 +6,9 @@ import Catalog from '../../../pages/Catalog/Catalog'; import PropTypes from 'prop-types'; import { PlannerContext } from '../PlannerContext'; import { NPOBackend } from '../../../utils/auth_utils'; -import AddEventToPublishedScheduleForm from '../../AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm'; import AddDayModal from '../../../pages/PublishedSchedule/AddDayModal'; +import AddEventToPublishedScheduleForm from '../../AddEventToPublishedScheduleForm/AddEventToPublishedScheduleForm'; +import EmptyDayModal from '../EmptyDayModal'; const PlannerEvents = ({ onClose }) => { const [isAddingEvent, setIsAddingEvent] = useState(false); @@ -15,6 +16,7 @@ const PlannerEvents = ({ onClose }) => { const [dateHeader, setDateHeader] = useState(''); const [dayData, setDayData] = useState({}); const { isOpen: isOpenDay, onOpen: onOpenDay, onClose: onCloseDay } = useDisclosure(); + const { isOpen: isOpenEmptyDay, onOpen: onOpenEmptyDay, onClose: onCloseEmptyDay } = useDisclosure(); const { plannedEventsContext, dayId, editContext, currEventContext } = useContext(PlannerContext); const [isEdit, setIsEdit] = editContext; @@ -71,23 +73,19 @@ const PlannerEvents = ({ onClose }) => { const closeModal = async () => { // delete day if empty if (plannedEvents.length === 0) { - try { - console.log('deleting day!!') - await NPOBackend.delete(`/day/${dayId}`); - } catch (error) { - console.error(error); - } + onOpenEmptyDay(); + } else { + onClose(); } - onClose(); } return (
{/* {overlayIsVisible && } */}
- + {(isAddingEvent || isEdit) && + + } +
); diff --git a/src/components/Planner/PlannerLayout.module.css b/src/components/Planner/PlannerLayout.module.css index 0799c47..8b2698e 100644 --- a/src/components/Planner/PlannerLayout.module.css +++ b/src/components/Planner/PlannerLayout.module.css @@ -52,7 +52,7 @@ } .grid-hour-container { - min-height: 64px; + min-height: 128px; position: relative; border-top: 2px solid var(--chakra-colors-blackAlpha-400); } diff --git a/src/components/Planner/PlannerTimeline/PlannerTimeline.jsx b/src/components/Planner/PlannerTimeline/PlannerTimeline.jsx index 6a4f659..47a982e 100644 --- a/src/components/Planner/PlannerTimeline/PlannerTimeline.jsx +++ b/src/components/Planner/PlannerTimeline/PlannerTimeline.jsx @@ -1,24 +1,18 @@ import s from '../PlannerLayout.module.css'; -import { useMemo, useContext, useEffect, useState } from 'react'; +import { useMemo, useContext, useEffect } from 'react'; import { generateTimestamps, minutesInFormattedTime } from '../chrono'; -import { Badge, Text, Box, IconButton, HStack, useDisclosure } from '@chakra-ui/react'; -import { DeleteIcon, EditIcon } from '@chakra-ui/icons'; +import { Badge, Text, Box, HStack } from '@chakra-ui/react'; import { PlannerContext } from '../PlannerContext'; import PlannedEvent, { convertTimeToMinutes } from '../PlannedEvent'; import { NPOBackend } from '../../../utils/auth_utils'; -// import PropTypes from 'prop-types'; -import RemoveTimelineEventModal from '../RemoveTimelineEventModal'; + const PlannerTimeline = () => { const { plannedEventsContext, dayId, currEventContext, editContext } = useContext(PlannerContext); - const { isOpen: isRemoveOpen, onOpen: onRemoveOpen, onClose: onRemoveClose } = useDisclosure(); const [plannedEvents, setPlannedEvents] = plannedEventsContext; const [eventData, setCurrEvent] = currEventContext; const [isEdit, setIsEdit] = editContext; - const [eventHover, setEventHover] = useState(-2); - const [deleteItemId, setDeleteItemId] = useState(-1); - //const [addedEvents, setAddedEvents] = useState([]); const addedEvents = []; @@ -113,9 +107,14 @@ const PlannerTimeline = () => { const formattedEndTime = minutesInFormattedTime(endTime); let border_color = '#2B93D1'; + let text_color = '#1A202C'; + let hover_text_color = '#171923'; + let hover_tentative_text_color = '#652B19'; let background_color = '#BEE3F8'; - let border_style = 'none none none solid'; - const border_width = '2px 2px 2px 10px' + let hover_background_color = '#90CDF4'; + let hover_tentative_background_color = '#FBD38D'; + let border_style = 'solid solid solid solid'; + const border_width = '1px 1px 1px 10px' if (isTentative) { border_color = '#F69052'; @@ -135,11 +134,15 @@ const PlannerTimeline = () => { setEventHover(id)} - onMouseLeave={() => setEventHover(-2)} + onClick={() => startEditAndSetCurrEventId(id)} > @@ -153,32 +156,11 @@ const PlannerTimeline = () => { {hostName} - {id == eventHover && - - } - onClick={() => startEditAndSetCurrEventId(id)} - size="sm" - /> - } - onClick={() => { - setDeleteItemId(id); - onRemoveOpen(); - }} - size="sm" - /> - {/* */} - - } ); })} - ); diff --git a/src/components/Planner/RemoveTimelineEventModal.jsx b/src/components/Planner/RemoveTimelineEventModal.jsx index 16860b0..a52d846 100644 --- a/src/components/Planner/RemoveTimelineEventModal.jsx +++ b/src/components/Planner/RemoveTimelineEventModal.jsx @@ -14,10 +14,11 @@ import { NPOBackend } from '../../utils/auth_utils'; import { useContext } from 'react'; import { PlannerContext } from './PlannerContext'; -const RemoveTimelineEventModal = ({ isOpen, onClose, deleteItemId }) => { +const RemoveTimelineEventModal = ({ isOpen, onClose, deleteItemId, closeForm }) => { - const { plannedEventsContext } = useContext(PlannerContext); + const { plannedEventsContext, currEventContext } = useContext(PlannerContext); const [plannedEvents, setPlannedEvents] = plannedEventsContext; + const setCurrEvent = currEventContext[1]; const toast = useToast(); @@ -38,8 +39,10 @@ const RemoveTimelineEventModal = ({ isOpen, onClose, deleteItemId }) => { duration: 3000, isClosable: true, }); - // setDataShouldRevalidate(true); onClose(); + + setCurrEvent({}); + closeForm(); } catch (error) { console.error(error); } @@ -67,6 +70,7 @@ RemoveTimelineEventModal.propTypes = { isOpen: PropTypes.bool.isRequired, onClose: PropTypes.func.isRequired, deleteItemId: PropTypes.number.isRequired, + closeForm: PropTypes.func, }; export default RemoveTimelineEventModal; diff --git a/src/pages/Accounts/Accounts.jsx b/src/pages/Accounts/Accounts.jsx index 6b65ef8..8d14e15 100644 --- a/src/pages/Accounts/Accounts.jsx +++ b/src/pages/Accounts/Accounts.jsx @@ -1,33 +1,88 @@ import PendingAccounts from "../../components/Accounts/PendingAccounts"; import ApprovedAccounts from "../../components/Accounts/ApprovedAccounts"; -import { Box, Heading, Tabs, TabList, TabPanels, Tab, TabPanel} from '@chakra-ui/react' +import { Box, Heading, Tabs, TabList, TabPanels, Tab, TabPanel, Input, InputGroup, InputLeftElement, HStack, Center } from '@chakra-ui/react' +import { SearchIcon } from '@chakra-ui/icons'; +import { useState } from 'react'; const Accounts = () => { + const [approvedAdminKeyword, setApprovedAdminKeyword] = useState(""); + const [approvedStudentKeyword, setApprovedStudentKeyword] = useState(""); + const [hasAdminPendingAccounts, setHasAdminPendingAccounts] = useState(true); + const [hasStudentPendingAccounts, setHasStudentPendingAccounts] = useState(true); + return ( - + +
- + Admins Students - Pending Accounts - - Accounts - + { hasAdminPendingAccounts ? ( + <> + + Pending + + + + ) : <> + } + + Accounts + + + + + + setApprovedAdminKeyword(e.target.value)} + /> + + + + - Pending Accounts - - Accounts - + { hasStudentPendingAccounts ? ( + + Pending + + + ): <> + } + + Accounts + + + + + + setApprovedStudentKeyword(e.target.value)} + /> + + + + +
); } -export default Accounts; \ No newline at end of file +export default Accounts; diff --git a/src/pages/Catalog/Catalog.jsx b/src/pages/Catalog/Catalog.jsx index 3a4517b..859155c 100644 --- a/src/pages/Catalog/Catalog.jsx +++ b/src/pages/Catalog/Catalog.jsx @@ -54,7 +54,7 @@ export default function Catalog({ onDayPlanner, addExistingEventFunc, setCurrEve const { currentPage, setCurrentPage, pagesCount, offset, pageSize, setPageSize } = usePagination({ initialState: { currentPage: 1, pageSize: 10 }, - pagesCount: Math.ceil(totalRowCount / 10), + total: totalRowCount }); // const handleEditForm = data => { @@ -116,7 +116,7 @@ export default function Catalog({ onDayPlanner, addExistingEventFunc, setCurrEve // Reset pagination on filter change useEffect(() => { setCurrentPage(1); - }, [filterValues, setCurrentPage]); + }, [filterValues, setCurrentPage, pageSize, searchTerm]); return ( diff --git a/src/pages/PublishedSchedule/PublishedSchedule.jsx b/src/pages/PublishedSchedule/PublishedSchedule.jsx index 035b21e..1f80f04 100644 --- a/src/pages/PublishedSchedule/PublishedSchedule.jsx +++ b/src/pages/PublishedSchedule/PublishedSchedule.jsx @@ -11,6 +11,7 @@ const PublishedSchedule = () => { const {currentUser} = useAuthContext(); const [allSeasons, setAllSeasons] = useState([]); const [selectedSeason, setSelectedSeason] = useState(''); + const [seasonHover, setSeasonHover] = useState(false); const getTodaySeason = () => { let today = new Date(); @@ -61,22 +62,25 @@ const PublishedSchedule = () => { return ( {selectedSeason != '' ? ( - + {selectedSeason} ) : ( - + {curSeason} )}
NameEmailAction {updateAllIndividualChecked(e); updateAllCheckedAccountIds(e);}}/>NameEmailAction + + +
{account.firstName} {account.lastName}{account.email} - - +
{updateIndividualCheckedAccountIds(e, account.id, i);}}> + + {account.firstName} {account.lastName}{account.email} + +
ApprovedDeclined