feat: status editing and deleting
This commit is contained in:
@ -4,14 +4,14 @@ import React, { FC, ReactNode } from "react";
|
|||||||
import DealCard from "@/app/deals/components/DealCard/DealCard";
|
import DealCard from "@/app/deals/components/DealCard/DealCard";
|
||||||
import DealContainer from "@/app/deals/components/DealContainer/DealContainer";
|
import DealContainer from "@/app/deals/components/DealContainer/DealContainer";
|
||||||
import StatusColumnWrapper from "@/app/deals/components/StatusColumnWrapper/StatusColumnWrapper";
|
import StatusColumnWrapper from "@/app/deals/components/StatusColumnWrapper/StatusColumnWrapper";
|
||||||
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
|
||||||
import useDealsAndStatusesDnd from "@/app/deals/hooks/useDealsAndStatusesDnd";
|
import useDealsAndStatusesDnd from "@/app/deals/hooks/useDealsAndStatusesDnd";
|
||||||
import FunnelDnd from "@/components/dnd/FunnelDnd/FunnelDnd";
|
import FunnelDnd from "@/components/dnd/FunnelDnd/FunnelDnd";
|
||||||
import { DealSchema, StatusSchema } from "@/lib/client";
|
import { DealSchema, StatusSchema } from "@/lib/client";
|
||||||
import { sortByLexorank } from "@/utils/lexorank";
|
import { sortByLexorank } from "@/utils/lexorank";
|
||||||
|
|
||||||
const Funnel: FC = () => {
|
const Funnel: FC = () => {
|
||||||
const { deals } = useStatusesContext();
|
const { deals } = useDealsContext();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
sortedStatuses,
|
sortedStatuses,
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { Box, Text } from "@mantine/core";
|
import { Box, Group, Text, TextInput } from "@mantine/core";
|
||||||
|
import StatusMenu from "@/app/deals/components/StatusColumnWrapper/StatusMenu";
|
||||||
|
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
||||||
import { StatusSchema } from "@/lib/client";
|
import { StatusSchema } from "@/lib/client";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -13,23 +15,98 @@ const StatusColumnWrapper = ({
|
|||||||
children,
|
children,
|
||||||
isDragging = false,
|
isDragging = false,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const { onUpdateStatus } = useStatusesContext();
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
const [editValue, setEditValue] = useState(status.name);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEditing && inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
}, [isEditing]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (
|
||||||
|
isEditing &&
|
||||||
|
inputRef.current &&
|
||||||
|
!inputRef.current.contains(event.target as Node)
|
||||||
|
) {
|
||||||
|
handleSave();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () =>
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
}, [isEditing, editValue]);
|
||||||
|
|
||||||
|
const handleEdit = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
setEditValue(status.name);
|
||||||
|
setIsEditing(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
const newValue = editValue.trim();
|
||||||
|
if (newValue && newValue !== status.name) {
|
||||||
|
onUpdateStatus(status.id, { name: newValue });
|
||||||
|
}
|
||||||
|
setIsEditing(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
p={"xs"}
|
||||||
style={{
|
style={{
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: "gray",
|
borderColor: "gray",
|
||||||
padding: 2,
|
|
||||||
width: "15vw",
|
width: "15vw",
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
}}>
|
}}>
|
||||||
<Text
|
<Group
|
||||||
style={{
|
wrap={"nowrap"}
|
||||||
cursor: "grab",
|
justify={"space-between"}
|
||||||
userSelect: "none",
|
ml={"xs"}
|
||||||
opacity: isDragging ? 0.5 : 1,
|
mb={"xs"}>
|
||||||
}}>
|
{isEditing ? (
|
||||||
{status.name}
|
<TextInput
|
||||||
</Text>
|
ref={inputRef}
|
||||||
|
value={editValue}
|
||||||
|
onChange={e => setEditValue(e.target.value)}
|
||||||
|
onKeyDown={e => {
|
||||||
|
if (e.key === "Enter") handleSave();
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
setEditValue(status.name);
|
||||||
|
setIsEditing(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="unstyled"
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
height: 25,
|
||||||
|
minHeight: 25,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
cursor: "grab",
|
||||||
|
userSelect: "none",
|
||||||
|
opacity: isDragging ? 0.5 : 1,
|
||||||
|
}}>
|
||||||
|
{status.name}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<StatusMenu
|
||||||
|
status={status}
|
||||||
|
handleEdit={handleEdit}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
48
src/app/deals/components/StatusColumnWrapper/StatusMenu.tsx
Normal file
48
src/app/deals/components/StatusColumnWrapper/StatusMenu.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React, { FC } from "react";
|
||||||
|
import { IconDotsVertical, IconEdit, IconTrash } from "@tabler/icons-react";
|
||||||
|
import { Box, Group, Menu, Text } from "@mantine/core";
|
||||||
|
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
||||||
|
import { StatusSchema } from "@/lib/client";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
status: StatusSchema;
|
||||||
|
handleEdit: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StatusMenu: FC<Props> = ({ status, handleEdit }) => {
|
||||||
|
const { onDeleteStatus } = useStatusesContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<Menu.Target>
|
||||||
|
<Box
|
||||||
|
p={5}
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}>
|
||||||
|
<IconDotsVertical size={16} />
|
||||||
|
</Box>
|
||||||
|
</Menu.Target>
|
||||||
|
<Menu.Dropdown>
|
||||||
|
<Menu.Item onClick={handleEdit}>
|
||||||
|
<Group wrap={"nowrap"}>
|
||||||
|
<IconEdit />
|
||||||
|
<Text>Переименовать</Text>
|
||||||
|
</Group>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item onClick={() => onDeleteStatus(status.id)}>
|
||||||
|
<Group wrap={"nowrap"}>
|
||||||
|
<IconTrash />
|
||||||
|
<Text>Удалить</Text>
|
||||||
|
</Group>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatusMenu;
|
||||||
80
src/app/deals/contexts/DealsContext.tsx
Normal file
80
src/app/deals/contexts/DealsContext.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
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 useDealsList from "@/hooks/useDealsList";
|
||||||
|
import {
|
||||||
|
DealSchema,
|
||||||
|
HttpValidationError,
|
||||||
|
Options,
|
||||||
|
UpdateDealData,
|
||||||
|
UpdateDealResponse,
|
||||||
|
} from "@/lib/client";
|
||||||
|
import { updateDealMutation } from "@/lib/client/@tanstack/react-query.gen";
|
||||||
|
import { notifications } from "@/lib/notifications";
|
||||||
|
|
||||||
|
type DealsContextState = {
|
||||||
|
deals: DealSchema[];
|
||||||
|
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
|
||||||
|
updateDeal: UseMutationResult<
|
||||||
|
UpdateDealResponse,
|
||||||
|
AxiosError<HttpValidationError>,
|
||||||
|
Options<UpdateDealData>
|
||||||
|
>;
|
||||||
|
refetchDeals: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DealsContext = createContext<DealsContextState | undefined>(undefined);
|
||||||
|
|
||||||
|
const useDealsContextState = () => {
|
||||||
|
const { selectedBoard } = useBoardsContext();
|
||||||
|
const {
|
||||||
|
deals,
|
||||||
|
setDeals,
|
||||||
|
refetch: refetchDeals,
|
||||||
|
} = useDealsList({ boardId: selectedBoard?.id });
|
||||||
|
|
||||||
|
const updateDeal = useMutation({
|
||||||
|
...updateDealMutation(),
|
||||||
|
onError: error => {
|
||||||
|
console.error(error);
|
||||||
|
notifications.error({
|
||||||
|
message: error.response?.data?.detail as string | undefined,
|
||||||
|
});
|
||||||
|
refetchDeals();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
deals,
|
||||||
|
setDeals,
|
||||||
|
updateDeal,
|
||||||
|
refetchDeals,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type DealsContextProviderProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DealsContextProvider: FC<DealsContextProviderProps> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const state = useDealsContextState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DealsContext.Provider value={state}>{children}</DealsContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDealsContext = () => {
|
||||||
|
const context = useContext(DealsContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
"useDealsContext must be used within a DealsContextProvider"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@ -4,22 +4,17 @@ import React, { createContext, FC, useContext, useEffect } from "react";
|
|||||||
import { useMutation, UseMutationResult } from "@tanstack/react-query";
|
import { useMutation, UseMutationResult } from "@tanstack/react-query";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
||||||
import useDealsList from "@/hooks/useDealsList";
|
|
||||||
import useStatusesList from "@/hooks/useStatusesList";
|
import useStatusesList from "@/hooks/useStatusesList";
|
||||||
|
import { useStatusesOperations } from "@/hooks/useStatusesOperations";
|
||||||
import {
|
import {
|
||||||
DealSchema,
|
|
||||||
HttpValidationError,
|
HttpValidationError,
|
||||||
Options,
|
Options,
|
||||||
StatusSchema,
|
StatusSchema,
|
||||||
UpdateDealData,
|
|
||||||
UpdateDealResponse,
|
|
||||||
UpdateStatusData,
|
UpdateStatusData,
|
||||||
UpdateStatusResponse,
|
UpdateStatusResponse,
|
||||||
|
UpdateStatusSchema,
|
||||||
} from "@/lib/client";
|
} from "@/lib/client";
|
||||||
import {
|
import { updateStatusMutation } from "@/lib/client/@tanstack/react-query.gen";
|
||||||
updateDealMutation,
|
|
||||||
updateStatusMutation,
|
|
||||||
} from "@/lib/client/@tanstack/react-query.gen";
|
|
||||||
import { notifications } from "@/lib/notifications";
|
import { notifications } from "@/lib/notifications";
|
||||||
|
|
||||||
type StatusesContextState = {
|
type StatusesContextState = {
|
||||||
@ -31,14 +26,9 @@ type StatusesContextState = {
|
|||||||
Options<UpdateStatusData>
|
Options<UpdateStatusData>
|
||||||
>;
|
>;
|
||||||
refetchStatuses: () => void;
|
refetchStatuses: () => void;
|
||||||
deals: DealSchema[];
|
onCreateStatus: (name: string) => void;
|
||||||
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
|
onUpdateStatus: (statusId: number, status: UpdateStatusSchema) => void;
|
||||||
updateDeal: UseMutationResult<
|
onDeleteStatus: (statusId: number) => void;
|
||||||
UpdateDealResponse,
|
|
||||||
AxiosError<HttpValidationError>,
|
|
||||||
Options<UpdateDealData>
|
|
||||||
>;
|
|
||||||
refetchDeals: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatusesContext = createContext<StatusesContextState | undefined>(
|
const StatusesContext = createContext<StatusesContextState | undefined>(
|
||||||
@ -55,12 +45,6 @@ const useStatusesContextState = () => {
|
|||||||
boardId: selectedBoard?.id,
|
boardId: selectedBoard?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
|
||||||
deals,
|
|
||||||
setDeals,
|
|
||||||
refetch: refetchDeals,
|
|
||||||
} = useDealsList({ boardId: selectedBoard?.id });
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refetchStatuses();
|
refetchStatuses();
|
||||||
}, [selectedBoard]);
|
}, [selectedBoard]);
|
||||||
@ -76,26 +60,22 @@ const useStatusesContextState = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateDeal = useMutation({
|
const { onCreateStatus, onUpdateStatus, onDeleteStatus } =
|
||||||
...updateDealMutation(),
|
useStatusesOperations({
|
||||||
onError: error => {
|
statuses,
|
||||||
console.error(error);
|
setStatuses,
|
||||||
notifications.error({
|
refetchStatuses,
|
||||||
message: error.response?.data?.detail as string | undefined,
|
boardId: selectedBoard?.id,
|
||||||
});
|
});
|
||||||
refetchDeals();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statuses,
|
statuses,
|
||||||
setStatuses,
|
setStatuses,
|
||||||
updateStatus,
|
updateStatus,
|
||||||
refetchStatuses,
|
refetchStatuses,
|
||||||
deals,
|
onCreateStatus,
|
||||||
setDeals,
|
onUpdateStatus,
|
||||||
updateDeal,
|
onDeleteStatus,
|
||||||
refetchDeals,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { DragOverEvent, DragStartEvent, Over } from "@dnd-kit/core";
|
import { DragOverEvent, DragStartEvent, Over } from "@dnd-kit/core";
|
||||||
import { useDebouncedCallback } from "@mantine/hooks";
|
import { useDebouncedCallback } from "@mantine/hooks";
|
||||||
|
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
|
||||||
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
||||||
import useGetNewRank from "@/app/deals/hooks/useGetNewRank";
|
import useGetNewRank from "@/app/deals/hooks/useGetNewRank";
|
||||||
import { getStatusId, isStatusId } from "@/app/deals/utils/statusId";
|
import { getStatusId, isStatusId } from "@/app/deals/utils/statusId";
|
||||||
@ -10,8 +11,8 @@ import { sortByLexorank } from "@/utils/lexorank";
|
|||||||
const useDealsAndStatusesDnd = () => {
|
const useDealsAndStatusesDnd = () => {
|
||||||
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, deals, setDeals, setStatuses, updateDeal, updateStatus } =
|
const { statuses, setStatuses, updateStatus } = useStatusesContext();
|
||||||
useStatusesContext();
|
const { deals, setDeals, updateDeal } = useDealsContext();
|
||||||
const sortedStatuses = useMemo(() => sortByLexorank(statuses), [statuses]);
|
const sortedStatuses = useMemo(() => sortByLexorank(statuses), [statuses]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext";
|
|||||||
import { StatusesContextProvider } from "@/app/deals/contexts/StatusesContext";
|
import { StatusesContextProvider } from "@/app/deals/contexts/StatusesContext";
|
||||||
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
||||||
import PageContainer from "@/components/layout/PageContainer/PageContainer";
|
import PageContainer from "@/components/layout/PageContainer/PageContainer";
|
||||||
|
import { DealsContextProvider } from "./contexts/DealsContext";
|
||||||
|
|
||||||
export default function DealsPage() {
|
export default function DealsPage() {
|
||||||
return (
|
return (
|
||||||
@ -18,7 +19,9 @@ export default function DealsPage() {
|
|||||||
<Boards />
|
<Boards />
|
||||||
<Divider my={"xl"} />
|
<Divider my={"xl"} />
|
||||||
<StatusesContextProvider>
|
<StatusesContextProvider>
|
||||||
<Funnel />
|
<DealsContextProvider>
|
||||||
|
<Funnel />
|
||||||
|
</DealsContextProvider>
|
||||||
</StatusesContextProvider>
|
</StatusesContextProvider>
|
||||||
</BoardsContextProvider>
|
</BoardsContextProvider>
|
||||||
</ProjectsContextProvider>
|
</ProjectsContextProvider>
|
||||||
|
|||||||
110
src/hooks/useStatusesOperations.ts
Normal file
110
src/hooks/useStatusesOperations.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import { LexoRank } from "lexorank";
|
||||||
|
import {
|
||||||
|
HttpValidationError,
|
||||||
|
StatusSchema,
|
||||||
|
UpdateStatusSchema,
|
||||||
|
} from "@/lib/client";
|
||||||
|
import {
|
||||||
|
createStatusMutation,
|
||||||
|
deleteStatusMutation,
|
||||||
|
updateStatusMutation,
|
||||||
|
} from "@/lib/client/@tanstack/react-query.gen";
|
||||||
|
import { notifications } from "@/lib/notifications";
|
||||||
|
import { getMaxByLexorank, getNewLexorank } from "@/utils/lexorank";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
statuses: StatusSchema[];
|
||||||
|
setStatuses: React.Dispatch<React.SetStateAction<StatusSchema[]>>;
|
||||||
|
refetchStatuses: () => void;
|
||||||
|
boardId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useStatusesOperations = ({
|
||||||
|
statuses,
|
||||||
|
setStatuses,
|
||||||
|
refetchStatuses,
|
||||||
|
boardId,
|
||||||
|
}: Props) => {
|
||||||
|
const onError = (error: AxiosError<HttpValidationError>) => {
|
||||||
|
console.error(error);
|
||||||
|
notifications.error({
|
||||||
|
message: error.response?.data?.detail as string | undefined,
|
||||||
|
});
|
||||||
|
refetchStatuses();
|
||||||
|
};
|
||||||
|
|
||||||
|
const createStatus = useMutation({
|
||||||
|
...createStatusMutation(),
|
||||||
|
onError,
|
||||||
|
onSuccess: res => {
|
||||||
|
setStatuses([...statuses, res.status]);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateStatus = useMutation({
|
||||||
|
...updateStatusMutation(),
|
||||||
|
onError,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteStatus = useMutation({
|
||||||
|
...deleteStatusMutation(),
|
||||||
|
onError,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onCreateStatus = (name: string) => {
|
||||||
|
if (!boardId) return;
|
||||||
|
const lastStatus = getMaxByLexorank(statuses);
|
||||||
|
const newLexorank = getNewLexorank(
|
||||||
|
lastStatus ? LexoRank.parse(lastStatus.lexorank) : null
|
||||||
|
);
|
||||||
|
|
||||||
|
createStatus.mutate({
|
||||||
|
body: {
|
||||||
|
status: {
|
||||||
|
name,
|
||||||
|
boardId,
|
||||||
|
lexorank: newLexorank.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUpdateStatus = (statusId: number, status: UpdateStatusSchema) => {
|
||||||
|
updateStatus.mutate({
|
||||||
|
path: { statusId },
|
||||||
|
body: { status },
|
||||||
|
});
|
||||||
|
|
||||||
|
setStatuses(statuses =>
|
||||||
|
statuses.map(oldStatus =>
|
||||||
|
oldStatus.id !== statusId
|
||||||
|
? oldStatus
|
||||||
|
: {
|
||||||
|
id: oldStatus.id,
|
||||||
|
name: status.name ? status.name : oldStatus.name,
|
||||||
|
lexorank: status.lexorank
|
||||||
|
? status.lexorank
|
||||||
|
: oldStatus.lexorank,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteStatus = (statusId: number) => {
|
||||||
|
deleteStatus.mutate({
|
||||||
|
path: { statusId },
|
||||||
|
});
|
||||||
|
setStatuses(statuses =>
|
||||||
|
statuses.filter(status => status.id !== statusId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onCreateStatus,
|
||||||
|
onUpdateStatus,
|
||||||
|
onDeleteStatus,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,8 +1,8 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
// This file is auto-generated by @hey-api/openapi-ts
|
||||||
|
|
||||||
import { type Options, getBoards, createBoard, deleteBoard, updateBoard, getDeals, updateDeal, getProjects, getStatuses, updateStatus } from '../sdk.gen';
|
import { type Options, getBoards, createBoard, deleteBoard, updateBoard, getDeals, updateDeal, getProjects, getStatuses, createStatus, deleteStatus, updateStatus } from '../sdk.gen';
|
||||||
import { queryOptions, type UseMutationOptions } from '@tanstack/react-query';
|
import { queryOptions, type UseMutationOptions } from '@tanstack/react-query';
|
||||||
import type { GetBoardsData, CreateBoardData, CreateBoardError, CreateBoardResponse2, DeleteBoardData, DeleteBoardError, DeleteBoardResponse2, UpdateBoardData, UpdateBoardError, UpdateBoardResponse2, GetDealsData, UpdateDealData, UpdateDealError, UpdateDealResponse2, GetProjectsData, GetStatusesData, UpdateStatusData, UpdateStatusError, UpdateStatusResponse2 } from '../types.gen';
|
import type { GetBoardsData, CreateBoardData, CreateBoardError, CreateBoardResponse2, DeleteBoardData, DeleteBoardError, DeleteBoardResponse2, UpdateBoardData, UpdateBoardError, UpdateBoardResponse2, GetDealsData, UpdateDealData, UpdateDealError, UpdateDealResponse2, GetProjectsData, GetStatusesData, CreateStatusData, CreateStatusError, CreateStatusResponse2, DeleteStatusData, DeleteStatusError, DeleteStatusResponse2, UpdateStatusData, UpdateStatusError, UpdateStatusResponse2 } from '../types.gen';
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
import { client as _heyApiClient } from '../client.gen';
|
import { client as _heyApiClient } from '../client.gen';
|
||||||
|
|
||||||
@ -205,6 +205,60 @@ export const getStatusesOptions = (options: Options<GetStatusesData>) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createStatusQueryKey = (options: Options<CreateStatusData>) => createQueryKey('createStatus', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Status
|
||||||
|
*/
|
||||||
|
export const createStatusOptions = (options: Options<CreateStatusData>) => {
|
||||||
|
return queryOptions({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await createStatus({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: createStatusQueryKey(options)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Status
|
||||||
|
*/
|
||||||
|
export const createStatusMutation = (options?: Partial<Options<CreateStatusData>>): UseMutationOptions<CreateStatusResponse2, AxiosError<CreateStatusError>, Options<CreateStatusData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<CreateStatusResponse2, AxiosError<CreateStatusError>, Options<CreateStatusData>> = {
|
||||||
|
mutationFn: async (localOptions) => {
|
||||||
|
const { data } = await createStatus({
|
||||||
|
...options,
|
||||||
|
...localOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Status
|
||||||
|
*/
|
||||||
|
export const deleteStatusMutation = (options?: Partial<Options<DeleteStatusData>>): UseMutationOptions<DeleteStatusResponse2, AxiosError<DeleteStatusError>, Options<DeleteStatusData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<DeleteStatusResponse2, AxiosError<DeleteStatusError>, Options<DeleteStatusData>> = {
|
||||||
|
mutationFn: async (localOptions) => {
|
||||||
|
const { data } = await deleteStatus({
|
||||||
|
...options,
|
||||||
|
...localOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Status
|
* Update Status
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
// This file is auto-generated by @hey-api/openapi-ts
|
||||||
|
|
||||||
import type { Options as ClientOptions, TDataShape, Client } from './client';
|
import type { Options as ClientOptions, TDataShape, Client } from './client';
|
||||||
import type { GetBoardsData, GetBoardsResponses, GetBoardsErrors, CreateBoardData, CreateBoardResponses, CreateBoardErrors, DeleteBoardData, DeleteBoardResponses, DeleteBoardErrors, UpdateBoardData, UpdateBoardResponses, UpdateBoardErrors, GetDealsData, GetDealsResponses, GetDealsErrors, UpdateDealData, UpdateDealResponses, UpdateDealErrors, GetProjectsData, GetProjectsResponses, GetStatusesData, GetStatusesResponses, GetStatusesErrors, UpdateStatusData, UpdateStatusResponses, UpdateStatusErrors } from './types.gen';
|
import type { GetBoardsData, GetBoardsResponses, GetBoardsErrors, CreateBoardData, CreateBoardResponses, CreateBoardErrors, DeleteBoardData, DeleteBoardResponses, DeleteBoardErrors, UpdateBoardData, UpdateBoardResponses, UpdateBoardErrors, GetDealsData, GetDealsResponses, GetDealsErrors, UpdateDealData, UpdateDealResponses, UpdateDealErrors, GetProjectsData, GetProjectsResponses, GetStatusesData, GetStatusesResponses, GetStatusesErrors, CreateStatusData, CreateStatusResponses, CreateStatusErrors, DeleteStatusData, DeleteStatusResponses, DeleteStatusErrors, UpdateStatusData, UpdateStatusResponses, UpdateStatusErrors } from './types.gen';
|
||||||
import { zGetBoardsData, zGetBoardsResponse2, zCreateBoardData, zCreateBoardResponse2, zDeleteBoardData, zDeleteBoardResponse2, zUpdateBoardData, zUpdateBoardResponse2, zGetDealsData, zGetDealsResponse2, zUpdateDealData, zUpdateDealResponse2, zGetProjectsData, zGetProjectsResponse2, zGetStatusesData, zGetStatusesResponse2, zUpdateStatusData, zUpdateStatusResponse2 } from './zod.gen';
|
import { zGetBoardsData, zGetBoardsResponse2, zCreateBoardData, zCreateBoardResponse2, zDeleteBoardData, zDeleteBoardResponse2, zUpdateBoardData, zUpdateBoardResponse2, zGetDealsData, zGetDealsResponse2, zUpdateDealData, zUpdateDealResponse2, zGetProjectsData, zGetProjectsResponse2, zGetStatusesData, zGetStatusesResponse2, zCreateStatusData, zCreateStatusResponse2, zDeleteStatusData, zDeleteStatusResponse2, zUpdateStatusData, zUpdateStatusResponse2 } from './zod.gen';
|
||||||
import { client as _heyApiClient } from './client.gen';
|
import { client as _heyApiClient } from './client.gen';
|
||||||
|
|
||||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
||||||
@ -167,6 +167,44 @@ export const getStatuses = <ThrowOnError extends boolean = false>(options: Optio
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Status
|
||||||
|
*/
|
||||||
|
export const createStatus = <ThrowOnError extends boolean = false>(options: Options<CreateStatusData, ThrowOnError>) => {
|
||||||
|
return (options.client ?? _heyApiClient).post<CreateStatusResponses, CreateStatusErrors, ThrowOnError>({
|
||||||
|
requestValidator: async (data) => {
|
||||||
|
return await zCreateStatusData.parseAsync(data);
|
||||||
|
},
|
||||||
|
responseType: 'json',
|
||||||
|
responseValidator: async (data) => {
|
||||||
|
return await zCreateStatusResponse2.parseAsync(data);
|
||||||
|
},
|
||||||
|
url: '/status/',
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...options.headers
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Status
|
||||||
|
*/
|
||||||
|
export const deleteStatus = <ThrowOnError extends boolean = false>(options: Options<DeleteStatusData, ThrowOnError>) => {
|
||||||
|
return (options.client ?? _heyApiClient).delete<DeleteStatusResponses, DeleteStatusErrors, ThrowOnError>({
|
||||||
|
requestValidator: async (data) => {
|
||||||
|
return await zDeleteStatusData.parseAsync(data);
|
||||||
|
},
|
||||||
|
responseType: 'json',
|
||||||
|
responseValidator: async (data) => {
|
||||||
|
return await zDeleteStatusResponse2.parseAsync(data);
|
||||||
|
},
|
||||||
|
url: '/status/{statusId}',
|
||||||
|
...options
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Status
|
* Update Status
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -54,6 +54,42 @@ export type CreateBoardSchema = {
|
|||||||
lexorank: string;
|
lexorank: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusRequest
|
||||||
|
*/
|
||||||
|
export type CreateStatusRequest = {
|
||||||
|
status: CreateStatusSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusResponse
|
||||||
|
*/
|
||||||
|
export type CreateStatusResponse = {
|
||||||
|
/**
|
||||||
|
* Message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
status: StatusSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusSchema
|
||||||
|
*/
|
||||||
|
export type CreateStatusSchema = {
|
||||||
|
/**
|
||||||
|
* Name
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* Boardid
|
||||||
|
*/
|
||||||
|
boardId: number;
|
||||||
|
/**
|
||||||
|
* Lexorank
|
||||||
|
*/
|
||||||
|
lexorank: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DealSchema
|
* DealSchema
|
||||||
*/
|
*/
|
||||||
@ -86,6 +122,16 @@ export type DeleteBoardResponse = {
|
|||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteStatusResponse
|
||||||
|
*/
|
||||||
|
export type DeleteStatusResponse = {
|
||||||
|
/**
|
||||||
|
* Message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetBoardsResponse
|
* GetBoardsResponse
|
||||||
*/
|
*/
|
||||||
@ -154,14 +200,14 @@ export type ProjectSchema = {
|
|||||||
* StatusSchema
|
* StatusSchema
|
||||||
*/
|
*/
|
||||||
export type StatusSchema = {
|
export type StatusSchema = {
|
||||||
/**
|
|
||||||
* Name
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
/**
|
||||||
* Id
|
* Id
|
||||||
*/
|
*/
|
||||||
id: number;
|
id: number;
|
||||||
|
/**
|
||||||
|
* Name
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
/**
|
/**
|
||||||
* Lexorank
|
* Lexorank
|
||||||
*/
|
*/
|
||||||
@ -504,6 +550,61 @@ export type GetStatusesResponses = {
|
|||||||
|
|
||||||
export type GetStatusesResponse2 = GetStatusesResponses[keyof GetStatusesResponses];
|
export type GetStatusesResponse2 = GetStatusesResponses[keyof GetStatusesResponses];
|
||||||
|
|
||||||
|
export type CreateStatusData = {
|
||||||
|
body: CreateStatusRequest;
|
||||||
|
path?: never;
|
||||||
|
query?: never;
|
||||||
|
url: '/status/';
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateStatusErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateStatusError = CreateStatusErrors[keyof CreateStatusErrors];
|
||||||
|
|
||||||
|
export type CreateStatusResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: CreateStatusResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateStatusResponse2 = CreateStatusResponses[keyof CreateStatusResponses];
|
||||||
|
|
||||||
|
export type DeleteStatusData = {
|
||||||
|
body?: never;
|
||||||
|
path: {
|
||||||
|
/**
|
||||||
|
* Statusid
|
||||||
|
*/
|
||||||
|
statusId: number;
|
||||||
|
};
|
||||||
|
query?: never;
|
||||||
|
url: '/status/{statusId}';
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteStatusErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteStatusError = DeleteStatusErrors[keyof DeleteStatusErrors];
|
||||||
|
|
||||||
|
export type DeleteStatusResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: DeleteStatusResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteStatusResponse2 = DeleteStatusResponses[keyof DeleteStatusResponses];
|
||||||
|
|
||||||
export type UpdateStatusData = {
|
export type UpdateStatusData = {
|
||||||
body: UpdateStatusRequest;
|
body: UpdateStatusRequest;
|
||||||
path: {
|
path: {
|
||||||
|
|||||||
@ -35,6 +35,39 @@ export const zCreateBoardResponse = z.object({
|
|||||||
board: zBoardSchema
|
board: zBoardSchema
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusSchema
|
||||||
|
*/
|
||||||
|
export const zCreateStatusSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
boardId: z.int(),
|
||||||
|
lexorank: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusRequest
|
||||||
|
*/
|
||||||
|
export const zCreateStatusRequest = z.object({
|
||||||
|
status: zCreateStatusSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StatusSchema
|
||||||
|
*/
|
||||||
|
export const zStatusSchema = z.object({
|
||||||
|
id: z.int(),
|
||||||
|
name: z.string(),
|
||||||
|
lexorank: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateStatusResponse
|
||||||
|
*/
|
||||||
|
export const zCreateStatusResponse = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
status: zStatusSchema
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DealSchema
|
* DealSchema
|
||||||
*/
|
*/
|
||||||
@ -52,6 +85,13 @@ export const zDeleteBoardResponse = z.object({
|
|||||||
message: z.string()
|
message: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeleteStatusResponse
|
||||||
|
*/
|
||||||
|
export const zDeleteStatusResponse = z.object({
|
||||||
|
message: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetBoardsResponse
|
* GetBoardsResponse
|
||||||
*/
|
*/
|
||||||
@ -81,15 +121,6 @@ export const zGetProjectsResponse = z.object({
|
|||||||
projects: z.array(zProjectSchema)
|
projects: z.array(zProjectSchema)
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* StatusSchema
|
|
||||||
*/
|
|
||||||
export const zStatusSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
id: z.int(),
|
|
||||||
lexorank: z.string()
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetStatusesResponse
|
* GetStatusesResponse
|
||||||
*/
|
*/
|
||||||
@ -304,6 +335,30 @@ export const zGetStatusesData = z.object({
|
|||||||
*/
|
*/
|
||||||
export const zGetStatusesResponse2 = zGetStatusesResponse;
|
export const zGetStatusesResponse2 = zGetStatusesResponse;
|
||||||
|
|
||||||
|
export const zCreateStatusData = z.object({
|
||||||
|
body: zCreateStatusRequest,
|
||||||
|
path: z.optional(z.never()),
|
||||||
|
query: z.optional(z.never())
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
export const zCreateStatusResponse2 = zCreateStatusResponse;
|
||||||
|
|
||||||
|
export const zDeleteStatusData = z.object({
|
||||||
|
body: z.optional(z.never()),
|
||||||
|
path: z.object({
|
||||||
|
statusId: z.int()
|
||||||
|
}),
|
||||||
|
query: z.optional(z.never())
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
export const zDeleteStatusResponse2 = zDeleteStatusResponse;
|
||||||
|
|
||||||
export const zUpdateStatusData = z.object({
|
export const zUpdateStatusData = z.object({
|
||||||
body: zUpdateStatusRequest,
|
body: zUpdateStatusRequest,
|
||||||
path: z.object({
|
path: z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user