feat: deal create, update, delete

This commit is contained in:
2025-08-24 12:49:19 +04:00
parent 10f50ac254
commit d5be9ce61a
23 changed files with 741 additions and 76 deletions

View File

@ -0,0 +1,10 @@
.create-button {
cursor: pointer;
@mixin light {
background-color: var(--color-light-white-blue);
}
@mixin dark {
background-color: var(--mantine-color-dark-7);
}
}

View File

@ -0,0 +1,51 @@
import { useState } from "react";
import { IconPlus } from "@tabler/icons-react";
import { Card, Center, Group, Text, Transition } from "@mantine/core";
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import CreateCardForm, { CreateDealForm } from "./components/CreateCardForm";
import styles from "./CreateDealButton.module.css";
const CreateCardButton = () => {
const [isCreating, setIsCreating] = useState(false);
const [isTransitionEnded, setIsTransitionEnded] = useState(true);
const { dealsCrud } = useDealsContext();
const onSubmit = (values: CreateDealForm) => {
dealsCrud.onCreate(values.name);
setIsCreating(prevState => !prevState);
setIsTransitionEnded(false);
};
return (
<Card
className={styles["create-button"]}
onClick={() => {
if (isCreating) return;
setIsCreating(prevState => !prevState);
setIsTransitionEnded(false);
}}>
{!isCreating && isTransitionEnded && (
<Center>
<Group gap={"xs"}>
<IconPlus />
<Text>Добавить</Text>
</Group>
</Center>
)}
<Transition
mounted={isCreating}
transition={"scale-y"}
onExited={() => setIsTransitionEnded(true)}>
{styles => (
<div style={styles}>
<CreateCardForm
onCancel={() => setIsCreating(false)}
onSubmit={onSubmit}
/>
</div>
)}
</Transition>
</Card>
);
};
export default CreateCardButton;

View File

