diff --git a/distribution_fe/app/(dashboard)/stock/_components/stock-adjust-dialog.tsx b/distribution_fe/app/(dashboard)/stock/_components/stock-adjust-dialog.tsx new file mode 100644 index 0000000..53e161f --- /dev/null +++ b/distribution_fe/app/(dashboard)/stock/_components/stock-adjust-dialog.tsx @@ -0,0 +1,166 @@ +'use client' + +import { useEffect, useState } from 'react' +import { useForm, zodResolver, z } from '@/lib/form' +import { FormField } from '@/components/shared/form-field' +import { Input } from '@/components/ui/input' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog' +import { FieldGroup } from '@/components/ui/field' +import { toast } from '@/components/ui/toast' +import { stock as stockApi, users as usersApi, getApiError, getPaginatedItems } from '@/lib/api/index' +import type { StockBalanceResponse, UserResponse } from '@/types/api' + +const schema = z.object({ + quantity: z.number().refine((v) => v !== 0, 'Adjustment quantity cannot be 0'), + reasonCode: z.string().min(1, 'Reason is required'), + adjustedByUserId: z.string().min(1, 'Adjusted by is required'), +}) + +type FormValues = z.infer + +interface StockAdjustDialogProps { + open: boolean + onClose: () => void + onSuccess: () => void + balance: StockBalanceResponse | null +} + +export function StockAdjustDialog({ open, onClose, onSuccess, balance }: StockAdjustDialogProps) { + const [usersList, setUsersList] = useState([]) + + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { quantity: 0, reasonCode: '', adjustedByUserId: '' }, + }) + + useEffect(() => { + if (!open) return + form.reset({ quantity: 0, reasonCode: '', adjustedByUserId: '' }) + usersApi.list({ pageSize: 200 }) + .then((res) => setUsersList(getPaginatedItems(res))) + .catch((err) => toast.add({ title: 'Failed to load users', description: getApiError(err), type: 'error' })) + }, [open]) + + if (!balance) return null + + async function onSubmit(values: FormValues) { + try { + await stockApi.adjust({ + itemId: balance!.itemId, + locationId: balance!.locationId, + locationType: balance!.locationType, + quantity: values.quantity, + reasonCode: values.reasonCode, + adjustedByUserId: values.adjustedByUserId, + }) + toast.add({ title: 'Stock adjusted', type: 'success' }) + onSuccess() + onClose() + } catch (err) { + toast.add({ title: 'Failed to adjust stock', description: getApiError(err), type: 'error' }) + } + } + + return ( + !v && onClose()}> + + + Adjust Stock — {balance.itemName} + + Enter a positive quantity to increase, or a negative quantity to decrease, the balance + at this location. Current quantity: {balance.quantity}. + + + +
+ + ( + field.onChange(Number(e.target.value))} + onBlur={field.onBlur} + placeholder="e.g. 10 or -5" + aria-invalid={invalid} + /> + )} + /> + + ( + + )} + /> + + ( + + )} + /> + + + + + + +
+
+
+ ) +}