Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add supplies history #303

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
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
3 changes: 3 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useGithubContributors } from './useGithubContributors';
import { useAuthRoles } from './useAuthRoles';
import { useSupporters } from './useSupporters';
import { useDonationOrder } from './useDonationOrder';
import { useSuppliesHistory } from './useSuppliesHistory'


export {
useShelters,
Expand All @@ -30,4 +32,5 @@ export {
useAuthRoles,
useSupporters,
useDonationOrder,
useSuppliesHistory
};
3 changes: 3 additions & 0 deletions src/hooks/useSuppliesHistory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { useSuppliesHistory } from './useSuppliesHistory';

export { useSuppliesHistory };
21 changes: 21 additions & 0 deletions src/hooks/useSuppliesHistory/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export interface IUseSuppliesHistoryData {
results: IUseSuppliesHistoryDataResults[];
}

export interface IUseSuppliesHistoryDataResults {
id: string;
supply: IUseSuppliesHistoryDataSupplyData;
priority: number;
quantity: number;
predecessor: IUseSupplierHistoryDataProdecessor;
createdAt: string;
}

export interface IUseSuppliesHistoryDataSupplyData {
name: string;
}

export interface IUseSupplierHistoryDataProdecessor {
priority: number;
quantity?: number | null;
}
11 changes: 11 additions & 0 deletions src/hooks/useSuppliesHistory/useSuppliesHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useFetch } from '../useFetch';
import { PaginatedQueryPath } from '../usePaginatedQuery/paths';
import { IUseSuppliesHistoryData } from './types';

const useSuppliesHistory = (shelterId: string) => {
return useFetch<IUseSuppliesHistoryData>(
`${PaginatedQueryPath.Supplies}/history/${shelterId}`
);
};

export { useSuppliesHistory };
26 changes: 25 additions & 1 deletion src/pages/Shelter/Shelter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Fragment, useCallback, useContext, useMemo, useState } from 'react';
import { ChevronLeft, Pencil } from 'lucide-react';
import { ChevronLeft, ChevronRight, History, Pencil } from 'lucide-react';
import { useNavigate, useParams } from 'react-router-dom';

import {
Expand Down Expand Up @@ -32,6 +32,7 @@ import { ShelterCategoryList } from './components';
import { Separator } from '@/components/ui/separator';
import { DonationCartContext } from '@/contexts';
import { ShelterCategoryListItemProps } from './components/ShelterCategoryList/types';
import { format } from 'date-fns';

const defaultPriorities: SupplyPriority[] = [
SupplyPriority.Urgent,
Expand Down Expand Up @@ -217,6 +218,29 @@ const Shelter = () => {
);
})}
</div>
{shelter.updatedAt && (
<div>
<div className="flex justify-between items-center">
<small className="text-sm md:text-md font-light text-muted-foreground mt-2">
Atualizado em {format(shelter.updatedAt, 'dd/MM/yyyy HH:mm')}
</small>
</div>

<div>
<Button
variant="ghost"
className="font-medium text-[16px] w-full sm:w-72 flex gap-2 justify-between bg-[#F6F8FC] hover:text-blue-500 border-[#E8F0F8]"
onClick={() => navigate(`/abrigo/${shelterId}/history`)}
>
<div className="flex gap-2 items-center">
<History size={17} />
Histórico de edições
</div>
<ChevronRight size={17} />
</Button>
</div>
</div>
)}
</div>
</div>
</Fragment>
Expand Down
171 changes: 171 additions & 0 deletions src/pages/SuppliesHistory/SuppliesHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { ChevronLeft, Info } from 'lucide-react';
import { useNavigate, useParams } from 'react-router-dom';
import {
CircleStatus,
Header,
LoadingScreen,
VerifiedBadge,
} from '@/components';
import { useShelter, useSuppliesHistory } from '@/hooks';
import { IUseSuppliesHistoryDataResults } from '@/hooks/useSuppliesHistory/types';
import { format } from 'date-fns';
import { getSupplyPriorityProps } from '@/lib/utils';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { SuppliesHistoryGroup } from './components/SuppliesHistoryGroup';
import { GroupedHistory, PriorityLabel } from './types';