@ -0,0 +1,54 @@
import { FC } from "react";
import { IconCheck, IconX } from "@tabler/icons-react";
import { Button, Group, Stack, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
export type CreateDealForm = {
name: string;
};
type Props = {
onSubmit: (values: CreateDealForm) => void;
onCancel: () => void;
};
const CreateCardForm: FC<Props> = ({ onSubmit, onCancel }) => {
const form = useForm<CreateDealForm>({
initialValues: {
name: "",
},
validate: {
name: value => !value && "Введите название",
},
});
return (
<form onSubmit={form.onSubmit(values => {
onSubmit(values);
form.reset();
})}>
<Stack>
<TextInput
placeholder={"Название"}
{...form.getInputProps("name")}
/>
<Group wrap={"nowrap"}>
<Button
variant={"default"}
w={"100%"}
onClick={onCancel}>
<IconX />
</Button>
<Button
variant={"default"}
w={"100%"}
type={"submit"}>
<IconCheck />
</Button>
</Group>
</Stack>
</form>
);
};
export default CreateCardForm;

View File

@ -1,4 +1,6 @@
import { Card, Group, Pill, Stack, Text } from "@mantine/core"; import { Card, Group, Pill, Stack, Text } from "@mantine/core";
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import { useDrawersContext } from "@/drawers/DrawersContext";
import { DealSchema } from "@/lib/client"; import { DealSchema } from "@/lib/client";
import styles from "./DealCard.module.css"; import styles from "./DealCard.module.css";
@ -7,8 +9,17 @@ type Props = {
}; };
const DealCard = ({ deal }: Props) => { const DealCard = ({ deal }: Props) => {
const { dealsCrud } = useDealsContext();
const { openDrawer } = useDrawersContext();
const onClick = () => {
openDrawer({ key: "dealEditorDrawer", props: { deal, dealsCrud } });
};
return ( return (
<Card className={styles.container}> <Card
onClick={onClick}
className={styles.container}>
<Text c={"dodgerblue"}>{deal.name}</Text> <Text c={"dodgerblue"}>{deal.name}</Text>
<Stack gap={0}> <Stack gap={0}>
<Text>Wb электросталь</Text> <Text>Wb электросталь</Text>

View File

@ -45,11 +45,13 @@ const Funnel: FC = () => {
renderContainer={( renderContainer={(
status: StatusSchema, status: StatusSchema,
funnelColumnComponent: ReactNode, funnelColumnComponent: ReactNode,
renderDraggable renderDraggable,
index
) => ( ) => (
<StatusColumnWrapper <StatusColumnWrapper
status={status} status={status}
renderHeader={renderDraggable}> renderHeader={renderDraggable}
createFormEnabled={index === 0}>
{funnelColumnComponent} {funnelColumnComponent}
</StatusColumnWrapper> </StatusColumnWrapper>
)} )}

View File

@ -1,5 +1,6 @@
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { Box, ScrollArea, Stack } from "@mantine/core"; import { Box, ScrollArea, Stack } from "@mantine/core";
import CreateCardButton from "@/app/deals/components/shared/CreateDealButton/CreateDealButton";
import { StatusSchema } from "@/lib/client"; import { StatusSchema } from "@/lib/client";
import styles from "./StatusColumnWrapper.module.css"; import styles from "./StatusColumnWrapper.module.css";
@ -7,9 +8,14 @@ type Props = {
status: StatusSchema; status: StatusSchema;
renderHeader: () => ReactNode; renderHeader: () => ReactNode;
children: ReactNode; children: ReactNode;
createFormEnabled?: boolean;
}; };
const StatusColumnWrapper = ({ renderHeader, children }: Props) => { const StatusColumnWrapper = ({
renderHeader,
children,
createFormEnabled = false,
}: Props) => {
return ( return (
<Box className={styles.container}> <Box className={styles.container}>
<Stack <Stack
@ -22,7 +28,12 @@ const StatusColumnWrapper = ({ renderHeader, children }: Props) => {
scrollbarSize={10} scrollbarSize={10}
type={"always"} type={"always"}
scrollbars={"y"}> scrollbars={"y"}>
<Stack mah={"calc(100vh - 220px)"}>{children}</Stack> <Stack
gap={"xs"}
mah={"calc(100vh - 220px)"}>
{createFormEnabled && <CreateCardButton />}
{children}
</Stack>
</ScrollArea> </ScrollArea>
</Stack> </Stack>
</Box> </Box>

View File

@ -13,8 +13,6 @@ type BoardsContextState = {
setSelectedBoardId: React.Dispatch<React.SetStateAction<number | null>>; setSelectedBoardId: React.Dispatch<React.SetStateAction<number | null>>;
refetchBoards: () => void; refetchBoards: () => void;
boardsCrud: BoardsCrud; boardsCrud: BoardsCrud;
isEditorDrawerOpened: boolean;
setIsEditorDrawerOpened: React.Dispatch<React.SetStateAction<boolean>>;
}; };
const BoardsContext = createContext<BoardsContextState | undefined>(undefined); const BoardsContext = createContext<BoardsContextState | undefined>(undefined);
@ -26,8 +24,6 @@ const useBoardsContextState = () => {
setBoards, setBoards,
refetch: refetchBoards, refetch: refetchBoards,
} = useBoardsList({ projectId: project?.id }); } = useBoardsList({ projectId: project?.id });
const [isEditorDrawerOpened, setIsEditorDrawerOpened] =
useState<boolean>(false);
const [selectedBoardId, setSelectedBoardId] = useState<number | null>(null); const [selectedBoardId, setSelectedBoardId] = useState<number | null>(null);
const selectedBoard = const selectedBoard =
@ -51,8 +47,6 @@ const useBoardsContextState = () => {
setSelectedBoardId, setSelectedBoardId,
refetchBoards, refetchBoards,
boardsCrud, boardsCrud,
isEditorDrawerOpened,
setIsEditorDrawerOpened,
}; };
}; };

View File

@ -1,57 +1,43 @@
"use client"; "use client";
import React, { createContext, FC, useContext } from "react"; import React, { createContext, FC, useContext } from "react";
import { useMutation, UseMutationResult } from "@tanstack/react-query";
import { AxiosError } from "axios";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext"; import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import { DealsCrud, useDealsCrud } from "@/hooks/cruds/useDealsCrud";
import useDealsList from "@/hooks/lists/useDealsList"; import useDealsList from "@/hooks/lists/useDealsList";
import { import { DealSchema } from "@/lib/client";
DealSchema,
HttpValidationError,
Options,
UpdateDealData,
UpdateDealResponse,
} from "@/lib/client";
import { updateDealMutation } from "@/lib/client/@tanstack/react-query.gen";
import { notifications } from "@/lib/notifications";
type DealsContextState = { type DealsContextState = {
deals: DealSchema[]; deals: DealSchema[];
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>; setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
updateDeal: UseMutationResult<
UpdateDealResponse,
AxiosError<HttpValidationError>,
Options<UpdateDealData>
>;
refetchDeals: () => void; refetchDeals: () => void;
dealsCrud: DealsCrud;
}; };
const DealsContext = createContext<DealsContextState | undefined>(undefined); const DealsContext = createContext<DealsContextState | undefined>(undefined);
const useDealsContextState = () => { const useDealsContextState = () => {
const { selectedBoard } = useBoardsContext(); const { selectedBoard } = useBoardsContext();
const { statuses } = useStatusesContext();
const { const {
deals, deals,
setDeals, setDeals,
refetch: refetchDeals, refetch: refetchDeals,
} = useDealsList({ boardId: selectedBoard?.id }); } = useDealsList({ boardId: selectedBoard?.id });
const updateDeal = useMutation({ const dealsCrud = useDealsCrud({
...updateDealMutation(), deals,
onError: error => { setDeals,
console.error(error); refetchDeals,
notifications.error({ boardId: selectedBoard?.id,
message: error.response?.data?.detail as string | undefined, statuses,
});
refetchDeals();
},
}); });
return { return {
deals, deals,
setDeals, setDeals,
updateDeal,
refetchDeals, refetchDeals,
dealsCrud,
}; };
}; };

View File

@ -0,0 +1,4 @@
.tab {
border-bottom-width: 3px;
}

View File

@ -0,0 +1,48 @@
"use client";
import React, { FC } from "react";
import { Drawer } from "@mantine/core";
import DealEditorBody from "@/app/deals/drawers/DealEditorDrawer/components/DealEditorBody";
import { DrawerProps } from "@/drawers/types";
import { DealsCrud } from "@/hooks/cruds/useDealsCrud";
import useIsMobile from "@/hooks/utils/useIsMobile";
import { DealSchema } from "@/lib/client";
type Props = {
deal: DealSchema;
dealsCrud: DealsCrud;
};
const DealEditorDrawer: FC<DrawerProps<Props>> = ({
opened,
onClose,
props,
}) => {
const isMobile = useIsMobile();
return (
<Drawer
size={isMobile ? "100%" : "60%"}
position={"right"}
onClose={onClose}
removeScrollProps={{ allowPinchZoom: true }}
withCloseButton={false}
opened={opened}
trapFocus={false}
styles={{
body: {
height: "100%",
display: "flex",
flexDirection: "column",
padding: 0,
},
}}>
<DealEditorBody
{...props}
onClose={onClose}
/>
</Drawer>
);
};
export default DealEditorDrawer;

View File

@ -0,0 +1,47 @@
import { FC } from "react";
import { IconCircleDotted, IconEdit } from "@tabler/icons-react";
import { Tabs, Text } from "@mantine/core";
import GeneralTab from "@/app/deals/drawers/DealEditorDrawer/components/GeneralTab";
import { DealsCrud } from "@/hooks/cruds/useDealsCrud";
import { DealSchema } from "@/lib/client";
import styles from "../DealEditorDrawer.module.css";
type Props = {
dealsCrud: DealsCrud;
deal: DealSchema;
onClose: () => void;
};
const DealEditorBody: FC<Props> = ({ dealsCrud, deal, onClose }) => {
return (
<Tabs
defaultValue="general"
classNames={{ tab: styles.tab }}>
<Tabs.List>
<Tabs.Tab
value="general"
leftSection={<IconEdit />}>
Общая информация
</Tabs.Tab>
<Tabs.Tab
value="mock"
leftSection={<IconCircleDotted />}>
Mock
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="general">
<GeneralTab
dealsCrud={dealsCrud}
deal={deal}
onClose={onClose}
/>
</Tabs.Panel>
<Tabs.Panel value="mock">
<Text>mock</Text>
</Tabs.Panel>
</Tabs>
);
};
export default DealEditorBody;

View File

@ -0,0 +1,67 @@
import { FC, useState } from "react";
import { isEqual } from "lodash";
import { Button, Group, Stack, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import { DealsCrud } from "@/hooks/cruds/useDealsCrud";
import { DealSchema } from "@/lib/client";
type Props = {
dealsCrud: DealsCrud;
deal: DealSchema;
onClose: () => void;
};
const GeneralTab: FC<Props> = ({ deal, dealsCrud, onClose }) => {
const [initialValues, setInitialValues] = useState(deal);
const form = useForm<DealSchema>({
initialValues,
validate: {
name: value => !value && "Введите название",
},
});
const onSubmit = (values: DealSchema) => {
dealsCrud.onUpdate(deal.id, values);
setInitialValues(values);
};
const onDelete = () => {
dealsCrud.onDelete(deal, onClose);
};
return (
<form onSubmit={form.onSubmit(onSubmit)}>
<Stack p={"md"}>
<TextInput
label={"Название"}
{...form.getInputProps("name")}
/>
<Group justify={"space-between"}>
<Group>
<Button
type={"submit"}
disabled={isEqual(form.values, initialValues)}
variant={"filled"}>
Сохранить
</Button>
<Button
type={"reset"}
onClick={() => form.reset()}
disabled={isEqual(form.values, initialValues)}
variant={"default"}>
Отменить
</Button>
</Group>
<Button
onClick={onDelete}
color={"red"}
variant={"outline"}>
Удалить
</Button>
</Group>
</Stack>
</form>
);
};
export default GeneralTab;

View File

@ -0,0 +1,3 @@
import ProjectsEditorDrawer from "@/app/deals/drawers/ProjectsEditorDrawer/ProjectsEditorDrawer";
export default ProjectsEditorDrawer;

View File

@ -25,7 +25,7 @@ const useDealsAndStatusesDnd = (): ReturnType => {
const [activeDeal, setActiveDeal] = useState<DealSchema | null>(null); const [activeDeal, setActiveDeal] = useState<DealSchema | null>(null);
const [activeStatus, setActiveStatus] = useState<StatusSchema | null>(null); const [activeStatus, setActiveStatus] = useState<StatusSchema | null>(null);
const { statuses, setStatuses, statusesCrud } = useStatusesContext(); const { statuses, setStatuses, statusesCrud } = useStatusesContext();
const { deals, setDeals, updateDeal } = useDealsContext(); const { deals, setDeals, dealsCrud } = useDealsContext();
const sortedStatuses = useMemo(() => sortByLexorank(statuses), [statuses]); const sortedStatuses = useMemo(() => sortByLexorank(statuses), [statuses]);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
@ -253,17 +253,7 @@ const useDealsAndStatusesDnd = (): ReturnType => {
statusId: number, statusId: number,
lexorank?: string lexorank?: string
) => { ) => {
updateDeal.mutate({ dealsCrud.onUpdate(dealId, { statusId, lexorank, name: null });
path: {
dealId,
},
body: {
deal: {
statusId,
lexorank,
},
},
});
}; };
const handleDragStart = ({ active }: DragStartEvent) => { const handleDragStart = ({ active }: DragStartEvent) => {

View File

@ -32,7 +32,8 @@ type Props<TContainer, TItem> = {
renderContainer: ( renderContainer: (
container: TContainer, container: TContainer,
children: ReactNode, children: ReactNode,
renderDraggable: () => ReactNode renderDraggable: () => ReactNode,
index: number
) => ReactNode; ) => ReactNode;
renderContainerHeader: (container: TContainer) => ReactNode; renderContainerHeader: (container: TContainer) => ReactNode;
renderContainerOverlay: ( renderContainerOverlay: (
@ -75,7 +76,7 @@ const FunnelDnd = <
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const renderContainers = () => const renderContainers = () =>
containers.map(container => { containers.map((container, index) => {
const containerItems = getItemsByContainer(container, items); const containerItems = getItemsByContainer(container, items);
const containerId = getContainerId(container); const containerId = getContainerId(container);
return ( return (
@ -94,7 +95,8 @@ const FunnelDnd = <
items={containerItems} items={containerItems}
renderItem={renderItem} renderItem={renderItem}
/>, />,
renderDraggable! renderDraggable!,
index
) )
} }
renderDraggable={() => renderContainerHeader(container)} renderDraggable={() => renderContainerHeader(container)}

View File

@ -49,7 +49,7 @@ const useDrawersContextState = () => {
setStack(prev => setStack(prev =>
key ? prev.filter(d => d.key !== key) : prev.slice(0, -1) key ? prev.filter(d => d.key !== key) : prev.slice(0, -1)
); );
}, 1000); }, 300);
}; };
return { return {

View File

@ -1,11 +1,13 @@
import BoardStatusesEditorDrawer from "@/app/deals/drawers/BoardStatusesEditorDrawer"; import BoardStatusesEditorDrawer from "@/app/deals/drawers/BoardStatusesEditorDrawer";
import ProjectsEditorDrawer from "@/app/deals/drawers/ProjectsEditorDrawer"; import DealEditorDrawer from "@/app/deals/drawers/DealEditorDrawer/DealEditorDrawer";
import ProjectBoardsEditorDrawer from "@/app/deals/drawers/ProjectBoardsEditorDrawer"; import ProjectBoardsEditorDrawer from "@/app/deals/drawers/ProjectBoardsEditorDrawer";
import ProjectsEditorDrawer from "@/app/deals/drawers/ProjectsEditorDrawer";
const drawerRegistry = { const drawerRegistry = {
projectsEditorDrawer: ProjectsEditorDrawer, projectsEditorDrawer: ProjectsEditorDrawer,
boardStatusesEditorDrawer: BoardStatusesEditorDrawer, boardStatusesEditorDrawer: BoardStatusesEditorDrawer,
projectBoardsEditorDrawer: ProjectBoardsEditorDrawer, projectBoardsEditorDrawer: ProjectBoardsEditorDrawer,
dealEditorDrawer: DealEditorDrawer,
}; };
export default drawerRegistry; export default drawerRegistry;

View File

@ -120,7 +120,7 @@ const useCrudOperations = <
}); });
}; };
const onDelete = (entity: TEntity) => { const onDelete = (entity: TEntity, onSuccess?: () => void) => {
modals.openConfirmModal({ modals.openConfirmModal({
title: getDeleteConfirmTitle(entity), title: getDeleteConfirmTitle(entity),
children: ( children: (
@ -130,6 +130,7 @@ const useCrudOperations = <
confirmProps: { color: "red" }, confirmProps: { color: "red" },
onConfirm: () => { onConfirm: () => {
deleteMutation.mutate({ path: { pk: entity.id } } as any); deleteMutation.mutate({ path: { pk: entity.id } } as any);
onSuccess && onSuccess();
setEntities(prev => prev.filter(e => e.id !== entity.id)); setEntities(prev => prev.filter(e => e.id !== entity.id));
}, },
}); });

View File

@ -0,0 +1,76 @@
import React from "react";
import { LexoRank } from "lexorank";
import { useCrudOperations } from "@/hooks/cruds/baseCrud";
import {
CreateDealSchema,
DealSchema,
StatusSchema,
UpdateDealSchema,
} from "@/lib/client";
import {
createDealMutation,
deleteDealMutation,
updateDealMutation,
} from "@/lib/client/@tanstack/react-query.gen";
import { getNewLexorank } from "@/utils/lexorank";
type UseDealsOperationsProps = {
deals: DealSchema[];
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
refetchDeals: () => void;
boardId?: number;
statuses: StatusSchema[];
};
export type DealsCrud = {
onCreate: (name: string) => void;
onUpdate: (dealId: number, deal: UpdateDealSchema) => void;
onDelete: (deal: DealSchema, onSuccess?: () => void) => void;
};
export const useDealsCrud = ({
deals,
setDeals,
refetchDeals,
boardId,
statuses,
}: UseDealsOperationsProps): DealsCrud => {
return useCrudOperations<DealSchema, UpdateDealSchema, CreateDealSchema>({
entities: deals,
setEntities: setDeals,
refetch: refetchDeals,
mutations: {
create: createDealMutation(),
update: updateDealMutation(),
delete: deleteDealMutation(),
},
getCreateEntity: name => {
if (!boardId || statuses.length === 0) return null;
const firstStatus = statuses[0];
const filteredDeals = deals.filter(
d => d.statusId === firstStatus.id
);
let firstDeal: DealSchema | null = null;
if (filteredDeals.length > 0) {
firstDeal = filteredDeals[0];
}
const newLexorank = getNewLexorank(
null,
firstDeal ? LexoRank.parse(firstDeal.lexorank) : null
);
return {
name,
boardId,
statusId: firstStatus.id,
lexorank: newLexorank.toString(),
};
},
getUpdateEntity: (old, update) => ({
...old,
name: update.name ?? old.name,
lexorank: update.lexorank ?? old.lexorank,
statusId: update.statusId ?? old.statusId,
}),
getDeleteConfirmTitle: () => "Удаление сделки",
});
};

View File

@ -5,9 +5,11 @@ import type { AxiosError } from "axios";
import { client as _heyApiClient } from "../client.gen"; import { client as _heyApiClient } from "../client.gen";
import { import {
createBoard, createBoard,
createDeal,
createProject, createProject,
createStatus, createStatus,
deleteBoard, deleteBoard,
deleteDeal,
deleteProject, deleteProject,
deleteStatus, deleteStatus,
getBoards, getBoards,
@ -24,6 +26,9 @@ import type {
CreateBoardData, CreateBoardData,
CreateBoardError, CreateBoardError,
CreateBoardResponse2, CreateBoardResponse2,
CreateDealData,
CreateDealError,
CreateDealResponse2,
CreateProjectData, CreateProjectData,
CreateProjectError, CreateProjectError,
CreateProjectResponse2, CreateProjectResponse2,
@ -33,6 +38,9 @@ import type {
DeleteBoardData, DeleteBoardData,
DeleteBoardError, DeleteBoardError,
DeleteBoardResponse2, DeleteBoardResponse2,
DeleteDealData,
DeleteDealError,
DeleteDealResponse2,
DeleteProjectData, DeleteProjectData,
DeleteProjectError, DeleteProjectError,
DeleteProjectResponse2, DeleteProjectResponse2,
@ -237,6 +245,81 @@ export const getDealsOptions = (options: Options<GetDealsData>) => {
}); });
}; };
export const createDealQueryKey = (options: Options<CreateDealData>) =>
createQueryKey("createDeal", options);
/**
* Create Deal
*/
export const createDealOptions = (options: Options<CreateDealData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await createDeal({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: createDealQueryKey(options),
});
};
/**
* Create Deal
*/
export const createDealMutation = (
options?: Partial<Options<CreateDealData>>
): UseMutationOptions<
CreateDealResponse2,
AxiosError<CreateDealError>,
Options<CreateDealData>
> => {
const mutationOptions: UseMutationOptions<
CreateDealResponse2,
AxiosError<CreateDealError>,
Options<CreateDealData>
> = {
mutationFn: async localOptions => {
const { data } = await createDeal({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
/**
* Delete Deal
*/
export const deleteDealMutation = (
options?: Partial<Options<DeleteDealData>>
): UseMutationOptions<
DeleteDealResponse2,
AxiosError<DeleteDealError>,
Options<DeleteDealData>
> => {
const mutationOptions: UseMutationOptions<
DeleteDealResponse2,
AxiosError<DeleteDealError>,
Options<DeleteDealData>
> = {
mutationFn: async localOptions => {
const { data } = await deleteDeal({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
/** /**
* Update Deal * Update Deal
*/ */

View File

@ -6,6 +6,9 @@ import type {
CreateBoardData, CreateBoardData,
CreateBoardErrors, CreateBoardErrors,
CreateBoardResponses, CreateBoardResponses,
CreateDealData,
CreateDealErrors,
CreateDealResponses,
CreateProjectData, CreateProjectData,
CreateProjectErrors, CreateProjectErrors,
CreateProjectResponses, CreateProjectResponses,
@ -15,6 +18,9 @@ import type {
DeleteBoardData, DeleteBoardData,
DeleteBoardErrors, DeleteBoardErrors,
DeleteBoardResponses, DeleteBoardResponses,
DeleteDealData,
DeleteDealErrors,
DeleteDealResponses,
DeleteProjectData, DeleteProjectData,
DeleteProjectErrors, DeleteProjectErrors,
DeleteProjectResponses, DeleteProjectResponses,
@ -48,12 +54,16 @@ import type {
import { import {
zCreateBoardData, zCreateBoardData,
zCreateBoardResponse2, zCreateBoardResponse2,
zCreateDealData,
zCreateDealResponse2,
zCreateProjectData, zCreateProjectData,
zCreateProjectResponse2, zCreateProjectResponse2,
zCreateStatusData, zCreateStatusData,
zCreateStatusResponse2, zCreateStatusResponse2,
zDeleteBoardData, zDeleteBoardData,
zDeleteBoardResponse2, zDeleteBoardResponse2,
zDeleteDealData,
zDeleteDealResponse2,
zDeleteProjectData, zDeleteProjectData,
zDeleteProjectResponse2, zDeleteProjectResponse2,
zDeleteStatusData, zDeleteStatusData,
@ -216,6 +226,56 @@ export const getDeals = <ThrowOnError extends boolean = false>(
}); });
}; };
/**
* Create Deal
*/
export const createDeal = <ThrowOnError extends boolean = false>(
options: Options<CreateDealData, ThrowOnError>
) => {
return (options.client ?? _heyApiClient).post<
CreateDealResponses,
CreateDealErrors,
ThrowOnError
>({
requestValidator: async data => {
return await zCreateDealData.parseAsync(data);
},
responseType: "json",
responseValidator: async data => {
return await zCreateDealResponse2.parseAsync(data);
},
url: "/deal/",
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
});
};
/**
* Delete Deal
*/
export const deleteDeal = <ThrowOnError extends boolean = false>(
options: Options<DeleteDealData, ThrowOnError>
) => {
return (options.client ?? _heyApiClient).delete<
DeleteDealResponses,
DeleteDealErrors,
ThrowOnError
>({
requestValidator: async data => {
return await zDeleteDealData.parseAsync(data);
},
responseType: "json",
responseValidator: async data => {
return await zDeleteDealResponse2.parseAsync(data);
},
url: "/deal/{pk}",
...options,
});
};
/** /**
* Update Deal * Update Deal
*/ */
@ -234,7 +294,7 @@ export const updateDeal = <ThrowOnError extends boolean = false>(
responseValidator: async data => { responseValidator: async data => {
return await zUpdateDealResponse2.parseAsync(data); return await zUpdateDealResponse2.parseAsync(data);
}, },
url: "/deal/{dealId}", url: "/deal/{pk}",
...options, ...options,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@ -54,6 +54,46 @@ export type CreateBoardSchema = {
lexorank: string; lexorank: string;
}; };
/**
* CreateDealRequest
*/
export type CreateDealRequest = {
entity: CreateDealSchema;
};
/**
* CreateDealResponse
*/
export type CreateDealResponse = {
/**
* Message
*/
message: string;
entity: DealSchema;
};
/**
* CreateDealSchema
*/
export type CreateDealSchema = {
/**
* Name
*/
name: string;
/**
* Boardid
*/
boardId: number;
/**
* Lexorank
*/
lexorank: string;
/**
* Statusid
*/
statusId: number;
};
/** /**
* CreateProjectRequest * CreateProjectRequest
*/ */
@ -122,14 +162,14 @@ export type CreateStatusSchema = {
* DealSchema * DealSchema
*/ */
export type DealSchema = { export type DealSchema = {
/**
* Name
*/
name: string;
/** /**
* Id * Id
*/ */
id: number; id: number;
/**
* Name
*/
name: string;
/** /**
* Lexorank * Lexorank
*/ */
@ -150,6 +190,16 @@ export type DeleteBoardResponse = {
message: string; message: string;
}; };
/**
* DeleteDealResponse
*/
export type DeleteDealResponse = {
/**
* Message
*/
message: string;
};
/** /**
* DeleteProjectResponse * DeleteProjectResponse
*/ */
@ -287,7 +337,7 @@ export type UpdateBoardSchema = {
* UpdateDealRequest * UpdateDealRequest
*/ */
export type UpdateDealRequest = { export type UpdateDealRequest = {
deal: UpdateDealSchema; entity: UpdateDealSchema;
}; };
/** /**
@ -542,16 +592,73 @@ export type GetDealsResponses = {
export type GetDealsResponse2 = GetDealsResponses[keyof GetDealsResponses]; export type GetDealsResponse2 = GetDealsResponses[keyof GetDealsResponses];
export type CreateDealData = {
body: CreateDealRequest;
path?: never;
query?: never;
url: "/deal/";
};
export type CreateDealErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type CreateDealError = CreateDealErrors[keyof CreateDealErrors];
export type CreateDealResponses = {
/**
* Successful Response
*/
200: CreateDealResponse;
};
export type CreateDealResponse2 =
CreateDealResponses[keyof CreateDealResponses];
export type DeleteDealData = {
body?: never;
path: {
/**
* Pk
*/
pk: number;
};
query?: never;
url: "/deal/{pk}";
};
export type DeleteDealErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type DeleteDealError = DeleteDealErrors[keyof DeleteDealErrors];
export type DeleteDealResponses = {
/**
* Successful Response
*/
200: DeleteDealResponse;
};
export type DeleteDealResponse2 =
DeleteDealResponses[keyof DeleteDealResponses];
export type UpdateDealData = { export type UpdateDealData = {
body: UpdateDealRequest; body: UpdateDealRequest;
path: { path: {
/** /**
* Dealid * Pk
*/ */
dealId: number; pk: number;
}; };
query?: never; query?: never;
url: "/deal/{dealId}"; url: "/deal/{pk}";
}; };
export type UpdateDealErrors = { export type UpdateDealErrors = {

View File

@ -35,6 +35,41 @@ export const zCreateBoardResponse = z.object({
entity: zBoardSchema, entity: zBoardSchema,
}); });
/**
* CreateDealSchema
*/
export const zCreateDealSchema = z.object({
name: z.string(),
boardId: z.int(),
lexorank: z.string(),
statusId: z.int(),
});
/**
* CreateDealRequest
*/
export const zCreateDealRequest = z.object({
entity: zCreateDealSchema,
});
/**
* DealSchema
*/
export const zDealSchema = z.object({
id: z.int(),
name: z.string(),
lexorank: z.string(),
statusId: z.int(),
});
/**
* CreateDealResponse
*/
export const zCreateDealResponse = z.object({
message: z.string(),
entity: zDealSchema,
});
/** /**
* CreateProjectSchema * CreateProjectSchema
*/ */
@ -98,16 +133,6 @@ export const zCreateStatusResponse = z.object({
entity: zStatusSchema, entity: zStatusSchema,
}); });
/**
* DealSchema
*/
export const zDealSchema = z.object({
name: z.string(),
id: z.int(),
lexorank: z.string(),
statusId: z.int(),
});
/** /**
* DeleteBoardResponse * DeleteBoardResponse
*/ */
@ -115,6 +140,13 @@ export const zDeleteBoardResponse = z.object({
message: z.string(), message: z.string(),
}); });
/**
* DeleteDealResponse
*/
export const zDeleteDealResponse = z.object({
message: z.string(),
});
/** /**
* DeleteProjectResponse * DeleteProjectResponse
*/ */
@ -208,7 +240,7 @@ export const zUpdateDealSchema = z.object({
* UpdateDealRequest * UpdateDealRequest
*/ */
export const zUpdateDealRequest = z.object({ export const zUpdateDealRequest = z.object({
deal: zUpdateDealSchema, entity: zUpdateDealSchema,
}); });
/** /**
@ -324,10 +356,34 @@ export const zGetDealsData = z.object({
*/ */
export const zGetDealsResponse2 = zGetDealsResponse; export const zGetDealsResponse2 = zGetDealsResponse;
export const zCreateDealData = z.object({
body: zCreateDealRequest,
path: z.optional(z.never()),
query: z.optional(z.never()),
});
/**
* Successful Response
*/
export const zCreateDealResponse2 = zCreateDealResponse;
export const zDeleteDealData = z.object({
body: z.optional(z.never()),
path: z.object({
pk: z.int(),
}),
query: z.optional(z.never()),
});
/**
* Successful Response
*/
export const zDeleteDealResponse2 = zDeleteDealResponse;
export const zUpdateDealData = z.object({ export const zUpdateDealData = z.object({
body: zUpdateDealRequest, body: zUpdateDealRequest,
path: z.object({ path: z.object({
dealId: z.int(), pk: z.int(),
}), }),
query: z.optional(z.never()), query: z.optional(z.never()),
}); });