diff --git a/src/app/attributes/components/AttrViewSegmentedControl.tsx b/src/app/attributes/components/AttrViewSegmentedControl.tsx new file mode 100644 index 0000000..db6554f --- /dev/null +++ b/src/app/attributes/components/AttrViewSegmentedControl.tsx @@ -0,0 +1,27 @@ +import { FC } from "react"; +import AttributePageView from "@/app/attributes/types/view"; +import BaseSegmentedControl, { + BaseSegmentedControlProps, +} from "@/components/ui/BaseSegmentedControl/BaseSegmentedControl"; + +type Props = Omit, "data">; + +const data = [ + { + label: "Аттрибуты", + value: AttributePageView.ATTRIBUTES, + }, + { + label: "Справочники", + value: AttributePageView.SELECTS, + }, +]; + +const AttrViewSegmentedControl: FC = props => ( + +); + +export default AttrViewSegmentedControl; diff --git a/src/app/attributes/components/AttributesHeader.tsx b/src/app/attributes/components/AttributesHeader.tsx index ca91ba8..f1f1603 100644 --- a/src/app/attributes/components/AttributesHeader.tsx +++ b/src/app/attributes/components/AttributesHeader.tsx @@ -1,34 +1,79 @@ "use client"; -import { FC } from "react"; +import { Dispatch, FC, SetStateAction, useMemo } from "react"; import { Group, TextInput } from "@mantine/core"; +import AttrViewSegmentedControl from "@/app/attributes/components/AttrViewSegmentedControl"; import { useAttributesContext } from "@/app/attributes/contexts/AttributesContext"; +import AttributePageView from "@/app/attributes/types/view"; import InlineButton from "@/components/ui/InlineButton/InlineButton"; import useIsMobile from "@/hooks/utils/useIsMobile"; -const AttributesHeader: FC = () => { +type Props = { + view: AttributePageView; + setView: Dispatch>; +}; + +const AttributesHeader: FC = ({ view, setView }) => { const { - attributesActions: { onCreate }, - search, - setSearch, + attributesActions, + selectsActions, + attrSearch, + setAttrSearch, + selectSearch, + setSelectSearch, } = useAttributesContext(); const isMobile = useIsMobile(); + const attributeActions = useMemo( + () => ( + + + Создать атрибут + + setAttrSearch(e.currentTarget.value)} + w={isMobile ? "100%" : "auto"} + placeholder={"Поиск..."} + /> + + ), + [isMobile, attrSearch] + ); + + const selectActions = useMemo( + () => ( + + + Создать справочник + + setSelectSearch(e.currentTarget.value)} + w={isMobile ? "100%" : "auto"} + placeholder={"Поиск..."} + /> + + ), + [isMobile, selectSearch] + ); + return ( - - Создать атрибут - - setSearch(e.currentTarget.value)} - w={isMobile ? "100%" : "auto"} - placeholder={"Поиск..."} + mx={isMobile ? "xs" : ""} + justify={"space-between"}> + {view === AttributePageView.ATTRIBUTES + ? attributeActions + : selectActions} + ); diff --git a/src/app/attributes/components/PageBody.tsx b/src/app/attributes/components/PageBody.tsx index 730d54b..66c8cc1 100644 --- a/src/app/attributes/components/PageBody.tsx +++ b/src/app/attributes/components/PageBody.tsx @@ -1,26 +1,42 @@ "use client"; +import { useState } from "react"; import AttributesHeader from "@/app/attributes/components/AttributesHeader"; import AttributesTable from "@/app/attributes/components/AttributesTable"; +import SelectsTable from "@/app/attributes/components/SelectsTable"; +import AttributePageView from "@/app/attributes/types/view"; import PageBlock from "@/components/layout/PageBlock/PageBlock"; -const PageBody = () => ( - -
- -
- +const PageBody = () => { + const [view, setView] = useState( + AttributePageView.ATTRIBUTES + ); + + return ( + +
+ +
+ {view === AttributePageView.ATTRIBUTES ? ( + + ) : ( + + )} +
-
- -); + + ); +}; export default PageBody; diff --git a/src/app/attributes/components/SelectsTable.tsx b/src/app/attributes/components/SelectsTable.tsx new file mode 100644 index 0000000..4983810 --- /dev/null +++ b/src/app/attributes/components/SelectsTable.tsx @@ -0,0 +1,36 @@ +import { IconMoodSad } from "@tabler/icons-react"; +import { Group, Text } from "@mantine/core"; +import { useAttributesContext } from "@/app/attributes/contexts/AttributesContext"; +import useSelectsTableColumns from "@/app/attributes/hooks/useSelectsTableColumns"; +import BaseTable from "@/components/ui/BaseTable/BaseTable"; +import useIsMobile from "@/hooks/utils/useIsMobile"; + +const SelectsTable = () => { + const { selects } = useAttributesContext(); + const isMobile = useIsMobile(); + const columns = useSelectsTableColumns(); + + return ( + + Нет справочников + + + } + groups={undefined} + styles={{ + table: { + width: "100%", + }, + }} + mx={isMobile ? "xs" : 0} + /> + ); +}; + +export default SelectsTable; diff --git a/src/app/attributes/contexts/AttributesContext.tsx b/src/app/attributes/contexts/AttributesContext.tsx index d2867c0..fd3402d 100644 --- a/src/app/attributes/contexts/AttributesContext.tsx +++ b/src/app/attributes/contexts/AttributesContext.tsx @@ -2,37 +2,59 @@ import { Dispatch, SetStateAction } from "react"; import useFilteredAttributes from "@/app/attributes/hooks/useFilteredAttributes"; +import useSelectsActions, { + SelectsActions, +} from "@/app/attributes/hooks/useSelectsActions"; import useAttributesActions, { AttributesActions, } from "@/app/module-editor/[moduleId]/hooks/useAttributesActions"; import useAttributesList from "@/app/module-editor/[moduleId]/hooks/useAttributesList"; -import { AttributeSchema } from "@/lib/client"; +import useAttrSelectsList from "@/hooks/lists/useAttrSelectsList"; +import { AttributeSchema, AttrSelectSchema } from "@/lib/client"; import makeContext from "@/lib/contextFactory/contextFactory"; +import useFilteredSelects from "@/app/attributes/hooks/useFilteredSelects"; type AttributesContextState = { attributes: AttributeSchema[]; - refetchAttributes: () => void; attributesActions: AttributesActions; - search: string; - setSearch: Dispatch>; + attrSearch: string; + setAttrSearch: Dispatch>; + selects: AttrSelectSchema[]; + selectsActions: SelectsActions; + selectSearch: string; + setSelectSearch: Dispatch>; }; const useAttributesContextState = (): AttributesContextState => { - const { attributes, refetch } = useAttributesList(); + const { attributes, refetch: refetchAttributes } = useAttributesList(); const attributesActions = useAttributesActions({ - refetchAttributes: refetch, + refetchAttributes, }); - const { search, setSearch, filteredAttributes } = useFilteredAttributes({ - attributes, - }); + const { + search: attrSearch, + setSearch: setAttrSearch, + filteredAttributes, + } = useFilteredAttributes({ attributes }); + + const { selects, queryKey } = useAttrSelectsList(); + const selectsActions = useSelectsActions({ queryKey }); + + const { + search: selectSearch, + setSearch: setSelectSearch, + filteredSelects, + } = useFilteredSelects({ selects }); return { attributes: filteredAttributes, - refetchAttributes: refetch, attributesActions, - search, - setSearch, + attrSearch, + setAttrSearch, + selects: filteredSelects, + selectsActions, + selectSearch, + setSelectSearch, }; }; diff --git a/src/app/attributes/hooks/useFilteredSelects.ts b/src/app/attributes/hooks/useFilteredSelects.ts new file mode 100644 index 0000000..15efb14 --- /dev/null +++ b/src/app/attributes/hooks/useFilteredSelects.ts @@ -0,0 +1,23 @@ +import { useMemo, useState } from "react"; +import { AttrSelectSchema } from "@/lib/client"; + +type Props = { + selects: AttrSelectSchema[]; +}; + +const useFilteredSelects = ({ selects }: Props) => { + const [search, setSearch] = useState(""); + + const filteredSelects = useMemo( + () => selects.filter(s => s.name.includes(search)), + [selects, search] + ); + + return { + search, + setSearch, + filteredSelects, + }; +}; + +export default useFilteredSelects; diff --git a/src/app/attributes/hooks/useSelectsActions.tsx b/src/app/attributes/hooks/useSelectsActions.tsx new file mode 100644 index 0000000..117abb5 --- /dev/null +++ b/src/app/attributes/hooks/useSelectsActions.tsx @@ -0,0 +1,49 @@ +import { modals } from "@mantine/modals"; +import { useAttrSelectsCrud } from "@/hooks/cruds/useSelectsCrud"; +import { AttrSelectSchema } from "@/lib/client"; + +type Props = { + queryKey: any[]; +}; + +export type SelectsActions = { + onCreate: () => void; + onUpdate: (select: AttrSelectSchema) => void; + onDelete: (select: AttrSelectSchema) => void; +}; + +const useSelectsActions = (props: Props): SelectsActions => { + const attrSelectsCrud = useAttrSelectsCrud(props); + + const onCreate = () => { + modals.openContextModal({ + modal: "enterNameModal", + title: "Создание справочника", + innerProps: { + onChange: values => attrSelectsCrud.onCreate(values), + }, + }); + }; + + const onUpdate = (select: AttrSelectSchema) => { + modals.openContextModal({ + modal: "attrSelectEditorModal", + title: "Редактирование справочника", + innerProps: { + onSelectChange: (values, onSuccess) => + attrSelectsCrud.onUpdate(select.id, values, onSuccess), + select, + }, + }); + }; + + const onDelete = attrSelectsCrud.onDelete; + + return { + onCreate, + onUpdate, + onDelete, + }; +}; + +export default useSelectsActions; diff --git a/src/app/attributes/hooks/useSelectsTableColumns.tsx b/src/app/attributes/hooks/useSelectsTableColumns.tsx new file mode 100644 index 0000000..eaa7ba8 --- /dev/null +++ b/src/app/attributes/hooks/useSelectsTableColumns.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useMemo } from "react"; +import { DataTableColumn } from "mantine-datatable"; +import { Center } from "@mantine/core"; +import UpdateDeleteTableActions from "@/components/ui/BaseTable/components/UpdateDeleteTableActions"; +import useIsMobile from "@/hooks/utils/useIsMobile"; +import { AttrSelectSchema } from "@/lib/client"; +import { useAttributesContext } from "../contexts/AttributesContext"; + +const useSelectsTableColumns = () => { + const isMobile = useIsMobile(); + const { selectsActions } = useAttributesContext(); + + return useMemo( + () => + [ + { + title: "Название справочника", + accessor: "name", + }, + { + accessor: "actions", + title:
Действия
, + width: "0%", + render: select => ( + selectsActions.onDelete(select)} + onChange={() => selectsActions.onUpdate(select)} + /> + ), + }, + ] as DataTableColumn[], + [isMobile] + ); +}; + +export default useSelectsTableColumns; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/AttrSelectEditorModal.tsx b/src/app/attributes/modals/AttrSelectEditorModal/AttrSelectEditorModal.tsx new file mode 100644 index 0000000..47c3e13 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/AttrSelectEditorModal.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { ContextModalProps } from "@mantine/modals"; +import EditorBody from "@/app/attributes/modals/AttrSelectEditorModal/components/EditorBody"; +import { SelectEditorContextProvider } from "@/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext"; +import { AttrSelectSchema, UpdateAttrSelectSchema } from "@/lib/client"; + +type Props = { + select: AttrSelectSchema; + onSelectChange: ( + values: UpdateAttrSelectSchema, + onSuccess: () => void + ) => void; +}; + +const AttrSelectEditorModal = ({ innerProps }: ContextModalProps) => { + return ( + + + + ); +}; + +export default AttrSelectEditorModal; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/components/CommonInfoEditor.tsx b/src/app/attributes/modals/AttrSelectEditorModal/components/CommonInfoEditor.tsx new file mode 100644 index 0000000..fc8028f --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/components/CommonInfoEditor.tsx @@ -0,0 +1,38 @@ +import { Button, Flex, TextInput } from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { useSelectEditorContext } from "@/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext"; +import { UpdateAttrSelectSchema } from "@/lib/client"; + +const CommonInfoEditor = () => { + const { select, onSelectChange } = useSelectEditorContext(); + + const form = useForm({ + initialValues: select || { + name: "", + }, + validate: { + name: name => !name && "Введите название", + }, + }); + + return ( +
onSelectChange(values))}> + + + + +
+ ); +}; + +export default CommonInfoEditor; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/components/CreateOptionButton.tsx b/src/app/attributes/modals/AttrSelectEditorModal/components/CreateOptionButton.tsx new file mode 100644 index 0000000..716cb0a --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/components/CreateOptionButton.tsx @@ -0,0 +1,37 @@ +import { IconCheck } from "@tabler/icons-react"; +import { Flex, TextInput } from "@mantine/core"; +import { useSelectEditorContext } from "@/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext"; +import ActionIconWithTip from "@/components/ui/ActionIconWithTip/ActionIconWithTip"; +import InlineButton from "@/components/ui/InlineButton/InlineButton"; + +const CreateOptionButton = () => { + const { + optionsActions: { + isCreatingOption, + createOptionForm, + onStartCreating, + onFinishCreating, + }, + } = useSelectEditorContext(); + + if (!isCreatingOption) { + return ( + + Добавить опцию + + ); + } + + return ( + + + + + + + ); +}; + +export default CreateOptionButton; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/components/EditorBody.tsx b/src/app/attributes/modals/AttrSelectEditorModal/components/EditorBody.tsx new file mode 100644 index 0000000..87aeab5 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/components/EditorBody.tsx @@ -0,0 +1,20 @@ +import { Divider, Stack } from "@mantine/core"; +import CommonInfoEditor from "@/app/attributes/modals/AttrSelectEditorModal/components/CommonInfoEditor"; +import CreateOptionButton from "@/app/attributes/modals/AttrSelectEditorModal/components/CreateOptionButton"; +import OptionsTable from "@/app/attributes/modals/AttrSelectEditorModal/components/OptionsTable"; + +const EditorBody = () => { + return ( + + + + + + + ); +}; + +export default EditorBody; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/components/OptionsTable.tsx b/src/app/attributes/modals/AttrSelectEditorModal/components/OptionsTable.tsx new file mode 100644 index 0000000..2b908d3 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/components/OptionsTable.tsx @@ -0,0 +1,37 @@ +import { IconMoodSad } from "@tabler/icons-react"; +import { Group, Text } from "@mantine/core"; +import { useSelectEditorContext } from "@/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext"; +import useOptionsTableColumns from "@/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsTableColumns"; +import BaseTable from "@/components/ui/BaseTable/BaseTable"; +import useIsMobile from "@/hooks/utils/useIsMobile"; + +const OptionsTable = () => { + const { options } = useSelectEditorContext(); + const isMobile = useIsMobile(); + const columns = useOptionsTableColumns(); + + return ( + + Нет опций + + + } + groups={undefined} + styles={{ + table: { + width: "100%", + }, + header: { zIndex: 1 }, + }} + mx={isMobile ? "xs" : 0} + /> + ); +}; + +export default OptionsTable; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext.tsx b/src/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext.tsx new file mode 100644 index 0000000..663a6f7 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext.tsx @@ -0,0 +1,56 @@ +"use client"; + +import useAttrOptionsList from "@/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsList"; +import { + AttrOptionSchema, + AttrSelectSchema, + UpdateAttrSelectSchema, +} from "@/lib/client"; +import makeContext from "@/lib/contextFactory/contextFactory"; +import { notifications } from "@/lib/notifications"; +import useOptionsActions, { OptionsActions } from "../hooks/useOptionsActions"; + +type SelectEditorContextState = { + select: AttrSelectSchema; + onSelectChange: (values: UpdateAttrSelectSchema) => void; + options: AttrOptionSchema[]; + optionsActions: OptionsActions; +}; + +type Props = { + select: AttrSelectSchema; + onSelectChange: ( + values: UpdateAttrSelectSchema, + onSuccess: () => void + ) => void; +}; + +const useSelectEditorContextState = ({ + select, + onSelectChange, +}: Props): SelectEditorContextState => { + const { options, queryKey } = useAttrOptionsList({ selectId: select.id }); + + const optionsActions = useOptionsActions({ queryKey, select }); + + const onSelectChangeWithMsg = (values: UpdateAttrSelectSchema) => { + onSelectChange(values, () => { + notifications.success({ + message: "Название справочника сохранено", + }); + }); + }; + + return { + select, + onSelectChange: onSelectChangeWithMsg, + options, + optionsActions, + }; +}; + +export const [SelectEditorContextProvider, useSelectEditorContext] = + makeContext( + useSelectEditorContextState, + "SelectEditor" + ); diff --git a/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsCrud.tsx b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsCrud.tsx new file mode 100644 index 0000000..93a6763 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsCrud.tsx @@ -0,0 +1,53 @@ +import { useCrudOperations } from "@/hooks/cruds/baseCrud"; +import { + AttrOptionSchema, + CreateAttrOptionSchema, + UpdateAttrOptionSchema, +} from "@/lib/client"; +import { + createAttrOptionMutation, + deleteAttrOptionMutation, + updateAttrOptionMutation, +} from "@/lib/client/@tanstack/react-query.gen"; + +type Props = { + queryKey: any[]; +}; + +export type AttrOptionsCrud = { + onCreate: ( + data: Partial, + onSuccess?: () => void + ) => void; + onUpdate: ( + optionId: number, + option: UpdateAttrOptionSchema, + onSuccess?: () => void + ) => void; + onDelete: (option: AttrOptionSchema, onSuccess?: () => void) => void; +}; + +export const useAttrOptionsCrud = ({ queryKey }: Props): AttrOptionsCrud => { + return useCrudOperations< + AttrOptionSchema, + UpdateAttrOptionSchema, + CreateAttrOptionSchema + >({ + key: "getAttrOptions", + queryKey, + mutations: { + create: createAttrOptionMutation(), + update: updateAttrOptionMutation(), + delete: deleteAttrOptionMutation(), + }, + getCreateEntity: data => ({ + name: data.name!, + selectId: data.selectId!, + }), + getUpdateEntity: (old, update) => ({ + ...old, + name: update.name ?? old.name, + }), + getDeleteConfirmTitle: () => "Удаление опции", + }); +}; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsList.ts b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsList.ts new file mode 100644 index 0000000..51cf17f --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsList.ts @@ -0,0 +1,37 @@ +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { AttrOptionSchema } from "@/lib/client"; +import { + getAttrOptionsOptions, + getAttrOptionsQueryKey, +} from "@/lib/client/@tanstack/react-query.gen"; + +type Props = { + selectId: number; +}; + +const useAttrOptionsList = ({ selectId }: Props) => { + const queryClient = useQueryClient(); + const options = { path: { selectId } }; + const { data, refetch } = useQuery(getAttrOptionsOptions(options)); + + const queryKey = getAttrOptionsQueryKey(options); + + const setOptions = (options: AttrOptionSchema[]) => { + queryClient.setQueryData( + queryKey, + (old: { items: AttrOptionSchema[] }) => ({ + ...old, + items: options, + }) + ); + }; + + return { + options: data?.items ?? [], + setOptions, + refetch, + queryKey, + }; +}; + +export default useAttrOptionsList; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsActions.tsx b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsActions.tsx new file mode 100644 index 0000000..40c83e8 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsActions.tsx @@ -0,0 +1,99 @@ +import { Dispatch, SetStateAction, useState } from "react"; +import { useForm, UseFormReturnType } from "@mantine/form"; +import { useAttrOptionsCrud } from "@/app/attributes/modals/AttrSelectEditorModal/hooks/useAttrOptionsCrud"; +import { + AttrOptionSchema, + AttrSelectSchema, + CreateAttrOptionSchema, +} from "@/lib/client"; +import { notifications } from "@/lib/notifications"; + +type Props = { + queryKey: any[]; + select: AttrSelectSchema; +}; + +export type OptionsActions = { + isCreatingOption: boolean; + createOptionForm: UseFormReturnType; + onStartCreating: () => void; + onFinishCreating: () => void; + editingOptionsData: Map; + setEditingOptionsData: Dispatch>>; + onStartEditing: (option: AttrOptionSchema) => void; + onFinishEditing: (option: AttrOptionSchema) => void; + onDelete: (option: AttrOptionSchema) => void; +}; + +const useOptionsActions = ({ queryKey, select }: Props) => { + const [isCreatingOption, setIsCreatingOption] = useState(false); + const [editingOptionsData, setEditingOptionsData] = useState< + Map + >(new Map()); + + const createOptionForm = useForm({ + initialValues: { + name: "", + selectId: select.id, + }, + validate: { + name: name => !name && "Введите название", + }, + }); + + const optionCrud = useAttrOptionsCrud({ queryKey }); + + const onStartCreating = () => { + setIsCreatingOption(true); + }; + const onFinishCreating = () => { + if (createOptionForm.validate().hasErrors) return; + optionCrud.onCreate(createOptionForm.values, () => { + notifications.success({ message: "Опция успешно создана" }); + createOptionForm.reset(); + }); + }; + + const onStartEditing = (option: AttrOptionSchema) => { + setEditingOptionsData(prev => { + prev.set(option.id, option.name); + return new Map(prev); + }); + }; + const onFinishEditing = (option: AttrOptionSchema) => { + if (!editingOptionsData.has(option.id)) return; + + const newName = editingOptionsData.get(option.id); + if (!newName) { + notifications.error({ message: "Название не может быть пустым" }); + return; + } + optionCrud.onUpdate(option.id, { name: newName }, () => { + notifications.success({ message: "Опция сохранена" }); + setEditingOptionsData(prev => { + prev.delete(option.id); + return new Map(prev); + }); + }); + }; + + const onDelete = (option: AttrOptionSchema) => { + optionCrud.onDelete(option, () => + notifications.success({ message: "Опция удалена" }) + ); + }; + + return { + isCreatingOption, + createOptionForm, + onStartCreating, + onFinishCreating, + editingOptionsData, + setEditingOptionsData, + onStartEditing, + onFinishEditing, + onDelete, + }; +}; + +export default useOptionsActions; diff --git a/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsTableColumns.tsx b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsTableColumns.tsx new file mode 100644 index 0000000..1ac44c1 --- /dev/null +++ b/src/app/attributes/modals/AttrSelectEditorModal/hooks/useOptionsTableColumns.tsx @@ -0,0 +1,84 @@ +"use client"; + +import React, { useMemo } from "react"; +import { IconCheck, IconEdit, IconTrash } from "@tabler/icons-react"; +import { DataTableColumn } from "mantine-datatable"; +import { Center, Flex, TextInput } from "@mantine/core"; +import { useSelectEditorContext } from "@/app/attributes/modals/AttrSelectEditorModal/contexts/SelectEditorContext"; +import ActionIconWithTip from "@/components/ui/ActionIconWithTip/ActionIconWithTip"; +import useIsMobile from "@/hooks/utils/useIsMobile"; +import { AttrOptionSchema } from "@/lib/client"; + +const useSelectsTableColumns = () => { + const isMobile = useIsMobile(); + const { + optionsActions: { + onStartEditing, + onFinishEditing, + onDelete, + editingOptionsData, + setEditingOptionsData, + }, + } = useSelectEditorContext(); + + const onChange = ( + e: React.ChangeEvent, + optionId: number + ) => { + setEditingOptionsData(prev => { + prev.set(optionId, e.currentTarget.value); + return new Map(prev); + }); + }; + + return useMemo( + () => + [ + { + title: "Название опции", + accessor: "name", + render: option => + editingOptionsData.has(option.id) ? ( + onChange(e, option.id)} + /> + ) : ( + option.name + ), + }, + { + accessor: "actions", + title:
Действия
, + width: "0%", + render: option => ( + + {editingOptionsData.has(option.id) ? ( + onFinishEditing(option)} + tipLabel={"Сохранить"}> + + + ) : ( + onStartEditing(option)} + tipLabel={"Редактировать"}> + + + )} + + onDelete(option)} + tipLabel={"Удалить"}> + + + + ), + }, + ] as DataTableColumn[], + [isMobile, editingOptionsData] + ); +}; + +export default useSelectsTableColumns; diff --git a/src/app/attributes/types/view.ts b/src/app/attributes/types/view.ts new file mode 100644 index 0000000..26e72a5 --- /dev/null +++ b/src/app/attributes/types/view.ts @@ -0,0 +1,6 @@ +enum AttributePageView { + ATTRIBUTES, + SELECTS, +} + +export default AttributePageView; diff --git a/src/app/deals/drawers/DealEditorDrawer/components/AttrOptionSelect.tsx b/src/app/deals/drawers/DealEditorDrawer/components/AttrOptionSelect.tsx index de603af..94f9f16 100644 --- a/src/app/deals/drawers/DealEditorDrawer/components/AttrOptionSelect.tsx +++ b/src/app/deals/drawers/DealEditorDrawer/components/AttrOptionSelect.tsx @@ -41,7 +41,6 @@ const AttrOptionSelect = (props: Props) => { setSelectedOption(undefined); props.onChange(null); }} - getLabelFn={option => option.label} clearable searchable /> diff --git a/src/app/module-editor/[moduleId]/components/shared/AttrSelectSelect/AttrSelectSelect.tsx b/src/app/module-editor/[moduleId]/components/shared/AttrSelectSelect/AttrSelectSelect.tsx index 4769f90..c0ebdea 100644 --- a/src/app/module-editor/[moduleId]/components/shared/AttrSelectSelect/AttrSelectSelect.tsx +++ b/src/app/module-editor/[moduleId]/components/shared/AttrSelectSelect/AttrSelectSelect.tsx @@ -1,12 +1,10 @@ -import ObjectSelect, { ObjectSelectProps } from "@/components/selects/ObjectSelect/ObjectSelect"; -import { AttributeSelectSchema } from "@/lib/client"; +import ObjectSelect, { + ObjectSelectProps, +} from "@/components/selects/ObjectSelect/ObjectSelect"; +import { AttrSelectSchema } from "@/lib/client"; import useAttributeSelectsList from "./useAttributeSelectsList"; - -type Props = Omit< - ObjectSelectProps, - "data" | "getLabelFn" ->; +type Props = Omit, "data" | "getLabelFn">; const AttrSelectSelect = (props: Props) => { const { selects } = useAttributeSelectsList(); @@ -14,7 +12,6 @@ const AttrSelectSelect = (props: Props) => { return ( select.label} data={selects} {...props} /> diff --git a/src/app/module-editor/[moduleId]/components/shared/DefaultAttrOptionSelect/DefaultAttrOptionSelect.tsx b/src/app/module-editor/[moduleId]/components/shared/DefaultAttrOptionSelect/DefaultAttrOptionSelect.tsx index 074112f..5ff3f1f 100644 --- a/src/app/module-editor/[moduleId]/components/shared/DefaultAttrOptionSelect/DefaultAttrOptionSelect.tsx +++ b/src/app/module-editor/[moduleId]/components/shared/DefaultAttrOptionSelect/DefaultAttrOptionSelect.tsx @@ -19,7 +19,6 @@ const DefaultAttrOptionSelect = ({ selectId, ...props }: Props) => { {...props} data={options} onClear={() => props.onChange(null)} - getLabelFn={(option: AttrOptionSchema) => option.label} clearable searchable /> diff --git a/src/hooks/cruds/useSelectsCrud.tsx b/src/hooks/cruds/useSelectsCrud.tsx new file mode 100644 index 0000000..7d84ad2 --- /dev/null +++ b/src/hooks/cruds/useSelectsCrud.tsx @@ -0,0 +1,49 @@ +import { useCrudOperations } from "@/hooks/cruds/baseCrud"; +import { + AttrSelectSchema, + CreateAttrSelectSchema, + UpdateAttrSelectSchema, +} from "@/lib/client"; +import { + createAttrSelectMutation, + deleteAttrSelectMutation, + updateAttrSelectMutation, +} from "@/lib/client/@tanstack/react-query.gen"; + +type Props = { + queryKey: any[]; +}; + +export type AttrSelectsCrud = { + onCreate: (data: Partial) => void; + onUpdate: ( + selectId: number, + select: UpdateAttrSelectSchema, + onSuccess?: () => void + ) => void; + onDelete: (select: AttrSelectSchema, onSuccess?: () => void) => void; +}; + +export const useAttrSelectsCrud = ({ queryKey }: Props): AttrSelectsCrud => { + return useCrudOperations< + AttrSelectSchema, + UpdateAttrSelectSchema, + CreateAttrSelectSchema + >({ + key: "getAttrSelects", + queryKey, + mutations: { + create: createAttrSelectMutation(), + update: updateAttrSelectMutation(), + delete: deleteAttrSelectMutation(), + }, + getCreateEntity: data => ({ + name: data.name!, + }), + getUpdateEntity: (old, update) => ({ + ...old, + name: update.name ?? old.name, + }), + getDeleteConfirmTitle: () => "Удаление справочника", + }); +}; diff --git a/src/hooks/lists/useAttrSelectsList.ts b/src/hooks/lists/useAttrSelectsList.ts new file mode 100644 index 0000000..cb20642 --- /dev/null +++ b/src/hooks/lists/useAttrSelectsList.ts @@ -0,0 +1,32 @@ +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { AttrSelectSchema } from "@/lib/client"; +import { + getAttrSelectsOptions, + getAttrSelectsQueryKey, +} from "@/lib/client/@tanstack/react-query.gen"; + +const useAttrSelectsList = () => { + const queryClient = useQueryClient(); + const { data, refetch } = useQuery(getAttrSelectsOptions()); + + const queryKey = getAttrSelectsQueryKey(); + + const setSelects = (selects: AttrSelectSchema[]) => { + queryClient.setQueryData( + queryKey, + (old: { items: AttrSelectSchema[] }) => ({ + ...old, + items: selects, + }) + ); + }; + + return { + selects: data?.items ?? [], + setSelects, + refetch, + queryKey, + }; +}; + +export default useAttrSelectsList; diff --git a/src/hooks/lists/useAttributeOptionsList.ts b/src/hooks/lists/useAttributeOptionsList.ts index a530a26..0e396d8 100644 --- a/src/hooks/lists/useAttributeOptionsList.ts +++ b/src/hooks/lists/useAttributeOptionsList.ts @@ -1,13 +1,13 @@ import { useQuery } from "@tanstack/react-query"; -import { getAttrSelectOptionsOptions } from "@/lib/client/@tanstack/react-query.gen"; +import { getAttrOptionsOptions } from "@/lib/client/@tanstack/react-query.gen"; type Props = { selectId: number; }; -const useAttributeSelectsList = ({ selectId }: Props) => { +const useAttributeOptionsList = ({ selectId }: Props) => { const { data, refetch } = useQuery( - getAttrSelectOptionsOptions({ path: { selectId } }) + getAttrOptionsOptions({ path: { selectId } }) ); return { @@ -16,4 +16,4 @@ const useAttributeSelectsList = ({ selectId }: Props) => { }; }; -export default useAttributeSelectsList; +export default useAttributeOptionsList; diff --git a/src/lib/client/@tanstack/react-query.gen.ts b/src/lib/client/@tanstack/react-query.gen.ts index 5e4eb20..5f82ae8 100644 --- a/src/lib/client/@tanstack/react-query.gen.ts +++ b/src/lib/client/@tanstack/react-query.gen.ts @@ -14,6 +14,8 @@ import { addKitToDeal, addKitToDealProduct, createAttribute, + createAttrOption, + createAttrSelect, createBarcodeTemplate, createBoard, createClient, @@ -32,6 +34,8 @@ import { createServicesKit, createStatus, deleteAttribute, + deleteAttrOption, + deleteAttrSelect, deleteBarcodeTemplate, deleteBoard, deleteClient, @@ -53,7 +57,7 @@ import { duplicateProductServices, getAttributes, getAttributeTypes, - getAttrSelectOptions, + getAttrOptions, getAttrSelects, getBarcodeTemplateAttributes, getBarcodeTemplates, @@ -84,6 +88,8 @@ import { switchDealTag, updateAttribute, updateAttributeLabel, + updateAttrOption, + updateAttrSelect, updateBarcodeTemplate, updateBoard, updateClient, @@ -120,6 +126,12 @@ import type { CreateAttributeData, CreateAttributeError, CreateAttributeResponse2, + CreateAttrOptionData, + CreateAttrOptionError, + CreateAttrOptionResponse2, + CreateAttrSelectData, + CreateAttrSelectError, + CreateAttrSelectResponse2, CreateBarcodeTemplateData, CreateBarcodeTemplateError, CreateBarcodeTemplateResponse2, @@ -174,6 +186,12 @@ import type { DeleteAttributeData, DeleteAttributeError, DeleteAttributeResponse2, + DeleteAttrOptionData, + DeleteAttrOptionError, + DeleteAttrOptionResponse2, + DeleteAttrSelectData, + DeleteAttrSelectError, + DeleteAttrSelectResponse2, DeleteBarcodeTemplateData, DeleteBarcodeTemplateError, DeleteBarcodeTemplateResponse2, @@ -233,7 +251,7 @@ import type { DuplicateProductServicesResponse, GetAttributesData, GetAttributeTypesData, - GetAttrSelectOptionsData, + GetAttrOptionsData, GetAttrSelectsData, GetBarcodeTemplateAttributesData, GetBarcodeTemplatesData, @@ -281,6 +299,12 @@ import type { UpdateAttributeLabelError, UpdateAttributeLabelResponse2, UpdateAttributeResponse2, + UpdateAttrOptionData, + UpdateAttrOptionError, + UpdateAttrOptionResponse2, + UpdateAttrSelectData, + UpdateAttrSelectError, + UpdateAttrSelectResponse2, UpdateBarcodeTemplateData, UpdateBarcodeTemplateError, UpdateBarcodeTemplateResponse2, @@ -382,6 +406,132 @@ const createQueryKey = ( return [params]; }; +export const getAttrOptionsQueryKey = (options: Options) => + createQueryKey("getAttrOptions", options); + +/** + * Get Attr Options + */ +export const getAttrOptionsOptions = (options: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getAttrOptions({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getAttrOptionsQueryKey(options), + }); +}; + +export const createAttrOptionQueryKey = ( + options: Options +) => createQueryKey("createAttrOption", options); + +/** + * Create Attr Select + */ +export const createAttrOptionOptions = ( + options: Options +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await createAttrOption({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: createAttrOptionQueryKey(options), + }); +}; + +/** + * Create Attr Select + */ +export const createAttrOptionMutation = ( + options?: Partial> +): UseMutationOptions< + CreateAttrOptionResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + CreateAttrOptionResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await createAttrOption({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Delete Attr Option + */ +export const deleteAttrOptionMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteAttrOptionResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteAttrOptionResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await deleteAttrOption({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Update Attr Option + */ +export const updateAttrOptionMutation = ( + options?: Partial> +): UseMutationOptions< + UpdateAttrOptionResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + UpdateAttrOptionResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await updateAttrOption({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + export const getAttrSelectsQueryKey = (options?: Options) => createQueryKey("getAttrSelects", options); @@ -405,19 +555,19 @@ export const getAttrSelectsOptions = ( }); }; -export const getAttrSelectOptionsQueryKey = ( - options: Options -) => createQueryKey("getAttrSelectOptions", options); +export const createAttrSelectQueryKey = ( + options: Options +) => createQueryKey("createAttrSelect", options); /** - * Get Attr Select Options + * Create Attr Select */ -export const getAttrSelectOptionsOptions = ( - options: Options +export const createAttrSelectOptions = ( + options: Options ) => { return queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await getAttrSelectOptions({ + const { data } = await createAttrSelect({ ...options, ...queryKey[0], signal, @@ -425,10 +575,91 @@ export const getAttrSelectOptionsOptions = ( }); return data; }, - queryKey: getAttrSelectOptionsQueryKey(options), + queryKey: createAttrSelectQueryKey(options), }); }; +/** + * Create Attr Select + */ +export const createAttrSelectMutation = ( + options?: Partial> +): UseMutationOptions< + CreateAttrSelectResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + CreateAttrSelectResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await createAttrSelect({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Delete Attr Select + */ +export const deleteAttrSelectMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteAttrSelectResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteAttrSelectResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await deleteAttrSelect({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Update Attr Select + */ +export const updateAttrSelectMutation = ( + options?: Partial> +): UseMutationOptions< + UpdateAttrSelectResponse2, + AxiosError, + Options +> => { + const mutationOptions: UseMutationOptions< + UpdateAttrSelectResponse2, + AxiosError, + Options + > = { + mutationFn: async localOptions => { + const { data } = await updateAttrSelect({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + export const getAttributesQueryKey = (options?: Options) => createQueryKey("getAttributes", options); diff --git a/src/lib/client/client/utils.ts b/src/lib/client/client/utils.ts index 8d86d8a..f202217 100644 --- a/src/lib/client/client/utils.ts +++ b/src/lib/client/client/utils.ts @@ -266,9 +266,9 @@ export const mergeHeaders = ( delete mergedHeaders[key]; } else if (Array.isArray(value)) { for (const v of value) { - // @ts-expect-error + // @ts-ignore mergedHeaders[key] = [ - ...(mergedHeaders[key] ?? []), + ...(mergedHeaders[key] ?? []) as any, v as string, ]; } diff --git a/src/lib/client/sdk.gen.ts b/src/lib/client/sdk.gen.ts index c1427ea..de37f73 100644 --- a/src/lib/client/sdk.gen.ts +++ b/src/lib/client/sdk.gen.ts @@ -20,6 +20,12 @@ import type { CreateAttributeData, CreateAttributeErrors, CreateAttributeResponses, + CreateAttrOptionData, + CreateAttrOptionErrors, + CreateAttrOptionResponses, + CreateAttrSelectData, + CreateAttrSelectErrors, + CreateAttrSelectResponses, CreateBarcodeTemplateData, CreateBarcodeTemplateErrors, CreateBarcodeTemplateResponses, @@ -74,6 +80,12 @@ import type { DeleteAttributeData, DeleteAttributeErrors, DeleteAttributeResponses, + DeleteAttrOptionData, + DeleteAttrOptionErrors, + DeleteAttrOptionResponses, + DeleteAttrSelectData, + DeleteAttrSelectErrors, + DeleteAttrSelectResponses, DeleteBarcodeTemplateData, DeleteBarcodeTemplateErrors, DeleteBarcodeTemplateResponses, @@ -135,9 +147,9 @@ import type { GetAttributesResponses, GetAttributeTypesData, GetAttributeTypesResponses, - GetAttrSelectOptionsData, - GetAttrSelectOptionsErrors, - GetAttrSelectOptionsResponses, + GetAttrOptionsData, + GetAttrOptionsErrors, + GetAttrOptionsResponses, GetAttrSelectsData, GetAttrSelectsResponses, GetBarcodeTemplateAttributesData, @@ -216,6 +228,12 @@ import type { UpdateAttributeLabelErrors, UpdateAttributeLabelResponses, UpdateAttributeResponses, + UpdateAttrOptionData, + UpdateAttrOptionErrors, + UpdateAttrOptionResponses, + UpdateAttrSelectData, + UpdateAttrSelectErrors, + UpdateAttrSelectResponses, UpdateBarcodeTemplateData, UpdateBarcodeTemplateErrors, UpdateBarcodeTemplateResponses, @@ -289,6 +307,10 @@ import { zAddKitToDealResponse, zCreateAttributeData, zCreateAttributeResponse2, + zCreateAttrOptionData, + zCreateAttrOptionResponse2, + zCreateAttrSelectData, + zCreateAttrSelectResponse2, zCreateBarcodeTemplateData, zCreateBarcodeTemplateResponse2, zCreateBoardData, @@ -325,6 +347,10 @@ import { zCreateStatusResponse2, zDeleteAttributeData, zDeleteAttributeResponse2, + zDeleteAttrOptionData, + zDeleteAttrOptionResponse2, + zDeleteAttrSelectData, + zDeleteAttrSelectResponse2, zDeleteBarcodeTemplateData, zDeleteBarcodeTemplateResponse2, zDeleteBoardData, @@ -367,8 +393,8 @@ import { zGetAttributesResponse, zGetAttributeTypesData, zGetAttributeTypesResponse, - zGetAttrSelectOptionsData, - zGetAttrSelectOptionsResponse, + zGetAttrOptionsData, + zGetAttrOptionsResponse, zGetAttrSelectsData, zGetAttrSelectsResponse, zGetBarcodeTemplateAttributesData, @@ -429,6 +455,10 @@ import { zUpdateAttributeLabelData, zUpdateAttributeLabelResponse2, zUpdateAttributeResponse2, + zUpdateAttrOptionData, + zUpdateAttrOptionResponse2, + zUpdateAttrSelectData, + zUpdateAttrSelectResponse2, zUpdateBarcodeTemplateData, zUpdateBarcodeTemplateResponse2, zUpdateBoardData, @@ -490,6 +520,106 @@ export type Options< meta?: Record; }; +/** + * Get Attr Options + */ +export const getAttrOptions = ( + options: Options +) => { + return (options.client ?? _heyApiClient).get< + GetAttrOptionsResponses, + GetAttrOptionsErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zGetAttrOptionsData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zGetAttrOptionsResponse.parseAsync(data); + }, + url: "/crm/v1/attr-option/{selectId}", + ...options, + }); +}; + +/** + * Create Attr Select + */ +export const createAttrOption = ( + options: Options +) => { + return (options.client ?? _heyApiClient).post< + CreateAttrOptionResponses, + CreateAttrOptionErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zCreateAttrOptionData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zCreateAttrOptionResponse2.parseAsync(data); + }, + url: "/crm/v1/attr-option/", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + +/** + * Delete Attr Option + */ +export const deleteAttrOption = ( + options: Options +) => { + return (options.client ?? _heyApiClient).delete< + DeleteAttrOptionResponses, + DeleteAttrOptionErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zDeleteAttrOptionData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zDeleteAttrOptionResponse2.parseAsync(data); + }, + url: "/crm/v1/attr-option/{pk}", + ...options, + }); +}; + +/** + * Update Attr Option + */ +export const updateAttrOption = ( + options: Options +) => { + return (options.client ?? _heyApiClient).patch< + UpdateAttrOptionResponses, + UpdateAttrOptionErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zUpdateAttrOptionData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zUpdateAttrOptionResponse2.parseAsync(data); + }, + url: "/crm/v1/attr-option/{pk}", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + /** * Get Attr Selects */ @@ -514,25 +644,79 @@ export const getAttrSelects = ( }; /** - * Get Attr Select Options + * Create Attr Select */ -export const getAttrSelectOptions = ( - options: Options +export const createAttrSelect = ( + options: Options ) => { - return (options.client ?? _heyApiClient).get< - GetAttrSelectOptionsResponses, - GetAttrSelectOptionsErrors, + return (options.client ?? _heyApiClient).post< + CreateAttrSelectResponses, + CreateAttrSelectErrors, ThrowOnError >({ requestValidator: async data => { - return await zGetAttrSelectOptionsData.parseAsync(data); + return await zCreateAttrSelectData.parseAsync(data); }, responseType: "json", responseValidator: async data => { - return await zGetAttrSelectOptionsResponse.parseAsync(data); + return await zCreateAttrSelectResponse2.parseAsync(data); }, - url: "/crm/v1/attr-select/{selectId}", + url: "/crm/v1/attr-select/", ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + +/** + * Delete Attr Select + */ +export const deleteAttrSelect = ( + options: Options +) => { + return (options.client ?? _heyApiClient).delete< + DeleteAttrSelectResponses, + DeleteAttrSelectErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zDeleteAttrSelectData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zDeleteAttrSelectResponse2.parseAsync(data); + }, + url: "/crm/v1/attr-select/{pk}", + ...options, + }); +}; + +/** + * Update Attr Select + */ +export const updateAttrSelect = ( + options: Options +) => { + return (options.client ?? _heyApiClient).patch< + UpdateAttrSelectResponses, + UpdateAttrSelectErrors, + ThrowOnError + >({ + requestValidator: async data => { + return await zUpdateAttrSelectData.parseAsync(data); + }, + responseType: "json", + responseValidator: async data => { + return await zUpdateAttrSelectResponse2.parseAsync(data); + }, + url: "/crm/v1/attr-select/{pk}", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, }); }; diff --git a/src/lib/client/types.gen.ts b/src/lib/client/types.gen.ts index 23d139a..2e1a698 100644 --- a/src/lib/client/types.gen.ts +++ b/src/lib/client/types.gen.ts @@ -19,9 +19,9 @@ export type AttrOptionSchema = { */ id: number; /** - * Label + * Name */ - label: string; + name: string; }; /** @@ -33,9 +33,9 @@ export type AttrSelectSchema = { */ id: number; /** - * Label + * Name */ - label: string; + name: string; /** * Isbuiltin */ @@ -295,6 +295,62 @@ export type ClientSchema = { isDeleted?: boolean; }; +/** + * CreateAttrOptionRequest + */ +export type CreateAttrOptionRequest = { + entity: CreateAttrOptionSchema; +}; + +/** + * CreateAttrOptionResponse + */ +export type CreateAttrOptionResponse = { + entity: AttrOptionSchema; +}; + +/** + * CreateAttrOptionSchema + */ +export type CreateAttrOptionSchema = { + /** + * Name + */ + name: string; + /** + * Selectid + */ + selectId: number; +}; + +/** + * CreateAttrSelectRequest + */ +export type CreateAttrSelectRequest = { + entity: CreateAttrSelectSchema; +}; + +/** + * CreateAttrSelectResponse + */ +export type CreateAttrSelectResponse = { + /** + * Message + */ + message: string; + entity: AttrSelectSchema; +}; + +/** + * CreateAttrSelectSchema + */ +export type CreateAttrSelectSchema = { + /** + * Name + */ + name: string; +}; + /** * CreateAttributeRequest */ @@ -1259,6 +1315,23 @@ export type DealTagSchema = { tagColor: DealTagColorSchema; }; +/** + * DeleteAttrOptionResponse + */ +export type DeleteAttrOptionResponse = { + [key: string]: unknown; +}; + +/** + * DeleteAttrSelectResponse + */ +export type DeleteAttrSelectResponse = { + /** + * Message + */ + message: string; +}; + /** * DeleteAttributeResponse */ @@ -2385,6 +2458,60 @@ export type SwitchDealTagResponse = { message: string; }; +/** + * UpdateAttrOptionRequest + */ +export type UpdateAttrOptionRequest = { + entity: UpdateAttrOptionSchema; +}; + +/** + * UpdateAttrOptionResponse + */ +export type UpdateAttrOptionResponse = { + /** + * Message + */ + message: string; +}; + +/** + * UpdateAttrOptionSchema + */ +export type UpdateAttrOptionSchema = { + /** + * Name + */ + name: string; +}; + +/** + * UpdateAttrSelectRequest + */ +export type UpdateAttrSelectRequest = { + entity: UpdateAttrSelectSchema; +}; + +/** + * UpdateAttrSelectResponse + */ +export type UpdateAttrSelectResponse = { + /** + * Message + */ + message: string; +}; + +/** + * UpdateAttrSelectSchema + */ +export type UpdateAttrSelectSchema = { + /** + * Name + */ + name: string; +}; + /** * UpdateAttributeLabelRequest */ @@ -3160,6 +3287,129 @@ export type ValidationError = { type: string; }; +export type GetAttrOptionsData = { + body?: never; + path: { + /** + * Selectid + */ + selectId: number; + }; + query?: never; + url: "/crm/v1/attr-option/{selectId}"; +}; + +export type GetAttrOptionsErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetAttrOptionsError = + GetAttrOptionsErrors[keyof GetAttrOptionsErrors]; + +export type GetAttrOptionsResponses = { + /** + * Successful Response + */ + 200: GetAllAttrSelectOptionsResponse; +}; + +export type GetAttrOptionsResponse = + GetAttrOptionsResponses[keyof GetAttrOptionsResponses]; + +export type CreateAttrOptionData = { + body: CreateAttrOptionRequest; + path?: never; + query?: never; + url: "/crm/v1/attr-option/"; +}; + +export type CreateAttrOptionErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateAttrOptionError = + CreateAttrOptionErrors[keyof CreateAttrOptionErrors]; + +export type CreateAttrOptionResponses = { + /** + * Successful Response + */ + 200: CreateAttrOptionResponse; +}; + +export type CreateAttrOptionResponse2 = + CreateAttrOptionResponses[keyof CreateAttrOptionResponses]; + +export type DeleteAttrOptionData = { + body?: never; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/attr-option/{pk}"; +}; + +export type DeleteAttrOptionErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteAttrOptionError = + DeleteAttrOptionErrors[keyof DeleteAttrOptionErrors]; + +export type DeleteAttrOptionResponses = { + /** + * Successful Response + */ + 200: DeleteAttrOptionResponse; +}; + +export type DeleteAttrOptionResponse2 = + DeleteAttrOptionResponses[keyof DeleteAttrOptionResponses]; + +export type UpdateAttrOptionData = { + body: UpdateAttrOptionRequest; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/attr-option/{pk}"; +}; + +export type UpdateAttrOptionErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateAttrOptionError = + UpdateAttrOptionErrors[keyof UpdateAttrOptionErrors]; + +export type UpdateAttrOptionResponses = { + /** + * Successful Response + */ + 200: UpdateAttrOptionResponse; +}; + +export type UpdateAttrOptionResponse2 = + UpdateAttrOptionResponses[keyof UpdateAttrOptionResponses]; + export type GetAttrSelectsData = { body?: never; path?: never; @@ -3177,37 +3427,96 @@ export type GetAttrSelectsResponses = { export type GetAttrSelectsResponse = GetAttrSelectsResponses[keyof GetAttrSelectsResponses]; -export type GetAttrSelectOptionsData = { - body?: never; - path: { - /** - * Selectid - */ - selectId: number; - }; +export type CreateAttrSelectData = { + body: CreateAttrSelectRequest; + path?: never; query?: never; - url: "/crm/v1/attr-select/{selectId}"; + url: "/crm/v1/attr-select/"; }; -export type GetAttrSelectOptionsErrors = { +export type CreateAttrSelectErrors = { /** * Validation Error */ 422: HttpValidationError; }; -export type GetAttrSelectOptionsError = - GetAttrSelectOptionsErrors[keyof GetAttrSelectOptionsErrors]; +export type CreateAttrSelectError = + CreateAttrSelectErrors[keyof CreateAttrSelectErrors]; -export type GetAttrSelectOptionsResponses = { +export type CreateAttrSelectResponses = { /** * Successful Response */ - 200: GetAllAttrSelectOptionsResponse; + 200: CreateAttrSelectResponse; }; -export type GetAttrSelectOptionsResponse = - GetAttrSelectOptionsResponses[keyof GetAttrSelectOptionsResponses]; +export type CreateAttrSelectResponse2 = + CreateAttrSelectResponses[keyof CreateAttrSelectResponses]; + +export type DeleteAttrSelectData = { + body?: never; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/attr-select/{pk}"; +}; + +export type DeleteAttrSelectErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteAttrSelectError = + DeleteAttrSelectErrors[keyof DeleteAttrSelectErrors]; + +export type DeleteAttrSelectResponses = { + /** + * Successful Response + */ + 200: DeleteAttrSelectResponse; +}; + +export type DeleteAttrSelectResponse2 = + DeleteAttrSelectResponses[keyof DeleteAttrSelectResponses]; + +export type UpdateAttrSelectData = { + body: UpdateAttrSelectRequest; + path: { + /** + * Pk + */ + pk: number; + }; + query?: never; + url: "/crm/v1/attr-select/{pk}"; +}; + +export type UpdateAttrSelectErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateAttrSelectError = + UpdateAttrSelectErrors[keyof UpdateAttrSelectErrors]; + +export type UpdateAttrSelectResponses = { + /** + * Successful Response + */ + 200: UpdateAttrSelectResponse; +}; + +export type UpdateAttrSelectResponse2 = + UpdateAttrSelectResponses[keyof UpdateAttrSelectResponses]; export type GetAttributesData = { body?: never; diff --git a/src/lib/client/zod.gen.ts b/src/lib/client/zod.gen.ts index 29e2fca..adb38ea 100644 --- a/src/lib/client/zod.gen.ts +++ b/src/lib/client/zod.gen.ts @@ -14,7 +14,7 @@ export const zAddAttributeResponse = z.object({ */ export const zAttrOptionSchema = z.object({ id: z.int(), - label: z.string(), + name: z.string(), }); /** @@ -22,7 +22,7 @@ export const zAttrOptionSchema = z.object({ */ export const zAttrSelectSchema = z.object({ id: z.int(), - label: z.string(), + name: z.string(), isBuiltIn: z.boolean(), }); @@ -115,14 +115,14 @@ export const zBoardSchema = z.object({ * Body_upload_product_barcode_image */ export const zBodyUploadProductBarcodeImage = z.object({ - upload_file: z.string(), + upload_file: z.any(), }); /** * Body_upload_product_image */ export const zBodyUploadProductImage = z.object({ - upload_file: z.string(), + upload_file: z.any(), }); /** @@ -147,6 +147,50 @@ export const zClientSchema = z.object({ isDeleted: z.optional(z.boolean()).default(false), }); +/** + * CreateAttrOptionSchema + */ +export const zCreateAttrOptionSchema = z.object({ + name: z.string(), + selectId: z.int(), +}); + +/** + * CreateAttrOptionRequest + */ +export const zCreateAttrOptionRequest = z.object({ + entity: zCreateAttrOptionSchema, +}); + +/** + * CreateAttrOptionResponse + */ +export const zCreateAttrOptionResponse = z.object({ + entity: zAttrOptionSchema, +}); + +/** + * CreateAttrSelectSchema + */ +export const zCreateAttrSelectSchema = z.object({ + name: z.string(), +}); + +/** + * CreateAttrSelectRequest + */ +export const zCreateAttrSelectRequest = z.object({ + entity: zCreateAttrSelectSchema, +}); + +/** + * CreateAttrSelectResponse + */ +export const zCreateAttrSelectResponse = z.object({ + message: z.string(), + entity: zAttrSelectSchema, +}); + /** * CreateAttributeSchema */ @@ -871,6 +915,18 @@ export const zDealProductAddKitResponse = z.object({ message: z.string(), }); +/** + * DeleteAttrOptionResponse + */ +export const zDeleteAttrOptionResponse = z.object({}); + +/** + * DeleteAttrSelectResponse + */ +export const zDeleteAttrSelectResponse = z.object({ + message: z.string(), +}); + /** * DeleteAttributeResponse */ @@ -1361,6 +1417,48 @@ export const zSwitchDealTagResponse = z.object({ message: z.string(), }); +/** + * UpdateAttrOptionSchema + */ +export const zUpdateAttrOptionSchema = z.object({ + name: z.string(), +}); + +/** + * UpdateAttrOptionRequest + */ +export const zUpdateAttrOptionRequest = z.object({ + entity: zUpdateAttrOptionSchema, +}); + +/** + * UpdateAttrOptionResponse + */ +export const zUpdateAttrOptionResponse = z.object({ + message: z.string(), +}); + +/** + * UpdateAttrSelectSchema + */ +export const zUpdateAttrSelectSchema = z.object({ + name: z.string(), +}); + +/** + * UpdateAttrSelectRequest + */ +export const zUpdateAttrSelectRequest = z.object({ + entity: zUpdateAttrSelectSchema, +}); + +/** + * UpdateAttrSelectResponse + */ +export const zUpdateAttrSelectResponse = z.object({ + message: z.string(), +}); + /** * UpdateAttributeLabelRequest */ @@ -1847,6 +1945,56 @@ export const zUpdateStatusResponse = z.object({ message: z.string(), }); +export const zGetAttrOptionsData = z.object({ + body: z.optional(z.never()), + path: z.object({ + selectId: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zGetAttrOptionsResponse = zGetAllAttrSelectOptionsResponse; + +export const zCreateAttrOptionData = z.object({ + body: zCreateAttrOptionRequest, + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zCreateAttrOptionResponse2 = zCreateAttrOptionResponse; + +export const zDeleteAttrOptionData = z.object({ + body: z.optional(z.never()), + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zDeleteAttrOptionResponse2 = zDeleteAttrOptionResponse; + +export const zUpdateAttrOptionData = z.object({ + body: zUpdateAttrOptionRequest, + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zUpdateAttrOptionResponse2 = zUpdateAttrOptionResponse; + export const zGetAttrSelectsData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), @@ -1858,10 +2006,21 @@ export const zGetAttrSelectsData = z.object({ */ export const zGetAttrSelectsResponse = zGetAllAttrSelectsResponse; -export const zGetAttrSelectOptionsData = z.object({ +export const zCreateAttrSelectData = z.object({ + body: zCreateAttrSelectRequest, + path: z.optional(z.never()), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zCreateAttrSelectResponse2 = zCreateAttrSelectResponse; + +export const zDeleteAttrSelectData = z.object({ body: z.optional(z.never()), path: z.object({ - selectId: z.int(), + pk: z.int(), }), query: z.optional(z.never()), }); @@ -1869,7 +2028,20 @@ export const zGetAttrSelectOptionsData = z.object({ /** * Successful Response */ -export const zGetAttrSelectOptionsResponse = zGetAllAttrSelectOptionsResponse; +export const zDeleteAttrSelectResponse2 = zDeleteAttrSelectResponse; + +export const zUpdateAttrSelectData = z.object({ + body: zUpdateAttrSelectRequest, + path: z.object({ + pk: z.int(), + }), + query: z.optional(z.never()), +}); + +/** + * Successful Response + */ +export const zUpdateAttrSelectResponse2 = zUpdateAttrSelectResponse; export const zGetAttributesData = z.object({ body: z.optional(z.never()), diff --git a/src/modals/modals.ts b/src/modals/modals.ts index 1a19442..c1f85f2 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -1,3 +1,4 @@ +import AttrSelectEditorModal from "@/app/attributes/modals/AttrSelectEditorModal/AttrSelectEditorModal"; import BarcodeTemplateEditorModal from "@/app/barcode-templates/modals/BarcodeTemplateFormModal/BarcodeTemplateEditorModal"; import MarketplaceEditorModal from "@/app/clients/drawers/ClientMarketplacesDrawer/modals/MarketplaceEditorModal"; import ClientEditorModal from "@/app/clients/modals/ClientFormModal/ClientFormModal"; @@ -46,4 +47,5 @@ export const modals = { dealTagModal: DealTagModal, attributeEditorModal: AttributeEditorModal, moduleCreatorModal: ModuleCreatorModal, + attrSelectEditorModal: AttrSelectEditorModal, };