feat: creating and updating groups

This commit is contained in:
2025-10-17 19:47:47 +04:00
parent daa9d12983
commit 30bc7bbee4
18 changed files with 657 additions and 290 deletions

View File

@ -38,6 +38,7 @@
"i18n-iso-countries": "^7.14.0", "i18n-iso-countries": "^7.14.0",
"lexorank": "^1.0.5", "lexorank": "^1.0.5",
"libphonenumber-js": "^1.12.10", "libphonenumber-js": "^1.12.10",
"mantine-contextmenu": "^8.2.0",
"mantine-datatable": "^8.2.0", "mantine-datatable": "^8.2.0",
"next": "15.4.7", "next": "15.4.7",
"phone": "^3.1.67", "phone": "^3.1.67",

View File

@ -12,6 +12,26 @@
} }
} }
.container-selected {
border: 2px dashed !important;
@mixin light {
border-color: dodgerblue !important;
}
@mixin dark {
border-color: dodgerblue !important;
}
}
.container-mainly-selected {
border: 2px solid;
@mixin light {
border-color: dodgerblue !important;
}
@mixin dark {
border-color: dodgerblue !important;
}
}
.container-in-group { .container-in-group {
padding: 0; padding: 0;
border: 1px dashed; border: 1px dashed;

View File

@ -1,3 +1,6 @@
import { IconCategoryPlus } from "@tabler/icons-react";
import classNames from "classnames";
import { useContextMenu } from "mantine-contextmenu";
import { Box, Card, Group, Pill, Stack, Text } from "@mantine/core"; import { Box, Card, Group, Pill, Stack, Text } from "@mantine/core";
import { useDealsContext } from "@/app/deals/contexts/DealsContext"; import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
@ -13,10 +16,16 @@ type Props = {
const DealCard = ({ deal, isInGroup = false }: Props) => { const DealCard = ({ deal, isInGroup = false }: Props) => {
const { selectedProject, modulesSet } = useProjectsContext(); const { selectedProject, modulesSet } = useProjectsContext();
const { dealsCrud, refetchDeals } = useDealsContext(); const { dealsCrud, refetchDeals, groupDealsSelection } = useDealsContext();
const { openDrawer } = useDrawersContext(); const { openDrawer } = useDrawersContext();
const onClick = () => { const onClick = () => {
if (groupDealsSelection.isDealsSelecting) {
if (groupDealsSelection.selectedBaseDealId !== deal.id)
groupDealsSelection.toggleDeal(deal.id);
return;
}
openDrawer({ openDrawer({
key: "dealEditorDrawer", key: "dealEditorDrawer",
props: { props: {
@ -29,12 +38,37 @@ const DealCard = ({ deal, isInGroup = false }: Props) => {
}); });
}; };
const { showContextMenu } = useContextMenu();
const dealContextMenu = deal.group
? []
: [
{
key: "startGroupForming",
onClick: () =>
groupDealsSelection.startSelectingWithDeal(deal.id),
title: "Создать группу",
icon: <IconCategoryPlus />,
},
];
const getSelectedStyles = () => {
if (groupDealsSelection.selectedBaseDealId === deal.id) {
return styles["container-mainly-selected"];
}
if (groupDealsSelection.selectedDealIds.has(deal.id)) {
return styles["container-selected"];
}
};
return ( return (
<Card <Card
onClick={onClick} onClick={onClick}
className={ className={classNames(
getSelectedStyles(),
isInGroup ? styles["container-in-group"] : styles.container isInGroup ? styles["container-in-group"] : styles.container
}> )}
onContextMenu={showContextMenu(dealContextMenu)}>
<Group <Group
justify={"space-between"} justify={"space-between"}
wrap={"nowrap"} wrap={"nowrap"}

View File

@ -10,3 +10,13 @@
border-color: var(--mantine-color-dark-5); border-color: var(--mantine-color-dark-5);
} }
} }
.selected-group {
border: 2px solid;
@mixin light {
border-color: dodgerblue;
}
@mixin dark {
border-color: dodgerblue;
}
}

View File

@ -1,6 +1,10 @@
import { FC } from "react"; import { FC, useEffect, useState } from "react";
import { Stack, Text } from "@mantine/core"; import classNames from "classnames";
import { Flex, Stack, TextInput } from "@mantine/core";
import { useDebouncedValue } from "@mantine/hooks";
import DealCard from "@/app/deals/components/shared/DealCard/DealCard"; import DealCard from "@/app/deals/components/shared/DealCard/DealCard";
import GroupMenu from "@/app/deals/components/shared/GroupMenu/GroupMenu";
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import GroupWithDealsSchema from "@/types/GroupWithDealsSchema"; import GroupWithDealsSchema from "@/types/GroupWithDealsSchema";
import styles from "./DealsGroup.module.css"; import styles from "./DealsGroup.module.css";
@ -9,13 +13,41 @@ type Props = {
}; };
const DealsGroup: FC<Props> = ({ group }) => { const DealsGroup: FC<Props> = ({ group }) => {
const [groupName, setGroupName] = useState(group.name ?? "");
const [debouncedGroupName] = useDebouncedValue(groupName, 600);
const { groupsCrud, groupDealsSelection } = useDealsContext();
useEffect(() => {
if (debouncedGroupName === group.name) return;
groupsCrud.onUpdate(group.id, { name: debouncedGroupName });
}, [debouncedGroupName]);
return ( return (
<Stack <Stack
className={styles["group-container"]} className={classNames(
styles["group-container"],
groupDealsSelection.selectedGroupId === group.id &&
styles["selected-group"]
)}
gap={"xs"} gap={"xs"}
bdrs={"lg"} bdrs={"lg"}
p={"xs"}> p={"xs"}>
<Text mx={"xs"}>{group.name}</Text> <Flex
mx={"xs"}
align={"center"}>
<TextInput
value={groupName}
onChange={e => setGroupName(e.target.value)}
variant={"unstyled"}
/>
<GroupMenu
group={group}
onDelete={groupsCrud.onDelete}
onStartDealsSelecting={
groupDealsSelection.startSelectingWithExistingGroup
}
/>
</Flex>
{group.items.map(deal => ( {group.items.map(deal => (
<DealCard <DealCard
deal={deal} deal={deal}

View File

@ -0,0 +1,8 @@
.shadow {
@mixin light {
box-shadow: var(--light-shadow);
}
@mixin dark {
box-shadow: var(--dark-shadow);
}
}

View File

@ -0,0 +1,51 @@
"use client";
import { Affix, Flex, Stack, Title, Transition } from "@mantine/core";
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import InlineButton from "@/components/ui/InlineButton/InlineButton";
import styles from "./GroupDealsSelectionAffix.module.css";
const GroupDealsSelectionAffix = () => {
const {
groupDealsSelection: {
selectedBaseDealId,
selectedGroupId,
finishDealsSelecting,
cancelDealsSelecting,
},
} = useDealsContext();
return (
<Affix position={{ bottom: 35, right: 35 }}>
<Transition
transition="slide-up"
mounted={!!(selectedBaseDealId || selectedGroupId)}>
{transitionStyles => (
<Stack
bdrs={"xl"}
bd={"1px solid var(--mantine-color-default-border"}
className={styles.shadow}
p={"md"}
gap={"md"}
style={transitionStyles}>
<Title
order={5}
ta={"center"}>
Выбор сделок для группы
</Title>
<Flex gap={"xs"}>
<InlineButton onClick={cancelDealsSelecting}>
Отмена
</InlineButton>
<InlineButton variant={"filled"} onClick={finishDealsSelecting}>
Сохранить
</InlineButton>
</Flex>
</Stack>
)}
</Transition>
</Affix>
);
};
export default GroupDealsSelectionAffix;

View File

@ -0,0 +1,41 @@
import React, { FC } from "react";
import { IconCheckbox, IconDotsVertical, IconTrash } from "@tabler/icons-react";
import { Box, Menu } from "@mantine/core";
import DropdownMenuItem from "@/components/ui/DropdownMenuItem/DropdownMenuItem";
import ThemeIcon from "@/components/ui/ThemeIcon/ThemeIcon";
import GroupWithDealsSchema from "@/types/GroupWithDealsSchema";
type Props = {
group: GroupWithDealsSchema;
onDelete: (groupId: number) => void;
onStartDealsSelecting: (group: GroupWithDealsSchema) => void;
};
const GroupMenu: FC<Props> = ({ group, onDelete, onStartDealsSelecting }) => {
return (
<Menu>
<Menu.Target>
<Box onClick={e => e.stopPropagation()}>
<ThemeIcon size={"sm"}>
<IconDotsVertical />
</ThemeIcon>
</Box>
</Menu.Target>
<Menu.Dropdown>
<DropdownMenuItem
onClick={() => onDelete(group.id)}
icon={<IconTrash />}
label={"Удалить"}
/>
<DropdownMenuItem
onClick={() => onStartDealsSelecting(group)}
icon={<IconCheckbox />}
label={"Добавить/удалить сделки"}
/>
</Menu.Dropdown>
</Menu>
);
};
export default GroupMenu;

View File

@ -1,11 +1,13 @@
import { Space } from "@mantine/core"; import { Space } from "@mantine/core";
import MainBlockHeader from "@/app/deals/components/mobile/MainBlockHeader/MainBlockHeader"; import MainBlockHeader from "@/app/deals/components/mobile/MainBlockHeader/MainBlockHeader";
import Funnel from "@/app/deals/components/shared/Funnel/Funnel"; import Funnel from "@/app/deals/components/shared/Funnel/Funnel";
import GroupDealsSelectionAffix from "@/app/deals/components/shared/GroupDealsSelectionAffix/GroupDealsSelectionAffix";
export const BoardView = () => ( export const BoardView = () => (
<> <>
<MainBlockHeader /> <MainBlockHeader />
<Space h="md" /> <Space h="md" />
<Funnel /> <Funnel />
<GroupDealsSelectionAffix />
</> </>
); );

View File

@ -1,10 +1,13 @@
"use client"; "use client";
import React from "react"; import { Dispatch, SetStateAction } from "react";
import { UseFormReturnType } from "@mantine/form"; import { UseFormReturnType } from "@mantine/form";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext"; import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import useDealsAndGroups from "@/app/deals/hooks/useDealsAndGroups"; import useDealsAndGroups from "@/app/deals/hooks/useDealsAndGroups";
import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters"; import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import useGroupDealsSelection, {
GroupDealsSelection,
} from "@/app/deals/hooks/useGroupDealsSelection";
import useDealGroupCrud, { GroupsCrud } from "@/hooks/cruds/useDealGroupCrud"; import useDealGroupCrud, { GroupsCrud } from "@/hooks/cruds/useDealGroupCrud";
import { DealsCrud, useDealsCrud } from "@/hooks/cruds/useDealsCrud"; import { DealsCrud, useDealsCrud } from "@/hooks/cruds/useDealsCrud";
import useDealsList from "@/hooks/lists/useDealsList"; import useDealsList from "@/hooks/lists/useDealsList";
@ -23,10 +26,11 @@ type DealsContextState = {
groupsCrud: GroupsCrud; groupsCrud: GroupsCrud;
paginationInfo?: PaginationInfoSchema; paginationInfo?: PaginationInfoSchema;
page: number; page: number;
setPage: React.Dispatch<React.SetStateAction<number>>; setPage: Dispatch<SetStateAction<number>>;
dealsFiltersForm: UseFormReturnType<DealsFiltersForm>; dealsFiltersForm: UseFormReturnType<DealsFiltersForm>;
isChangedFilters: boolean; isChangedFilters: boolean;
sortingForm: UseFormReturnType<SortingForm>; sortingForm: UseFormReturnType<SortingForm>;
groupDealsSelection: GroupDealsSelection;
}; };
type Props = { type Props = {
@ -56,6 +60,8 @@ const useDealsContextState = ({
const groupsCrud = useDealGroupCrud(); const groupsCrud = useDealGroupCrud();
const groupDealsSelection = useGroupDealsSelection({ groupsCrud });
const { dealsWithoutGroup, groupsWithDeals } = const { dealsWithoutGroup, groupsWithDeals } =
useDealsAndGroups(dealsListObjects); useDealsAndGroups(dealsListObjects);
@ -65,6 +71,7 @@ const useDealsContextState = ({
groupsCrud, groupsCrud,
dealsWithoutGroup, dealsWithoutGroup,
groupsWithDeals, groupsWithDeals,
groupDealsSelection,
}; };
}; };

View File

@ -0,0 +1,92 @@
import { Dispatch, SetStateAction, useState } from "react";
import { GroupsCrud } from "@/hooks/cruds/useDealGroupCrud";
import GroupWithDealsSchema from "@/types/GroupWithDealsSchema";
type Props = {
groupsCrud: GroupsCrud;
};
export type GroupDealsSelection = {
isDealsSelecting: boolean;
selectedBaseDealId: number | null;
startSelectingWithDeal: (dealId: number) => void;
selectedGroupId: number | null;
startSelectingWithExistingGroup: (group: GroupWithDealsSchema) => void;
selectedDealIds: Set<number>;
setSelectedDealIds: Dispatch<SetStateAction<Set<number>>>;
toggleDeal: (dealId: number) => void;
finishDealsSelecting: () => void;
cancelDealsSelecting: () => void;
};
const useGroupDealsSelection = ({ groupsCrud }: Props): GroupDealsSelection => {
const [selectedDealIds, setSelectedDealIds] = useState<Set<number>>(
new Set()
);
const [isDealsSelecting, setIsDealsSelecting] = useState<boolean>(false);
const [selectedBaseDealId, setSelectedBaseDealId] = useState<number | null>(
null
);
const [selectedGroupId, setSelectedGroupId] = useState<number | null>(null);
const toggleDeal = (dealId: number) => {
if (selectedDealIds.has(dealId)) {
selectedDealIds.delete(dealId);
} else {
selectedDealIds.add(dealId);
}
setSelectedDealIds(new Set(selectedDealIds));
};
const finishDealsSelecting = () => {
if (selectedBaseDealId) {
groupsCrud.onCreate(
selectedBaseDealId,
selectedDealIds.values().toArray()
);
setSelectedBaseDealId(null);
} else if (selectedGroupId) {
groupsCrud.onUpdateDealsInGroup(
selectedGroupId,
selectedDealIds.values().toArray()
);
setSelectedGroupId(null);
}
setIsDealsSelecting(false);
setSelectedDealIds(new Set());
};
const cancelDealsSelecting = () => {
setSelectedDealIds(new Set());
setSelectedBaseDealId(null);
setSelectedGroupId(null);
setIsDealsSelecting(false);
};
const startSelectingWithExistingGroup = (group: GroupWithDealsSchema) => {
setSelectedDealIds(new Set(group.items.map(item => item.id)));
setSelectedGroupId(group.id);
setIsDealsSelecting(true);
};
const startSelectingWithDeal = (dealId: number) => {
setSelectedDealIds(new Set([dealId]));
setSelectedBaseDealId(dealId);
setIsDealsSelecting(true);
};
return {
isDealsSelecting,
selectedBaseDealId,
startSelectingWithDeal,
selectedGroupId,
startSelectingWithExistingGroup,
selectedDealIds,
setSelectedDealIds,
toggleDeal,
finishDealsSelecting,
cancelDealsSelecting,
};
};
export default useGroupDealsSelection;

View File

@ -2,6 +2,7 @@ import "@mantine/core/styles.css";
import "mantine-datatable/styles.layer.css"; import "mantine-datatable/styles.layer.css";
import "@mantine/notifications/styles.css"; import "@mantine/notifications/styles.css";
import "@mantine/dates/styles.css"; import "@mantine/dates/styles.css";
import "mantine-contextmenu/styles.css";
import "swiper/css"; import "swiper/css";
import "swiper/css/pagination"; import "swiper/css/pagination";
import "swiper/css/scrollbar"; import "swiper/css/scrollbar";
@ -14,6 +15,7 @@ import {
} from "@mantine/core"; } from "@mantine/core";
import { theme } from "@/theme"; import { theme } from "@/theme";
import "@/app/global.css"; import "@/app/global.css";
import { ContextMenuProvider } from "mantine-contextmenu";
import { ModalsProvider } from "@mantine/modals"; import { ModalsProvider } from "@mantine/modals";
import { Notifications } from "@mantine/notifications"; import { Notifications } from "@mantine/notifications";
import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext"; import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext";
@ -63,6 +65,7 @@ export default function RootLayout({ children }: Props) {
<MantineProvider <MantineProvider
theme={theme} theme={theme}
defaultColorScheme={"auto"}> defaultColorScheme={"auto"}>
<ContextMenuProvider>
<ReactQueryProvider> <ReactQueryProvider>
<ReduxProvider> <ReduxProvider>
<ModalsProvider <ModalsProvider
@ -97,6 +100,7 @@ export default function RootLayout({ children }: Props) {
</ReduxProvider> </ReduxProvider>
<Notifications position="bottom-right" /> <Notifications position="bottom-right" />
</ReactQueryProvider> </ReactQueryProvider>
</ContextMenuProvider>
</MantineProvider> </MantineProvider>
</body> </body>
</html> </html>

View File

@ -1,19 +1,54 @@
import { useMutation } from "@tanstack/react-query"; import React from "react";
import { UpdateDealGroupSchema } from "@/lib/client"; import { useMutation, useQueryClient } from "@tanstack/react-query";
import { AxiosError } from "axios";
import { Text } from "@mantine/core";
import { modals } from "@mantine/modals";
import { HttpValidationError, UpdateDealGroupSchema } from "@/lib/client";
import { import {
addDealMutation,
createDealGroupMutation, createDealGroupMutation,
removeDealMutation, deleteDealGroupMutation,
updateDealGroupMutation, updateDealGroupMutation,
updateDealsInGroupMutation,
} from "@/lib/client/@tanstack/react-query.gen"; } from "@/lib/client/@tanstack/react-query.gen";
import { notifications } from "@/lib/notifications";
export type GroupsCrud = { export type GroupsCrud = {
onUpdate: (groupId: number, group: UpdateDealGroupSchema) => void; onUpdate: (groupId: number, group: UpdateDealGroupSchema) => void;
// onDelete: (group: DealGroupSchema, onSuccess?: () => void) => void; onCreate: (mainDealId: number, otherDealIds: number[]) => void;
onUpdateDealsInGroup: (groupId: number, dealIds: number[]) => void;
onDelete: (groupId: number) => void;
}; };
const useDealGroupCrud = (): GroupsCrud => { const useDealGroupCrud = (): GroupsCrud => {
const updateMutation = useMutation(updateDealGroupMutation()); const queryClient = useQueryClient();
const key = "getDeals";
const onError = (
error: AxiosError<HttpValidationError>,
_: any,
context: any
) => {
console.error(error);
notifications.error({
message: error.response?.data?.detail as string | undefined,
});
if (context?.previous) {
queryClient.setQueryData([key], context.previous);
}
};
const onSettled = () => {
queryClient.invalidateQueries({
predicate: (query: { queryKey: any }) =>
query.queryKey[0]?._id === key,
});
};
const updateMutation = useMutation({
...updateDealGroupMutation(),
onSettled,
onError,
});
const onUpdate = (groupId: number, entity: UpdateDealGroupSchema) => { const onUpdate = (groupId: number, entity: UpdateDealGroupSchema) => {
updateMutation.mutate({ updateMutation.mutate({
@ -26,43 +61,64 @@ const useDealGroupCrud = (): GroupsCrud => {
}); });
}; };
const createMutation = useMutation(createDealGroupMutation()); const createMutation = useMutation({
...createDealGroupMutation(),
onSettled,
onError,
});
const onCreate = (draggingDealId: number, hoveredDealId: number) => { const onCreate = (mainDealId: number, otherDealIds: number[]) => {
createMutation.mutate({ createMutation.mutate({
body: { body: {
draggingDealId, mainDealId,
hoveredDealId, otherDealIds,
}, },
}); });
}; };
const addDealToGroupMutation = useMutation(addDealMutation()); const updateDealsMutation = useMutation({
...updateDealsInGroupMutation(),
onSettled,
onError,
});
const onAddDeal = (dealId: number, groupId: number) => { const onUpdateDealsInGroup = (groupId: number, dealIds: number[]) => {
addDealToGroupMutation.mutate({ updateDealsMutation.mutate({
path: {
pk: groupId,
},
body: { body: {
dealId, dealIds,
groupId,
}, },
}); });
}; };
const removeDealFromGroupMutation = useMutation(removeDealMutation()); const deleteMutation = useMutation({
...deleteDealGroupMutation(),
onSettled,
onError,
});
const onRemoveDeal = (dealId: number) => { const onDelete = (groupId: number) => {
removeDealFromGroupMutation.mutate({ modals.openConfirmModal({
body: { title: "Удаление группы",
dealId, children: <Text>Вы уверены, что хотите удалить группу?</Text>,
confirmProps: { color: "red" },
onConfirm: () => {
deleteMutation.mutate({
path: {
pk: groupId,
},
});
}, },
}); });
}; };
return { return {
onUpdate, onUpdate,
// onCreate, onCreate,
// onAddDeal, onUpdateDealsInGroup,
// onRemoveDeal, onDelete,
}; };
}; };

View File

@ -9,7 +9,6 @@ import {
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { client as _heyApiClient } from "../client.gen"; import { client as _heyApiClient } from "../client.gen";
import { import {
addDeal,
addKitToDeal, addKitToDeal,
addKitToDealProduct, addKitToDealProduct,
createBarcodeTemplate, createBarcodeTemplate,
@ -31,6 +30,7 @@ import {
deleteBoard, deleteBoard,
deleteClient, deleteClient,
deleteDeal, deleteDeal,
deleteDealGroup,
deleteDealProduct, deleteDealProduct,
deleteDealProductService, deleteDealProductService,
deleteDealService, deleteDealService,
@ -61,7 +61,6 @@ import {
getServicesKits, getServicesKits,
getStatuses, getStatuses,
getStatusHistory, getStatusHistory,
removeDeal,
updateBarcodeTemplate, updateBarcodeTemplate,
updateBoard, updateBoard,
updateClient, updateClient,
@ -70,6 +69,7 @@ import {
updateDealProduct, updateDealProduct,
updateDealProductService, updateDealProductService,
updateDealService, updateDealService,
updateDealsInGroup,
updateMarketplace, updateMarketplace,
updateProduct, updateProduct,
updateProject, updateProject,
@ -80,9 +80,6 @@ import {
type Options, type Options,
} from "../sdk.gen"; } from "../sdk.gen";
import type { import type {
AddDealData,
AddDealError,
AddDealResponse,
AddKitToDealData, AddKitToDealData,
AddKitToDealError, AddKitToDealError,
AddKitToDealProductData, AddKitToDealProductData,
@ -145,6 +142,9 @@ import type {
DeleteClientResponse2, DeleteClientResponse2,
DeleteDealData, DeleteDealData,
DeleteDealError, DeleteDealError,
DeleteDealGroupData,
DeleteDealGroupError,
DeleteDealGroupResponse2,
DeleteDealProductData, DeleteDealProductData,
DeleteDealProductError, DeleteDealProductError,
DeleteDealProductResponse2, DeleteDealProductResponse2,
@ -204,9 +204,6 @@ import type {
GetServicesKitsData, GetServicesKitsData,
GetStatusesData, GetStatusesData,
GetStatusHistoryData, GetStatusHistoryData,
RemoveDealData,
RemoveDealError,
RemoveDealResponse,
UpdateBarcodeTemplateData, UpdateBarcodeTemplateData,
UpdateBarcodeTemplateError, UpdateBarcodeTemplateError,
UpdateBarcodeTemplateResponse2, UpdateBarcodeTemplateResponse2,
@ -231,6 +228,9 @@ import type {
UpdateDealServiceData, UpdateDealServiceData,
UpdateDealServiceError, UpdateDealServiceError,
UpdateDealServiceResponse2, UpdateDealServiceResponse2,
UpdateDealsInGroupData,
UpdateDealsInGroupError,
UpdateDealsInGroupResponse2,
UpdateMarketplaceData, UpdateMarketplaceData,
UpdateMarketplaceError, UpdateMarketplaceError,
UpdateMarketplaceResponse2, UpdateMarketplaceResponse2,
@ -621,6 +621,33 @@ export const updateDealMutation = (
return mutationOptions; return mutationOptions;
}; };
/**
* Delete Group
*/
export const deleteDealGroupMutation = (
options?: Partial<Options<DeleteDealGroupData>>
): UseMutationOptions<
DeleteDealGroupResponse2,
AxiosError<DeleteDealGroupError>,
Options<DeleteDealGroupData>
> => {
const mutationOptions: UseMutationOptions<
DeleteDealGroupResponse2,
AxiosError<DeleteDealGroupError>,
Options<DeleteDealGroupData>
> = {
mutationFn: async localOptions => {
const { data } = await deleteDealGroup({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
/** /**
* Update Group * Update Group
*/ */
@ -699,43 +726,19 @@ export const createDealGroupMutation = (
return mutationOptions; return mutationOptions;
}; };
/** export const updateDealsInGroupQueryKey = (
* Remove Deal options: Options<UpdateDealsInGroupData>
*/ ) => createQueryKey("updateDealsInGroup", options);
export const removeDealMutation = (
options?: Partial<Options<RemoveDealData>>
): UseMutationOptions<
RemoveDealResponse,
AxiosError<RemoveDealError>,
Options<RemoveDealData>
> => {
const mutationOptions: UseMutationOptions<
RemoveDealResponse,
AxiosError<RemoveDealError>,
Options<RemoveDealData>
> = {
mutationFn: async localOptions => {
const { data } = await removeDeal({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
export const addDealQueryKey = (options: Options<AddDealData>) =>
createQueryKey("addDeal", options);
/** /**
* Add Deal * Update Deals In Group
*/ */
export const addDealOptions = (options: Options<AddDealData>) => { export const updateDealsInGroupOptions = (
options: Options<UpdateDealsInGroupData>
) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await addDeal({ const { data } = await updateDealsInGroup({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
@ -743,27 +746,27 @@ export const addDealOptions = (options: Options<AddDealData>) => {
}); });
return data; return data;
}, },
queryKey: addDealQueryKey(options), queryKey: updateDealsInGroupQueryKey(options),
}); });
}; };
/** /**
* Add Deal * Update Deals In Group
*/ */
export const addDealMutation = ( export const updateDealsInGroupMutation = (
options?: Partial<Options<AddDealData>> options?: Partial<Options<UpdateDealsInGroupData>>
): UseMutationOptions< ): UseMutationOptions<
AddDealResponse, UpdateDealsInGroupResponse2,
AxiosError<AddDealError>, AxiosError<UpdateDealsInGroupError>,
Options<AddDealData> Options<UpdateDealsInGroupData>
> => { > => {
const mutationOptions: UseMutationOptions< const mutationOptions: UseMutationOptions<
AddDealResponse, UpdateDealsInGroupResponse2,
AxiosError<AddDealError>, AxiosError<UpdateDealsInGroupError>,
Options<AddDealData> Options<UpdateDealsInGroupData>
> = { > = {
mutationFn: async localOptions => { mutationFn: async localOptions => {
const { data } = await addDeal({ const { data } = await updateDealsInGroup({
...options, ...options,
...localOptions, ...localOptions,
throwOnError: true, throwOnError: true,

View File

@ -3,9 +3,6 @@
import type { Client, Options as ClientOptions, TDataShape } from "./client"; import type { Client, Options as ClientOptions, TDataShape } from "./client";
import { client as _heyApiClient } from "./client.gen"; import { client as _heyApiClient } from "./client.gen";
import type { import type {
AddDealData,
AddDealErrors,
AddDealResponses,
AddKitToDealData, AddKitToDealData,
AddKitToDealErrors, AddKitToDealErrors,
AddKitToDealProductData, AddKitToDealProductData,
@ -68,6 +65,9 @@ import type {
DeleteClientResponses, DeleteClientResponses,
DeleteDealData, DeleteDealData,
DeleteDealErrors, DeleteDealErrors,
DeleteDealGroupData,
DeleteDealGroupErrors,
DeleteDealGroupResponses,
DeleteDealProductData, DeleteDealProductData,
DeleteDealProductErrors, DeleteDealProductErrors,
DeleteDealProductResponses, DeleteDealProductResponses,
@ -150,9 +150,6 @@ import type {
GetStatusHistoryData, GetStatusHistoryData,
GetStatusHistoryErrors, GetStatusHistoryErrors,
GetStatusHistoryResponses, GetStatusHistoryResponses,
RemoveDealData,
RemoveDealErrors,
RemoveDealResponses,
UpdateBarcodeTemplateData, UpdateBarcodeTemplateData,
UpdateBarcodeTemplateErrors, UpdateBarcodeTemplateErrors,
UpdateBarcodeTemplateResponses, UpdateBarcodeTemplateResponses,
@ -177,6 +174,9 @@ import type {
UpdateDealServiceData, UpdateDealServiceData,
UpdateDealServiceErrors, UpdateDealServiceErrors,
UpdateDealServiceResponses, UpdateDealServiceResponses,
UpdateDealsInGroupData,
UpdateDealsInGroupErrors,
UpdateDealsInGroupResponses,
UpdateMarketplaceData, UpdateMarketplaceData,
UpdateMarketplaceErrors, UpdateMarketplaceErrors,
UpdateMarketplaceResponses, UpdateMarketplaceResponses,
@ -200,8 +200,6 @@ import type {
UpdateStatusResponses, UpdateStatusResponses,
} from "./types.gen"; } from "./types.gen";
import { import {
zAddDealData,
zAddDealResponse,
zAddKitToDealData, zAddKitToDealData,
zAddKitToDealProductData, zAddKitToDealProductData,
zAddKitToDealProductResponse, zAddKitToDealProductResponse,
@ -243,6 +241,8 @@ import {
zDeleteClientData, zDeleteClientData,
zDeleteClientResponse2, zDeleteClientResponse2,
zDeleteDealData, zDeleteDealData,
zDeleteDealGroupData,
zDeleteDealGroupResponse2,
zDeleteDealProductData, zDeleteDealProductData,
zDeleteDealProductResponse2, zDeleteDealProductResponse2,
zDeleteDealProductServiceData, zDeleteDealProductServiceData,
@ -304,8 +304,6 @@ import {
zGetStatusesResponse2, zGetStatusesResponse2,
zGetStatusHistoryData, zGetStatusHistoryData,
zGetStatusHistoryResponse2, zGetStatusHistoryResponse2,
zRemoveDealData,
zRemoveDealResponse,
zUpdateBarcodeTemplateData, zUpdateBarcodeTemplateData,
zUpdateBarcodeTemplateResponse2, zUpdateBarcodeTemplateResponse2,
zUpdateBoardData, zUpdateBoardData,
@ -322,6 +320,8 @@ import {
zUpdateDealResponse2, zUpdateDealResponse2,
zUpdateDealServiceData, zUpdateDealServiceData,
zUpdateDealServiceResponse2, zUpdateDealServiceResponse2,
zUpdateDealsInGroupData,
zUpdateDealsInGroupResponse2,
zUpdateMarketplaceData, zUpdateMarketplaceData,
zUpdateMarketplaceResponse2, zUpdateMarketplaceResponse2,
zUpdateProductData, zUpdateProductData,
@ -555,6 +555,29 @@ export const updateDeal = <ThrowOnError extends boolean = false>(
}); });
}; };
/**
* Delete Group
*/
export const deleteDealGroup = <ThrowOnError extends boolean = false>(
options: Options<DeleteDealGroupData, ThrowOnError>
) => {
return (options.client ?? _heyApiClient).delete<
DeleteDealGroupResponses,
DeleteDealGroupErrors,
ThrowOnError
>({
requestValidator: async data => {
return await zDeleteDealGroupData.parseAsync(data);
},
responseType: "json",
responseValidator: async data => {
return await zDeleteDealGroupResponse2.parseAsync(data);
},
url: "/deal-group/{pk}",
...options,
});
};
/** /**
* Update Group * Update Group
*/ */
@ -610,51 +633,24 @@ export const createDealGroup = <ThrowOnError extends boolean = false>(
}; };
/** /**
* Remove Deal * Update Deals In Group
*/ */
export const removeDeal = <ThrowOnError extends boolean = false>( export const updateDealsInGroup = <ThrowOnError extends boolean = false>(
options: Options<RemoveDealData, ThrowOnError> options: Options<UpdateDealsInGroupData, ThrowOnError>
) => {
return (options.client ?? _heyApiClient).delete<
RemoveDealResponses,
RemoveDealErrors,
ThrowOnError
>({
requestValidator: async data => {
return await zRemoveDealData.parseAsync(data);
},
responseType: "json",
responseValidator: async data => {
return await zRemoveDealResponse.parseAsync(data);
},
url: "/deal-group/deal",
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
});
};
/**
* Add Deal
*/
export const addDeal = <ThrowOnError extends boolean = false>(
options: Options<AddDealData, ThrowOnError>
) => { ) => {
return (options.client ?? _heyApiClient).post< return (options.client ?? _heyApiClient).post<
AddDealResponses, UpdateDealsInGroupResponses,
AddDealErrors, UpdateDealsInGroupErrors,
ThrowOnError ThrowOnError
>({ >({
requestValidator: async data => { requestValidator: async data => {
return await zAddDealData.parseAsync(data); return await zUpdateDealsInGroupData.parseAsync(data);
}, },
responseType: "json", responseType: "json",
responseValidator: async data => { responseValidator: async data => {
return await zAddDealResponse.parseAsync(data); return await zUpdateDealsInGroupResponse2.parseAsync(data);
}, },
url: "/deal-group/deal", url: "/deal-group/{pk}/deals",
...options, ...options,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@ -1,29 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/**
* AddDealToGroupRequest
*/
export type AddDealToGroupRequest = {
/**
* Dealid
*/
dealId: number;
/**
* Groupid
*/
groupId: number;
};
/**
* AddDealToGroupResponse
*/
export type AddDealToGroupResponse = {
/**
* Message
*/
message: string;
};
/** /**
* BarcodeTemplateAttributeSchema * BarcodeTemplateAttributeSchema
*/ */
@ -376,13 +352,13 @@ export type CreateClientSchema = {
*/ */
export type CreateDealGroupRequest = { export type CreateDealGroupRequest = {
/** /**
* Draggingdealid * Maindealid
*/ */
draggingDealId: number; mainDealId: number;
/** /**
* Hovereddealid * Otherdealids
*/ */
hoveredDealId: number; otherDealIds: Array<number>;
}; };
/** /**
@ -950,26 +926,6 @@ export type DealProductSchema = {
productServices: Array<ProductServiceSchema>; productServices: Array<ProductServiceSchema>;
}; };
/**
* DealRemoveFromGroupRequest
*/
export type DealRemoveFromGroupRequest = {
/**
* Dealid
*/
dealId: number;
};
/**
* DealRemoveFromGroupResponse
*/
export type DealRemoveFromGroupResponse = {
/**
* Message
*/
message: string;
};
/** /**
* DealSchema * DealSchema
*/ */
@ -1061,6 +1017,16 @@ export type DeleteClientResponse = {
message: string; message: string;
}; };
/**
* DeleteDealGroupResponse
*/
export type DeleteDealGroupResponse = {
/**
* Message
*/
message: string;
};
/** /**
* DeleteDealProductResponse * DeleteDealProductResponse
*/ */
@ -1978,6 +1944,26 @@ export type UpdateDealServiceSchema = {
isFixedPrice: boolean; isFixedPrice: boolean;
}; };
/**
* UpdateDealsInGroupRequest
*/
export type UpdateDealsInGroupRequest = {
/**
* Dealids
*/
dealIds: Array<number>;
};
/**
* UpdateDealsInGroupResponse
*/
export type UpdateDealsInGroupResponse = {
/**
* Message
*/
message: string;
};
/** /**
* UpdateMarketplaceRequest * UpdateMarketplaceRequest
*/ */
@ -2585,6 +2571,38 @@ export type UpdateDealResponses = {
export type UpdateDealResponse2 = export type UpdateDealResponse2 =
UpdateDealResponses[keyof UpdateDealResponses]; UpdateDealResponses[keyof UpdateDealResponses];
export type DeleteDealGroupData = {
body?: never;
path: {
/**
* Pk
*/
pk: number;
};
query?: never;
url: "/deal-group/{pk}";
};
export type DeleteDealGroupErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type DeleteDealGroupError =
DeleteDealGroupErrors[keyof DeleteDealGroupErrors];
export type DeleteDealGroupResponses = {
/**
* Successful Response
*/
200: DeleteDealGroupResponse;
};
export type DeleteDealGroupResponse2 =
DeleteDealGroupResponses[keyof DeleteDealGroupResponses];
export type UpdateDealGroupData = { export type UpdateDealGroupData = {
body: UpdateDealGroupRequest; body: UpdateDealGroupRequest;
path: { path: {
@ -2644,55 +2662,37 @@ export type CreateDealGroupResponses = {
export type CreateDealGroupResponse2 = export type CreateDealGroupResponse2 =
CreateDealGroupResponses[keyof CreateDealGroupResponses]; CreateDealGroupResponses[keyof CreateDealGroupResponses];
export type RemoveDealData = { export type UpdateDealsInGroupData = {
body: DealRemoveFromGroupRequest; body: UpdateDealsInGroupRequest;
path?: never; path: {
/**
* Pk
*/
pk: number;
};
query?: never; query?: never;
url: "/deal-group/deal"; url: "/deal-group/{pk}/deals";
}; };
export type RemoveDealErrors = { export type UpdateDealsInGroupErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type RemoveDealError = RemoveDealErrors[keyof RemoveDealErrors]; export type UpdateDealsInGroupError =
UpdateDealsInGroupErrors[keyof UpdateDealsInGroupErrors];
export type RemoveDealResponses = { export type UpdateDealsInGroupResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: DealRemoveFromGroupResponse; 200: UpdateDealsInGroupResponse;
}; };
export type RemoveDealResponse = RemoveDealResponses[keyof RemoveDealResponses]; export type UpdateDealsInGroupResponse2 =
UpdateDealsInGroupResponses[keyof UpdateDealsInGroupResponses];
export type AddDealData = {
body: AddDealToGroupRequest;
path?: never;
query?: never;
url: "/deal-group/deal";
};
export type AddDealErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type AddDealError = AddDealErrors[keyof AddDealErrors];
export type AddDealResponses = {
/**
* Successful Response
*/
200: AddDealToGroupResponse;
};
export type AddDealResponse = AddDealResponses[keyof AddDealResponses];
export type GetBuiltInModulesData = { export type GetBuiltInModulesData = {
body?: never; body?: never;

View File

@ -2,21 +2,6 @@
import { z } from "zod"; import { z } from "zod";
/**
* AddDealToGroupRequest
*/
export const zAddDealToGroupRequest = z.object({
dealId: z.int(),
groupId: z.int(),
});
/**
* AddDealToGroupResponse
*/
export const zAddDealToGroupResponse = z.object({
message: z.string(),
});
/** /**
* BarcodeTemplateAttributeSchema * BarcodeTemplateAttributeSchema
*/ */
@ -212,8 +197,8 @@ export const zCreateClientResponse = z.object({
* CreateDealGroupRequest * CreateDealGroupRequest
*/ */
export const zCreateDealGroupRequest = z.object({ export const zCreateDealGroupRequest = z.object({
draggingDealId: z.int(), mainDealId: z.int(),
hoveredDealId: z.int(), otherDealIds: z.array(z.int()),
}); });
/** /**
@ -694,20 +679,6 @@ export const zDealProductAddKitResponse = z.object({
message: z.string(), message: z.string(),
}); });
/**
* DealRemoveFromGroupRequest
*/
export const zDealRemoveFromGroupRequest = z.object({
dealId: z.int(),
});
/**
* DealRemoveFromGroupResponse
*/
export const zDealRemoveFromGroupResponse = z.object({
message: z.string(),
});
/** /**
* DeleteBarcodeTemplateResponse * DeleteBarcodeTemplateResponse
*/ */
@ -729,6 +700,13 @@ export const zDeleteClientResponse = z.object({
message: z.string(), message: z.string(),
}); });
/**
* DeleteDealGroupResponse
*/
export const zDeleteDealGroupResponse = z.object({
message: z.string(),
});
/** /**
* DeleteDealProductResponse * DeleteDealProductResponse
*/ */
@ -1181,6 +1159,20 @@ export const zUpdateDealServiceResponse = z.object({
message: z.string(), message: z.string(),
}); });
/**
* UpdateDealsInGroupRequest
*/
export const zUpdateDealsInGroupRequest = z.object({
dealIds: z.array(z.int()),
});
/**
* UpdateDealsInGroupResponse
*/
export const zUpdateDealsInGroupResponse = z.object({
message: z.string(),
});
/** /**
* UpdateMarketplaceSchema * UpdateMarketplaceSchema
*/ */
@ -1489,6 +1481,19 @@ export const zUpdateDealData = z.object({
*/ */
export const zUpdateDealResponse2 = zUpdateDealResponse; export const zUpdateDealResponse2 = zUpdateDealResponse;
export const zDeleteDealGroupData = z.object({
body: z.optional(z.never()),
path: z.object({
pk: z.int(),
}),
query: z.optional(z.never()),
});
/**
* Successful Response
*/
export const zDeleteDealGroupResponse2 = zDeleteDealGroupResponse;
export const zUpdateDealGroupData = z.object({ export const zUpdateDealGroupData = z.object({
body: zUpdateDealGroupRequest, body: zUpdateDealGroupRequest,
path: z.object({ path: z.object({
@ -1513,27 +1518,18 @@ export const zCreateDealGroupData = z.object({
*/ */
export const zCreateDealGroupResponse2 = zCreateDealGroupResponse; export const zCreateDealGroupResponse2 = zCreateDealGroupResponse;
export const zRemoveDealData = z.object({ export const zUpdateDealsInGroupData = z.object({
body: zDealRemoveFromGroupRequest, body: zUpdateDealsInGroupRequest,
path: z.optional(z.never()), path: z.object({
pk: z.int(),
}),
query: z.optional(z.never()), query: z.optional(z.never()),
}); });
/** /**
* Successful Response * Successful Response
*/ */
export const zRemoveDealResponse = zDealRemoveFromGroupResponse; export const zUpdateDealsInGroupResponse2 = zUpdateDealsInGroupResponse;
export const zAddDealData = z.object({
body: zAddDealToGroupRequest,
path: z.optional(z.never()),
query: z.optional(z.never()),
});
/**
* Successful Response
*/
export const zAddDealResponse = zAddDealToGroupResponse;
export const zGetBuiltInModulesData = z.object({ export const zGetBuiltInModulesData = z.object({
body: z.optional(z.never()), body: z.optional(z.never()),

View File

@ -6198,6 +6198,7 @@ __metadata:
jest-environment-jsdom: "npm:^30.0.0" jest-environment-jsdom: "npm:^30.0.0"
lexorank: "npm:^1.0.5" lexorank: "npm:^1.0.5"
libphonenumber-js: "npm:^1.12.10" libphonenumber-js: "npm:^1.12.10"
mantine-contextmenu: "npm:^8.2.0"
mantine-datatable: "npm:^8.2.0" mantine-datatable: "npm:^8.2.0"
next: "npm:15.4.7" next: "npm:15.4.7"
phone: "npm:^3.1.67" phone: "npm:^3.1.67"
@ -10181,6 +10182,19 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"mantine-contextmenu@npm:^8.2.0":
version: 8.2.0
resolution: "mantine-contextmenu@npm:8.2.0"
peerDependencies:
"@mantine/core": ">=8.2"
"@mantine/hooks": ">=8.2"
clsx: ">=2"
react: ">=19"
react-dom: ">=19"
checksum: 10c0/fea66f890eb9baea7e1ebcdcf3732d8522e2322938d7d0de168acffa9abe6ab0efae8838d7af2ae4399d044bca27879775efd0a07d7f6193cf0ebfe250d4b786
languageName: node
linkType: hard
"mantine-datatable@npm:^8.2.0": "mantine-datatable@npm:^8.2.0":
version: 8.2.0 version: 8.2.0
resolution: "mantine-datatable@npm:8.2.0" resolution: "mantine-datatable@npm:8.2.0"