feat: status updating on the server and statuses fetching
This commit is contained in:
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { AxiosError } from "axios";
|
|
||||||
import { ScrollArea } from "@mantine/core";
|
import { ScrollArea } from "@mantine/core";
|
||||||
import Board from "@/app/deals/components/Board/Board";
|
import Board from "@/app/deals/components/Board/Board";
|
||||||
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
||||||
@ -10,17 +9,16 @@ import { BoardSchema } from "@/client";
|
|||||||
import { updateBoardMutation } from "@/client/@tanstack/react-query.gen";
|
import { updateBoardMutation } from "@/client/@tanstack/react-query.gen";
|
||||||
import SortableDnd from "@/components/SortableDnd";
|
import SortableDnd from "@/components/SortableDnd";
|
||||||
import { notifications } from "@/lib/notifications";
|
import { notifications } from "@/lib/notifications";
|
||||||
import { ErrorBody } from "@/types/ErrorBody";
|
|
||||||
|
|
||||||
const Boards = () => {
|
const Boards = () => {
|
||||||
const { boards, setSelectedBoard, refetchBoards } = useBoardsContext();
|
const { boards, setSelectedBoard, refetchBoards } = useBoardsContext();
|
||||||
|
|
||||||
const updateBoard = useMutation({
|
const updateBoard = useMutation({
|
||||||
...updateBoardMutation(),
|
...updateBoardMutation(),
|
||||||
onError: (error: AxiosError<ErrorBody>) => {
|
onError: error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
notifications.error({
|
notifications.error({
|
||||||
message: error.response?.data?.detail,
|
message: error.response?.data?.detail as string | undefined,
|
||||||
});
|
});
|
||||||
refetchBoards();
|
refetchBoards();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,25 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import StatusColumnsDnd from "@/app/deals/components/StatusColumnsDnd/StatusColumnsDnd";
|
import StatusColumnsDnd from "@/app/deals/components/StatusColumnsDnd/StatusColumnsDnd";
|
||||||
|
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
|
||||||
|
import { updateStatusMutation } from "@/client/@tanstack/react-query.gen";
|
||||||
|
import { notifications } from "@/lib/notifications";
|
||||||
|
|
||||||
const StatusColumns = () => {
|
const StatusColumns = () => {
|
||||||
|
const { refetchStatuses } = useStatusesContext();
|
||||||
|
|
||||||
|
const updateStatus = useMutation({
|
||||||
|
...updateStatusMutation(),
|
||||||
|
onError: error => {
|
||||||
|
console.error(error);
|
||||||
|
notifications.error({
|
||||||
|
message: error.response?.data?.detail as string | undefined,
|
||||||
|
});
|
||||||
|
refetchStatuses();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const onDealDragEnd = (
|
const onDealDragEnd = (
|
||||||
dealId: number,
|
dealId: number,
|
||||||
statusId: number,
|
statusId: number,
|
||||||
@ -19,7 +36,25 @@ const StatusColumns = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onStatusDragEnd = (statusId: number, lexorank: string) => {};
|
const onStatusDragEnd = (statusId: number, lexorank: string) => {
|
||||||
|
console.log(
|
||||||
|
"onStatusDragEnd, statusId:",
|
||||||
|
statusId,
|
||||||
|
", lexo:",
|
||||||
|
lexorank
|
||||||
|
);
|
||||||
|
|
||||||
|
updateStatus.mutate({
|
||||||
|
path: {
|
||||||
|
statusId,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
status: {
|
||||||
|
lexorank,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StatusColumnsDnd
|
<StatusColumnsDnd
|
||||||
|
|||||||
@ -1,21 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, {
|
import React, { createContext, FC, useContext, useEffect } from "react";
|
||||||
createContext,
|
|
||||||
FC,
|
|
||||||
useContext,
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
} from "react";
|
|
||||||
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
||||||
import { DealSchema, StatusSchema } from "@/client";
|
import { DealSchema, StatusSchema } from "@/client";
|
||||||
import useDealsList from "@/hooks/useDealsList";
|
import useDealsList from "@/hooks/useDealsList";
|
||||||
|
import useStatusesList from "@/hooks/useStatusesList";
|
||||||
|
|
||||||
type StatusesContextState = {
|
type StatusesContextState = {
|
||||||
statuses: StatusSchema[];
|
statuses: StatusSchema[];
|
||||||
setStatuses: React.Dispatch<React.SetStateAction<StatusSchema[]>>;
|
setStatuses: React.Dispatch<React.SetStateAction<StatusSchema[]>>;
|
||||||
deals: DealSchema[];
|
deals: DealSchema[];
|
||||||
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
|
setDeals: React.Dispatch<React.SetStateAction<DealSchema[]>>;
|
||||||
|
refetchStatuses: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatusesContext = createContext<StatusesContextState | undefined>(
|
const StatusesContext = createContext<StatusesContextState | undefined>(
|
||||||
@ -23,12 +19,14 @@ const StatusesContext = createContext<StatusesContextState | undefined>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const useStatusesContextState = () => {
|
const useStatusesContextState = () => {
|
||||||
const [statuses, setStatuses] = useState<StatusSchema[]>([]);
|
|
||||||
const { selectedBoard } = useBoardsContext();
|
const { selectedBoard } = useBoardsContext();
|
||||||
|
const { statuses, setStatuses, refetch } = useStatusesList({
|
||||||
|
boardId: selectedBoard?.id,
|
||||||
|
});
|
||||||
const { deals, setDeals } = useDealsList({ boardId: selectedBoard?.id });
|
const { deals, setDeals } = useDealsList({ boardId: selectedBoard?.id });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setStatuses(selectedBoard?.statuses ?? []);
|
refetch();
|
||||||
}, [selectedBoard]);
|
}, [selectedBoard]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -36,6 +34,7 @@ const useStatusesContextState = () => {
|
|||||||
setStatuses,
|
setStatuses,
|
||||||
deals,
|
deals,
|
||||||
setDeals,
|
setDeals,
|
||||||
|
refetchStatuses: refetch,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -175,7 +175,7 @@ const useDnd = (props: Props) => {
|
|||||||
overStatusId = deal.statusId;
|
overStatusId = deal.statusId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overStatusId || activeStatusId === overStatusId) return;
|
if (!overStatusId) return;
|
||||||
|
|
||||||
const newRank = getNewStatusRank(activeStatusId, overStatusId);
|
const newRank = getNewStatusRank(activeStatusId, overStatusId);
|
||||||
if (!newRank) return;
|
if (!newRank) return;
|
||||||
|
|||||||
@ -7,16 +7,22 @@ import {
|
|||||||
getBoards,
|
getBoards,
|
||||||
getDeals,
|
getDeals,
|
||||||
getProjects,
|
getProjects,
|
||||||
|
getStatuses,
|
||||||
updateBoard,
|
updateBoard,
|
||||||
|
updateStatus,
|
||||||
type Options,
|
type Options,
|
||||||
} from "../sdk.gen";
|
} from "../sdk.gen";
|
||||||
import type {
|
import type {
|
||||||
GetBoardsData,
|
GetBoardsData,
|
||||||
GetDealsData,
|
GetDealsData,
|
||||||
GetProjectsData,
|
GetProjectsData,
|
||||||
|
GetStatusesData,
|
||||||
UpdateBoardData,
|
UpdateBoardData,
|
||||||
UpdateBoardError,
|
UpdateBoardError,
|
||||||
UpdateBoardResponse2,
|
UpdateBoardResponse2,
|
||||||
|
UpdateStatusData,
|
||||||
|
UpdateStatusError,
|
||||||
|
UpdateStatusResponse2,
|
||||||
} from "../types.gen";
|
} from "../types.gen";
|
||||||
|
|
||||||
export type QueryKey<TOptions extends Options> = [
|
export type QueryKey<TOptions extends Options> = [
|
||||||
@ -124,6 +130,54 @@ export const updateBoardMutation = (
|
|||||||
return mutationOptions;
|
return mutationOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getStatusesQueryKey = (options: Options<GetStatusesData>) =>
|
||||||
|
createQueryKey("getStatuses", options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Statuses
|
||||||
|
*/
|
||||||
|
export const getStatusesOptions = (options: Options<GetStatusesData>) => {
|
||||||
|
return queryOptions({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await getStatuses({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: getStatusesQueryKey(options),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Status
|
||||||
|
*/
|
||||||
|
export const updateStatusMutation = (
|
||||||
|
options?: Partial<Options<UpdateStatusData>>
|
||||||
|
): UseMutationOptions<
|
||||||
|
UpdateStatusResponse2,
|
||||||
|
AxiosError<UpdateStatusError>,
|
||||||
|
Options<UpdateStatusData>
|
||||||
|
> => {
|
||||||
|
const mutationOptions: UseMutationOptions<
|
||||||
|
UpdateStatusResponse2,
|
||||||
|
AxiosError<UpdateStatusError>,
|
||||||
|
Options<UpdateStatusData>
|
||||||
|
> = {
|
||||||
|
mutationFn: async localOptions => {
|
||||||
|
const { data } = await updateStatus({
|
||||||
|
...options,
|
||||||
|
...localOptions,
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
export const getDealsQueryKey = (options: Options<GetDealsData>) =>
|
export const getDealsQueryKey = (options: Options<GetDealsData>) =>
|
||||||
createQueryKey("getDeals", options);
|
createQueryKey("getDeals", options);
|
||||||
|
|
||||||
|
|||||||
@ -11,9 +11,15 @@ import type {
|
|||||||
GetDealsResponses,
|
GetDealsResponses,
|
||||||
GetProjectsData,
|
GetProjectsData,
|
||||||
GetProjectsResponses,
|
GetProjectsResponses,
|
||||||
|
GetStatusesData,
|
||||||
|
GetStatusesErrors,
|
||||||
|
GetStatusesResponses,
|
||||||
UpdateBoardData,
|
UpdateBoardData,
|
||||||
UpdateBoardErrors,
|
UpdateBoardErrors,
|
||||||
UpdateBoardResponses,
|
UpdateBoardResponses,
|
||||||
|
UpdateStatusData,
|
||||||
|
UpdateStatusErrors,
|
||||||
|
UpdateStatusResponses,
|
||||||
} from "./types.gen";
|
} from "./types.gen";
|
||||||
|
|
||||||
export type Options<
|
export type Options<
|
||||||
@ -88,6 +94,44 @@ export const updateBoard = <ThrowOnError extends boolean = false>(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Statuses
|
||||||
|
*/
|
||||||
|
export const getStatuses = <ThrowOnError extends boolean = false>(
|
||||||
|
options: Options<GetStatusesData, ThrowOnError>
|
||||||
|
) => {
|
||||||
|
return (options.client ?? _heyApiClient).get<
|
||||||
|
GetStatusesResponses,
|
||||||
|
GetStatusesErrors,
|
||||||
|
ThrowOnError
|
||||||
|
>({
|
||||||
|
responseType: "json",
|
||||||
|
url: "/status/{boardId}",
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Status
|
||||||
|
*/
|
||||||
|
export const updateStatus = <ThrowOnError extends boolean = false>(
|
||||||
|
options: Options<UpdateStatusData, ThrowOnError>
|
||||||
|
) => {
|
||||||
|
return (options.client ?? _heyApiClient).patch<
|
||||||
|
UpdateStatusResponses,
|
||||||
|
UpdateStatusErrors,
|
||||||
|
ThrowOnError
|
||||||
|
>({
|
||||||
|
responseType: "json",
|
||||||
|
url: "/status/{statusId}",
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options.headers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Deals
|
* Get Deals
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -16,10 +16,6 @@ export type BoardSchema = {
|
|||||||
* Lexorank
|
* Lexorank
|
||||||
*/
|
*/
|
||||||
lexorank: string;
|
lexorank: string;
|
||||||
/**
|
|
||||||
* Statuses
|
|
||||||
*/
|
|
||||||
statuses: Array<StatusSchema>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +70,16 @@ export type GetProjectsResponse = {
|
|||||||
projects: Array<ProjectSchema>;
|
projects: Array<ProjectSchema>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetStatusesResponse
|
||||||
|
*/
|
||||||
|
export type GetStatusesResponse = {
|
||||||
|
/**
|
||||||
|
* Statuses
|
||||||
|
*/
|
||||||
|
statuses: Array<StatusSchema>;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPValidationError
|
* HTTPValidationError
|
||||||
*/
|
*/
|
||||||
@ -147,6 +153,37 @@ export type UpdateBoardSchema = {
|
|||||||
lexorank?: string | null;
|
lexorank?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateStatusRequest
|
||||||
|
*/
|
||||||
|
export type UpdateStatusRequest = {
|
||||||
|
status: UpdateStatusSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateStatusResponse
|
||||||
|
*/
|
||||||
|
export type UpdateStatusResponse = {
|
||||||
|
/**
|
||||||
|
* Message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateStatusSchema
|
||||||
|
*/
|
||||||
|
export type UpdateStatusSchema = {
|
||||||
|
/**
|
||||||
|
* Name
|
||||||
|
*/
|
||||||
|
name?: string | null;
|
||||||
|
/**
|
||||||
|
* Lexorank
|
||||||
|
*/
|
||||||
|
lexorank?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ValidationError
|
* ValidationError
|
||||||
*/
|
*/
|
||||||
@ -225,10 +262,6 @@ export type UpdateBoardData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateBoardErrors = {
|
export type UpdateBoardErrors = {
|
||||||
/**
|
|
||||||
* Item not found
|
|
||||||
*/
|
|
||||||
404: unknown;
|
|
||||||
/**
|
/**
|
||||||
* Validation Error
|
* Validation Error
|
||||||
*/
|
*/
|
||||||
@ -247,6 +280,68 @@ export type UpdateBoardResponses = {
|
|||||||
export type UpdateBoardResponse2 =
|
export type UpdateBoardResponse2 =
|
||||||
UpdateBoardResponses[keyof UpdateBoardResponses];
|
UpdateBoardResponses[keyof UpdateBoardResponses];
|
||||||
|
|
||||||
|
export type GetStatusesData = {
|
||||||
|
body?: never;
|
||||||
|
path: {
|
||||||
|
/**
|
||||||
|
* Boardid
|
||||||
|
*/
|
||||||
|
boardId: number;
|
||||||
|
};
|
||||||
|
query?: never;
|
||||||
|
url: "/status/{boardId}";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetStatusesErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetStatusesError = GetStatusesErrors[keyof GetStatusesErrors];
|
||||||
|
|
||||||
|
export type GetStatusesResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: GetStatusesResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetStatusesResponse2 =
|
||||||
|
GetStatusesResponses[keyof GetStatusesResponses];
|
||||||
|
|
||||||
|
export type UpdateStatusData = {
|
||||||
|
body: UpdateStatusRequest;
|
||||||
|
path: {
|
||||||
|
/**
|
||||||
|
* Statusid
|
||||||
|
*/
|
||||||
|
statusId: number;
|
||||||
|
};
|
||||||
|
query?: never;
|
||||||
|
url: "/status/{statusId}";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateStatusErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateStatusError = UpdateStatusErrors[keyof UpdateStatusErrors];
|
||||||
|
|
||||||
|
export type UpdateStatusResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: UpdateStatusResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateStatusResponse2 =
|
||||||
|
UpdateStatusResponses[keyof UpdateStatusResponses];
|
||||||
|
|
||||||
export type GetDealsData = {
|
export type GetDealsData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path: {
|
path: {
|
||||||
|
|||||||
29
src/hooks/useStatusesList.ts
Normal file
29
src/hooks/useStatusesList.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { StatusSchema } from "@/client";
|
||||||
|
import { getStatusesOptions } from "@/client/@tanstack/react-query.gen";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
boardId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStatusesList = ({ boardId }: Props) => {
|
||||||
|
const [statuses, setStatuses] = useState<StatusSchema[]>([]);
|
||||||
|
|
||||||
|
const { data, refetch, isLoading } = useQuery({
|
||||||
|
...getStatusesOptions({ path: { boardId: boardId! } }),
|
||||||
|
enabled: boardId !== undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (boardId === undefined) {
|
||||||
|
setStatuses([]);
|
||||||
|
} else if (data?.statuses) {
|
||||||
|
setStatuses(data.statuses);
|
||||||
|
}
|
||||||
|
}, [data?.statuses, boardId]);
|
||||||
|
|
||||||
|
return { statuses, setStatuses, refetch, isLoading };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useStatusesList;
|
||||||
@ -1,3 +0,0 @@
|
|||||||
export type ErrorBody = {
|
|
||||||
detail?: string;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user