diff --git a/apps/frontend/src/api/apiClient.ts b/apps/frontend/src/api/apiClient.ts index 25a96a7ba..cfd4e5c2a 100644 --- a/apps/frontend/src/api/apiClient.ts +++ b/apps/frontend/src/api/apiClient.ts @@ -20,6 +20,7 @@ import { OrderSummary, UserDto, OrderDetails, + ConfirmDeliveryDto, } from 'types/types'; const defaultBaseUrl = @@ -160,6 +161,12 @@ export class ApiClient { .then((response) => response.data); } + public async getPantryOrders(pantryId: number): Promise { + return this.axiosInstance + .get(`/api/pantries/${pantryId}/orders`) + .then((response) => response.data); + } + public async getPantry(pantryId: number): Promise { return this.get(`/api/pantries/${pantryId}`) as Promise; } @@ -213,6 +220,32 @@ export class ApiClient { .then((response) => response.data); } + public async confirmOrderDelivery( + orderId: number, + dto: ConfirmDeliveryDto, + photos: File[], + ): Promise { + const formData = new FormData(); + + // DTO fields + formData.append('dateReceived', dto.dateReceived); + if (dto.feedback) { + formData.append('feedback', dto.feedback); + } + + // files (must be key = "photos") + for (const file of photos) { + formData.append('photos', file); + } + + const { data } = await this.axiosInstance.patch( + `/api/orders/${orderId}/confirm-delivery`, + formData, + ); + + return data; + } + public async postManufacturer( data: ManufacturerApplicationDto, ): Promise> { diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx index c844de298..540a173c5 100644 --- a/apps/frontend/src/app.tsx +++ b/apps/frontend/src/app.tsx @@ -27,6 +27,7 @@ import ForgotPasswordPage from '@containers/forgotPasswordPage'; import ProtectedRoute from '@components/protectedRoute'; import Unauthorized from '@containers/unauthorized'; import { Authenticator } from '@aws-amplify/ui-react'; +import PantryOrderManagement from '@containers/pantryOrderManagement'; import FoodManufacturerApplication from '@containers/foodManufacturerApplication'; import { submitManufacturerApplicationForm } from '@components/forms/manufacturerApplicationForm'; @@ -198,6 +199,14 @@ const router = createBrowserRouter([ ), }, + { + path: '/pantry-order-management', + element: ( + + + + ), + }, { path: '/confirm-delivery', action: submitDeliveryConfirmationFormModal, diff --git a/apps/frontend/src/chakra-ui.d.ts b/apps/frontend/src/chakra-ui.d.ts index d4db3faea..175a19c79 100644 --- a/apps/frontend/src/chakra-ui.d.ts +++ b/apps/frontend/src/chakra-ui.d.ts @@ -33,6 +33,10 @@ declare module '@chakra-ui/react' { extends ComponentPropsStrictChildren {} export interface MenuRadioItemProps extends ComponentPropsLenientChildren {} + // FileUpload components + export interface FileUploadDropzoneProps + extends ComponentPropsLenientChildren {} + // Dialog components export interface DialogCloseTriggerProps extends ComponentPropsStrictChildren {} diff --git a/apps/frontend/src/components/forms/orderReceivedActionModal.tsx b/apps/frontend/src/components/forms/orderReceivedActionModal.tsx new file mode 100644 index 000000000..2823d9c4a --- /dev/null +++ b/apps/frontend/src/components/forms/orderReceivedActionModal.tsx @@ -0,0 +1,228 @@ +import React, { useState } from 'react'; +import { + Flex, + Button, + Textarea, + Text, + Dialog, + Box, + Field, + CloseButton, + Input, + FileUpload, + Icon, +} from '@chakra-ui/react'; +import { Upload } from 'lucide-react'; +import { ConfirmDeliveryDto } from 'types/types'; +import apiClient from '@api/apiClient'; + +interface OrderReceivedActionModalProps { + orderId: number; + isOpen: boolean; + onClose: () => void; + onSuccess: () => void; +} + +const MAX_FILES = 10; + +const OrderReceivedActionModal: React.FC = ({ + orderId, + isOpen, + onClose, + onSuccess, +}) => { + const [alertMessage, setAlertMessage] = useState(''); + const [feedback, setFeedback] = useState(''); + const [dateReceived, setDateReceived] = useState(''); + const [photos, setPhotos] = useState([]); + + const isFormValid = dateReceived !== ''; + + const resetForm = () => { + setAlertMessage(''); + setFeedback(''); + setDateReceived(''); + setPhotos([]); + }; + + const handleSubmit = async () => { + try { + const dto: ConfirmDeliveryDto = { + dateReceived: new Date(dateReceived).toISOString(), + feedback: feedback, + }; + + await apiClient.confirmOrderDelivery(orderId, dto, photos); + + setAlertMessage('Delivery Confirmed'); + resetForm(); + onSuccess(); + onClose(); + } catch (err) { + setAlertMessage('Delivery could not be confirmed.'); + resetForm(); + onClose(); + } + }; + + return ( + { + if (!e.open) onClose(); + }} + closeOnInteractOutside + > + {alertMessage && ( + // TODO: add Justin's alert component/uncomment below out and remove text component + // + {alertMessage} + )} + + + + + + Action Required + + + + + As this order arrives, please confirm the donation receipt and + delivery of the order by filling out the details below. + + + + + + Date Received + + + setDateReceived(e.target.value)} + value={dateReceived} + /> + + + + + + Feedback + + +