From b1e5b7de93e2f8451c4321ec9a54ff45904b4ef1 Mon Sep 17 00:00:00 2001 From: DjonniStorm Date: Tue, 20 May 2025 00:31:38 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D1=84=D0=BE=D1=80=D0=BC=D0=BE=D1=87=D0=BA=D0=B5=20?= =?UTF-8?q?=D0=BA=D1=80=D0=B5=D0=B4=D0=B8=D1=82=D0=BD=D1=8B=D1=85=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/features/CreditProgramForm.tsx | 216 ++++++++++++------ .../src/components/features/CurrencyForm.tsx | 1 - .../src/components/pages/CreditPrograms.tsx | 125 ++++++++-- 3 files changed, 255 insertions(+), 87 deletions(-) diff --git a/TheBank/bankui/src/components/features/CreditProgramForm.tsx b/TheBank/bankui/src/components/features/CreditProgramForm.tsx index 14783a3..35e46d8 100644 --- a/TheBank/bankui/src/components/features/CreditProgramForm.tsx +++ b/TheBank/bankui/src/components/features/CreditProgramForm.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -22,59 +22,144 @@ import { Button } from '@/components/ui/button'; import type { CreditProgramBindingModel } from '@/types/types'; import { useAuthStore } from '@/store/workerStore'; import { usePeriods } from '@/hooks/usePeriods'; -import { useCurrencies } from '@/hooks/useCurrencies'; -const formSchema = z.object({ +type BaseFormValues = { + id?: string; + name: string; + cost: number; + maxCost: number; + periodId: string; +}; + +type EditFormValues = Partial; + +const baseSchema = z.object({ id: z.string().optional(), - name: z.string().min(5, 'Название должно быть не короче 5 символов'), + name: z.string().min(1, 'Название обязательно'), cost: z.coerce.number().min(0, 'Стоимость не может быть отрицательной'), maxCost: z.coerce .number() .min(0, 'Максимальная стоимость не может быть отрицательной'), periodId: z.string().min(1, 'Выберите период'), - currencyCreditPrograms: z - .array(z.string()) - .min(1, 'Выберите хотя бы одну валюту'), }); -type FormValues = z.infer; +const addSchema = baseSchema; -type CreditProgramFormProps = { +const editSchema = z.object({ + id: z.string().optional(), + name: z.string().min(1, 'Название обязательно').optional(), + cost: z.coerce + .number() + .min(0, 'Стоимость не может быть отрицательной') + .optional(), + maxCost: z.coerce + .number() + .min(0, 'Максимальная стоимость не может быть отрицательной') + .optional(), + periodId: z.string().min(1, 'Выберите период').optional(), +}); + +interface BaseCreditProgramFormProps { onSubmit: (data: CreditProgramBindingModel) => void; -}; + schema: z.ZodType; + defaultValues?: Partial; +} -export const CreditProgramForm = ({ +const BaseCreditProgramForm = ({ onSubmit, -}: CreditProgramFormProps): React.JSX.Element => { - const form = useForm({ - resolver: zodResolver(formSchema), - defaultValues: { - id: '', - name: '', - cost: 0, - maxCost: 0, - periodId: '', - currencyCreditPrograms: [], - }, + schema, + defaultValues, +}: BaseCreditProgramFormProps): React.JSX.Element => { + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: defaultValues + ? { + id: defaultValues.id ?? '', + name: defaultValues.name ?? '', + cost: defaultValues.cost ?? 0, + maxCost: defaultValues.maxCost ?? 0, + periodId: defaultValues.periodId ?? '', + } + : { + id: '', + name: '', + cost: 0, + maxCost: 0, + periodId: '', + }, }); const { periods } = usePeriods(); - const { currencies } = useCurrencies(); + + useEffect(() => { + if (defaultValues) { + form.reset({ + id: defaultValues.id ?? '', + name: defaultValues.name ?? '', + cost: defaultValues.cost ?? 0, + maxCost: defaultValues.maxCost ?? 0, + periodId: defaultValues.periodId ?? '', + }); + } + }, [defaultValues, form]); const storekeeper = useAuthStore((store) => store.user); - const handleSubmit = (data: FormValues) => { - const dataWithId = { - ...data, - id: crypto.randomUUID(), - }; - const payload: CreditProgramBindingModel = { - ...dataWithId, - currencyCreditPrograms: data.currencyCreditPrograms.map((currencyId) => ({ - currencyId, - })), - storekeeperId: storekeeper?.id, - }; + const handleSubmit = (data: BaseFormValues | EditFormValues) => { + if (!storekeeper?.id) { + console.error('Storekeeper ID is not available.'); + return; + } + + let payload: CreditProgramBindingModel; + + if (schema === addSchema) { + const addData = data as BaseFormValues; + payload = { + id: addData.id || crypto.randomUUID(), + storekeeperId: storekeeper.id, + name: addData.name, + cost: addData.cost, + maxCost: addData.maxCost, + periodId: addData.periodId, + }; + } else { + const editData = data as EditFormValues; + const currentDefaultValues = defaultValues as Partial; + + const changedData: Partial = {}; + + if (editData.id !== undefined && editData.id !== currentDefaultValues?.id) + changedData.id = editData.id; + if ( + editData.name !== undefined && + editData.name !== currentDefaultValues?.name + ) + changedData.name = editData.name; + if ( + editData.cost !== undefined && + editData.cost !== currentDefaultValues?.cost + ) + changedData.cost = editData.cost; + if ( + editData.maxCost !== undefined && + editData.maxCost !== currentDefaultValues?.maxCost + ) + changedData.maxCost = editData.maxCost; + if ( + editData.periodId !== undefined && + editData.periodId !== currentDefaultValues?.periodId + ) + changedData.periodId = editData.periodId; + + if (currentDefaultValues?.id) changedData.id = currentDefaultValues.id; + changedData.storekeeperId = storekeeper.id; + + payload = { + ...(defaultValues as CreditProgramBindingModel), + ...changedData, + }; + } onSubmit(payload); }; @@ -139,7 +224,7 @@ export const CreditProgramForm = ({ render={({ field }) => ( Период - @@ -147,7 +232,7 @@ export const CreditProgramForm = ({ {periods && - periods.map((period) => ( + periods?.map((period) => ( {`${new Date( period.startTime, @@ -162,38 +247,7 @@ export const CreditProgramForm = ({ )} /> - ( - - Валюты - -
- -
-
- -
- )} - /> + @@ -201,3 +255,27 @@ export const CreditProgramForm = ({ ); }; + +export const CreditProgramFormAdd = ({ + onSubmit, +}: { + onSubmit: (data: CreditProgramBindingModel) => void; +}): React.JSX.Element => { + return ; +}; + +export const CreditProgramFormEdit = ({ + onSubmit, + defaultValues, +}: { + onSubmit: (data: CreditProgramBindingModel) => void; + defaultValues: Partial; +}): React.JSX.Element => { + return ( + + ); +}; diff --git a/TheBank/bankui/src/components/features/CurrencyForm.tsx b/TheBank/bankui/src/components/features/CurrencyForm.tsx index 9a4a855..c497e7a 100644 --- a/TheBank/bankui/src/components/features/CurrencyForm.tsx +++ b/TheBank/bankui/src/components/features/CurrencyForm.tsx @@ -83,7 +83,6 @@ const BaseCurrencyForm = ({ const storekeeper = useAuthStore((store) => store.user); const handleSubmit = (data: BaseFormValues | EditFormValues) => { - // Если это форма редактирования, используем только заполненные поля const payload: CurrencyBindingModel = { id: data.id || crypto.randomUUID(), storekeeperId: storekeeper?.id, diff --git a/TheBank/bankui/src/components/pages/CreditPrograms.tsx b/TheBank/bankui/src/components/pages/CreditPrograms.tsx index cce8cfc..0492905 100644 --- a/TheBank/bankui/src/components/pages/CreditPrograms.tsx +++ b/TheBank/bankui/src/components/pages/CreditPrograms.tsx @@ -3,11 +3,22 @@ import { AppSidebar } from '../layout/Sidebar'; import { useCreditPrograms } from '@/hooks/useCreditPrograms'; import { DialogForm } from '../layout/DialogForm'; import { DataTable } from '../layout/DataTable'; -import { CreditProgramForm } from '../features/CreditProgramForm'; +import { + CreditProgramFormAdd, + CreditProgramFormEdit, +} from '../features/CreditProgramForm'; import type { CreditProgramBindingModel } from '@/types/types'; import type { ColumnDef } from '../layout/DataTable'; +import { toast } from 'sonner'; +import { usePeriods } from '@/hooks/usePeriods'; +import { useStorekeepers } from '@/hooks/useStorekeepers'; -const columns: ColumnDef[] = [ +interface CreditProgramTableData extends CreditProgramBindingModel { + formattedPeriod: string; + storekeeperFullName: string; +} + +const columns: ColumnDef[] = [ { accessorKey: 'id', header: 'ID', @@ -25,12 +36,12 @@ const columns: ColumnDef[] = [ header: 'Макс. стоимость', }, { - accessorKey: 'storekeeperId', - header: 'ID Кладовщика', + accessorKey: 'storekeeperFullName', + header: 'Кладовщик', }, { - accessorKey: 'periodId', - header: 'ID Периода', + accessorKey: 'formattedPeriod', + header: 'Период', }, ]; @@ -43,12 +54,73 @@ export const CreditPrograms = (): React.JSX.Element => { createCreditProgram, updateCreditProgram, } = useCreditPrograms(); + const { periods } = usePeriods(); + const { storekeepers } = useStorekeepers(); - const [isDialogOpen, setIsDialogOpen] = React.useState(false); + const finalData = React.useMemo(() => { + if (!creditPrograms || !periods || !storekeepers) return []; + + return creditPrograms.map((program) => { + const period = periods?.find((p) => p.id === program.periodId); + const storekeeper = storekeepers?.find( + (s) => s.id === program.storekeeperId, + ); + + const formattedPeriod = period + ? `${new Date(period.startTime).toLocaleDateString()} - ${new Date( + period.endTime, + ).toLocaleDateString()}` + : 'Неизвестный период'; + + const storekeeperFullName = storekeeper + ? [storekeeper.surname, storekeeper.name, storekeeper.middleName] + .filter(Boolean) + .join(' ') || 'Неизвестный кладовщик' + : 'Неизвестный кладовщик'; + + return { + ...program, + formattedPeriod, + storekeeperFullName, + }; + }); + }, [creditPrograms, periods, storekeepers]); + + const [isAddDialogOpen, setIsAddDialogOpen] = React.useState(false); + const [isEditDialogOpen, setIsEditDialogOpen] = + React.useState(false); + const [selectedItem, setSelectedItem] = React.useState< + CreditProgramBindingModel | undefined + >(); const handleAdd = (data: CreditProgramBindingModel) => { - console.log(data); createCreditProgram(data); + setIsAddDialogOpen(false); + }; + + const handleEdit = (data: CreditProgramBindingModel) => { + if (selectedItem) { + updateCreditProgram({ + ...selectedItem, + ...data, + }); + setIsEditDialogOpen(false); + setSelectedItem(undefined); + } + }; + + const handleSelectItem = (id: string | undefined) => { + const item = creditPrograms?.find((cp) => cp.id === id); + setSelectedItem(item); + }; + + const openEditForm = () => { + if (!selectedItem) { + toast('Выберите элемент для редактирования'); + return; + } + + setIsEditDialogOpen(true); }; if (isLoading) { @@ -67,22 +139,41 @@ export const CreditPrograms = (): React.JSX.Element => {
{ - setIsDialogOpen(true); + setIsAddDialogOpen(true); + }} + onEditClick={() => { + openEditForm(); }} - onEditClick={function (): void {}} />
- title="Форма" - description="Описание" - isOpen={isDialogOpen} - onClose={() => setIsDialogOpen(false)} + title="Форма кредитной программы" + description="Добавить новую кредитную программу" + isOpen={isAddDialogOpen} + onClose={() => setIsAddDialogOpen(false)} onSubmit={handleAdd} - children={} - /> + > + + + {selectedItem && ( + + title="Форма кредитной программы" + description="Изменить кредитную программу" + isOpen={isEditDialogOpen} + onClose={() => setIsEditDialogOpen(false)} + onSubmit={handleEdit} + > + + + )}
- + handleSelectItem(id)} + selectedRow={selectedItem?.id} + />