From 72ed69db24cab9522a675479700dda6bbef73af5 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Tue, 2 Sep 2025 14:41:28 +0400 Subject: [PATCH] feat: board and status selects in deal editor --- .../DealsTable/useDealsTableColumns.tsx | 4 ++ .../components/shared/DealCard/DealCard.tsx | 14 +++- .../deals/components/shared/Funnel/Funnel.tsx | 2 +- .../DealEditorDrawer/DealEditorDrawer.tsx | 3 +- .../components/DealEditorBody.tsx | 8 ++- .../components/GeneralTab.tsx | 71 ------------------- .../tabs/GeneralTab/Footer.tsx | 43 +++++++++++ .../tabs/GeneralTab/GeneralTab.tsx | 71 +++++++++++++++++++ src/app/deals/hooks/useDealsAndStatusesDnd.ts | 42 ++++++----- .../selects/StatusSelect/StatusSelect.tsx | 9 ++- src/hooks/cruds/useDealsCrud.tsx | 9 ++- src/lib/client/types.gen.ts | 14 ++-- src/lib/client/zod.gen.ts | 23 +++--- 13 files changed, 192 insertions(+), 121 deletions(-) delete mode 100644 src/app/deals/drawers/DealEditorDrawer/components/GeneralTab.tsx create mode 100644 src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/Footer.tsx create mode 100644 src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab.tsx diff --git a/src/app/deals/components/desktop/DealsTable/useDealsTableColumns.tsx b/src/app/deals/components/desktop/DealsTable/useDealsTableColumns.tsx index 6e5f2a6..ddbfedf 100644 --- a/src/app/deals/components/desktop/DealsTable/useDealsTableColumns.tsx +++ b/src/app/deals/components/desktop/DealsTable/useDealsTableColumns.tsx @@ -3,21 +3,25 @@ import { IconEdit } from "@tabler/icons-react"; import { DataTableColumn } from "mantine-datatable"; import { ActionIcon, Tooltip } from "@mantine/core"; import { useDealsContext } from "@/app/deals/contexts/DealsContext"; +import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; import { useDrawersContext } from "@/drawers/DrawersContext"; import { DealSchema } from "@/lib/client"; import { utcDateTimeToLocalString } from "@/utils/datetime"; const useDealsTableColumns = () => { + const { selectedProject } = useProjectsContext(); const { dealsCrud } = useDealsContext(); const { openDrawer } = useDrawersContext(); const onEditDeal = useCallback( (deal: DealSchema) => { + if (!selectedProject) return; openDrawer({ key: "dealEditorDrawer", props: { deal, dealsCrud, + project: selectedProject, }, }); }, diff --git a/src/app/deals/components/shared/DealCard/DealCard.tsx b/src/app/deals/components/shared/DealCard/DealCard.tsx index d3accd1..28cad7c 100644 --- a/src/app/deals/components/shared/DealCard/DealCard.tsx +++ b/src/app/deals/components/shared/DealCard/DealCard.tsx @@ -1,5 +1,6 @@ import { Box, Card, Group, Pill, Stack, Text } from "@mantine/core"; import { useDealsContext } from "@/app/deals/contexts/DealsContext"; +import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; import { useDrawersContext } from "@/drawers/DrawersContext"; import { DealSchema } from "@/lib/client"; import styles from "./DealCard.module.css"; @@ -9,11 +10,16 @@ type Props = { }; const DealCard = ({ deal }: Props) => { + const { selectedProject } = useProjectsContext(); const { dealsCrud } = useDealsContext(); const { openDrawer } = useDrawersContext(); const onClick = () => { - openDrawer({ key: "dealEditorDrawer", props: { deal, dealsCrud } }); + if (!selectedProject) return; + openDrawer({ + key: "dealEditorDrawer", + props: { project: selectedProject, deal, dealsCrud }, + }); }; return ( @@ -22,7 +28,9 @@ const DealCard = ({ deal }: Props) => { className={styles.container}> { {deal.name} - ID: {deal.id} + ID: {deal.id} diff --git a/src/app/deals/components/shared/Funnel/Funnel.tsx b/src/app/deals/components/shared/Funnel/Funnel.tsx index ecb91f8..da1a5bc 100644 --- a/src/app/deals/components/shared/Funnel/Funnel.tsx +++ b/src/app/deals/components/shared/Funnel/Funnel.tsx @@ -39,7 +39,7 @@ const Funnel: FC = () => { getContainerId={(status: StatusSchema) => `${status.id}-status`} getItemsByContainer={(status: StatusSchema, items: DealSchema[]) => sortByLexorank( - items.filter(deal => deal.statusId === status.id) + items.filter(deal => deal.status.id === status.id) ) } renderContainer={( diff --git a/src/app/deals/drawers/DealEditorDrawer/DealEditorDrawer.tsx b/src/app/deals/drawers/DealEditorDrawer/DealEditorDrawer.tsx index 41ffffc..b5f660e 100644 --- a/src/app/deals/drawers/DealEditorDrawer/DealEditorDrawer.tsx +++ b/src/app/deals/drawers/DealEditorDrawer/DealEditorDrawer.tsx @@ -6,9 +6,10 @@ import DealEditorBody from "@/app/deals/drawers/DealEditorDrawer/components/Deal import { DrawerProps } from "@/drawers/types"; import { DealsCrud } from "@/hooks/cruds/useDealsCrud"; import useIsMobile from "@/hooks/utils/useIsMobile"; -import { DealSchema } from "@/lib/client"; +import { DealSchema, ProjectSchema } from "@/lib/client"; type Props = { + project: ProjectSchema; deal: DealSchema; dealsCrud: DealsCrud; }; diff --git a/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx b/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx index 157ef57..0a3a30a 100644 --- a/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx +++ b/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx @@ -1,18 +1,19 @@ import { FC } from "react"; import { IconCircleDotted, IconEdit } from "@tabler/icons-react"; import { Tabs, Text } from "@mantine/core"; -import GeneralTab from "@/app/deals/drawers/DealEditorDrawer/components/GeneralTab"; +import GeneralTab from "@/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab"; import { DealsCrud } from "@/hooks/cruds/useDealsCrud"; -import { DealSchema } from "@/lib/client"; +import { DealSchema, ProjectSchema } from "@/lib/client"; import styles from "../DealEditorDrawer.module.css"; type Props = { + project: ProjectSchema; dealsCrud: DealsCrud; deal: DealSchema; onClose: () => void; }; -const DealEditorBody: FC = ({ dealsCrud, deal, onClose }) => { +const DealEditorBody: FC = ({ project, dealsCrud, deal, onClose }) => { return ( = ({ dealsCrud, deal, onClose }) => { void; -}; - -const GeneralTab: FC = ({ deal, dealsCrud, onClose }) => { - const [initialValues, setInitialValues] = useState(deal); - const form = useForm({ - initialValues, - validate: { - name: value => !value && "Введите название", - }, - }); - - const onSubmit = (values: DealSchema) => { - dealsCrud.onUpdate(deal.id, values); - setInitialValues(values); - }; - - const onDelete = () => { - dealsCrud.onDelete(deal, onClose); - }; - - return ( -
- - - Создано: {utcDateTimeToLocalString(deal.createdAt)} - - - - - - - - -
- ); -}; - -export default GeneralTab; diff --git a/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/Footer.tsx b/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/Footer.tsx new file mode 100644 index 0000000..47bb369 --- /dev/null +++ b/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/Footer.tsx @@ -0,0 +1,43 @@ +import { FC } from "react"; +import { isEqual } from "lodash"; +import { Button, Group } from "@mantine/core"; +import { UseFormReturnType } from "@mantine/form"; +import { DealSchema } from "@/lib/client"; + +type Props = { + form: UseFormReturnType>; + initialValues: Partial; + onDelete: () => void; +}; + +const Footer: FC = ({ form, initialValues, onDelete }) => { + return ( + + + + + + + + ); +}; + +export default Footer; diff --git a/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab.tsx b/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab.tsx new file mode 100644 index 0000000..bd3ca38 --- /dev/null +++ b/src/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab.tsx @@ -0,0 +1,71 @@ +import { FC, useState } from "react"; +import { Stack, Text, TextInput } from "@mantine/core"; +import { useForm } from "@mantine/form"; +import Footer from "@/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/Footer"; +import BoardSelect from "@/components/selects/BoardSelect/BoardSelect"; +import StatusSelect from "@/components/selects/StatusSelect/StatusSelect"; +import { DealsCrud } from "@/hooks/cruds/useDealsCrud"; +import { DealSchema, ProjectSchema } from "@/lib/client"; +import { utcDateTimeToLocalString } from "@/utils/datetime"; + +type Props = { + project: ProjectSchema; + dealsCrud: DealsCrud; + deal: DealSchema; + onClose: () => void; +}; + +const GeneralTab: FC = ({ project, deal, dealsCrud, onClose }) => { + const [initialValues, setInitialValues] = + useState>(deal); + const form = useForm>({ + initialValues, + validate: { + name: value => !value && "Введите название", + board: value => !value && "Выберите доску", + status: value => !value && "Выберите статус", + }, + }); + + const onSubmit = (values: Partial) => { + dealsCrud.onUpdate(deal.id, { + ...values, + boardId: values.board?.id, + statusId: values.status?.id, + }); + setInitialValues(values); + }; + + const onDelete = () => { + dealsCrud.onDelete(deal, onClose); + }; + + return ( +
+ + + Создано: {utcDateTimeToLocalString(deal.createdAt)} + + +