Skip to content

Commit 38d7c14

Browse files
kelvinsbmarcodmc
authored and
marcodmc
committed
feat: edit shelter supply item quantity (SOS-RS#170)
1 parent 5fd9550 commit 38d7c14

File tree

5 files changed

+84
-14
lines changed

5 files changed

+84
-14
lines changed

src/components/DialogSelector/DialogSelector.tsx

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useState, useRef } from 'react';
22

33
import {
44
Dialog,
@@ -12,6 +12,7 @@ import { IDialogSelectorProps } from './types';
1212
import { RadioGroup, RadioGroupItem } from '../ui/radio-group';
1313
import { Label } from '../ui/label';
1414
import { Button } from '../ui/button';
15+
import { Input } from '../ui/input';
1516

1617
const DialogSelector = (props: IDialogSelectorProps) => {
1718
const {
@@ -21,10 +22,23 @@ const DialogSelector = (props: IDialogSelectorProps) => {
2122
description,
2223
options,
2324
value,
25+
quantity: quantityProp,
2426
onSave,
2527
isSubmitting,
2628
} = props;
2729
const [selectedItem, setSelectedItem] = useState<string>(value);
30+
const selectedItemRef = useRef<string>(value); // to prevent dated prop values bug on the previous line
31+
const [quantity, setQuantity] = useState<number>(quantityProp);
32+
const quantityRef = useRef<number>(quantityProp);
33+
34+
if (quantityRef.current !== quantityProp) {
35+
setQuantity(quantityProp);
36+
quantityRef.current = quantityProp;
37+
}
38+
if (selectedItemRef.current !== value) {
39+
setSelectedItem(value);
40+
selectedItemRef.current = value;
41+
}
2842

2943
return (
3044
<Dialog open={open} onOpenChange={onClose}>
@@ -33,15 +47,57 @@ const DialogSelector = (props: IDialogSelectorProps) => {
3347
<DialogTitle className="text-base font-medium">{title}</DialogTitle>
3448
{description && <DialogDescription>{description}</DialogDescription>}
3549
</DialogHeader>
50+
<div className="flex flex-col">
51+
<label htmlFor="quantity" className="text-muted-foreground">
52+
Quantidade
53+
</label>
54+
<div className="flex gap-2 items-center justify-center py-2">
55+
<Button
56+
onClick={(event) => {
57+
event.preventDefault();
58+
setQuantity((prev) => {
59+
const newQuantity = Math.max(prev - 1, 0);
60+
return newQuantity;
61+
});
62+
}}
63+
className="bg-blue-700 text-white hover:bg-blue-600 active:bg-blue-500 px-8"
64+
>
65+
-
66+
</Button>
67+
<Input
68+
type="number"
69+
name="quantity"
70+
value={quantity}
71+
onChange={(event) => setQuantity(+event.target.value)}
72+
placeholder="Quantidade"
73+
min={0}
74+
/>
75+
<Button
76+
onClick={(event) => {
77+
event.preventDefault();
78+
setQuantity((prev) => prev + 1);
79+
}}
80+
className="bg-blue-700 text-white hover:bg-blue-600 active:bg-blue-500 px-8"
81+
>
82+
+
83+
</Button>
84+
</div>
85+
</div>
3686
<div className="px-2 py-4 max-h-[50vh] overflow-y-auto">
3787
<RadioGroup
3888
value={selectedItem}
3989
onValueChange={(v) => setSelectedItem(v)}
4090
>
4191
{options.map((option, idx) => (
4292
<div key={idx} className="flex items-center space-x-2 py-2">
43-
<RadioGroupItem value={option.value} id="r1" />
44-
<Label htmlFor="r1">{option.label}</Label>
93+
<RadioGroupItem
94+
value={option.value}
95+
id={option.value}
96+
className="cursor-pointer"
97+
/>
98+
<Label htmlFor={option.value} className="cursor-pointer">
99+
{option.label}
100+
</Label>
45101
</div>
46102
))}
47103
</RadioGroup>
@@ -50,7 +106,9 @@ const DialogSelector = (props: IDialogSelectorProps) => {
50106
<Button
51107
className="w-full bg-blue-700 text-white hover:bg-blue-600 active:bg-blue-500"
52108
size="sm"
53-
onClick={() => (onSave ? onSave(selectedItem) : undefined)}
109+
onClick={() =>
110+
onSave ? onSave(selectedItem, quantity) : undefined
111+
}
54112
loading={isSubmitting}
55113
>
56114
Salvar

src/components/DialogSelector/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface IDialogSelectorProps {
1010
options: IDialogSelectorItemProps[];
1111
value: string;
1212
isSubmitting?: boolean;
13-
onSave?: (value: string) => void;
13+
onSave?: (value: string, newQuantity: number) => void;
1414
onClose?: () => void;
15+
quantity: number;
1516
}

src/pages/EditShelterSupply/EditShelterSupply.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,16 @@ const EditShelterSupply = () => {
3030
if (v) {
3131
setFilteredSupplies(
3232
supplies.filter((s) =>
33-
s.name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
34-
.includes(v.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, ''))
33+
s.name
34+
.toLowerCase()
35+
.normalize('NFD')
36+
.replace(/[\u0300-\u036f]/g, '')
37+
.includes(
38+
v
39+
.toLowerCase()
40+
.normalize('NFD')
41+
.replace(/[\u0300-\u036f]/g, '')
42+
)
3543
)
3644
);
3745
} else setFilteredSupplies(supplies);
@@ -43,7 +51,7 @@ const EditShelterSupply = () => {
4351
const [loadingSave, setLoadingSave] = useState<boolean>(false);
4452
const [modalData, setModalData] = useState<Pick<
4553
IDialogSelectorProps,
46-
'value' | 'onSave'
54+
'value' | 'onSave' | 'quantity'
4755
> | null>();
4856
const shelterSupplyData = useMemo(() => {
4957
return (shelter?.shelterSupplies ?? []).reduce(
@@ -61,7 +69,8 @@ const EditShelterSupply = () => {
6169
setModalOpened(true);
6270
setModalData({
6371
value: `${item.priority ?? SupplyPriority.NotNeeded}`,
64-
onSave: (v) => {
72+
quantity: item.quantity ?? 0,
73+
onSave: (v, quantity) => {
6574
const isNewSupply = item.priority === undefined;
6675
setLoadingSave(true);
6776

@@ -85,14 +94,18 @@ const EditShelterSupply = () => {
8594
shelterId,
8695
supplyId: item.id,
8796
priority: +v,
97+
quantity,
8898
})
8999
.then(successCallback)
90100
.catch(errorCallback)
91101
.finally(() => {
92102
setLoadingSave(false);
93103
});
94104
} else {
95-
ShelterSupplyServices.update(shelterId, item.id, { priority: +v })
105+
ShelterSupplyServices.update(shelterId, item.id, {
106+
priority: +v,
107+
quantity,
108+
})
96109
.then(successCallback)
97110
.catch(errorCallback)
98111
.finally(() => {

src/pages/EditShelterSupply/components/SupplyRowInfo/SupplyRowInfo.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ const SupplyRowInfo = (props: ISupplyRowInfoProps) => {
2222
<div className="flex justify-end items-center gap-2">
2323
<CircleStatus className={className} />
2424
<p className="text-muted-foreground text-nowrap pl-1">{label}</p>
25-
{quantity && (
26-
<Badge className="bg-gray-700">{quantity}</Badge>
27-
)}
25+
{Boolean(quantity) && <Badge className="bg-gray-700">{quantity}</Badge>}
2826
</div>
2927
</div>
3028
);

src/service/shelterSupply/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface IShelterSupply {
1111
}
1212

1313
export type IUpdateShelterSupply = Partial<
14-
Pick<IShelterSupply, 'priority' | 'shelterId' | 'supplyId'>
14+
Pick<IShelterSupply, 'priority' | 'shelterId' | 'supplyId' | 'quantity'>
1515
>;
1616

1717
export type ICreateShelterSupply = Pick<

0 commit comments

Comments
 (0)