diff --git a/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx b/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx index 855097d..e921e0e 100644 --- a/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx +++ b/src/app/deals/drawers/DealEditorDrawer/components/DealEditorBody.tsx @@ -1,7 +1,8 @@ import React, { FC, ReactNode } from "react"; -import { IconEdit } from "@tabler/icons-react"; +import { IconEdit, IconHistory } from "@tabler/icons-react"; import { motion } from "framer-motion"; import { Box, Tabs, Text } from "@mantine/core"; +import DealStatusHistoryTab from "@/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/DealStatusHistoryTab"; import GeneralTab from "@/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab"; import useIsMobile from "@/hooks/utils/useIsMobile"; import { DealSchema, ProjectSchema } from "@/lib/client"; @@ -35,22 +36,24 @@ const DealEditorBody: FC = props => { ); + const getTab = (key: string, label: string, icon: ReactNode) => ( + + + {label} + + + ); + const getModuleTabs = () => props.project?.builtInModules.map(module => { - const moduleRender = MODULES[module.key].renderInfo; - return ( - - - {moduleRender.label} - - - ); + const info = MODULES[module.key].renderInfo; + return getTab(info.key, info.label, info.icon); }); const getModuleTabPanels = () => @@ -66,15 +69,13 @@ const DealEditorBody: FC = props => { mih={"97vh"} classNames={{ tab: styles.tab }}> - }> - Общая информация - + {getTab("general", "Общая информация", )} + {getTab("history", "История", )} {getModuleTabs()} {getTabPanel("general", )} + {getTabPanel("history", )} {getModuleTabPanels()} ); diff --git a/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/DealStatusHistoryTab.tsx b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/DealStatusHistoryTab.tsx new file mode 100644 index 0000000..9540c8c --- /dev/null +++ b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/DealStatusHistoryTab.tsx @@ -0,0 +1,29 @@ +import { FC } from "react"; +import { useDealStatusHistoryTableColumns } from "@/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/columns"; +import useStatusHistoryList from "@/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/useStatusHistoryList"; +import BaseTable from "@/components/ui/BaseTable/BaseTable"; +import { DealSchema } from "@/lib/client"; + +type Props = { + value: DealSchema; +}; + +const DealStatusHistoryTab: FC = ({ value }) => { + const { history } = useStatusHistoryList({ dealId: value.id }); + const columns = useDealStatusHistoryTableColumns(); + + return ( + + ); +}; + +export default DealStatusHistoryTab; diff --git a/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/columns.tsx b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/columns.tsx new file mode 100644 index 0000000..c9822ae --- /dev/null +++ b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/columns.tsx @@ -0,0 +1,31 @@ +import { useMemo } from "react"; +import { DataTableColumn } from "mantine-datatable"; +import { StatusHistorySchema } from "@/lib/client"; +import { utcDateTimeToLocalString } from "@/utils/datetime"; + +export const useDealStatusHistoryTableColumns = () => { + return useMemo( + () => + [ + { + accessor: "createdAt", + title: "Дата", + render: row => + utcDateTimeToLocalString(new Date(row.createdAt)), + }, + // { + // title: "Пользователь", + // cell: row => `${row.user.firstName} ${row.user.secondName}`, + // }, + { + accessor: "fromStatus.name", + title: "Из статуса", + }, + { + accessor: "toStatus.name", + title: "В статус", + }, + ] as DataTableColumn[], + [] + ); +}; diff --git a/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/useStatusHistoryList.ts b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/useStatusHistoryList.ts new file mode 100644 index 0000000..62b0a4f --- /dev/null +++ b/src/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/useStatusHistoryList.ts @@ -0,0 +1,20 @@ +import { useQuery } from "@tanstack/react-query"; +import { getStatusHistoryOptions } from "@/lib/client/@tanstack/react-query.gen"; + +type Props = { + dealId: number; +}; + +const useStatusHistoryList = ({ dealId }: Props) => { + const options = { + path: { dealId }, + }; + const { data, refetch } = useQuery(getStatusHistoryOptions(options)); + + return { + history: data?.items ?? [], + refetch, + }; +}; + +export default useStatusHistoryList; diff --git a/src/lib/client/@tanstack/react-query.gen.ts b/src/lib/client/@tanstack/react-query.gen.ts index fb794c2..c9fb157 100644 --- a/src/lib/client/@tanstack/react-query.gen.ts +++ b/src/lib/client/@tanstack/react-query.gen.ts @@ -42,6 +42,7 @@ import { getServices, getServicesKits, getStatuses, + getStatusHistory, updateBoard, updateDeal, updateDealProduct, @@ -138,6 +139,7 @@ import type { GetServicesData, GetServicesKitsData, GetStatusesData, + GetStatusHistoryData, UpdateBoardData, UpdateBoardError, UpdateBoardResponse2, @@ -807,6 +809,30 @@ export const updateStatusMutation = ( return mutationOptions; }; +export const getStatusHistoryQueryKey = ( + options: Options +) => createQueryKey("getStatusHistory", options); + +/** + * Get Status History + */ +export const getStatusHistoryOptions = ( + options: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getStatusHistory({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getStatusHistoryQueryKey(options), + }); +}; + export const getDealProductsQueryKey = ( options: Options ) => createQueryKey("getDealProducts", options); diff --git a/src/lib/client/sdk.gen.ts b/src/lib/client/sdk.gen.ts index ba087dc..681a281 100644 --- a/src/lib/client/sdk.gen.ts +++ b/src/lib/client/sdk.gen.ts @@ -98,6 +98,9 @@ import type { GetStatusesData, GetStatusesErrors, GetStatusesResponses, + GetStatusHistoryData, + GetStatusHistoryErrors, + GetStatusHistoryResponses, UpdateBoardData, UpdateBoardErrors, UpdateBoardResponses, @@ -196,6 +199,8 @@ import { zGetServicesResponse2, zGetStatusesData, zGetStatusesResponse2, + zGetStatusHistoryData, + zGetStatusHistoryResponse2, zUpdateBoardData, zUpdateBoardResponse2, zUpdateDealData, @@ -658,6 +663,29 @@ export const updateStatus = ( }); }; +/** + * Get Status History + */ +export const getStatusHistory = ( + options: Options +) => { + return (options.client ?? _heyApiClient).get< + GetStatusHistoryResponses, + GetStatusHistoryErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zGetStatusHistoryData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zGetStatusHistoryResponse2.parseAsync(data); + }, + url: "/status/history/{dealId}", + ...options, + }); +}; + /** * Get Deal Products */ diff --git a/src/lib/client/types.gen.ts b/src/lib/client/types.gen.ts index d05c5a9..267f282 100644 --- a/src/lib/client/types.gen.ts +++ b/src/lib/client/types.gen.ts @@ -808,6 +808,16 @@ export type GetServicesResponse = { items: Array; }; +/** + * GetStatusHistoryResponse + */ +export type GetStatusHistoryResponse = { + /** + * Items + */ + items: Array; +}; + /** * GetStatusesResponse */ @@ -1078,6 +1088,26 @@ export type ServicesKitSchema = { export type SortDir = "asc" | "desc"; +/** + * StatusHistorySchema + */ +export type StatusHistorySchema = { + /** + * Id + */ + id: number; + /** + * Createdat + */ + createdAt: string; + fromStatus: StatusSchema; + toStatus: StatusSchema; + /** + * Dealid + */ + dealId: number; +}; + /** * StatusSchema */ @@ -1998,6 +2028,38 @@ export type UpdateStatusResponses = { export type UpdateStatusResponse2 = UpdateStatusResponses[keyof UpdateStatusResponses]; +export type GetStatusHistoryData = { + body?: never; + path: { + /** + * Dealid + */ + dealId: number; + }; + query?: never; + url: "/status/history/{dealId}"; +}; + +export type GetStatusHistoryErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetStatusHistoryError = + GetStatusHistoryErrors[keyof GetStatusHistoryErrors]; + +export type GetStatusHistoryResponses = { + /** + * Successful Response + */ + 200: GetStatusHistoryResponse; +}; + +export type GetStatusHistoryResponse2 = + GetStatusHistoryResponses[keyof GetStatusHistoryResponses]; + export type GetDealProductsData = { body?: never; path: { diff --git a/src/lib/client/zod.gen.ts b/src/lib/client/zod.gen.ts index 8b79751..9b1c08d 100644 --- a/src/lib/client/zod.gen.ts +++ b/src/lib/client/zod.gen.ts @@ -600,6 +600,26 @@ export const zGetServicesResponse = z.object({ items: z.array(zServiceSchema), }); +/** + * StatusHistorySchema + */ +export const zStatusHistorySchema = z.object({ + id: z.int(), + createdAt: z.iso.datetime({ + offset: true, + }), + fromStatus: zStatusSchema, + toStatus: zStatusSchema, + dealId: z.int(), +}); + +/** + * GetStatusHistoryResponse + */ +export const zGetStatusHistoryResponse = z.object({ + items: z.array(zStatusHistorySchema), +}); + /** * GetStatusesResponse */ @@ -1106,6 +1126,19 @@ export const zUpdateStatusData = z.object({ */ export const zUpdateStatusResponse2 = zUpdateStatusResponse; +export const zGetStatusHistoryData = z.object({ + body: z.optional(z.never()), + path: z.object({ + dealId: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zGetStatusHistoryResponse2 = zGetStatusHistoryResponse; + export const zGetDealProductsData = z.object({ body: z.optional(z.never()), path: z.object({