Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions apps/frontend/src/components/floatingAlert.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Alert.Root
color={status === 'info' ? 'neutral.800' : 'red'}
status="info"
bg="white"
variant="subtle"
boxShadow="lg"
position="fixed"
zIndex="toast"
top="12px"
right="12px"
w="fit-content"
maxW="400px"
>
<Alert.Indicator />
<Alert.Title textStyle="p2" fontWeight={500}>
{message}
</Alert.Title>
</Alert.Root>
);
}
8 changes: 7 additions & 1 deletion apps/frontend/src/components/forms/donationDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,6 +26,8 @@ const DonationDetailsModal: React.FC<DonationDetailsModalProps> = ({
const [loadedDonation, setLoadedDonation] = useState<Donation>();
const [items, setItems] = useState<DonationItem[]>([]);

const [alertMessage, setAlertMessage] = useState<string>('');

const donationId = donation?.donationId; // adjust if your ID field is different

useEffect(() => {
Expand All @@ -40,7 +43,7 @@ const DonationDetailsModal: React.FC<DonationDetailsModalProps> = ({
setLoadedDonation(donationData);
setItems(itemsData);
} catch (err) {
alert('Error fetching donation details: ' + err);
setAlertMessage('Error fetching donation details: ' + err);
}
};

Expand All @@ -64,6 +67,9 @@ const DonationDetailsModal: React.FC<DonationDetailsModalProps> = ({
scrollBehavior="inside"
>
<Portal>
{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}
<Dialog.Backdrop bg="blackAlpha.300" />

<Dialog.Positioner>
Expand Down
8 changes: 7 additions & 1 deletion apps/frontend/src/components/forms/orderDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,6 +26,8 @@ const OrderDetailsModal: React.FC<OrderDetailsModalProps> = ({
}) => {
const [foodRequest, setFoodRequest] = useState<FoodRequest | null>(null);

const [alertMessage, setAlertMessage] = useState<string>('');

useEffect(() => {
if (isOpen) {
const fetchData = async () => {
Expand All @@ -34,7 +37,7 @@ const OrderDetailsModal: React.FC<OrderDetailsModalProps> = ({
);
setFoodRequest(foodRequestData);
} catch (error) {
alert('Error fetching food request details:' + error);
setAlertMessage('Error fetching food request details:' + error);
}
};

Expand All @@ -51,6 +54,9 @@ const OrderDetailsModal: React.FC<OrderDetailsModalProps> = ({
}}
closeOnInteractOutside
>
{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content maxW={650}>
Expand Down
12 changes: 9 additions & 3 deletions apps/frontend/src/components/forms/requestFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -32,6 +33,8 @@ const FoodRequestFormModal: React.FC<FoodRequestFormModalProps> = ({
const [requestedSize, setRequestedSize] = useState<string>('');
const [additionalNotes, setAdditionalNotes] = useState<string>('');

const [alertMessage, setAlertMessage] = useState<string>('');

const isFormValid = requestedSize !== '' && selectedItems.length > 0;

useEffect(() => {
Expand All @@ -54,6 +57,9 @@ const FoodRequestFormModal: React.FC<FoodRequestFormModalProps> = ({
}}
closeOnInteractOutside
>
{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content maxW={650}>
Expand Down Expand Up @@ -81,11 +87,11 @@ const FoodRequestFormModal: React.FC<FoodRequestFormModalProps> = ({
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.');
}
}}
>
Expand Down Expand Up @@ -279,7 +285,7 @@ const FoodRequestFormModal: React.FC<FoodRequestFormModalProps> = ({
if (words.length <= 250) {
setAdditionalNotes(e.target.value);
} else {
alert('Exceeded word limit');
setAlertMessage('Exceeded word limit');
}
}}
/>
Expand Down
8 changes: 7 additions & 1 deletion apps/frontend/src/containers/FormRequests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<number>(1);
Expand All @@ -37,6 +38,8 @@ const FormRequests: React.FC = () => {
const [openReadOnlyRequest, setOpenReadOnlyRequest] =
useState<FoodRequest | null>(null);

const [alertMessage, setAlertMessage] = useState<string>('');

const pageSize = 10;

useEffect(() => {
Expand All @@ -53,7 +56,7 @@ const FormRequests: React.FC = () => {
setPreviousRequest(sortedData[0]);
}
} catch (error) {
alert('Error fetching requests: ' + error);
setAlertMessage('Error fetching requests: ' + error);
}
}
};
Expand All @@ -71,6 +74,9 @@ const FormRequests: React.FC = () => {
<Text textStyle="h1" color="#515151">
Food Request Management
</Text>
{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}
<HStack gap={3} my={5}>
<Button
fontFamily="ibm"
Expand Down
8 changes: 7 additions & 1 deletion apps/frontend/src/containers/adminDonation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Donation } from 'types/types';
import DonationDetailsModal from '@components/forms/donationDetailsModal';
import ApiClient from '@api/apiClient';
import { formatDate } from '@utils/utils';
import { FloatingAlert } from '@components/floatingAlert';

const AdminDonation: React.FC = () => {
const [donations, setDonations] = useState<Donation[]>([]);
Expand All @@ -28,13 +29,15 @@ const AdminDonation: React.FC = () => {
null,
);

const [alertMessage, setAlertMessage] = useState<string>('');

useEffect(() => {
const fetchDonations = async () => {
try {
const data = await ApiClient.getAllDonations();
setDonations(data);
} catch (error) {
alert('Error fetching donations: ' + error);
setAlertMessage('Error fetching donations: ' + error);
}
};
fetchDonations();
Expand Down Expand Up @@ -99,6 +102,9 @@ const AdminDonation: React.FC = () => {
<Heading textStyle="h1" color="gray.600" mb={6}>
Donation Management
</Heading>
{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}
<Box display="flex" gap={2} mb={6} fontFamily="'Inter', sans-serif">
<Box position="relative">
<Button
Expand Down
9 changes: 8 additions & 1 deletion apps/frontend/src/containers/adminOrderManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { capitalize, formatDate } from '@utils/utils';
import ApiClient from '@api/apiClient';
import { OrderStatus, OrderSummary } from '../types/types';
import OrderDetailsModal from '@components/forms/orderDetailsModal';
import { FloatingAlert } from '@components/floatingAlert';

// Extending the OrderSummary type to include assignee color for display
type OrderWithColor = OrderSummary & { assigneeColor?: string };
Expand All @@ -50,6 +51,8 @@ const AdminOrderManagement: React.FC = () => {
},
);

const [alertMessage, setAlertMessage] = useState<string>('');

// State to hold filter state per status
type FilterState = {
selectedPantries: string[];
Expand Down Expand Up @@ -139,7 +142,7 @@ const AdminOrderManagement: React.FC = () => {
};
setCurrentPages(initialPages);
} catch (error) {
alert('Error fetching orders: ' + error);
setAlertMessage('Error fetching orders: ' + error);
}
};

Expand All @@ -164,6 +167,10 @@ const AdminOrderManagement: React.FC = () => {
Order Management
</Heading>

{alertMessage && (
<FloatingAlert message={alertMessage} status="error" timeout={6000} />
)}

{STATUS_ORDER.map((status) => {
const allOrders = statusOrders[status] || [];
const filterState = filterStates[status];
Expand Down