diff --git a/src/App.jsx b/src/App.jsx index 1ac716d..adfdb17 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -19,13 +19,14 @@ import { AuthProvider } from './contexts/AuthContext'; import ProtectedRoute from './utils/ProtectedRoute.jsx'; import ViewBusiness from './components/ViewBusiness/ViewBusiness.jsx'; import BusinessForm from './components/BusinessForm/BusinessForm.jsx'; +import ViewDonation from './components/ViewDonation/ViewDonation.jsx'; const App = () => { return (
- +
Welcome to the App
} /> @@ -97,6 +98,11 @@ const App = () => { path="/EditBusiness/:id" element={} /> + } + />
diff --git a/src/components/DonationTrackingTable/DonationSite.jsx b/src/components/DonationTrackingTable/DonationSite.jsx index 5db5782..a93a38c 100644 --- a/src/components/DonationTrackingTable/DonationSite.jsx +++ b/src/components/DonationTrackingTable/DonationSite.jsx @@ -1,10 +1,11 @@ /* eslint react/prop-types: 0 */ import { Tr, Td, Checkbox } from '@chakra-ui/react'; import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; const DonationSite = ({ donation_site, checkSet, setCheck, topCheckBox }) => { const [individualCheckBox, setIndividualCheckBox] = useState(topCheckBox); - + const navigate = useNavigate(); useEffect(() => { setIndividualCheckBox(topCheckBox); }, [topCheckBox]); @@ -40,6 +41,10 @@ const DonationSite = ({ donation_site, checkSet, setCheck, topCheckBox }) => { } }; + const handleRowClick = async id => { + navigate(`/ViewDonation/${id}`); + }; + return ( { sx={{ top: '15px', padding: '0 10px' }} /> {headers.map((header, index) => ( - {header} + handleRowClick(donation_site.donation_id)}>{header} ))} ); diff --git a/src/components/EditContactInformation.jsx b/src/components/EditContactInformation.jsx index 6de325d..1e73d3e 100644 --- a/src/components/EditContactInformation.jsx +++ b/src/components/EditContactInformation.jsx @@ -13,12 +13,19 @@ import { Tabs, TabList, Tab, + useToast, + TabPanels, + TabPanel, } from '@chakra-ui/react'; import { useEffect, useState } from 'react'; import { useBackend } from '../contexts/BackendContext'; +import ReferenceGuide from '../components/ReferenceGuide.jsx'; + const EditContactInformation = () => { const BUSINESS_ID = 1; // hard coded business_id constant for development purposes const { backend } = useBackend(); + const [toastOpen, setToastOpen] = useState(false); + const toast = useToast(); const [businessContactInfo, setBusinessContactInfo] = useState({ businessName: '', @@ -34,27 +41,65 @@ const EditContactInformation = () => { business_hours: '', }); + const [initialBusinessContactInfo, setInitialBusinessContactInfo] = useState({ + businessName: '', + phoneNumber: '', + email: '', + website: '', + street: '', + firstName: '', + lastName: '', + zip: '', + state: '', + city: '', + business_hours: '', + }); + + function showToast() { + if (!toastOpen) { + setToastOpen(true); + toast({ + title: 'Unsaved Changes', + description: 'You have unsaved changes', + status: 'warning', + duration: 9000, + position: 'bottom-right', + onCloseComplete: () => setToastOpen(false), + }); + } + } + const handleChange = event => { const name = event.target.name; var value = event.target.value; - setBusinessContactInfo(prevState => ({ ...prevState, [name]: value })); + showToast(); }; const updateContactInfo = async () => { try { + setInitialBusinessContactInfo(businessContactInfo); await backend.put(`/business/${BUSINESS_ID}`, { - business_name: businessContactInfo.businessName, + name: businessContactInfo.businessName, contact_name: `${businessContactInfo.firstName} ${businessContactInfo.lastName}`, - contact_phone: businessContactInfo.phoneNumber, + primary_phone: businessContactInfo.phoneNumber, primary_email: businessContactInfo.email, website: businessContactInfo.website, street: businessContactInfo.street, - zip: businessContactInfo.zip, + zip_code: businessContactInfo.zip, city: businessContactInfo.city, state: businessContactInfo.state, business_hours: businessContactInfo.business_hours, }); + + return toast({ + title: 'Saved Changes', + description: 'Your changes have been saved', + status: 'success', + duration: 9000, + position: 'bottom-right', + onCloseComplete: () => setToastOpen(false), + }); } catch (error) { console.error('Error updating data:', error); } @@ -82,6 +127,20 @@ const EditContactInformation = () => { zip: businessContact.zip_code, business_hours: businessContact.business_hours, }); + + setInitialBusinessContactInfo({ + businessName: businessContact.name, + phoneNumber: businessContact.contact_phone, + email: businessContact.primary_email, + website: businessContact.website, + street: businessContact.street, + firstName: firstName, + lastName: lastName, + city: businessContact.city, + state: businessContact.state, + zip: businessContact.zip_code, + business_hours: businessContact.business_hours, + }); } catch (error) { console.error('Error fetching data:', error); } @@ -92,225 +151,240 @@ const EditContactInformation = () => { return ( <> - - + + Settings - + - + Business - Donation Site Kit + Reference Guide + + + + + + + BUSINESS NAME + + { + setBusinessContactInfo({ + ...businessContactInfo, + businessName: e.target.value, + }); + showToast(); + }} + /> + + + + NAME + + + + + + + EMAIL + + + + + + WEBSITE + + + + + + LOCATION + + + + + + { + setBusinessContactInfo({ ...businessContactInfo, city: e.target.value }); + showToast(); + }} + /> + { + setBusinessContactInfo({ ...businessContactInfo, state: e.target.value }); + showToast(); + }} + /> + { + setBusinessContactInfo({ ...businessContactInfo, zip: e.target.value }); + showToast(); + }} + /> + + + + PHONE + + + + + + BUSINESS HOURS + + { + setBusinessContactInfo({ + ...businessContactInfo, + business_hours: e.target.value, + }); + showToast(); + }} + /> + + + + + + + + + + + + - - - - - BUSINESS NAME - - { - setBusinessContactInfo({ - ...businessContactInfo, - businessName: e.target.value, - }); - }} - /> - - - - NAME - - - - - - - EMAIL - - - - - - WEBSITE - - - - - - LOCATION - - - - - - { - setBusinessContactInfo({ ...businessContactInfo, city: e.target.value }); - }} - /> - { - setBusinessContactInfo({ ...businessContactInfo, state: e.target.value }); - }} - /> - { - setBusinessContactInfo({ ...businessContactInfo, zip: e.target.value }); - }} - /> - - - - PHONE - - - - - - BUSINESS HOURS - - { - setBusinessContactInfo({ - ...businessContactInfo, - business_hours: e.target.value, - }); - }} - /> - - - - - - - - - diff --git a/src/components/ReferenceGuide.jsx b/src/components/ReferenceGuide.jsx new file mode 100644 index 0000000..bfd2702 --- /dev/null +++ b/src/components/ReferenceGuide.jsx @@ -0,0 +1,132 @@ +import { + Flex, + Box, + Card, + TabPanel, + CardBody, + Text, + Accordion, + AccordionItem, + AccordionButton, + AccordionPanel, + AccordionIcon, +} from '@chakra-ui/react'; +import { Icon } from '@chakra-ui/react'; +import { BiCalendar, BiBone, BiCar, BiCopyAlt, BiConversation } from 'react-icons/bi'; +import { PropTypes } from 'prop-types'; + +const ReferenceGuide = () => { + const CustomAccordionItem = ({ title, panelInfo }) => ( + + + + + + {title} + + + + + + {panelInfo} + + ); + + CustomAccordionItem.propTypes = { + title: PropTypes.string.isRequired, + panelInfo: PropTypes.string.isRequired, + }; + return ( + + + + + Refer to the following if you have any questions, otherwise contact us at + + info@petsofthehomeless.org + + + + + + + + + + + + + + + + + Tips on how to increase donations + + + + + + + + + + Host events and ask that a donation of pet food be the admittance ticket. + + + + + + Offer a service with a donation as the fee for your services. Example: grooming, + pet sitting, boarding, etc. + + + + + Fill a truck or police vehicle (popular choice). + + + + + Print our newsletter or flyer and post it to boards in your community with your + business name and address. + + + + + We are always open to other suggestions. + + + + + + + + ); +}; + +export default ReferenceGuide; diff --git a/src/components/ViewBusiness/ViewBusiness.jsx b/src/components/ViewBusiness/ViewBusiness.jsx index bf44829..ba50a13 100644 --- a/src/components/ViewBusiness/ViewBusiness.jsx +++ b/src/components/ViewBusiness/ViewBusiness.jsx @@ -27,9 +27,9 @@ import { Checkbox, Link as ChakraLink, } from '@chakra-ui/react'; -import { ChevronDownIcon, ArrowForwardIcon } from '@chakra-ui/icons'; +import { ChevronDownIcon, ArrowForwardIcon, ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons'; import { useBackend } from '../../contexts/BackendContext'; -import { useParams, useNavigate } from 'react-router-dom'; +import { useParams, useNavigate} from 'react-router-dom'; import 'boxicons'; function formatDateDFH(dateTimeString) { @@ -52,9 +52,14 @@ const ViewBusiness = () => { const [donationFormsData, setDonationData] = useState([]); const [lastReminder, setLastReminder] = useState(''); const [lastRequest, setLastRequest] = useState(''); - + const [currentPage, setCurrentPage] = useState(1); const { backend } = useBackend(); + const itemsPerPage = 5; + const totalPages = Math.ceil(donationFormsData.length / itemsPerPage); + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(startIndex + itemsPerPage, donationFormsData.length); + const currentPageData = donationFormsData.slice(startIndex, endIndex); const fetchBusiness = async () => { try { const response = await backend.get(`/business/${id}`); @@ -100,6 +105,10 @@ const ViewBusiness = () => { navigate(`/AdminDashboard`); }; + const handleFormClick = (id) => { + navigate(`/ViewDonation/${id}`); + }; + // ViewBusiness.PropTypes = { // id: PropTypes.number.isRequired, // } @@ -118,6 +127,14 @@ const ViewBusiness = () => { return
Loading...
; } + const handlePrevClick = () => { + setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); + }; + + const handleNextClick = () => { + setCurrentPage((prevPage) => Math.min(prevPage + 1, totalPages)); + }; + return ( @@ -462,23 +479,46 @@ const ViewBusiness = () => { - - + + DONATION FORM HISTORY - +
- {donationFormsData.map((item, index) => ( -
- {/* Render the date property of each object */} -

{formatDateDFH(item.date)}

- {index !== data.length - 1 && } -
+ + {currentPageData.map((item, index) => ( +
handleFormClick(item.donation_id)}> + {/* Render the date property of each object */} +

{formatDateDFH(item.date)}

+ {index !== data.length - 1 && } +
))}
+ + + + {currentPageData.length > 0 ? (currentPage - 1) * itemsPerPage + 1 : 0}- + {Math.min(currentPage * itemsPerPage, donationFormsData.length)} of {donationFormsData.length} + + } + backgroundColor={'#00000000'} + /> + = totalPages} + onClick={handleNextClick} + icon={} + backgroundColor={'#00000000'} + /> + +
diff --git a/src/components/ViewDonation/ViewDonation.css b/src/components/ViewDonation/ViewDonation.css new file mode 100644 index 0000000..e69de29 diff --git a/src/components/ViewDonation/ViewDonation.jsx b/src/components/ViewDonation/ViewDonation.jsx new file mode 100644 index 0000000..4fa445d --- /dev/null +++ b/src/components/ViewDonation/ViewDonation.jsx @@ -0,0 +1,175 @@ +import { useBackend } from '../../contexts/BackendContext'; +import { useParams, useNavigate} from 'react-router-dom'; +import { useState, useEffect } from 'react'; +import { + Card, + Heading, + CardBody, + Stack, + Box, + Text, + StackDivider, + Flex, + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + Button, + IconButton, +} from '@chakra-ui/react'; +import { + ArrowDownIcon, + } from '@chakra-ui/icons'; + +import DownloadCSV from '../../utils/downloadCSV'; +import PropTypes from 'prop-types'; + +const ViewDonation = () => { + const { backend } = useBackend(); + const { id } = useParams(); + const [donationData, setDonationData] = useState([]); + const [businessName, setBusinessName] = useState(''); + const navigate = useNavigate(); + + const getData = async () => { + try { + const donationResponse = await backend.get( + `/donation/${id}` + ); + setDonationData(donationResponse.data[0]); + } catch (error) { + console.error('Error fetching donation data:', error); + } + }; + + const getBusinessName = async () => { + console.log('started getbusiness name'); + try { + const businessResponse = await backend.get( + `/business/${donationData.business_id}` + ); + console.log('businessResponse yessir'); + setBusinessName(businessResponse.data[0].name); + } catch (error) { + console.error('Error fetching business name:', error); + } + } + + const handleDownloadCSV = () => { + const headers = [ + 'business_id', + 'donation_id', + 'food_bank_donation', + 'reporter', + 'email', + 'date', + 'misc_items', + 'volunteer_hours', + 'canned_cat_food_quantity', + 'canned_dog_food_quantity', + 'dry_cat_food_quantity', + 'dry_dog_food_quantity', + ]; + DownloadCSV(headers, id, 'donation_tracking'); + }; + + const handleViewBusiness = () => { + navigate(`/ViewBusiness/${donationData.business_id}`); + }; + + useEffect(() => { + const fetchData = async () => { + await getData(); + await getBusinessName(); + }; + fetchData(); + }, []); + + return ( + <> + + + + + Donation Tracking + + + + View Business + + + + {businessName} + + + } /> + + + + {businessName}’s Donation Summary + + + + + + + + + + } spacing='4'> + + + + + + + + + + + + + + + + + ); +} + +export default ViewDonation; + + +const CustomRow = ({ title, info }) => { + const shouldShowLb = ['Canned Dog Food QTY','Dry Dog Food QTY','Canned Cat Food QTY', 'Dry Cat Food QTY'].includes(title); + console.log(`${title}: ${shouldShowLb}`); + return ( + + + + {title} + + {typeof info === 'number' && shouldShowLb ? ( + + {info} lb + + ) : ( + + {info} + + )} + + + ); +}; + + + + +CustomRow.propTypes = { + title: PropTypes.string.isRequired, + info: PropTypes.string.isRequired, +};