const groupByDateTime = (histories: IUseSuppliesHistoryDataResults[]) => {
return histories.reduce((groups, history) => {
const dateTime = format(new Date(history.createdAt), 'dd/MM/yyyy HH:mm');
groups[dateTime] = groups[dateTime] || [];
groups[dateTime].push(history);
return groups;
}, {} as Record<string, IUseSuppliesHistoryDataResults[]>);
};

const isExcluded = (history: IUseSuppliesHistoryDataResults): boolean => {
return (
(history.priority === 0 || history.predecessor?.priority === 0) &&
(history.priority < 0 || history.quantity === history.predecessor?.quantity)
);
};

const isEdited = (history: IUseSuppliesHistoryDataResults): boolean => {
return history.predecessor !== null && !isExcluded(history);
};

const processHistory = (
history: IUseSuppliesHistoryDataResults,
groups: Record<PriorityLabel, GroupedHistory>,
priorityLabel: PriorityLabel
) => {
if (history.predecessor === null) {
groups[priorityLabel].added.push(history);
} else if (isEdited(history)) {
groups[priorityLabel].edited.push(history);
} else {
groups[priorityLabel].excluded.push(history);
}
};

const groupByPriority = (
histories: IUseSuppliesHistoryDataResults[]
): Record<PriorityLabel, GroupedHistory> => {
return histories.reduce((groups, history) => {
const { className, label } = getSupplyPriorityProps(history.priority);
const priorityLabel = label as PriorityLabel;

if (!groups[priorityLabel]) {
groups[priorityLabel] = {
added: [],
edited: [],
excluded: [],
className,
};
}

processHistory(history, groups, priorityLabel);
return groups;
}, {} as Record<PriorityLabel, GroupedHistory>);
};

const SuppliesHistory = () => {
const params = useParams();
const { shelterId = '-1' } = params;
const navigate = useNavigate();
const { data: shelter, loading } = useShelter(shelterId);
const { data: histories, loading: historiesLoading } =
useSuppliesHistory(shelterId);

if (loading && historiesLoading) return <LoadingScreen />;

return (
<div className="flex flex-col h-screen items-center">
<Header
title="Histórico de edições"
startAdornment={
<Button
size="sm"
variant="ghost"
className="[&_svg]:stroke-white disabled:bg-red-500 hover:bg-red-400"
onClick={() => navigate(`/abrigo/${shelterId}`)}
>
<ChevronLeft size={20} />
</Button>
}
/>
<div className="p-4 flex flex-col max-w-5xl w-full h-full">
<h1 className="text-[#2f2f2f] font-semibold text-2xl">
Histórico de edições
</h1>
<div className="flex items-center gap-1">
<h1 className="text-[#677183] font-semibold text-lg">
{shelter.name}
</h1>
{shelter.verified && <VerifiedBadge />}
</div>
<div className="py-4">
<Card className="border-[#677183]">
<CardContent className="p-2 flex items-top sm:items-center">
<Info
color="#677183"
size={18}
className="w-24 mt-1 sm:w-12 lg:w-8 sm:mt-0"
/>
<p className="text-[#677183] text-sm">
Confira a lista de itens que foram adicionados em cada uma das
modificações feitas a esse abrigo
</p>
</CardContent>
</Card>
</div>
{histories && histories?.results ? (
Object.entries(groupByDateTime(histories.results)).map(
([dateTime, histories]) => (
<div key={dateTime} className="py-4 flex flex-col gap-2 border-b">
<div className="flex justify-between items-center">
<p className="font-semibold text-[18px]">{dateTime}</p>
</div>
<p className="text-[#677183] font-normal text-md mt-2">
Modificações
</p>
{Object.entries(groupByPriority(histories)).map(
([priority, items], index) => (
<div key={index} className="flex flex-col gap-2">
<p className="font-semibold text-md flex gap-2 items-center">
<CircleStatus className={items.className} />
{priority}
</p>
<SuppliesHistoryGroup
title="Excluído"
items={items.excluded}
className={items.className}
/>
<SuppliesHistoryGroup
title="Editado"
items={items.edited}
className={items.className}
/>
<SuppliesHistoryGroup
title="Adicionado"
items={items.added}
className={items.className}
/>
</div>
)
)}
</div>
)
)
) : (
<div className="flex flex-col h-screen items-center justify-center">
<p className='text-[#677183]'>Nenhum histórico de edição disponível</p>
</div>
)}
</div>
</div>
);
};

