diff --git a/apps/frontend/src/components/floatingAlert.tsx b/apps/frontend/src/components/floatingAlert.tsx new file mode 100644 index 00000000..b6f6a755 --- /dev/null +++ b/apps/frontend/src/components/floatingAlert.tsx @@ -0,0 +1,56 @@ +import { Alert } from '@chakra-ui/react'; +import { useEffect, useState } from 'react'; + +type FloatingAlertProps = { + message?: string | null; + status?: 'info' | 'error'; + timeout?: number; +}; + +export function FloatingAlert({ + message, + status, + timeout, +}: FloatingAlertProps) { + const [visible, setVisible] = useState(!!message); + + useEffect(() => { + if (!message) { + setVisible(false); + return; + } + + setVisible(true); + + if (!timeout) return; + + const timer = setTimeout(() => { + setVisible(false); + }, timeout); + + return () => clearTimeout(timer); + }, [message, timeout]); + + if (!message || !visible) return null; + + return ( + + + + {message} + + + ); +} diff --git a/apps/frontend/src/components/forms/donationDetailsModal.tsx b/apps/frontend/src/components/forms/donationDetailsModal.tsx index 80b8d15c..5689ea60 100644 --- a/apps/frontend/src/components/forms/donationDetailsModal.tsx +++ b/apps/frontend/src/components/forms/donationDetailsModal.tsx @@ -10,6 +10,7 @@ import { import ApiClient from '@api/apiClient'; import { Donation, DonationItem, FoodType } from 'types/types'; import { formatDate } from '@utils/utils'; +import { FloatingAlert } from '@components/floatingAlert'; interface DonationDetailsModalProps { donation?: Donation; @@ -25,6 +26,8 @@ const DonationDetailsModal: React.FC = ({ const [loadedDonation, setLoadedDonation] = useState(); const [items, setItems] = useState([]); + const [alertMessage, setAlertMessage] = useState(''); + const donationId = donation?.donationId; // adjust if your ID field is different useEffect(() => { @@ -40,7 +43,7 @@ const DonationDetailsModal: React.FC = ({ setLoadedDonation(donationData); setItems(itemsData); } catch (err) { - alert('Error fetching donation details: ' + err); + setAlertMessage('Error fetching donation details: ' + err); } }; @@ -64,6 +67,9 @@ const DonationDetailsModal: React.FC = ({ scrollBehavior="inside" > + {alertMessage && ( + + )} diff --git a/apps/frontend/src/components/forms/orderDetailsModal.tsx b/apps/frontend/src/components/forms/orderDetailsModal.tsx index 672fefe0..932196b5 100644 --- a/apps/frontend/src/components/forms/orderDetailsModal.tsx +++ b/apps/frontend/src/components/forms/orderDetailsModal.tsx @@ -11,6 +11,7 @@ import { import ApiClient from '@api/apiClient'; import { FoodRequest, OrderSummary } from 'types/types'; import { formatDate } from '@utils/utils'; +import { FloatingAlert } from '@components/floatingAlert'; interface OrderDetailsModalProps { order: OrderSummary; @@ -25,6 +26,8 @@ const OrderDetailsModal: React.FC = ({ }) => { const [foodRequest, setFoodRequest] = useState(null); + const [alertMessage, setAlertMessage] = useState(''); + useEffect(() => { if (isOpen) { const fetchData = async () => { @@ -34,7 +37,7 @@ const OrderDetailsModal: React.FC = ({ ); setFoodRequest(foodRequestData); } catch (error) { - alert('Error fetching food request details:' + error); + setAlertMessage('Error fetching food request details:' + error); } }; @@ -51,6 +54,9 @@ const OrderDetailsModal: React.FC = ({ }} closeOnInteractOutside > + {alertMessage && ( + + )} diff --git a/apps/frontend/src/components/forms/requestFormModal.tsx b/apps/frontend/src/components/forms/requestFormModal.tsx index f54e625e..21278c3a 100644 --- a/apps/frontend/src/components/forms/requestFormModal.tsx +++ b/apps/frontend/src/components/forms/requestFormModal.tsx @@ -14,6 +14,7 @@ import { import { Form, ActionFunction, ActionFunctionArgs } from 'react-router-dom'; import { FoodRequest, FoodTypes, RequestSize } from '../../types/types'; import { ChevronDownIcon } from 'lucide-react'; +import { FloatingAlert } from '@components/floatingAlert'; interface FoodRequestFormModalProps { previousRequest?: FoodRequest; @@ -32,6 +33,8 @@ const FoodRequestFormModal: React.FC = ({ const [requestedSize, setRequestedSize] = useState(''); const [additionalNotes, setAdditionalNotes] = useState(''); + const [alertMessage, setAlertMessage] = useState(''); + const isFormValid = requestedSize !== '' && selectedItems.length > 0; useEffect(() => { @@ -54,6 +57,9 @@ const FoodRequestFormModal: React.FC = ({ }} closeOnInteractOutside > + {alertMessage && ( + + )} @@ -81,11 +87,11 @@ const FoodRequestFormModal: React.FC = ({ onSubmit={(e) => { if (selectedItems.length === 0) { e.preventDefault(); - alert('Please select at least one food type'); + setAlertMessage('Please select at least one food type'); } if (requestedSize === '') { e.preventDefault(); - alert('Please select a requested size.'); + setAlertMessage('Please select a requested size.'); } }} > @@ -279,7 +285,7 @@ const FoodRequestFormModal: React.FC = ({ if (words.length <= 250) { setAdditionalNotes(e.target.value); } else { - alert('Exceeded word limit'); + setAlertMessage('Exceeded word limit'); } }} /> diff --git a/apps/frontend/src/containers/FormRequests.tsx b/apps/frontend/src/containers/FormRequests.tsx index 8d5b2246..79da4dc4 100644 --- a/apps/frontend/src/containers/FormRequests.tsx +++ b/apps/frontend/src/containers/FormRequests.tsx @@ -20,6 +20,7 @@ import { OrderStatus, FoodRequest } from '../types/types'; import RequestDetailsModal from '@components/forms/requestDetailsModal'; import { formatDate } from '@utils/utils'; import ApiClient from '@api/apiClient'; +import { FloatingAlert } from '@components/floatingAlert'; const FormRequests: React.FC = () => { const [currentPage, setCurrentPage] = useState(1); @@ -37,6 +38,8 @@ const FormRequests: React.FC = () => { const [openReadOnlyRequest, setOpenReadOnlyRequest] = useState(null); + const [alertMessage, setAlertMessage] = useState(''); + const pageSize = 10; useEffect(() => { @@ -53,7 +56,7 @@ const FormRequests: React.FC = () => { setPreviousRequest(sortedData[0]); } } catch (error) { - alert('Error fetching requests: ' + error); + setAlertMessage('Error fetching requests: ' + error); } } }; @@ -71,6 +74,9 @@ const FormRequests: React.FC = () => { Food Request Management + {alertMessage && ( + + )}