diff --git a/package-lock.json b/package-lock.json index 7aa87d0b..3e9020bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "axios": "^1.6.8", @@ -1937,6 +1938,37 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz", + "integrity": "sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-roving-focus": "1.0.4", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-toast": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz", diff --git a/package.json b/package.json index 62a1de6d..bd6d7a11 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "axios": "^1.6.8", diff --git a/src/components/BurgerMenu/BurgerMenu.tsx b/src/components/BurgerMenu/BurgerMenu.tsx index db04d613..2a756df0 100644 --- a/src/components/BurgerMenu/BurgerMenu.tsx +++ b/src/components/BurgerMenu/BurgerMenu.tsx @@ -10,6 +10,7 @@ import { ShieldAlert, X, } from 'lucide-react'; +import clsx from 'clsx'; import { SessionServices } from '@/service'; import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'; @@ -17,9 +18,8 @@ import { BurguerMenuItem } from './components'; import { Separator } from '../ui/separator'; import { SessionContext } from '@/contexts'; import { usePartners } from '@/hooks'; -import { DialogClose } from '@radix-ui/react-dialog'; import { Button } from '../ui/button'; -import { DialogFooter } from '../ui/dialog'; +import { DialogClose, DialogFooter } from '../ui/dialog'; const BurgerMenu = () => { const { session } = useContext(SessionContext); @@ -63,6 +63,12 @@ const BurgerMenu = () => { link="/sobre-nos" icon={} /> + } + className={clsx({ hidden: !session })} + /> { return ( - + {donationOrderId ? ( ) : ( diff --git a/src/components/DonationCart/components/DonationSuccess/DonationSuccess.tsx b/src/components/DonationCart/components/DonationSuccess/DonationSuccess.tsx index 1e2cb63d..1d0df144 100644 --- a/src/components/DonationCart/components/DonationSuccess/DonationSuccess.tsx +++ b/src/components/DonationCart/components/DonationSuccess/DonationSuccess.tsx @@ -22,10 +22,6 @@ const DonationSuccess = React.forwardRef( if (loading) return ; - const handleRedirect = () => { - navigate(`/abrigo/${donation.shelter.id}/doacoes`); - }; - return (
@@ -80,7 +76,7 @@ const DonationSuccess = React.forwardRef( diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx new file mode 100644 index 00000000..9c9ca74c --- /dev/null +++ b/src/components/Loader/Loader.tsx @@ -0,0 +1,12 @@ +import { Loader2 } from 'lucide-react'; +import { ILoader } from './types'; + +const Loader = (props: ILoader) => { + const { loading, children } = props; + + if (loading) return ; + + return children; +}; + +export { Loader }; diff --git a/src/components/Loader/index.ts b/src/components/Loader/index.ts new file mode 100644 index 00000000..ba8bc1d7 --- /dev/null +++ b/src/components/Loader/index.ts @@ -0,0 +1,3 @@ +import { Loader } from './Loader'; + +export { Loader }; diff --git a/src/components/Loader/types.ts b/src/components/Loader/types.ts new file mode 100644 index 00000000..6fc5e483 --- /dev/null +++ b/src/components/Loader/types.ts @@ -0,0 +1,4 @@ +export interface ILoader { + loading: boolean; + children?: React.ReactNode; +} diff --git a/src/components/index.ts b/src/components/index.ts index fe877999..591ec155 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -17,6 +17,7 @@ import { BurgerMenu } from './BurgerMenu'; import { BackToTop } from './BackToTop'; import { DonationCartIcon } from './DonationCartIcon'; import { DonationCart } from './DonationCart'; +import { Loader } from './Loader'; export { LoadingScreen, @@ -38,4 +39,5 @@ export { BackToTop, DonationCartIcon, DonationCart, + Loader, }; diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 00000000..f57fffdb --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,53 @@ +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index f28c05ed..f2d13836 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -13,6 +13,7 @@ import { useGithubContributors } from './useGithubContributors'; import { useAuthRoles } from './useAuthRoles'; import { useSupporters } from './useSupporters'; import { useDonationOrder } from './useDonationOrder'; +import { useDonations } from './useDonations'; export { useShelters, @@ -30,4 +31,5 @@ export { useAuthRoles, useSupporters, useDonationOrder, + useDonations, }; diff --git a/src/hooks/useDonations/types.ts b/src/hooks/useDonations/types.ts index b1c28fc8..787e522f 100755 --- a/src/hooks/useDonations/types.ts +++ b/src/hooks/useDonations/types.ts @@ -1,3 +1,6 @@ +import { DonateOrderStatus } from '@/service/donationOrder/types'; +import { SupplyMeasure } from '../useShelter/types'; + export interface IUseDonationsData { page: number; perPage: number; @@ -8,7 +11,7 @@ export interface IUseDonationsData { export interface IDonationsData { id: string; userId: string; - status: string; + status: DonateOrderStatus; shelter: { id: string; name: string; @@ -16,10 +19,10 @@ export interface IDonationsData { donationOrderSupplies: { quantity: number; supply: { - measure: string; + measure: SupplyMeasure; name: string; }; - }; + }[]; createdAt: string; updatedAt: string; } diff --git a/src/hooks/useDonations/useDonations.tsx b/src/hooks/useDonations/useDonations.tsx index 2a378827..dba89357 100755 --- a/src/hooks/useDonations/useDonations.tsx +++ b/src/hooks/useDonations/useDonations.tsx @@ -2,8 +2,15 @@ import { useFetch } from '../useFetch'; import { PaginatedQueryPath } from '../usePaginatedQuery/paths'; import { IUseDonationsData } from './types'; -const useDonations = (shelterId: string) => { - return useFetch(`${PaginatedQueryPath.DonationOrder}`); +const useDonations = () => { + return useFetch(`${PaginatedQueryPath.DonationOrder}`, { + initialValue: { + count: 0, + page: 1, + perPage: 20, + results: [], + }, + }); }; export { useDonations }; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 42513669..3d161d9e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,9 +1,11 @@ import { ShelterCategory, SupplyMeasure } from '@/hooks/useShelter/types'; import { IUseSheltersDataSupplyData } from '@/hooks/useShelters/types'; +import { ShelterAvailabilityStatus } from '@/pages/Home/components/Filter/types'; import { ShelterTagInfo, ShelterTagType, } from '@/pages/Home/components/ShelterListItem/types'; +import { DonateOrderStatus } from '@/service/donationOrder/types'; import { SupplyPriority } from '@/service/supply/types'; import { type ClassValue, clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; @@ -158,6 +160,19 @@ const SupplyMeasureMap: Record = { Unit: 'un', }; +const ShelterAvailabilityStatusMap: Record = + { + available: 'Abrigo Disponivel', + unavailable: 'Abrigo Indisponivel', + waiting: 'Sem informação de disponibilidade', + }; + +const DonationStatusMap: Record = { + [DonateOrderStatus.Canceled]: 'Cancelado', + [DonateOrderStatus.Pending]: 'Pendente', + [DonateOrderStatus.Complete]: 'Entregue', +}; + export { cn, getAvailabilityProps, @@ -169,4 +184,6 @@ export { normalizedCompare, checkIsNull, SupplyMeasureMap, + ShelterAvailabilityStatusMap, + DonationStatusMap, }; diff --git a/src/pages/DonationsHistory/DonationsHistory.tsx b/src/pages/DonationsHistory/DonationsHistory.tsx index a445bcdc..b7f29e0d 100644 --- a/src/pages/DonationsHistory/DonationsHistory.tsx +++ b/src/pages/DonationsHistory/DonationsHistory.tsx @@ -1,155 +1,155 @@ -import { Header, LoadingScreen } from '@/components'; -import { Button } from '@/components/ui/button'; -import { ChevronLeft } from 'lucide-react'; -import { useNavigate, useParams } from 'react-router-dom'; -import { useShelter } from '@/hooks'; -import { IDonations, IDonationsPerDay, ViewOptions } from './types'; -import { useDonations } from '@/hooks/useDonations'; -import { useEffect, useState } from 'react'; -import { DonationsPerDay } from './components/DonationsPerDay'; -import { format } from 'date-fns'; -import { ptBR } from 'date-fns/locale'; - -const DonationsHistory = () => { - const navigate = useNavigate(); - const params = useParams(); - const { shelterId = '-1' } = params; - const { data: shelter, loading: shelterLoading } = useShelter(shelterId); - const { data: shelterDonations, loading: donationsLoading } = - useDonations(shelterId); - const [donationsReceivedPerDay, setDonationsReceivedPerDay] = useState< - IDonationsPerDay | {} - >([]); - const [donationsGivenPerDay, setDonationsGivenPerDay] = useState< - IDonationsPerDay | {} - >([]); - - const [viewOption, setViewOption] = useState(ViewOptions.Donated); - - const toggleViewOption = () => { - setViewOption((prevOption) => - prevOption === ViewOptions.Donated - ? ViewOptions.Received - : ViewOptions.Donated - ); - }; - - const donationGroupedByDate = (donations: IDonations): IDonationsPerDay => { - return donations.reduce((acc, donation) => { - const date = donation.createdAt.split('T')[0]; - - if (!acc[date]) { - acc[date] = []; - } - acc[date].push(donation); - - return acc; - }, {}); - }; +import { useCallback, useState } from 'react'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@radix-ui/react-tabs'; +import { cva } from 'class-variance-authority'; - const filterDonationsByCase = ( - donations: IDonationsPerDay, - shelterId: string - ) => { - const receivedDonations: IDonationsPerDay = {}; - const givenDonations: IDonationsPerDay = {}; - - Object.keys(donations).forEach((date) => { - receivedDonations[date] = donations[date].filter( - (donation) => donation.shelter.id === shelterId - ); - givenDonations[date] = donations[date].filter( - (donation) => donation.shelter.id !== shelterId - ); - }); - - return { receivedDonations, givenDonations }; - }; +import { BurgerMenu, Header, Loader } from '@/components'; +import { useDonations } from '@/hooks/useDonations'; +import { DonationHistoryListItem } from './components'; +import { DonationOrderServices } from '@/service'; +import { DonateOrderStatus } from '@/service/donationOrder/types'; +import { useToast } from '@/components/ui/use-toast'; +import { withAuth } from '@/hocs'; - useEffect(() => { - if (!donationsLoading) { - const donationsPerDay = donationGroupedByDate(shelterDonations.results); - const { receivedDonations, givenDonations } = filterDonationsByCase( - donationsPerDay, - shelterId - ); - setDonationsGivenPerDay(givenDonations); - setDonationsReceivedPerDay(receivedDonations); - } - }, [donationsLoading]); +const DonationsHistoryComponent = () => { + const [selectedTab, setSelectedTab] = useState<'made' | 'received'>('made'); + const { + data: donations, + loading: loadingDonations, + refresh, + } = useDonations(); + const [loading, setLoading] = useState>({}); + const { toast } = useToast(); - if (!donationsLoading) { - const dailyDonations = { - donated: donationsGivenPerDay, - received: donationsReceivedPerDay, - }; + const handleChangeTab = useCallback( + (newStatus: 'made' | 'received') => { + setSelectedTab(newStatus); + refresh({ + params: { + op: newStatus, + }, + }); + }, + [refresh] + ); - const segmentedDonationsDisplay = Object.keys( - dailyDonations[viewOption] - ).map((day) => { - return ( -
-

- {format(day, "dd 'de' MMMM yyyy ", { locale: ptBR })} -

- -
- ); - }); + const handleUpdateDonationStatus = useCallback( + (shelterId: string, newStatus: DonateOrderStatus) => { + setLoading((prev) => ({ ...prev, [shelterId]: true })); + DonationOrderServices.update(shelterId, { status: newStatus }) + .then(() => { + refresh({ params: { op: selectedTab } }); + }) + .catch((err) => { + toast({ + title: 'Ocorreu um erro ao atualizar o status da doação', + description: `${err?.response?.data?.message ?? err}`, + }); + }) + .finally(() => { + setLoading((prev) => ({ ...prev, [shelterId]: false })); + }); + }, + [refresh, selectedTab, toast] + ); - if (donationsLoading) return ; + const tabsVariants = cva('font-semibold text-lg border-b-2 !text-black', { + variants: { + variant: { + active: 'border-red-500', + default: 'border-transparent', + }, + }, + defaultVariants: { + variant: 'default', + }, + }); - return ( -
-
navigate('/')} + return ( +
+
} /> +
+

Suas Doações

+ + + handleChangeTab('made')} + className={tabsVariants({ + variant: selectedTab === 'made' ? 'active' : 'default', + })} > - - - } - /> -
-
-

- Suas doações -

-
-
-
toggleViewOption()} + Doado + + handleChangeTab('received')} + className={tabsVariants({ + variant: selectedTab === 'received' ? 'active' : 'default', + })} > -

- Doado -

-
-
toggleViewOption()} - > -

- Recebido -

-
-
- {segmentedDonationsDisplay} -
+ Recebido +
+
+ + + {donations.results.length === 0 ? ( +

Nenhuma doação encontrada

+ ) : ( + donations.results.map((donation) => ( + + handleUpdateDonationStatus( + donation.id, + DonateOrderStatus.Canceled + ) + } + onConfirm={() => + handleUpdateDonationStatus( + donation.id, + DonateOrderStatus.Complete + ) + } + /> + )) + )} +
+
+ + + {donations.results.length === 0 ? ( +

Nenhuma doação encontrada

+ ) : ( + donations.results.map((donation) => ( + + handleUpdateDonationStatus( + donation.id, + DonateOrderStatus.Canceled + ) + } + onConfirm={() => + handleUpdateDonationStatus( + donation.id, + DonateOrderStatus.Complete + ) + } + /> + )) + )} +
+
+
- ); - } +
+ ); }; + +const DonationsHistory = withAuth(DonationsHistoryComponent); + export { DonationsHistory }; diff --git a/src/pages/DonationsHistory/components/ConfirmationDialog.tsx b/src/pages/DonationsHistory/components/ConfirmationDialog.tsx deleted file mode 100644 index 0c7da3ef..00000000 --- a/src/pages/DonationsHistory/components/ConfirmationDialog.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import * as React from 'react'; -import { - Dialog, - DialogTrigger, - DialogPortal, - DialogOverlay, - DialogContent, - DialogFooter, - DialogTitle, - DialogDescription, -} from '../../../components/ui/dialog'; -import { Button } from '../../../components/ui/button'; - -interface ConfirmationDialogProps { - title: string; - description: string; - confirmLabel: string; - cancelLabel: string; - onConfirm: () => void; - onCancel: () => void; - triggerLabel: React.ReactNode; - Icon: React.ComponentType>; -} - -const ConfirmationDialog: React.FC = ({ - title, - description, - confirmLabel, - cancelLabel, - onConfirm, - - triggerLabel, - Icon, -}) => { - const [isOpen, setIsOpen] = React.useState(false); - - return ( - - - - - - - -
- {title} -
- - {description} - - - - - -
-
-
- ); -}; - -export { ConfirmationDialog }; diff --git a/src/pages/DonationsHistory/components/Donation.tsx b/src/pages/DonationsHistory/components/Donation.tsx deleted file mode 100644 index 6e910111..00000000 --- a/src/pages/DonationsHistory/components/Donation.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { useState, useEffect } from 'react'; -import { Printer, PackageCheck, CircleX } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Card } from '@/components/ui/card'; -import { ChevronDown, ChevronUp } from 'lucide-react'; -import { IDonationProps, ViewOptions } from '../types'; -import { Chip } from '@/components'; -import { DonationOrderServices } from '@/service/donationOrder/donationOrder.service'; -import { DonateOrderStatus } from '@/service/donationOrder/types'; -import { ConfirmationDialog } from './ConfirmationDialog'; - -const Donation = ({ viewOption, donation }: IDonationProps) => { - const [opened, setOpened] = useState(false); - const [status, setStatus] = useState(donation.status); - const [error, setError] = useState(null); - - const getDisplayDate = (status: string): DonateOrderStatus => { - if (status === DonateOrderStatus.Complete) { - return `Entregue no dia ${donation.createdAt.split('T')[0]} às - ${donation.createdAt.split('T')[1].slice(0, -5)}`; - } else if (status === DonateOrderStatus.Pending) { - return `Criado no dia ${donation.createdAt.split('T')[0]} às - ${donation.createdAt.split('T')[1].slice(0, -5)}`; - } else if (status === DonateOrderStatus.Canceled) { - return `Cancelado no dia ${donation.createdAt.split('T')[0]} às - ${donation.createdAt.split('T')[1].slice(0, -5)}`; - } - }; - - const [displayDate, setDisplayDate] = useState(getDisplayDate(status)); - - useEffect(() => { - const displayDate = getDisplayDate(status); - setDisplayDate(displayDate); - }, [status]); - - const Icon = !opened ? ChevronUp : ChevronDown; - const btnLabel = !opened ? 'Ocultar itens doados' : 'Mostrar itens doados'; - - //Creates list of all items to be displayed - const listOfItems = donation.items.map((item: string, index) => { - return ( -
  • - {`${item.quantity} ${ - item.supply.measure == 'Unit' ? 'unidade(s)' : item.supply.measure - } ${item.supply.name}`} -
  • - ); - }); - - const getStatusVariant = (status: string) => { - if (status === DonateOrderStatus.Complete) { - return { label: 'Entregue', color: '#A9CB9D' }; - } else if (status === DonateOrderStatus.Pending) { - return { label: 'Pendente', color: '#F69F9D' }; - } else { - return { label: 'Cancelado', color: '#D3D3D3' }; - } - }; - - const statusVariant = getStatusVariant(status); - - const handleConfirm = async () => { - try { - await DonationOrderServices.update(donation.donationId, { - status: DonateOrderStatus.Complete, - }); - setStatus(DonateOrderStatus.Complete); - } catch (err) { - setError('Failed to confirm the delivery. Please try again.'); - } - }; - - const handleCancel = async () => { - try { - await DonationOrderServices.update(donation.donationId, { - status: DonateOrderStatus.Canceled, - }); - setStatus(DonateOrderStatus.Canceled); - } catch (err) { - setError('Failed to cancel the delivery. Please try again.'); - } - }; - return ( - -
    - {viewOption == ViewOptions.Received ? 'Doação para' : 'Doação de'} - -
    -
    - {viewOption == ViewOptions.Received - ? donation.donatorName - : donation.shelterName} -
    -
    {displayDate}
    -
    - -
    - {opened &&
      {listOfItems}
    } -
    - - {status !== DonateOrderStatus.Complete && - status !== DonateOrderStatus.Canceled && ( - <> - {}} - triggerLabel={ - - Cancelar entrega - - } - Icon={CircleX} - /> - {}} - triggerLabel={ - - Confirmar entrega - - } - Icon={PackageCheck} - /> - - )} -
    -
    - ); -}; - -export { Donation }; diff --git a/src/pages/DonationsHistory/components/DonationHistoryListItem/DonationHistoryListItem.tsx b/src/pages/DonationsHistory/components/DonationHistoryListItem/DonationHistoryListItem.tsx new file mode 100644 index 00000000..375d3e28 --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryListItem/DonationHistoryListItem.tsx @@ -0,0 +1,105 @@ +import { useMemo, useState } from 'react'; +import { format } from 'date-fns'; +import { + ChevronDown, + ChevronUp, + Circle, + CircleX, + PackageCheck, + Printer, +} from 'lucide-react'; +import clsx from 'clsx'; + +import { IDonationHistoryListItem } from './types'; +import { SupplyMeasureMap } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { DonateOrderStatus } from '@/service/donationOrder/types'; +import { DonationHistoryStatus } from '../DonationHistoryStatus'; + +const DonationHistoryListItem = (props: IDonationHistoryListItem) => { + const { data: donation, onCancel, onConfirm, loading } = props; + const [visible, setVisible] = useState(false); + const accordeonLabel = useMemo( + () => (visible ? 'Ocultar itens doados' : 'Mostrar itens doados'), + [visible] + ); + const AccordeonIcon = useMemo( + () => (visible ? ChevronUp : ChevronDown), + [visible] + ); + + return ( +
    + + + +
    + + Doação para + +

    {donation.shelter.name}

    + + às {format(new Date(donation.createdAt), "HH'h'mm 'de' dd/MM/yy")} + +
    + +
      + {donation.donationOrderSupplies.map((s, idx) => ( +
    • + + {s.quantity} + {SupplyMeasureMap[s.supply.measure]} de {s.supply.name} +
    • + ))} +
    +
    + + +
    +
    + ); +}; + +export { DonationHistoryListItem }; diff --git a/src/pages/DonationsHistory/components/DonationHistoryListItem/index.ts b/src/pages/DonationsHistory/components/DonationHistoryListItem/index.ts new file mode 100644 index 00000000..498912cb --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryListItem/index.ts @@ -0,0 +1,3 @@ +import { DonationHistoryListItem } from './DonationHistoryListItem'; + +export { DonationHistoryListItem }; diff --git a/src/pages/DonationsHistory/components/DonationHistoryListItem/types.ts b/src/pages/DonationsHistory/components/DonationHistoryListItem/types.ts new file mode 100644 index 00000000..9b2c6927 --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryListItem/types.ts @@ -0,0 +1,8 @@ +import { IDonationsData } from '@/hooks/useDonations/types'; + +export interface IDonationHistoryListItem { + data: IDonationsData; + onConfirm?: () => void; + onCancel?: () => void; + loading?: boolean; +} diff --git a/src/pages/DonationsHistory/components/DonationHistoryStatus/DonationHistoryStatus.tsx b/src/pages/DonationsHistory/components/DonationHistoryStatus/DonationHistoryStatus.tsx new file mode 100644 index 00000000..1466288e --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryStatus/DonationHistoryStatus.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { cva } from 'class-variance-authority'; + +import { IDonationHistoryStatus } from './types'; +import { DonationStatusMap, cn } from '@/lib/utils'; +import { DonateOrderStatus } from '@/service/donationOrder/types'; + +const DonationHistoryStatus = React.forwardRef< + HTMLDivElement, + IDonationHistoryStatus +>((props, ref) => { + const { status, className = '', children, chipProps = {}, ...rest } = props; + const { className: chipClassName, ...restChipProps } = chipProps; + + const variants = cva('px-2 py-1 font-medium text-xs rounded-2xl', { + variants: { + variant: { + [DonateOrderStatus.Pending]: 'bg-light-yellow', + [DonateOrderStatus.Canceled]: 'bg-gray-300', + [DonateOrderStatus.Complete]: 'bg-light-green', + }, + }, + defaultVariants: { + variant: status, + }, + }); + + return ( +
    +
    + {DonationStatusMap[status]} +
    + {children} +
    + ); +}); + +export { DonationHistoryStatus }; diff --git a/src/pages/DonationsHistory/components/DonationHistoryStatus/index.ts b/src/pages/DonationsHistory/components/DonationHistoryStatus/index.ts new file mode 100644 index 00000000..ea6f681c --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryStatus/index.ts @@ -0,0 +1,3 @@ +import { DonationHistoryStatus } from './DonationHistoryStatus'; + +export { DonationHistoryStatus }; diff --git a/src/pages/DonationsHistory/components/DonationHistoryStatus/types.ts b/src/pages/DonationsHistory/components/DonationHistoryStatus/types.ts new file mode 100644 index 00000000..abbd3925 --- /dev/null +++ b/src/pages/DonationsHistory/components/DonationHistoryStatus/types.ts @@ -0,0 +1,8 @@ +import { DonateOrderStatus } from '@/service/donationOrder/types'; +import React from 'react'; + +export interface IDonationHistoryStatus + extends React.ComponentPropsWithoutRef<'div'> { + status: DonateOrderStatus; + chipProps?: React.ComponentPropsWithoutRef<'div'>; +} diff --git a/src/pages/DonationsHistory/components/DonationsPerDay.tsx b/src/pages/DonationsHistory/components/DonationsPerDay.tsx deleted file mode 100644 index 4e694967..00000000 --- a/src/pages/DonationsHistory/components/DonationsPerDay.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { IDonationsPerDayProps } from '../types'; -import { Donation } from './Donation'; - -const DonationsPerDay = ({ donations, viewOption }: IDonationsPerDayProps) => { - const donationsOfDay = donations.map((donation) => { - donation = { - donationId: donation.id, - donatorName: donation.shelter.name, - donatorId: donation.userId, - shelterId: donation.shelter.id, - shelterName: donation.shelter.name, - status: donation.status, - createdAt: donation.createdAt, - updatedAt: donation.updatedAt || null, - items: donation.donationOrderSupplies, - }; - - return ( - - ); - }); - - return ( -
    -
    -
    {donationsOfDay}
    -
    - ); -}; -export { DonationsPerDay }; diff --git a/src/pages/DonationsHistory/components/index.ts b/src/pages/DonationsHistory/components/index.ts new file mode 100644 index 00000000..0e6453de --- /dev/null +++ b/src/pages/DonationsHistory/components/index.ts @@ -0,0 +1,4 @@ +import { DonationHistoryListItem } from './DonationHistoryListItem'; +import { DonationHistoryStatus } from './DonationHistoryStatus'; + +export { DonationHistoryListItem, DonationHistoryStatus }; diff --git a/src/pages/DonationsHistory/types.ts b/src/pages/DonationsHistory/types.ts index 1229f76a..cb0ff5c3 100644 --- a/src/pages/DonationsHistory/types.ts +++ b/src/pages/DonationsHistory/types.ts @@ -1,25 +1 @@ -import { IDonationsData } from '@/hooks/useDonations/types'; - -export type IDonations = IDonationsData[]; - -export interface IDonationsPerDay { - [date: string]: IDonations; -} - -export interface IDonationsInGivenDay { - donations: IDonations; -} - -export enum ViewOptions { - Donated = 'donated', - Received = 'received', -} -export interface IDonationsPerDayProps { - donations: IDonations; - viewOption: ViewOptions; -} - -export interface IDonationProps { - viewOption: ViewOptions; - donation: IDonationProps; -} +export {}; diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index d19ebf1b..b8cfab6e 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -21,20 +21,11 @@ import { IFilterProps, ShelterAvailabilityStatus, } from './types'; -import { priorityOptions } from '@/lib/utils'; +import { ShelterAvailabilityStatusMap, priorityOptions } from '@/lib/utils'; import CitiesFilter from './CitiesFilter'; import { IUseSuppliesData } from '@/hooks/useSupplies/types'; import { SupplyPriority } from '@/service/supply/types'; -const ShelterAvailabilityStatusMapped: Record< - ShelterAvailabilityStatus, - string -> = { - available: 'Abrigo Disponivel', - unavailable: 'Abrigo Indisponivel', - waiting: 'Sem informação de disponibilidade', -}; - const priorityOpts = Object.entries(priorityOptions).reduce( (prev, [priority, label]) => priority === `${SupplyPriority.NotNeeded}` @@ -71,7 +62,7 @@ const Filter = (props: IFilterProps) => { })), search: data.search, shelterStatus: data.shelterStatus.map((s) => ({ - label: ShelterAvailabilityStatusMapped[s], + label: ShelterAvailabilityStatusMap[s], value: s, })), supplyCategories: data.supplyCategoryIds.map((id) => ({ @@ -134,7 +125,7 @@ const Filter = (props: IFilterProps) => { checked ? [ ...values.shelterStatus, - { label: ShelterAvailabilityStatusMapped[status], value: status }, + { label: ShelterAvailabilityStatusMap[status], value: status }, ] : values.shelterStatus.filter((s) => s.value !== status) ); diff --git a/src/pages/Shelter/Shelter.tsx b/src/pages/Shelter/Shelter.tsx index 7b41487c..e8e64f66 100644 --- a/src/pages/Shelter/Shelter.tsx +++ b/src/pages/Shelter/Shelter.tsx @@ -211,6 +211,7 @@ const Shelter = () => { quantity: l.quantity, }))} onDonate={handleDonate} + shelterId={shelterId} /> {!isLastElement && } diff --git a/src/pages/Shelter/components/ShelterCategoryList/ShelterCategoryList.tsx b/src/pages/Shelter/components/ShelterCategoryList/ShelterCategoryList.tsx index a5ac597a..7a0f14a2 100644 --- a/src/pages/Shelter/components/ShelterCategoryList/ShelterCategoryList.tsx +++ b/src/pages/Shelter/components/ShelterCategoryList/ShelterCategoryList.tsx @@ -1,12 +1,20 @@ +import { useContext, useMemo } from 'react'; import clsx from 'clsx'; import { SupplyMeasureMap, cn, getSupplyPriorityProps } from '@/lib/utils'; import { ShelterCategoryListProps } from './types'; import { CircleStatus } from '@/components'; import { SupplyPriority } from '@/service/supply/types'; +import { DonationCartContext } from '@/contexts'; +import { IDonationCartItem } from '@/contexts/DonationCartContext/types'; const ShelterCategoryList = (props: ShelterCategoryListProps) => { - const { items, name, onDonate } = props; + const { items, name, onDonate, shelterId } = props; + const { carts } = useContext(DonationCartContext); + const cart: IDonationCartItem[] = useMemo( + () => carts[shelterId] ?? [], + [carts, shelterId] + ); return (
    @@ -36,8 +44,9 @@ const ShelterCategoryList = (props: ShelterCategoryListProps) => {