export { SuppliesHistory };
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { SuppliesHistoryItem } from '../SuppliesHistoryItem';
import { ISuppliesHistoryGroupProps } from './types';

const SuppliesHistoryGroup = (props: ISuppliesHistoryGroupProps) => {
const { items, className, title } = props;
return (
items.length > 0 && (
<>
<p className="text-xs px-6">{title}</p>
<div className="flex gap-2 px-6 flex-wrap">
{items.map((history, index) => (
<SuppliesHistoryItem
key={index}
history={history}
className={className}
/>
))}
</div>
</>
)
);
};

export { SuppliesHistoryGroup };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SuppliesHistoryGroup } from './SuppliesHistoryGroup';

export { SuppliesHistoryGroup };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IUseSuppliesHistoryDataResults } from '@/hooks/useSuppliesHistory/types';

export interface ISuppliesHistoryGroupProps {
title: string;
items: IUseSuppliesHistoryDataResults[];
className: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Chip } from '@/components';
import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';
import { ISuppliesHistoryItemProps } from './types';

const SuppliesHistoryItem = ({
history,
className,
}: ISuppliesHistoryItemProps) => {
const quantity = history.quantity ?? history.predecessor?.quantity;
const showBadge = quantity !== null && quantity !== undefined && quantity > 0;

return (
<div className={cn('flex gap-x-1 relative', { 'mr-3': history.quantity })}>
<Chip label={history.supply.name} className={className} />
{showBadge && (
<Badge
variant="default"
className="absolute z-10 right-4 top-0 -translate-y-2 translate-x-full text-xs flex items-center justify-center w-7 h-6"
>
{quantity > 99 ? '99+' : quantity}
</Badge>
)}
</div>
);
};

export { SuppliesHistoryItem };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SuppliesHistoryItem } from './SuppliesHistoryItem';

export { SuppliesHistoryItem };
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IUseSuppliesHistoryDataResults } from '@/hooks/useSuppliesHistory/types';

export interface ISuppliesHistoryItemProps {
history: IUseSuppliesHistoryDataResults;
className: string;
}
3 changes: 3 additions & 0 deletions src/pages/SuppliesHistory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SuppliesHistory } from "./SuppliesHistory";

export { SuppliesHistory };
15 changes: 15 additions & 0 deletions src/pages/SuppliesHistory/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IUseSuppliesHistoryDataResults } from "@/hooks/useSuppliesHistory/types";


export type PriorityLabel =
| 'Precisa urgentemente'
| 'Precisa'
| 'Disponível para doação'
| 'Não preciso';

export interface GroupedHistory {
added: IUseSuppliesHistoryDataResults[];
edited: IUseSuppliesHistoryDataResults[];
excluded: IUseSuppliesHistoryDataResults[];
className: string;
}
2 changes: 2 additions & 0 deletions src/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { UpdateShelter } from './UpdateShelter';
import { PrivacyPolicy } from './PrivacyPolicy';
import { AboutUs } from './AboutUs';
import { Supporters } from './Supporters';
import { SuppliesHistory} from './SuppliesHistory'

export {
SignIn,
Expand All @@ -20,4 +21,5 @@ export {
PrivacyPolicy,
AboutUs,
Supporters,
SuppliesHistory
};
Loading