Skip to content

Commit 8ed7449

Browse files
authored
Fix/develop bugs (#90)
* fix: cache bug (invalite cache on create/update operation) * feat: added update many shelter supplies and admin rule
1 parent 8237671 commit 8ed7449

File tree

18 files changed

+309
-80
lines changed

18 files changed

+309
-80
lines changed

src/api/api.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import axios, { AxiosRequestHeaders, InternalAxiosRequestConfig } from 'axios';
2-
import { getCacheRequestData, handleCacheResponse } from './cache';
2+
import { clearCache, getCacheRequestData, handleCacheResponse } from './cache';
33

44
const api = axios.create({
55
baseURL: import.meta.env.VITE_API_URL ?? 'http://localhost:4000/',
@@ -31,6 +31,7 @@ api.interceptors.response.use(
3131
},
3232
(error) => {
3333
if (error.response && error.response.status === 401) {
34+
clearCache(false);
3435
localStorage.removeItem('token');
3536
}
3637
return Promise.reject(error);

src/api/cache.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ function checkCacheHasExpired(
1616
return new Date().getTime() - timestamp >= ttl;
1717
}
1818

19-
function clearExpiredCache() {
20-
log('cache - checando caches expirados...');
19+
function clearCache(onlyExpired: boolean = true) {
20+
log(
21+
onlyExpired
22+
? 'cache - checando caches expirados...'
23+
: 'cache - limpando cache...'
24+
);
2125
Object.keys(localStorage)
2226
.filter((key: string) => key.startsWith('cache:'))
2327
.forEach((key) => {
2428
const data = localStorage.getItem(key);
2529
if (data) {
2630
const { timestamp } = JSON.parse(data);
27-
if (checkCacheHasExpired(timestamp)) {
31+
if (!onlyExpired || checkCacheHasExpired(timestamp)) {
2832
localStorage.removeItem(key);
2933
}
3034
}
@@ -74,6 +78,6 @@ function handleCacheResponse(resp: AxiosResponse<any, any>) {
7478
}
7579
}
7680

77-
clearExpiredCache();
81+
clearCache();
7882

79-
export { handleCacheResponse, getCacheRequestData };
83+
export { handleCacheResponse, getCacheRequestData, clearCache };

src/components/Authenticated/Authenticated.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
import { Fragment, useContext } from 'react';
22

33
import { SessionContext } from '@/contexts';
4+
import { IAuthenticatedProps } from './types';
5+
import { AccessLevel } from '@/service/sessions/types';
46

5-
const Authenticated = ({ children }: { children?: React.ReactNode }) => {
7+
const MappedRoles: Record<AccessLevel, AccessLevel[]> = {
8+
Admin: ['Admin'],
9+
DistributionCenter: ['Admin', 'DistributionCenter'],
10+
Staff: ['Admin', 'Staff'],
11+
User: ['Admin', 'Staff', 'DistributionCenter', 'User'],
12+
};
13+
14+
const Authenticated = ({ children, role = 'User' }: IAuthenticatedProps) => {
615
const { session } = useContext(SessionContext);
716

8-
if (!session) return <Fragment />;
17+
if (!session || !MappedRoles[role].includes(session.accessLevel))
18+
return <Fragment />;
919

1020
return <div className="contents">{children}</div>;
1121
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { AccessLevel } from '@/service/sessions/types';
2+
3+
export interface IAuthenticatedProps {
4+
role?: AccessLevel;
5+
children?: React.ReactNode;
6+
}

src/components/CardAboutShelter/CardAboutShelter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ const CardAboutShelter = (props: ICardAboutShelter) => {
3030
check(shelter.petFriendly) ? (
3131
shelter.petFriendly ? (
3232
<p>
33-
O abrigo <b className="text-green-600">aceita</b> animais
33+
O abrigo <b>aceita</b> animais
3434
</p>
3535
) : (
3636
<p>
37-
O abrigo <b className="text-red-600">não</b> aceita animais
37+
O abrigo <b>não</b> aceita animais
3838
</p>
3939
)
4040
) : (

src/pages/CreateShelter/CreateShelter.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ICreateShelter } from '@/service/shelter/types';
1616
import { toast } from '@/components/ui/use-toast';
1717
import { ShelterServices } from '@/service';
1818
import { withAuth } from '@/hocs';
19+
import { clearCache } from '@/api/cache';
1920

2021
const CreateShelterComponent = () => {
2122
const navigate = useNavigate();
@@ -33,6 +34,7 @@ const CreateShelterComponent = () => {
3334
address: '',
3435
shelteredPeople: 0,
3536
capacity: 0,
37+
verified: false,
3638
petFriendly: false,
3739
contact: null,
3840
pix: null,
@@ -57,6 +59,7 @@ const CreateShelterComponent = () => {
5759
onSubmit: async (values, { resetForm }) => {
5860
try {
5961
await ShelterServices.create(values);
62+
clearCache(false);
6063
toast({
6164
title: 'Cadastro feita com sucesso',
6265
});

src/pages/CreateSupply/CreateSupply.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ICreateSupply, SupplyPriority } from '@/service/supply/types';
1818
import { getSupplyPriorityProps } from '@/lib/utils';
1919
import { ShelterSupplyServices, SupplyServices } from '@/service';
2020
import { ICreateShelterSupply } from '@/service/shelterSupply/types';
21+
import { clearCache } from '@/api/cache';
2122

2223
const CreateSupply = () => {
2324
const navigate = useNavigate();
@@ -60,6 +61,7 @@ const CreateSupply = () => {
6061
priority: +values.priority,
6162
shelterId,
6263
});
64+
clearCache(false);
6365
toast({
6466
title: 'Item cadastrado com sucesso',
6567
});

src/pages/EditShelterSupply/EditShelterSupply.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ShelterSupplyServices } from '@/service';
1313
import { useToast } from '@/components/ui/use-toast';
1414
import { ISupply, SupplyPriority } from '@/service/supply/types';
1515
import { IUseShelterDataSupply } from '@/hooks/useShelter/types';
16+
import { clearCache } from '@/api/cache';
1617

1718
const EditShelterSupply = () => {
1819
const navigate = useNavigate();
@@ -66,6 +67,7 @@ const EditShelterSupply = () => {
6667
const successCallback = () => {
6768
setModalOpened(false);
6869
setModalData(null);
70+
clearCache(false);
6971
refresh();
7072
};
7173

src/pages/Home/components/Filter/Filter.tsx

Lines changed: 107 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useCallback, useMemo } from 'react';
12
import Select from 'react-select';
23
import { useFormik } from 'formik';
34
import * as Yup from 'yup';
@@ -15,38 +16,99 @@ import {
1516
DialogTitle,
1617
} from '@/components/ui/dialog';
1718
import {
18-
IFilterFormProps,
19+
IFilterFormikProps,
1920
IFilterProps,
2021
ShelterAvailabilityStatus,
2122
} from './types';
2223
import { priorityOptions } from '@/lib/utils';
2324
import { ISupply, SupplyPriority } from '@/service/supply/types';
24-
import { useCallback } from 'react';
25+
26+
const ShelterAvailabilityStatusMapped: Record<
27+
ShelterAvailabilityStatus,
28+
string
29+
> = {
30+
available: 'Abrigo Disponivel',
31+
unavailable: 'Abrigo Indisponivel',
32+
waiting: 'Sem informação de disponibilidade',
33+
};
34+
35+
const priorityOpts = Object.entries(priorityOptions).reduce(
36+
(prev, [priority, label]) =>
37+
priority === `${SupplyPriority.NotNeeded}`
38+
? prev
39+
: { ...prev, [priority]: label },
40+
{} as Record<SupplyPriority, string>
41+
);
2542

2643
const Filter = (props: IFilterProps) => {
2744
const { data, onClose, onSubmit, open } = props;
2845
const { data: supplies, loading: loadingSupplies } = useSupplies();
2946
const { data: supplyCategories, loading: loadingSupplyCategories } =
3047
useSupplyCategories();
31-
const { handleSubmit, values, setFieldValue } = useFormik<IFilterFormProps>({
32-
initialValues: data,
33-
enableReinitialize: true,
34-
validateOnChange: false,
35-
validateOnBlur: false,
36-
validateOnMount: false,
37-
validationSchema: Yup.object().shape({
38-
search: Yup.string(),
39-
}),
40-
onSubmit,
41-
});
48+
const mappedSupplyCategories = useMemo(() => {
49+
return supplyCategories.reduce(
50+
(prev, current) => ({ ...prev, [current.id]: current }),
51+
{} as Record<string, ISupplyCategory>
52+
);
53+
}, [supplyCategories]);
54+
const mappedSupplies = useMemo(() => {
55+
return supplies.reduce(
56+
(prev, current) => ({ ...prev, [current.id]: current }),
57+
{} as Record<string, ISupply>
58+
);
59+
}, [supplies]);
60+
const { handleSubmit, values, setFieldValue } = useFormik<IFilterFormikProps>(
61+
{
62+
initialValues: {
63+
priority: {
64+
value: data.priority ?? SupplyPriority.Urgent,
65+
label: priorityOpts[data.priority ?? SupplyPriority.Urgent],
66+
},
67+
search: data.search,
68+
shelterStatus: data.shelterStatus.map((s) => ({
69+
label: ShelterAvailabilityStatusMapped[s],
70+
value: s,
71+
})),
72+
supplyCategories: data.supplyCategoryIds.map((id) => ({
73+
label: mappedSupplyCategories[id]?.name,
74+
value: id,
75+
})),
76+
supplies: data.supplyIds.map((id) => ({
77+
value: id,
78+
label: mappedSupplies[id]?.name,
79+
})),
80+
},
81+
enableReinitialize: true,
82+
validateOnChange: false,
83+
validateOnBlur: false,
84+
validateOnMount: false,
85+
validationSchema: Yup.object().shape({
86+
search: Yup.string(),
87+
}),
88+
onSubmit: (values) => {
89+
const { priority, search, shelterStatus, supplies, supplyCategories } =
90+
values;
91+
onSubmit({
92+
priority: priority?.value ? +priority.value : null,
93+
search,
94+
shelterStatus: shelterStatus.map((s) => s.value),
95+
supplyCategoryIds: supplyCategories.map((s) => s.value),
96+
supplyIds: supplies.map((s) => s.value),
97+
});
98+
},
99+
}
100+
);
42101

43102
const handleToggleShelterStatus = useCallback(
44-
(checked: boolean, value: ShelterAvailabilityStatus) => {
103+
(checked: boolean, status: ShelterAvailabilityStatus) => {
45104
setFieldValue(
46105
'shelterStatus',
47106
checked
48-
? [...values.shelterStatus, value]
49-
: values.shelterStatus.filter((s) => s !== value)
107+
? [
108+
...values.shelterStatus,
109+
{ label: ShelterAvailabilityStatusMapped[status], value: status },
110+
]
111+
: values.shelterStatus.filter((s) => s.value !== status)
50112
);
51113
},
52114
[setFieldValue, values.shelterStatus]
@@ -88,31 +150,38 @@ const Filter = (props: IFilterProps) => {
88150
</label>
89151
<Select
90152
placeholder="Selecione"
91-
options={Object.entries(priorityOptions).map(
92-
([priority, label]) => ({ label, value: priority } as any)
153+
value={{
154+
label:
155+
priorityOpts[
156+
values.priority?.value ?? SupplyPriority.Urgent
157+
],
158+
value: values.priority?.value ?? SupplyPriority.Needing,
159+
}}
160+
options={Object.entries(priorityOpts).map(
161+
([priority, label]) => ({ label, value: +priority } as any)
93162
)}
94-
onChange={(
95-
v: { label: string; value: SupplyPriority } | null
96-
) => setFieldValue('priority', v?.value)}
163+
onChange={(v) => {
164+
const newValue = {
165+
...v,
166+
value: v ? +v.value : SupplyPriority.Urgent,
167+
};
168+
setFieldValue('priority', newValue);
169+
}}
97170
/>
98171
</div>
99172
<div className="flex flex-col gap-1 w-full">
100173
<label className="text-muted-foreground text-sm md:text-lg font-medium">
101174
Categoria
102175
</label>
103176
<Select
177+
value={values.supplyCategories}
104178
placeholder="Selecione"
105179
isMulti
106180
options={supplyCategories.map((el: ISupplyCategory) => ({
107181
label: el.name,
108182
value: el.id,
109183
}))}
110-
onChange={(v) =>
111-
setFieldValue(
112-
'supplyCategoryIds',
113-
v.map((s) => s.value)
114-
)
115-
}
184+
onChange={(v) => setFieldValue('supplyCategories', v)}
116185
/>
117186
</div>
118187
<div className="flex flex-col w-full">
@@ -122,16 +191,12 @@ const Filter = (props: IFilterProps) => {
122191
<Select
123192
placeholder="Selecione"
124193
isMulti
194+
value={values.supplies}
125195
options={supplies.map((el: ISupply) => ({
126196
label: el.name,
127197
value: el.id,
128198
}))}
129-
onChange={(v) =>
130-
setFieldValue(
131-
'supplyIds',
132-
v.map((s) => s.value)
133-
)
134-
}
199+
onChange={(v) => setFieldValue('supplies', v)}
135200
/>
136201
</div>
137202
</div>
@@ -148,7 +213,9 @@ const Filter = (props: IFilterProps) => {
148213
onChange={(ev) =>
149214
handleToggleShelterStatus(ev.target.checked, 'available')
150215
}
151-
defaultChecked={values.shelterStatus.includes('available')}
216+
defaultChecked={values.shelterStatus.some(
217+
(s) => s.value === 'available'
218+
)}
152219
/>
153220
Abrigo Disponivel
154221
</label>
@@ -164,8 +231,8 @@ const Filter = (props: IFilterProps) => {
164231
'unavailable'
165232
)
166233
}
167-
defaultChecked={values.shelterStatus.includes(
168-
'unavailable'
234+
defaultChecked={values.shelterStatus.some(
235+
(s) => s.value === 'unavailable'
169236
)}
170237
/>
171238
Abrigo Indisponível
@@ -179,9 +246,11 @@ const Filter = (props: IFilterProps) => {
179246
onChange={(ev) =>
180247
handleToggleShelterStatus(ev.target.checked, 'waiting')
181248
}
182-
defaultChecked={values.shelterStatus.includes('waiting')}
249+
defaultChecked={values.shelterStatus.some(
250+
(s) => s.value === 'waiting'
251+
)}
183252
/>
184-
Aguardando disponibilidade
253+
Sem informação de disponibilidade
185254
</label>
186255
</div>
187256
</div>

0 commit comments

Comments
 (0)