diff --git a/package.json b/package.json index e96bb75..1be0c1e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@tabler/icons-react": "^3.34.0", "@tailwindcss/postcss": "^4.1.11", "@tanstack/react-query": "^5.83.0", - "axios": "^1.11.0", + "axios": "1.12.0", "classnames": "^2.5.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", diff --git a/src/app/barcode-templates/components/desktop/BarcodeTemplatesDesktopHeader/BarcodeTemplatesDesktopHeader.tsx b/src/app/barcode-templates/components/desktop/BarcodeTemplatesDesktopHeader/BarcodeTemplatesDesktopHeader.tsx new file mode 100644 index 0000000..e13afd8 --- /dev/null +++ b/src/app/barcode-templates/components/desktop/BarcodeTemplatesDesktopHeader/BarcodeTemplatesDesktopHeader.tsx @@ -0,0 +1,19 @@ +import { FC } from "react"; +import { Group } from "@mantine/core"; +import InlineButton from "@/components/ui/InlineButton/InlineButton"; + +type Props = { + onCreateClick: () => void; +}; + +const BarcodeTemplatesDesktopHeader: FC = ({ onCreateClick }) => { + return ( + + + Создать шаблон + + + ); +}; + +export default BarcodeTemplatesDesktopHeader; diff --git a/src/app/barcode-templates/components/mobile/BarcodeTemplatesMobileHeader/BarcodeTemplatesMobileHeader.tsx b/src/app/barcode-templates/components/mobile/BarcodeTemplatesMobileHeader/BarcodeTemplatesMobileHeader.tsx new file mode 100644 index 0000000..d71c25d --- /dev/null +++ b/src/app/barcode-templates/components/mobile/BarcodeTemplatesMobileHeader/BarcodeTemplatesMobileHeader.tsx @@ -0,0 +1,23 @@ +import { FC } from "react"; +import { Box } from "@mantine/core"; +import InlineButton from "@/components/ui/InlineButton/InlineButton"; + +type Props = { + onCreateClick: () => void; +}; + +const BarcodeTemplatesMobileHeader: FC = ({ onCreateClick }) => { + return ( + + + Создать шаблон + + + ); +}; + +export default BarcodeTemplatesMobileHeader; diff --git a/src/app/barcode-templates/components/shared/BarcodeTemplateAttributeMultiselect/BarcodeTemplateAttributeMultiselect.tsx b/src/app/barcode-templates/components/shared/BarcodeTemplateAttributeMultiselect/BarcodeTemplateAttributeMultiselect.tsx new file mode 100644 index 0000000..abf1451 --- /dev/null +++ b/src/app/barcode-templates/components/shared/BarcodeTemplateAttributeMultiselect/BarcodeTemplateAttributeMultiselect.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { FC } from "react"; +import useBarcodeTemplateAttributesList from "@/app/barcode-templates/hooks/useBarcodeTemplateAttributesList"; +import ObjectMultiSelect, { + ObjectMultiSelectProps, +} from "@/components/selects/ObjectMultiSelect/ObjectMultiSelect"; +import { BarcodeTemplateAttributeSchema } from "@/lib/client"; + +type Props = Omit< + ObjectMultiSelectProps, + "data" | "getLabelFn" | "getValueFn" +>; + +const BarcodeTemplateAttributeMultiselect: FC = (props: Props) => { + const { barcodeTemplateAttributes } = useBarcodeTemplateAttributesList(); + + return ( + + ); +}; + +export default BarcodeTemplateAttributeMultiselect; diff --git a/src/app/barcode-templates/components/shared/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx b/src/app/barcode-templates/components/shared/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx new file mode 100644 index 0000000..a5d8a43 --- /dev/null +++ b/src/app/barcode-templates/components/shared/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx @@ -0,0 +1,22 @@ +"use client"; + +import useBarcodeTemplateSizesList from "@/app/barcode-templates/hooks/useBarcodeTemplateSizesList"; +import ObjectSelect, { + ObjectSelectProps, +} from "@/components/selects/ObjectSelect/ObjectSelect"; +import { BarcodeTemplateSizeSchema } from "@/lib/client"; + +type Props = Omit, "data">; + +const BarcodeTemplateSizeSelect = (props: Props) => { + const { barcodeTemplateSizes } = useBarcodeTemplateSizesList(); + + return ( + `${size.name} (${size.width}x${size.height})`} + {...props} + /> + ); +}; +export default BarcodeTemplateSizeSelect; diff --git a/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/BarcodeTemplatesTable.tsx b/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/BarcodeTemplatesTable.tsx new file mode 100644 index 0000000..5137819 --- /dev/null +++ b/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/BarcodeTemplatesTable.tsx @@ -0,0 +1,30 @@ +import { FC } from "react"; +import { useBarcodeTemplatesTableColumns } from "@/app/barcode-templates/components/shared/BarcodeTemplatesTable/columns"; +import BaseTable from "@/components/ui/BaseTable/BaseTable"; +import useIsMobile from "@/hooks/utils/useIsMobile"; +import { BarcodeTemplateSchema } from "@/lib/client"; + +type Props = { + items: BarcodeTemplateSchema[]; + onDelete: (template: BarcodeTemplateSchema) => void; + onChange: (template: BarcodeTemplateSchema) => void; +}; + +const BarcodeTemplatesTable: FC = ({ items, ...props }) => { + const isMobile = useIsMobile(); + const columns = useBarcodeTemplatesTableColumns(props); + + return ( + + ); +}; + +export default BarcodeTemplatesTable; diff --git a/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/columns.tsx b/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/columns.tsx new file mode 100644 index 0000000..62080b6 --- /dev/null +++ b/src/app/barcode-templates/components/shared/BarcodeTemplatesTable/columns.tsx @@ -0,0 +1,60 @@ +import { useMemo } from "react"; +import { IconCheck, IconX } from "@tabler/icons-react"; +import { DataTableColumn } from "mantine-datatable"; +import { Center } from "@mantine/core"; +import UpdateDeleteTableActions from "@/components/ui/BaseTable/components/UpdateDeleteTableActions"; +import { BarcodeTemplateSchema } from "@/lib/client"; + +type Props = { + onDelete: (template: BarcodeTemplateSchema) => void; + onChange: (template: BarcodeTemplateSchema) => void; +}; + +export const useBarcodeTemplatesTableColumns = ({ + onDelete, + onChange, +}: Props) => { + return useMemo( + () => + [ + { + accessor: "actions", + title:
Действия
, + width: "0%", + render: template => ( + onDelete(template)} + onChange={() => onChange(template)} + /> + ), + }, + { + accessor: "name", + title: "Название", + }, + { + accessor: "attributes", + title: "Атрибуты", + render: template => ( + <> + {template.attributes + .map(attr => attr.name) + .join(", ")} + + ), + }, + { + accessor: "size.name", + title: "Размер", + render: template => `${template.size.name} (${template.size.width}x${template.size.height})` + }, + { + accessor: "isDefault", + title: "По умолчанию", + render: template => + template.isDefault ? : , + }, + ] as DataTableColumn[], + [] + ); +}; diff --git a/src/app/barcode-templates/components/shared/PageBody/PageBody.tsx b/src/app/barcode-templates/components/shared/PageBody/PageBody.tsx new file mode 100644 index 0000000..fac2797 --- /dev/null +++ b/src/app/barcode-templates/components/shared/PageBody/PageBody.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { Stack } from "@mantine/core"; +import BarcodeTemplatesDesktopHeader from "@/app/barcode-templates/components/desktop/BarcodeTemplatesDesktopHeader/BarcodeTemplatesDesktopHeader"; +import BarcodeTemplatesMobileHeader from "@/app/barcode-templates/components/mobile/BarcodeTemplatesMobileHeader/BarcodeTemplatesMobileHeader"; +import BarcodeTemplatesTable from "@/app/barcode-templates/components/shared/BarcodeTemplatesTable/BarcodeTemplatesTable"; +import useBarcodeTemplateActions from "@/app/barcode-templates/hooks/useBarcodeTemplateActions"; +import { useBarcodeTemplatesCrud } from "@/app/barcode-templates/hooks/useBarcodeTemplatesCrud"; +import useBarcodeTemplatesList from "@/app/barcode-templates/hooks/useBarcodeTemplatesList"; +import PageBlock from "@/components/layout/PageBlock/PageBlock"; +import useIsMobile from "@/hooks/utils/useIsMobile"; + +const PageBody = () => { + const isMobile = useIsMobile(); + const { barcodeTemplates, queryKey } = useBarcodeTemplatesList(); + const barcodeTemplatesCrud = useBarcodeTemplatesCrud({ queryKey }); + + const { onCreate, onChange } = useBarcodeTemplateActions(); + + return ( + + {!isMobile && ( + + + + )} + + + {isMobile && ( + + )} +
+ +
+
+
+
+ ); +}; + +export default PageBody; diff --git a/src/app/barcode-templates/hooks/useBarcodeTemplateActions.tsx b/src/app/barcode-templates/hooks/useBarcodeTemplateActions.tsx new file mode 100644 index 0000000..c09c484 --- /dev/null +++ b/src/app/barcode-templates/hooks/useBarcodeTemplateActions.tsx @@ -0,0 +1,42 @@ +import { modals } from "@mantine/modals"; +import { useBarcodeTemplatesCrud } from "@/app/barcode-templates/hooks/useBarcodeTemplatesCrud"; +import useBarcodeTemplatesList from "@/app/barcode-templates/hooks/useBarcodeTemplatesList"; +import { BarcodeTemplateSchema } from "@/lib/client"; + +const useBarcodeTemplateActions = () => { + const { queryKey } = useBarcodeTemplatesList(); + const barcodeTemplatesCrud = useBarcodeTemplatesCrud({ queryKey }); + + const onChange = (template: BarcodeTemplateSchema) => { + modals.openContextModal({ + modal: "barcodeTemplateEditorModal", + title: "Редактирование шаблона", + withCloseButton: false, + innerProps: { + onChange: updated => + barcodeTemplatesCrud.onUpdate(template.id, updated), + entity: template, + isEditing: true, + }, + }); + }; + + const onCreate = () => { + modals.openContextModal({ + modal: "barcodeTemplateEditorModal", + title: "Создание шаблона", + withCloseButton: false, + innerProps: { + onCreate: barcodeTemplatesCrud.onCreate, + isEditing: false, + }, + }); + }; + + return { + onChange, + onCreate, + }; +}; + +export default useBarcodeTemplateActions; diff --git a/src/app/barcode-templates/hooks/useBarcodeTemplateAttributesList.tsx b/src/app/barcode-templates/hooks/useBarcodeTemplateAttributesList.tsx new file mode 100644 index 0000000..89196e5 --- /dev/null +++ b/src/app/barcode-templates/hooks/useBarcodeTemplateAttributesList.tsx @@ -0,0 +1,11 @@ +import { useQuery } from "@tanstack/react-query"; +import { getBarcodeTemplateAttributesOptions } from "@/lib/client/@tanstack/react-query.gen"; + +const useBarcodeTemplateAttributesList = () => { + const { isLoading, data, refetch } = useQuery( + getBarcodeTemplateAttributesOptions() + ); + + return { barcodeTemplateAttributes: data?.items ?? [], refetch, isLoading }; +}; +export default useBarcodeTemplateAttributesList; diff --git a/src/app/barcode-templates/hooks/useBarcodeTemplateSizesList.tsx b/src/app/barcode-templates/hooks/useBarcodeTemplateSizesList.tsx new file mode 100644 index 0000000..a5e43a8 --- /dev/null +++ b/src/app/barcode-templates/hooks/useBarcodeTemplateSizesList.tsx @@ -0,0 +1,12 @@ +import { useQuery } from "@tanstack/react-query"; +import { getBarcodeTemplateSizesOptions } from "@/lib/client/@tanstack/react-query.gen"; + +const useBarcodeTemplateSizesList = () => { + const { isLoading, data, refetch } = useQuery( + getBarcodeTemplateSizesOptions() + ); + + return { barcodeTemplateSizes: data?.items ?? [], refetch, isLoading }; +}; + +export default useBarcodeTemplateSizesList; diff --git a/src/app/barcode-templates/hooks/useBarcodeTemplatesCrud.tsx b/src/app/barcode-templates/hooks/useBarcodeTemplatesCrud.tsx new file mode 100644 index 0000000..4da2db3 --- /dev/null +++ b/src/app/barcode-templates/hooks/useBarcodeTemplatesCrud.tsx @@ -0,0 +1,50 @@ +import { useCrudOperations } from "@/hooks/cruds/baseCrud"; +import { + BarcodeTemplateSchema, + CreateBarcodeTemplateSchema, + UpdateBarcodeTemplateSchema, +} from "@/lib/client"; +import { + createBarcodeTemplateMutation, + deleteBarcodeTemplateMutation, + updateBarcodeTemplateMutation, +} from "@/lib/client/@tanstack/react-query.gen"; + +type UseBarcodeTemplateOperationsProps = { + queryKey: any[]; +}; + +export type BarcodeTemplateCrud = { + onCreate: (template: CreateBarcodeTemplateSchema) => void; + onUpdate: ( + templateId: number, + template: UpdateBarcodeTemplateSchema + ) => void; + onDelete: (template: BarcodeTemplateSchema) => void; +}; + +export const useBarcodeTemplatesCrud = ({ + queryKey, +}: UseBarcodeTemplateOperationsProps): BarcodeTemplateCrud => { + return useCrudOperations< + BarcodeTemplateSchema, + UpdateBarcodeTemplateSchema, + CreateBarcodeTemplateSchema + >({ + key: "getBarcodeTemplates", + queryKey, + mutations: { + create: createBarcodeTemplateMutation(), + update: updateBarcodeTemplateMutation(), + delete: deleteBarcodeTemplateMutation(), + }, + getUpdateEntity: (old, update) => ({ + ...old, + name: update.name ?? old.name, + attributes: update.attributes ?? old.attributes, + size: update.size ?? old.size, + isDefault: update.isDefault ?? old.isDefault, + }), + getDeleteConfirmTitle: () => "Удаление шаблона штрихкода", + }); +}; diff --git a/src/app/barcode-templates/hooks/useBarcodeTemplatesList.tsx b/src/app/barcode-templates/hooks/useBarcodeTemplatesList.tsx new file mode 100644 index 0000000..dc48c61 --- /dev/null +++ b/src/app/barcode-templates/hooks/useBarcodeTemplatesList.tsx @@ -0,0 +1,15 @@ +import { useQuery } from "@tanstack/react-query"; +import { + getBarcodeTemplatesOptions, + getBarcodeTemplatesQueryKey, +} from "@/lib/client/@tanstack/react-query.gen"; + +const useBarcodeTemplatesList = () => { + const { isLoading, data, refetch } = useQuery(getBarcodeTemplatesOptions()); + + const queryKey = getBarcodeTemplatesQueryKey(); + + return { barcodeTemplates: data?.items ?? [], queryKey, refetch, isLoading }; +}; + +export default useBarcodeTemplatesList; diff --git a/src/app/barcode-templates/modals/BarcodeTemplateFormModal/BarcodeTemplateEditorModal.tsx b/src/app/barcode-templates/modals/BarcodeTemplateFormModal/BarcodeTemplateEditorModal.tsx new file mode 100644 index 0000000..2150d6d --- /dev/null +++ b/src/app/barcode-templates/modals/BarcodeTemplateFormModal/BarcodeTemplateEditorModal.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { Checkbox, Flex, TextInput } from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { ContextModalProps } from "@mantine/modals"; +import BarcodeTemplateAttributeMultiselect from "@/app/barcode-templates/components/shared/BarcodeTemplateAttributeMultiselect/BarcodeTemplateAttributeMultiselect"; +import BarcodeTemplateSizeSelect from "@/app/barcode-templates/components/shared/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect"; +import { + BarcodeTemplateSchema, + CreateBarcodeTemplateSchema, + UpdateBarcodeTemplateSchema, +} from "@/lib/client"; +import BaseFormModal, { + CreateEditFormProps, +} from "@/modals/base/BaseFormModal/BaseFormModal"; + +type Props = CreateEditFormProps< + BarcodeTemplateSchema, + CreateBarcodeTemplateSchema, + UpdateBarcodeTemplateSchema +>; + +const BarcodeTemplateEditorModal = ({ + context, + id, + innerProps, +}: ContextModalProps) => { + const initialValues = innerProps.isEditing + ? innerProps.entity + : ({ + name: "", + isDefault: false, + attributes: [], + } as Partial); + + const form = useForm({ + initialValues, + validate: { + attributes: attributes => + !attributes && "Необходимо добавить хотя бы один атрибут", + name: name => + !name || + (name.trim() === "" && "Необходимо ввести название шаблона"), + size: size => !size && "Необходимо выбрать размер шаблона", + }, + }); + + return ( + context.closeContextModal(id)}> + + + + + + + + ); +}; + +export default BarcodeTemplateEditorModal; diff --git a/src/app/barcode-templates/page.tsx b/src/app/barcode-templates/page.tsx new file mode 100644 index 0000000..526b321 --- /dev/null +++ b/src/app/barcode-templates/page.tsx @@ -0,0 +1,19 @@ +import { Suspense } from "react"; +import { Center, Loader } from "@mantine/core"; +import PageBody from "@/app/barcode-templates/components/shared/PageBody/PageBody"; +import PageContainer from "@/components/layout/PageContainer/PageContainer"; + +export default async function BarcodeTemplatesPage() { + return ( + + + + }> + + + + + ); +} diff --git a/src/components/layout/Navbar/Navbar.tsx b/src/components/layout/Navbar/Navbar.tsx index af8da46..3ea4d08 100644 --- a/src/components/layout/Navbar/Navbar.tsx +++ b/src/components/layout/Navbar/Navbar.tsx @@ -1,4 +1,8 @@ -import { IconColumns, IconLayoutKanban } from "@tabler/icons-react"; +import { + IconColumns, + IconFileBarcode, + IconLayoutKanban, +} from "@tabler/icons-react"; import { Box, Flex } from "@mantine/core"; import PageBlock from "@/components/layout/PageBlock/PageBlock"; import { ColorSchemeToggle } from "@/components/ui/ColorSchemeToggle/ColorSchemeToggle"; @@ -17,6 +21,11 @@ const linksData = [ label: "Услуги", href: "/services", }, + { + icon: IconFileBarcode, + label: "Шаблоны штрихкодов", + href: "/barcode-templates", + }, ]; const Navbar = () => { diff --git a/src/components/selects/ObjectMultiSelect/ObjectMultiSelect.tsx b/src/components/selects/ObjectMultiSelect/ObjectMultiSelect.tsx index 4ae1a05..e346f3d 100644 --- a/src/components/selects/ObjectMultiSelect/ObjectMultiSelect.tsx +++ b/src/components/selects/ObjectMultiSelect/ObjectMultiSelect.tsx @@ -17,8 +17,8 @@ type ControlledValueProps = { }; type CustomLabelAndKeyProps = { - getLabelFn: (item: MultiselectObjectType) => string; - getValueFn: (item: MultiselectObjectType) => string; + getLabelFn?: (item: MultiselectObjectType) => string; + getValueFn?: (item: MultiselectObjectType) => string; }; type RestProps = { defaultValue?: MultiselectObjectType[]; diff --git a/src/components/selects/ObjectSelect/ObjectSelect.tsx b/src/components/selects/ObjectSelect/ObjectSelect.tsx index 7b80302..3413f27 100644 --- a/src/components/selects/ObjectSelect/ObjectSelect.tsx +++ b/src/components/selects/ObjectSelect/ObjectSelect.tsx @@ -16,8 +16,8 @@ type ControlledValueProps = { onChange: (value: SelectObjectType) => void; }; type CustomLabelAndKeyProps = { - getLabelFn: (item: SelectObjectType) => string; - getValueFn: (item: SelectObjectType) => string; + getLabelFn?: (item: SelectObjectType) => string; + getValueFn?: (item: SelectObjectType) => string; }; type RestProps = { diff --git a/src/lib/client/@tanstack/react-query.gen.ts b/src/lib/client/@tanstack/react-query.gen.ts index 2ec42bc..b22178f 100644 --- a/src/lib/client/@tanstack/react-query.gen.ts +++ b/src/lib/client/@tanstack/react-query.gen.ts @@ -11,6 +11,7 @@ import { client as _heyApiClient } from "../client.gen"; import { addKitToDeal, addKitToDealProduct, + createBarcodeTemplate, createBoard, createDeal, createDealProduct, @@ -22,6 +23,7 @@ import { createServiceCategory, createServicesKit, createStatus, + deleteBarcodeTemplate, deleteBoard, deleteDeal, deleteDealProduct, @@ -34,6 +36,9 @@ import { deleteServicesKit, deleteStatus, duplicateProductServices, + getBarcodeTemplateAttributes, + getBarcodeTemplates, + getBarcodeTemplateSizes, getBoards, getBuiltInModules, getDealProducts, @@ -46,6 +51,7 @@ import { getServicesKits, getStatuses, getStatusHistory, + updateBarcodeTemplate, updateBoard, updateDeal, updateDealProduct, @@ -66,6 +72,9 @@ import type { AddKitToDealProductError, AddKitToDealProductResponse, AddKitToDealResponse, + CreateBarcodeTemplateData, + CreateBarcodeTemplateError, + CreateBarcodeTemplateResponse2, CreateBoardData, CreateBoardError, CreateBoardResponse2, @@ -99,6 +108,9 @@ import type { CreateStatusData, CreateStatusError, CreateStatusResponse2, + DeleteBarcodeTemplateData, + DeleteBarcodeTemplateError, + DeleteBarcodeTemplateResponse2, DeleteBoardData, DeleteBoardError, DeleteBoardResponse2, @@ -135,6 +147,9 @@ import type { DuplicateProductServicesData, DuplicateProductServicesError, DuplicateProductServicesResponse, + GetBarcodeTemplateAttributesData, + GetBarcodeTemplatesData, + GetBarcodeTemplateSizesData, GetBoardsData, GetBuiltInModulesData, GetDealProductsData, @@ -151,6 +166,9 @@ import type { GetServicesKitsData, GetStatusesData, GetStatusHistoryData, + UpdateBarcodeTemplateData, + UpdateBarcodeTemplateError, + UpdateBarcodeTemplateResponse2, UpdateBoardData, UpdateBoardError, UpdateBoardResponse2, @@ -847,6 +865,183 @@ export const getStatusHistoryOptions = ( }); }; +export const getBarcodeTemplatesQueryKey = ( + options?: Options +) => createQueryKey("getBarcodeTemplates", options); + +/** + * Get Barcode Templates + */ +export const getBarcodeTemplatesOptions = ( + options?: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getBarcodeTemplates({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getBarcodeTemplatesQueryKey(options), + }); +}; + +export const createBarcodeTemplateQueryKey = ( + options: Options +) => createQueryKey("createBarcodeTemplate", options); + +/** + * Create Barcode Template + */ +export const createBarcodeTemplateOptions = ( + options: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await createBarcodeTemplate({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: createBarcodeTemplateQueryKey(options), + }); +}; + +/** + * Create Barcode Template + */ +export const createBarcodeTemplateMutation = ( + options?: Partial> +): UseMutationOptions< + CreateBarcodeTemplateResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + CreateBarcodeTemplateResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await createBarcodeTemplate({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Delete Barcode Template + */ +export const deleteBarcodeTemplateMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteBarcodeTemplateResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteBarcodeTemplateResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await deleteBarcodeTemplate({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Update Barcode Template + */ +export const updateBarcodeTemplateMutation = ( + options?: Partial> +): UseMutationOptions< + UpdateBarcodeTemplateResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + UpdateBarcodeTemplateResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await updateBarcodeTemplate({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +export const getBarcodeTemplateAttributesQueryKey = ( + options?: Options +) => createQueryKey("getBarcodeTemplateAttributes", options); + +/** + * Get Barcode Template Attributes + */ +export const getBarcodeTemplateAttributesOptions = ( + options?: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getBarcodeTemplateAttributes({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getBarcodeTemplateAttributesQueryKey(options), + }); +}; + +export const getBarcodeTemplateSizesQueryKey = ( + options?: Options +) => createQueryKey("getBarcodeTemplateSizes", options); + +/** + * Get Barcode Template Sizes + */ +export const getBarcodeTemplateSizesOptions = ( + options?: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getBarcodeTemplateSizes({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getBarcodeTemplateSizesQueryKey(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 095c809..11a2689 100644 --- a/src/lib/client/sdk.gen.ts +++ b/src/lib/client/sdk.gen.ts @@ -9,6 +9,9 @@ import type { AddKitToDealProductErrors, AddKitToDealProductResponses, AddKitToDealResponses, + CreateBarcodeTemplateData, + CreateBarcodeTemplateErrors, + CreateBarcodeTemplateResponses, CreateBoardData, CreateBoardErrors, CreateBoardResponses, @@ -42,6 +45,9 @@ import type { CreateStatusData, CreateStatusErrors, CreateStatusResponses, + DeleteBarcodeTemplateData, + DeleteBarcodeTemplateErrors, + DeleteBarcodeTemplateResponses, DeleteBoardData, DeleteBoardErrors, DeleteBoardResponses, @@ -78,6 +84,12 @@ import type { DuplicateProductServicesData, DuplicateProductServicesErrors, DuplicateProductServicesResponses, + GetBarcodeTemplateAttributesData, + GetBarcodeTemplateAttributesResponses, + GetBarcodeTemplatesData, + GetBarcodeTemplateSizesData, + GetBarcodeTemplateSizesResponses, + GetBarcodeTemplatesResponses, GetBoardsData, GetBoardsErrors, GetBoardsResponses, @@ -109,6 +121,9 @@ import type { GetStatusHistoryData, GetStatusHistoryErrors, GetStatusHistoryResponses, + UpdateBarcodeTemplateData, + UpdateBarcodeTemplateErrors, + UpdateBarcodeTemplateResponses, UpdateBoardData, UpdateBoardErrors, UpdateBoardResponses, @@ -148,6 +163,8 @@ import { zAddKitToDealProductData, zAddKitToDealProductResponse, zAddKitToDealResponse, + zCreateBarcodeTemplateData, + zCreateBarcodeTemplateResponse2, zCreateBoardData, zCreateBoardResponse2, zCreateDealData, @@ -170,6 +187,8 @@ import { zCreateServicesKitResponse2, zCreateStatusData, zCreateStatusResponse2, + zDeleteBarcodeTemplateData, + zDeleteBarcodeTemplateResponse2, zDeleteBoardData, zDeleteBoardResponse2, zDeleteDealData, @@ -194,6 +213,12 @@ import { zDeleteStatusResponse2, zDuplicateProductServicesData, zDuplicateProductServicesResponse, + zGetBarcodeTemplateAttributesData, + zGetBarcodeTemplateAttributesResponse, + zGetBarcodeTemplatesData, + zGetBarcodeTemplateSizesData, + zGetBarcodeTemplateSizesResponse2, + zGetBarcodeTemplatesResponse2, zGetBoardsData, zGetBoardsResponse2, zGetBuiltInModulesData, @@ -218,6 +243,8 @@ import { zGetStatusesResponse2, zGetStatusHistoryData, zGetStatusHistoryResponse2, + zUpdateBarcodeTemplateData, + zUpdateBarcodeTemplateResponse2, zUpdateBoardData, zUpdateBoardResponse2, zUpdateDealData, @@ -705,6 +732,154 @@ export const getStatusHistory = ( }); }; +/** + * Get Barcode Templates + */ +export const getBarcodeTemplates = ( + options?: Options +) => { + return (options?.client ?? _heyApiClient).get< + GetBarcodeTemplatesResponses, + unknown, + ThrowOnError + >({ + requestValidator: async data => { + return await zGetBarcodeTemplatesData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zGetBarcodeTemplatesResponse2.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/", + ...options, + }); +}; + +/** + * Create Barcode Template + */ +export const createBarcodeTemplate = ( + options: Options +) => { + return (options.client ?? _heyApiClient).post< + CreateBarcodeTemplateResponses, + CreateBarcodeTemplateErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zCreateBarcodeTemplateData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zCreateBarcodeTemplateResponse2.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + +/** + * Delete Barcode Template + */ +export const deleteBarcodeTemplate = ( + options: Options +) => { + return (options.client ?? _heyApiClient).delete< + DeleteBarcodeTemplateResponses, + DeleteBarcodeTemplateErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zDeleteBarcodeTemplateData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zDeleteBarcodeTemplateResponse2.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/{pk}", + ...options, + }); +}; + +/** + * Update Barcode Template + */ +export const updateBarcodeTemplate = ( + options: Options +) => { + return (options.client ?? _heyApiClient).patch< + UpdateBarcodeTemplateResponses, + UpdateBarcodeTemplateErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zUpdateBarcodeTemplateData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zUpdateBarcodeTemplateResponse2.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/{pk}", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + +/** + * Get Barcode Template Attributes + */ +export const getBarcodeTemplateAttributes = < + ThrowOnError extends boolean = false, +>( + options?: Options +) => { + return (options?.client ?? _heyApiClient).get< + GetBarcodeTemplateAttributesResponses, + unknown, + ThrowOnError + >({ + requestValidator: async data => { + return await zGetBarcodeTemplateAttributesData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zGetBarcodeTemplateAttributesResponse.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/attributes", + ...options, + }); +}; + +/** + * Get Barcode Template Sizes + */ +export const getBarcodeTemplateSizes = ( + options?: Options +) => { + return (options?.client ?? _heyApiClient).get< + GetBarcodeTemplateSizesResponses, + unknown, + ThrowOnError + >({ + requestValidator: async data => { + return await zGetBarcodeTemplateSizesData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zGetBarcodeTemplateSizesResponse2.parseAsync(data); + }, + url: "/modules/fulfillment-base/barcode-template/sizes", + ...options, + }); +}; + /** * Get Deal Products */ diff --git a/src/lib/client/types.gen.ts b/src/lib/client/types.gen.ts index 8ac58ef..5c33e76 100644 --- a/src/lib/client/types.gen.ts +++ b/src/lib/client/types.gen.ts @@ -1,5 +1,68 @@ // This file is auto-generated by @hey-api/openapi-ts +/** + * BarcodeTemplateAttributeSchema + */ +export type BarcodeTemplateAttributeSchema = { + /** + * Id + */ + id: number; + /** + * Key + */ + key: string; + /** + * Name + */ + name: string; +}; + +/** + * BarcodeTemplateSchema + */ +export type BarcodeTemplateSchema = { + /** + * Name + */ + name: string; + /** + * Attributes + */ + attributes: Array; + /** + * Isdefault + */ + isDefault: boolean; + size: BarcodeTemplateSizeSchema; + /** + * Id + */ + id: number; +}; + +/** + * BarcodeTemplateSizeSchema + */ +export type BarcodeTemplateSizeSchema = { + /** + * Id + */ + id: number; + /** + * Name + */ + name: string; + /** + * Width + */ + width: number; + /** + * Height + */ + height: number; +}; + /** * BoardSchema */ @@ -108,6 +171,43 @@ export type BuiltInModuleTabSchema = { device: string; }; +/** + * CreateBarcodeTemplateRequest + */ +export type CreateBarcodeTemplateRequest = { + entity: CreateBarcodeTemplateSchema; +}; + +/** + * CreateBarcodeTemplateResponse + */ +export type CreateBarcodeTemplateResponse = { + /** + * Message + */ + message: string; + entity: BarcodeTemplateSchema; +}; + +/** + * CreateBarcodeTemplateSchema + */ +export type CreateBarcodeTemplateSchema = { + /** + * Name + */ + name: string; + /** + * Attributes + */ + attributes: Array; + /** + * Isdefault + */ + isDefault: boolean; + size: BarcodeTemplateSizeSchema; +}; + /** * CreateBoardRequest */ @@ -679,6 +779,16 @@ export type DealServiceSchema = { isFixedPrice: boolean; }; +/** + * DeleteBarcodeTemplateResponse + */ +export type DeleteBarcodeTemplateResponse = { + /** + * Message + */ + message: string; +}; + /** * DeleteBoardResponse */ @@ -799,6 +909,36 @@ export type GetAllBuiltInModulesResponse = { items: Array; }; +/** + * GetBarcodeAttributesResponse + */ +export type GetBarcodeAttributesResponse = { + /** + * Items + */ + items: Array; +}; + +/** + * GetBarcodeTemplateSizesResponse + */ +export type GetBarcodeTemplateSizesResponse = { + /** + * Items + */ + items: Array; +}; + +/** + * GetBarcodeTemplatesResponse + */ +export type GetBarcodeTemplatesResponse = { + /** + * Items + */ + items: Array; +}; + /** * GetBoardsResponse */ @@ -1212,6 +1352,42 @@ export type StatusSchema = { lexorank: string; }; +/** + * UpdateBarcodeTemplateRequest + */ +export type UpdateBarcodeTemplateRequest = { + entity: UpdateBarcodeTemplateSchema; +}; + +/** + * UpdateBarcodeTemplateResponse + */ +export type UpdateBarcodeTemplateResponse = { + /** + * Message + */ + message: string; +}; + +/** + * UpdateBarcodeTemplateSchema + */ +export type UpdateBarcodeTemplateSchema = { + /** + * Name + */ + name?: string | null; + /** + * Attributes + */ + attributes?: Array | null; + /** + * Isdefault + */ + isDefault?: boolean | null; + size?: BarcodeTemplateSizeSchema | null; +}; + /** * UpdateBoardRequest */ @@ -2181,6 +2357,148 @@ export type GetStatusHistoryResponses = { export type GetStatusHistoryResponse2 = GetStatusHistoryResponses[keyof GetStatusHistoryResponses]; +export type GetBarcodeTemplatesData = { + body?: never; + path?: never; + query?: never; + url: "/modules/fulfillment-base/barcode-template/"; +}; + +export type GetBarcodeTemplatesResponses = { + /** + * Successful Response + */ + 200: GetBarcodeTemplatesResponse; +}; + +export type GetBarcodeTemplatesResponse2 = + GetBarcodeTemplatesResponses[keyof GetBarcodeTemplatesResponses]; + +export type CreateBarcodeTemplateData = { + body: CreateBarcodeTemplateRequest; + path?: never; + query?: never; + url: "/modules/fulfillment-base/barcode-template/"; +}; + +export type CreateBarcodeTemplateErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateBarcodeTemplateError = + CreateBarcodeTemplateErrors[keyof CreateBarcodeTemplateErrors]; + +export type CreateBarcodeTemplateResponses = { + /** + * Successful Response + */ + 200: CreateBarcodeTemplateResponse; +}; + +export type CreateBarcodeTemplateResponse2 = + CreateBarcodeTemplateResponses[keyof CreateBarcodeTemplateResponses]; + +export type DeleteBarcodeTemplateData = { + body?: never; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/modules/fulfillment-base/barcode-template/{pk}"; +}; + +export type DeleteBarcodeTemplateErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteBarcodeTemplateError = + DeleteBarcodeTemplateErrors[keyof DeleteBarcodeTemplateErrors]; + +export type DeleteBarcodeTemplateResponses = { + /** + * Successful Response + */ + 200: DeleteBarcodeTemplateResponse; +}; + +export type DeleteBarcodeTemplateResponse2 = + DeleteBarcodeTemplateResponses[keyof DeleteBarcodeTemplateResponses]; + +export type UpdateBarcodeTemplateData = { + body: UpdateBarcodeTemplateRequest; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/modules/fulfillment-base/barcode-template/{pk}"; +}; + +export type UpdateBarcodeTemplateErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateBarcodeTemplateError = + UpdateBarcodeTemplateErrors[keyof UpdateBarcodeTemplateErrors]; + +export type UpdateBarcodeTemplateResponses = { + /** + * Successful Response + */ + 200: UpdateBarcodeTemplateResponse; +}; + +export type UpdateBarcodeTemplateResponse2 = + UpdateBarcodeTemplateResponses[keyof UpdateBarcodeTemplateResponses]; + +export type GetBarcodeTemplateAttributesData = { + body?: never; + path?: never; + query?: never; + url: "/modules/fulfillment-base/barcode-template/attributes"; +}; + +export type GetBarcodeTemplateAttributesResponses = { + /** + * Successful Response + */ + 200: GetBarcodeAttributesResponse; +}; + +export type GetBarcodeTemplateAttributesResponse = + GetBarcodeTemplateAttributesResponses[keyof GetBarcodeTemplateAttributesResponses]; + +export type GetBarcodeTemplateSizesData = { + body?: never; + path?: never; + query?: never; + url: "/modules/fulfillment-base/barcode-template/sizes"; +}; + +export type GetBarcodeTemplateSizesResponses = { + /** + * Successful Response + */ + 200: GetBarcodeTemplateSizesResponse; +}; + +export type GetBarcodeTemplateSizesResponse2 = + GetBarcodeTemplateSizesResponses[keyof GetBarcodeTemplateSizesResponses]; + export type GetDealProductsData = { body?: never; path: { diff --git a/src/lib/client/zod.gen.ts b/src/lib/client/zod.gen.ts index 86860ec..21b48b0 100644 --- a/src/lib/client/zod.gen.ts +++ b/src/lib/client/zod.gen.ts @@ -2,6 +2,36 @@ import { z } from "zod"; +/** + * BarcodeTemplateAttributeSchema + */ +export const zBarcodeTemplateAttributeSchema = z.object({ + id: z.int(), + key: z.string(), + name: z.string(), +}); + +/** + * BarcodeTemplateSizeSchema + */ +export const zBarcodeTemplateSizeSchema = z.object({ + id: z.int(), + name: z.string(), + width: z.int(), + height: z.int(), +}); + +/** + * BarcodeTemplateSchema + */ +export const zBarcodeTemplateSchema = z.object({ + name: z.string(), + attributes: z.array(zBarcodeTemplateAttributeSchema), + isDefault: z.boolean(), + size: zBarcodeTemplateSizeSchema, + id: z.int(), +}); + /** * BoardSchema */ @@ -59,6 +89,31 @@ export const zBuiltInModuleSchemaOutput = z.object({ tabs: z.array(zBuiltInModuleTabSchema), }); +/** + * CreateBarcodeTemplateSchema + */ +export const zCreateBarcodeTemplateSchema = z.object({ + name: z.string(), + attributes: z.array(zBarcodeTemplateAttributeSchema), + isDefault: z.boolean(), + size: zBarcodeTemplateSizeSchema, +}); + +/** + * CreateBarcodeTemplateRequest + */ +export const zCreateBarcodeTemplateRequest = z.object({ + entity: zCreateBarcodeTemplateSchema, +}); + +/** + * CreateBarcodeTemplateResponse + */ +export const zCreateBarcodeTemplateResponse = z.object({ + message: z.string(), + entity: zBarcodeTemplateSchema, +}); + /** * CreateBoardSchema */ @@ -494,6 +549,13 @@ export const zDealProductAddKitResponse = z.object({ message: z.string(), }); +/** + * DeleteBarcodeTemplateResponse + */ +export const zDeleteBarcodeTemplateResponse = z.object({ + message: z.string(), +}); + /** * DeleteBoardResponse */ @@ -578,6 +640,27 @@ export const zGetAllBuiltInModulesResponse = z.object({ items: z.array(zBuiltInModuleSchemaOutput), }); +/** + * GetBarcodeAttributesResponse + */ +export const zGetBarcodeAttributesResponse = z.object({ + items: z.array(zBarcodeTemplateAttributeSchema), +}); + +/** + * GetBarcodeTemplateSizesResponse + */ +export const zGetBarcodeTemplateSizesResponse = z.object({ + items: z.array(zBarcodeTemplateSizeSchema), +}); + +/** + * GetBarcodeTemplatesResponse + */ +export const zGetBarcodeTemplatesResponse = z.object({ + items: z.array(zBarcodeTemplateSchema), +}); + /** * GetBoardsResponse */ @@ -720,6 +803,32 @@ export const zProductServicesDuplicateResponse = z.object({ export const zSortDir = z.enum(["asc", "desc"]); +/** + * UpdateBarcodeTemplateSchema + */ +export const zUpdateBarcodeTemplateSchema = z.object({ + name: z.optional(z.union([z.string(), z.null()])), + attributes: z.optional( + z.union([z.array(zBarcodeTemplateAttributeSchema), z.null()]) + ), + isDefault: z.optional(z.union([z.boolean(), z.null()])), + size: z.optional(z.union([zBarcodeTemplateSizeSchema, z.null()])), +}); + +/** + * UpdateBarcodeTemplateRequest + */ +export const zUpdateBarcodeTemplateRequest = z.object({ + entity: zUpdateBarcodeTemplateSchema, +}); + +/** + * UpdateBarcodeTemplateResponse + */ +export const zUpdateBarcodeTemplateResponse = z.object({ + message: z.string(), +}); + /** * UpdateBoardSchema */ @@ -1214,6 +1323,78 @@ export const zGetStatusHistoryData = z.object({ */ export const zGetStatusHistoryResponse2 = zGetStatusHistoryResponse; +export const zGetBarcodeTemplatesData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zGetBarcodeTemplatesResponse2 = zGetBarcodeTemplatesResponse; + +export const zCreateBarcodeTemplateData = z.object({ + body: zCreateBarcodeTemplateRequest, + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zCreateBarcodeTemplateResponse2 = zCreateBarcodeTemplateResponse; + +export const zDeleteBarcodeTemplateData = z.object({ + body: z.optional(z.never()), + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zDeleteBarcodeTemplateResponse2 = zDeleteBarcodeTemplateResponse; + +export const zUpdateBarcodeTemplateData = z.object({ + body: zUpdateBarcodeTemplateRequest, + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zUpdateBarcodeTemplateResponse2 = zUpdateBarcodeTemplateResponse; + +export const zGetBarcodeTemplateAttributesData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zGetBarcodeTemplateAttributesResponse = + zGetBarcodeAttributesResponse; + +export const zGetBarcodeTemplateSizesData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zGetBarcodeTemplateSizesResponse2 = + zGetBarcodeTemplateSizesResponse; + export const zGetDealProductsData = z.object({ body: z.optional(z.never()), path: z.object({ diff --git a/src/modals/modals.ts b/src/modals/modals.ts index d8d778e..176ca92 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -11,6 +11,7 @@ import { ProductServiceEditorModal, ServicesKitSelectModal, } from "@/modules/dealModularEditorTabs/FulfillmentBase/shared/modals"; +import BarcodeTemplateEditorModal from "@/app/barcode-templates/modals/BarcodeTemplateFormModal/BarcodeTemplateEditorModal"; export const modals = { enterNameModal: EnterNameModal, @@ -26,4 +27,5 @@ export const modals = { servicesKitEditorModal: ServicesKitEditorModal, serviceCategoryEditorModal: ServiceCategoryEditorModal, serviceEditorModal: ServiceEditorModal, + barcodeTemplateEditorModal: BarcodeTemplateEditorModal, }; diff --git a/yarn.lock b/yarn.lock index a63450e..afea96d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5128,14 +5128,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.11.0": - version: 1.11.0 - resolution: "axios@npm:1.11.0" +"axios@npm:1.12.0": + version: 1.12.0 + resolution: "axios@npm:1.12.0" dependencies: follow-redirects: "npm:^1.15.6" form-data: "npm:^4.0.4" proxy-from-env: "npm:^1.1.0" - checksum: 10c0/5de273d33d43058610e4d252f0963cc4f10714da0bfe872e8ef2cbc23c2c999acc300fd357b6bce0fc84a2ca9bd45740fa6bb28199ce2c1266c8b1a393f2b36e + checksum: 10c0/44a1e4cfb69a2d59aa12bbc441a336e5c18e87c02b904c509fd33607d94e8cb8cc221c17e9d53f67841a4efe13abf1aa1497c85df390cdb8681ee723998d11b0 languageName: node linkType: hard @@ -6179,7 +6179,7 @@ __metadata: "@types/redux-persist": "npm:^4.3.1" "@types/slick-carousel": "npm:^1" autoprefixer: "npm:^10.4.21" - axios: "npm:^1.11.0" + axios: "npm:1.12.0" babel-loader: "npm:^10.0.0" classnames: "npm:^2.5.1" clsx: "npm:^2.1.1"