From 9c6fb768c5b406130650deb2223444574640b097 Mon Sep 17 00:00:00 2001 From: Heidi Jiang Date: Wed, 24 Jun 2026 00:22:04 -0400 Subject: [PATCH 1/3] fixing lint errors --- .../src/donations/donations.controller.ts | 5 - apps/frontend/src/api/apiClient.ts | 14 +- .../src/components/editDeleteButtons.tsx | 2 +- .../components/forms/donationDetailsModal.tsx | 535 ++++++++++++++++-- .../forms/fmDeleteDonationModal.tsx | 127 +++++ .../foodManufacturerDonationManagement.tsx | 81 ++- apps/frontend/src/types/types.ts | 10 + 7 files changed, 688 insertions(+), 86 deletions(-) create mode 100644 apps/frontend/src/components/forms/fmDeleteDonationModal.tsx diff --git a/apps/backend/src/donations/donations.controller.ts b/apps/backend/src/donations/donations.controller.ts index 3bd34c73f..75542cf30 100644 --- a/apps/backend/src/donations/donations.controller.ts +++ b/apps/backend/src/donations/donations.controller.ts @@ -64,11 +64,6 @@ export class DonationsController { } @Roles(Role.FOODMANUFACTURER) - @CheckOwnership({ - idParam: 'foodManufacturerId', - idSource: 'body', - resolver: resolveCreateDonationAuthorizedUserIds, - }) @Post() @ApiBody({ description: 'Details for creating a donation', diff --git a/apps/frontend/src/api/apiClient.ts b/apps/frontend/src/api/apiClient.ts index 2f09a76c8..eb762a849 100644 --- a/apps/frontend/src/api/apiClient.ts +++ b/apps/frontend/src/api/apiClient.ts @@ -8,12 +8,10 @@ import { NavigateFunction } from 'react-router-dom'; import { ROUTES } from '../routes'; import { User, - Order, FoodRequest, FoodManufacturer, DonationItem, Donation, - Allocation, CreateFoodRequestBody, Pantry, PantryApplicationDto, @@ -45,6 +43,7 @@ import { PendingApplication, UpdateFoodRequestBody, DonationReminderDto, + ReplaceDonationItemDto, } from 'types/types'; const defaultBaseUrl = @@ -443,6 +442,17 @@ export class ApiClient { ); } + public async editDonationItems( + donationId: number, + items: ReplaceDonationItemDto[], + ): Promise { + await this.axiosInstance.patch(`/api/donations/${donationId}/item`, items); + } + + public async deleteDonation(donationId: number): Promise { + await this.axiosInstance.delete(`/api/donations/${donationId}`); + } + public async updateFoodManufacturerApplicationData( manufacturerId: number, data: UpdateFoodManufacturerApplicationDto, diff --git a/apps/frontend/src/components/editDeleteButtons.tsx b/apps/frontend/src/components/editDeleteButtons.tsx index 279ae8f46..fcdf1a4cb 100644 --- a/apps/frontend/src/components/editDeleteButtons.tsx +++ b/apps/frontend/src/components/editDeleteButtons.tsx @@ -2,7 +2,7 @@ import { HStack } from '@chakra-ui/react'; import { Pencil, Trash2 } from 'lucide-react'; interface EditDeleteButtonProps { - onClick: () => void; + onClick?: () => void; } export const EditButton: React.FC = ({ onClick }) => { diff --git a/apps/frontend/src/components/forms/donationDetailsModal.tsx b/apps/frontend/src/components/forms/donationDetailsModal.tsx index 198e72fdf..be231d86a 100644 --- a/apps/frontend/src/components/forms/donationDetailsModal.tsx +++ b/apps/frontend/src/components/forms/donationDetailsModal.tsx @@ -1,31 +1,187 @@ import React, { useState, useEffect } from 'react'; -import { Box, Text, VStack, Dialog, CloseButton } from '@chakra-ui/react'; +import { + Box, + Text, + VStack, + Dialog, + CloseButton, + HStack, + Table, + Button, + Input, + NativeSelect, + NativeSelectIndicator, + Checkbox, + Flex, +} from '@chakra-ui/react'; import ApiClient from '@api/apiClient'; -import { Donation, DonationItem, FoodType } from 'types/types'; +import { + Donation, + DonationItem, + FoodType, + AlertStatus, + ReplaceDonationItemDto, + DonationStatus, + Role, + User, +} from '../../types/types'; import { formatDate } from '@utils/utils'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../../hooks/alert'; import { useModalBodyCleanup } from '../../hooks/modalBodyCleanup'; -import { AlertStatus } from '../../types/types'; +import { EditButton, DeleteButton } from '@components/editDeleteButtons'; +import { Minus } from 'lucide-react'; +import { useCallback } from 'react'; interface DonationDetailsModalProps { donation: Donation; isOpen: boolean; onClose: () => void; + onSuccess?: () => void; + onDelete?: () => void; } +interface DonationRow { + id: number; + foodItem: string; + foodType: FoodType | ''; + numItems: string; + ozPerItem: string; + valuePerItem: string; + foodRescue: boolean; +} + +const mapItemsToRows = (items: DonationItem[]): DonationRow[] => + items.map((item) => ({ + id: item.itemId, + foodItem: item.itemName, + foodType: item.foodType, + numItems: String(item.quantity), + ozPerItem: String(item.ozPerItem), + valuePerItem: String(item.estimatedValue), + foodRescue: item.foodRescue, + })); + const DonationDetailsModal: React.FC = ({ donation, isOpen, onClose, + onSuccess, + onDelete, }) => { useModalBodyCleanup(); + const [currentUser, setCurrentUser] = useState(null); + const [items, setItems] = useState([]); + const [rows, setRows] = useState([]); + const [alertState, setAlertMessage] = useAlert(); + const [isEditing, setIsEditing] = useState(false); + const donationId = donation.donationId; + const hasAllocations = items.some((i) => i.reservedQuantity > 0); + + useEffect(() => { + const fetchUser = async () => { + try { + const user = await ApiClient.getMe(); + setCurrentUser(user); + } catch { + setCurrentUser(null); + } + }; + fetchUser(); + }, []); + + const placeholderStyles = { + color: 'neutral.300', + fontFamily: 'inter', + fontSize: 'sm', + fontWeight: '400', + }; + + const deleteRow = (id: number) => { + if (rows.length > 1) { + const newRows = rows.filter((r) => r.id !== id); + setRows(newRows); + } + }; + + const handleChange = (id: number, field: string, value: string | boolean) => { + const newRows = rows.map((row) => + row.id === id ? { ...row, [field]: value } : row, + ); + setRows(newRows); + }; + + const addRow = () => { + setRows([ + ...rows, + { + id: Date.now(), + foodItem: '', + foodType: '', + numItems: '', + ozPerItem: '', + valuePerItem: '', + foodRescue: false, + }, + ]); + }; + + const handleCancel = () => { + setRows(mapItemsToRows(items)); + setIsEditing(false); + }; + + const loadItems = useCallback(async () => { + try { + const itemsData = await ApiClient.getDonationItemsByDonationId( + donationId, + ); + setItems(itemsData); + setRows(mapItemsToRows(itemsData)); + } catch { + setAlertMessage('Error fetching donation details', AlertStatus.ERROR); + } + }, [donationId, setAlertMessage]); + + const handleUpdate = () => { + const existingIds = new Set(items.map((i) => i.itemId)); + const body: ReplaceDonationItemDto[] = rows.map((r) => ({ + ...(existingIds.has(r.id) ? { itemId: r.id } : {}), + itemName: r.foodItem, + quantity: parseInt(r.numItems), + ozPerItem: parseFloat(r.ozPerItem), + estimatedValue: parseFloat(r.valuePerItem), + foodType: r.foodType as FoodType, + foodRescue: r.foodRescue, + })); + + const updateData = async () => { + try { + await ApiClient.editDonationItems(donationId, body); + await loadItems(); + onSuccess?.(); + setAlertMessage( + 'Successfully updated donation items.', + AlertStatus.INFO, + ); + setIsEditing(false); + } catch { + setAlertMessage( + 'Donation items could not be updated.', + AlertStatus.ERROR, + ); + } + }; + + updateData(); + }; + useEffect(() => { if (!isOpen) return; @@ -34,8 +190,8 @@ const DonationDetailsModal: React.FC = ({ const itemsData = await ApiClient.getDonationItemsByDonationId( donationId, ); - setItems(itemsData); + setRows(mapItemsToRows(itemsData)); } catch { setAlertMessage('Error fetching donation details', AlertStatus.ERROR); } @@ -71,16 +227,31 @@ const DonationDetailsModal: React.FC = ({ - + - - Donation #{donationId} Stock - + + + Donation #{donationId} Stock + + {currentUser?.role === Role.FOODMANUFACTURER && + donation.status === DonationStatus.AVAILABLE && + !hasAllocations && ( + <> + setIsEditing(true)} + > + + + )} + {donation.foodManufacturer?.foodManufacturerName} @@ -89,56 +260,316 @@ const DonationDetailsModal: React.FC = ({ - - {Object.entries(groupedItems).map(([foodType, typeItems]) => ( - - + + - {foodType} - - - - {typeItems.map((item, index) => ( - - - {item.itemName} - + + + + + Food Item + + * + + + + Food Type + + * + + + + Quantity + + * + + + + Oz. per item + + * + + + + Donation Value + + * + + + + Food Rescue + + * + + + + + + + {rows.map((row) => ( + + + + + + + + handleChange(row.id, 'foodItem', e.target.value) + } + /> + + + + + + handleChange( + row.id, + 'foodType', + e.target.value, + ) + } + > + {Object.values(FoodType).map((type) => ( + + ))} + + + + + + + + handleChange(row.id, 'numItems', e.target.value) + } + /> + + + + + handleChange( + row.id, + 'ozPerItem', + e.target.value, + ) + } + /> + + + + handleChange( + row.id, + 'valuePerItem', + e.target.value, + ) + } + /> + + + + + handleChange(row.id, 'foodRescue', !!e.checked) + } + > + + + + + + + + ))} + + + + + + + + + + + + ) : ( + + {Object.entries(groupedItems).map(([foodType, typeItems]) => ( + + + {foodType} + + + + {typeItems.map((item, index) => ( - - {item.quantity - item.reservedQuantity} of{' '} - {item.quantity} Remaining - + + {item.itemName} + + + + + {item.quantity - item.reservedQuantity} of{' '} + {item.quantity} Remaining + + - - ))} - - - ))} - + ))} + + + ))} + + )} diff --git a/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx b/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx new file mode 100644 index 000000000..4cf149d6c --- /dev/null +++ b/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { + Box, + Button, + VStack, + CloseButton, + Text, + Flex, + Dialog, +} from '@chakra-ui/react'; +import { AlertStatus, Donation } from '../../types/types'; +import { formatDate } from '@utils/utils'; +import apiClient from '@api/apiClient'; +import { useAlert } from '../../hooks/alert'; +import { FloatingAlert } from '@components/floatingAlert'; +import { useModalBodyCleanup } from '../../hooks/modalBodyCleanup'; + +interface FMDeleteDonationActionModalProps { + donation: Donation; + isOpen: boolean; + onClose: () => void; + onSuccess: () => void; +} + +const FMDeleteDonationActionModal: React.FC< + FMDeleteDonationActionModalProps +> = ({ donation, isOpen, onClose, onSuccess }) => { + useModalBodyCleanup(); + const [alertState, setAlertMessage] = useAlert(); + + const onDeleteDonation = async () => { + try { + await apiClient.deleteDonation(donation.donationId); + onClose(); + onSuccess(); + } catch { + setAlertMessage('Donation could not be deleted.', AlertStatus.ERROR); + } + }; + + return ( + { + if (!e.open) onClose(); + }} + closeOnInteractOutside + > + {alertState && ( + + )} + + + + + + + + + + Confirm Action + + + + + + Are you sure you want to delete this donation? This action + cannot be undone. + + + + Donation #{donation.donationId} + + + Submitted {formatDate(donation.dateDonated)} + + + + + + + + + + + + ); +}; + +export default FMDeleteDonationActionModal; diff --git a/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx b/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx index ef0d3e320..2da5eb98d 100644 --- a/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx +++ b/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx @@ -13,7 +13,12 @@ import { import { ChevronRight, ChevronLeft, Mail, CircleCheck } from 'lucide-react'; import { capitalize, formatDate, DONATION_STATUS_COLORS } from '@utils/utils'; import ApiClient from '@api/apiClient'; -import { AlertStatus, DonationDetails, DonationStatus } from '../types/types'; +import { + AlertStatus, + Donation, + DonationDetails, + DonationStatus, +} from '../types/types'; import DonationDetailsModal from '@components/forms/donationDetailsModal'; import NewDonationFormModal from '@components/forms/newDonationFormModal'; import ResubmitDonationModal from '@components/forms/resubmitDonationModal'; @@ -22,6 +27,7 @@ import { ROUTES } from '../routes'; import { FloatingAlert } from '@components/floatingAlert'; import { useAlert } from '../hooks/alert'; import FmCompleteRequiredActionsModal from '@components/forms/fmCompleteRequiredActionsModal'; +import FMDeleteDonationActionModal from '@components/forms/fmDeleteDonationModal'; const MAX_PER_STATUS = 5; @@ -53,10 +59,9 @@ const FoodManufacturerDonationManagement: React.FC = () => { [DonationStatus.FULFILLED]: 1, }); - // State to hold selected donation for details modal - const [selectedDonationId, setSelectedDonationId] = useState( - null, - ); + const [selectedViewDetailsDonation, setSelectedViewDetailsDonation] = + useState(null); + const [deleteDonation, setDeleteDonation] = useState(null); // Fetch all donations on component mount and sorts them into their appropriate status lists const fetchDonations = async () => { @@ -156,8 +161,15 @@ const FoodManufacturerDonationManagement: React.FC = () => { if (!donationIdParam) return; const id = Number(donationIdParam); - setSelectedDonationId(id); - }, [searchParams, setAlertMessage]); + + // match the ID to a donation from any of the three donation status buckets + const match = Object.values(statusDonations) + .flat() + .find((d) => d.donation.donationId === id); + if (match) { + setSelectedViewDetailsDonation(match.donation); + } + }, [searchParams, statusDonations]); const handleResubmitClose = () => { setIsResubmitOpen(false); @@ -260,6 +272,39 @@ const FoodManufacturerDonationManagement: React.FC = () => { /> )} + {deleteDonation && ( + { + setSelectedViewDetailsDonation(deleteDonation); + setDeleteDonation(null); + }} + onSuccess={() => { + setAlertMessage( + 'Successfully deleted donation items.', + AlertStatus.INFO, + ); + fetchDonations(); + setDeleteDonation(null); + setSelectedViewDetailsDonation(null); + }} + /> + )} + + {selectedViewDetailsDonation && ( + setSelectedViewDetailsDonation(null)} + onSuccess={() => fetchDonations()} + onDelete={() => { + setDeleteDonation(selectedViewDetailsDonation); + setSelectedViewDetailsDonation(null); + }} + /> + )} + {Object.values(DonationStatus).map((status) => { const allDonationsByStatus = statusDonations[status] || []; @@ -275,16 +320,11 @@ const FoodManufacturerDonationManagement: React.FC = () => { donations={displayedDonations} status={status} colors={DONATION_STATUS_COLORS[status]} - selectedDonationId={selectedDonationId} - onDonationSelect={setSelectedDonationId} + onDonationSelect={setSelectedViewDetailsDonation} totalDonations={allDonationsByStatus.length} currentPage={currentPage} onPageChange={(page) => handlePageChange(status, page)} onActionSelect={setSelectedActionDonation} - onDonationClose={() => { - setSelectedDonationId(null); - navigate(ROUTES.FM_DONATION_MANAGEMENT, { replace: true }); - }} /> ); @@ -297,13 +337,11 @@ interface DonationStatusSectionProps { donations: DonationDetails[]; status: DonationStatus; colors: string[]; - onDonationSelect: (donationId: number | null) => void; - selectedDonationId: number | null; + onDonationSelect: (donation: Donation | null) => void; totalDonations: number; currentPage: number; onPageChange: (page: number) => void; onActionSelect: (donation: DonationDetails | null) => void; - onDonationClose: () => void; } const DonationStatusSection: React.FC = ({ @@ -313,10 +351,8 @@ const DonationStatusSection: React.FC = ({ onDonationSelect, totalDonations, currentPage, - selectedDonationId, onPageChange, onActionSelect, - onDonationClose, }) => { const totalPages = Math.ceil(totalDonations / MAX_PER_STATUS); @@ -439,17 +475,10 @@ const DonationStatusSection: React.FC = ({ onDonationSelect(donation.donationId)} + onClick={() => onDonationSelect(donation)} > {donation.donationId} - {selectedDonationId === donation.donationId && ( - - )} Date: Thu, 25 Jun 2026 04:20:20 -0400 Subject: [PATCH 2/3] requested changes --- .../src/donations/donations.controller.ts | 1 - .../src/components/editDeleteButtons.tsx | 2 +- .../components/forms/donationDetailsModal.tsx | 38 ++++++------------- .../foodManufacturerDonationManagement.tsx | 2 - 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/apps/backend/src/donations/donations.controller.ts b/apps/backend/src/donations/donations.controller.ts index 75542cf30..7a7c6375c 100644 --- a/apps/backend/src/donations/donations.controller.ts +++ b/apps/backend/src/donations/donations.controller.ts @@ -111,7 +111,6 @@ export class DonationsController { }, }, }) - @Roles(Role.FOODMANUFACTURER) async createDonation( @Req() req: AuthenticatedRequest, @Body() body: CreateDonationDto, diff --git a/apps/frontend/src/components/editDeleteButtons.tsx b/apps/frontend/src/components/editDeleteButtons.tsx index fcdf1a4cb..279ae8f46 100644 --- a/apps/frontend/src/components/editDeleteButtons.tsx +++ b/apps/frontend/src/components/editDeleteButtons.tsx @@ -2,7 +2,7 @@ import { HStack } from '@chakra-ui/react'; import { Pencil, Trash2 } from 'lucide-react'; interface EditDeleteButtonProps { - onClick?: () => void; + onClick: () => void; } export const EditButton: React.FC = ({ onClick }) => { diff --git a/apps/frontend/src/components/forms/donationDetailsModal.tsx b/apps/frontend/src/components/forms/donationDetailsModal.tsx index be231d86a..3dd999839 100644 --- a/apps/frontend/src/components/forms/donationDetailsModal.tsx +++ b/apps/frontend/src/components/forms/donationDetailsModal.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Box, Text, @@ -31,7 +31,6 @@ import { useAlert } from '../../hooks/alert'; import { useModalBodyCleanup } from '../../hooks/modalBodyCleanup'; import { EditButton, DeleteButton } from '@components/editDeleteButtons'; import { Minus } from 'lucide-react'; -import { useCallback } from 'react'; interface DonationDetailsModalProps { donation: Donation; @@ -104,10 +103,8 @@ const DonationDetailsModal: React.FC = ({ }; const deleteRow = (id: number) => { - if (rows.length > 1) { - const newRows = rows.filter((r) => r.id !== id); - setRows(newRows); - } + const newRows = rows.filter((r) => r.id !== id); + setRows(newRows); }; const handleChange = (id: number, field: string, value: string | boolean) => { @@ -184,21 +181,8 @@ const DonationDetailsModal: React.FC = ({ useEffect(() => { if (!isOpen) return; - - const fetchData = async () => { - try { - const itemsData = await ApiClient.getDonationItemsByDonationId( - donationId, - ); - setItems(itemsData); - setRows(mapItemsToRows(itemsData)); - } catch { - setAlertMessage('Error fetching donation details', AlertStatus.ERROR); - } - }; - - fetchData(); - }, [isOpen, donationId, setAlertMessage]); + loadItems(); + }, [isOpen, loadItems]); // Group items by food type const groupedItems = items.reduce((acc, item) => { @@ -248,7 +232,9 @@ const DonationDetailsModal: React.FC = ({ setIsEditing(true)} > - + {onDelete && ( + + )} )} @@ -414,7 +400,7 @@ const DonationDetailsModal: React.FC = ({ type="number" min={0.01} step={0.01} - value={row.ozPerItem ?? ''} + value={row.ozPerItem} onChange={(e) => handleChange( row.id, @@ -433,7 +419,7 @@ const DonationDetailsModal: React.FC = ({ type="number" min={0.01} step={0.01} - value={row.valuePerItem ?? ''} + value={row.valuePerItem} onChange={(e) => handleChange( row.id, @@ -532,9 +518,9 @@ const DonationDetailsModal: React.FC = ({ - {typeItems.map((item, index) => ( + {typeItems.map((item, _) => ( { donation={deleteDonation} isOpen={deleteDonation !== null} onClose={() => { - setSelectedViewDetailsDonation(deleteDonation); setDeleteDonation(null); }} onSuccess={() => { @@ -300,7 +299,6 @@ const FoodManufacturerDonationManagement: React.FC = () => { onSuccess={() => fetchDonations()} onDelete={() => { setDeleteDonation(selectedViewDetailsDonation); - setSelectedViewDetailsDonation(null); }} /> )} From f0d7ea50a1ac6c29599c3a69644ffafb2f1518eb Mon Sep 17 00:00:00 2001 From: Heidi Jiang Date: Thu, 25 Jun 2026 05:43:48 -0400 Subject: [PATCH 3/3] fix unresponsive ui bug after clicking cancel on delete donation modal --- .../forms/fmDeleteDonationModal.tsx | 128 +++++++++--------- .../foodManufacturerDonationManagement.tsx | 34 +++-- 2 files changed, 83 insertions(+), 79 deletions(-) diff --git a/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx b/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx index 4cf149d6c..05e2da2e2 100644 --- a/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx +++ b/apps/frontend/src/components/forms/fmDeleteDonationModal.tsx @@ -16,7 +16,9 @@ import { FloatingAlert } from '@components/floatingAlert'; import { useModalBodyCleanup } from '../../hooks/modalBodyCleanup'; interface FMDeleteDonationActionModalProps { - donation: Donation; + // allow null donation prop to close modal + // prevents unresponsive UI from unmounting the modal before removing body lock + donation: Donation | null; isOpen: boolean; onClose: () => void; onSuccess: () => void; @@ -29,6 +31,7 @@ const FMDeleteDonationActionModal: React.FC< const [alertState, setAlertMessage] = useAlert(); const onDeleteDonation = async () => { + if (!donation) return; try { await apiClient.deleteDonation(donation.donationId); onClose(); @@ -56,70 +59,73 @@ const FMDeleteDonationActionModal: React.FC< /> )} - - - - - - - - Confirm Action - - - - - - Are you sure you want to delete this donation? This action - cannot be undone. - - + {donation && ( + + + + + + + + + Confirm Action + + + + - Donation #{donation.donationId} - - - Submitted {formatDate(donation.dateDonated)} + Are you sure you want to delete this donation? This action + cannot be undone. - - - - - - - - - + + Donation #{donation.donationId} + + + Submitted {formatDate(donation.dateDonated)} + + + + + + + + + + + )} ); }; diff --git a/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx b/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx index a39838784..5f13aa7c4 100644 --- a/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx +++ b/apps/frontend/src/containers/foodManufacturerDonationManagement.tsx @@ -272,24 +272,22 @@ const FoodManufacturerDonationManagement: React.FC = () => { /> )} - {deleteDonation && ( - { - setDeleteDonation(null); - }} - onSuccess={() => { - setAlertMessage( - 'Successfully deleted donation items.', - AlertStatus.INFO, - ); - fetchDonations(); - setDeleteDonation(null); - setSelectedViewDetailsDonation(null); - }} - /> - )} + { + setDeleteDonation(null); + }} + onSuccess={() => { + setAlertMessage( + 'Successfully deleted donation items.', + AlertStatus.INFO, + ); + fetchDonations(); + setDeleteDonation(null); + setSelectedViewDetailsDonation(null); + }} + /> {selectedViewDetailsDonation && (