feat: board updating on the server

This commit is contained in:
2025-08-04 16:57:54 +04:00
parent f13417e73a
commit 24de9f5446
8 changed files with 172 additions and 15 deletions

View File

@ -1,21 +1,46 @@
"use client";
import React from "react";
import { useMutation } from "@tanstack/react-query";
import { AxiosError } from "axios";
import { ScrollArea } from "@mantine/core";
import Board from "@/app/deals/components/Board/Board";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import { BoardSchema } from "@/client";
import { updateBoardMutation } from "@/client/@tanstack/react-query.gen";
import SortableDnd from "@/components/SortableDnd";
import { notifications } from "@/lib/notifications";
import { ErrorBody } from "@/types/ErrorBody";
const Boards = () => {
const { boards, setSelectedBoard } = useBoardsContext();
const { boards, setSelectedBoard, refetchBoards } = useBoardsContext();
const updateBoard = useMutation({
...updateBoardMutation(),
onError: (error: AxiosError<ErrorBody>) => {
console.error(error);
notifications.error({
message: error.response?.data?.detail,
});
refetchBoards();
},
});
const renderBoard = (board: BoardSchema) => {
return <Board board={board} />;
};
const onDragEnd = (itemId: number, newLexorank: string) => {
console.log("onDragEnd:", itemId, newLexorank);
updateBoard.mutate({
path: {
boardId: itemId,
},
body: {
board: {
lexorank: newLexorank,
},
},
});
};
const selectBoard = (board: BoardSchema) => {

View File

@ -16,13 +16,14 @@ type BoardsContextState = {
setBoards: React.Dispatch<React.SetStateAction<BoardSchema[]>>;
selectedBoard: BoardSchema | null;
setSelectedBoard: React.Dispatch<React.SetStateAction<BoardSchema | null>>;
refetchBoards: () => void;
};
const BoardsContext = createContext<BoardsContextState | undefined>(undefined);
const useBoardsContextState = () => {
const { selectedProject: project } = useProjectsContext();
const { boards, setBoards } = useBoardsList({ projectId: project?.id });
const { boards, setBoards, refetch: refetchBoards } = useBoardsList({ projectId: project?.id });
const [selectedBoard, setSelectedBoard] = useState<BoardSchema | null>(
null
);
@ -48,6 +49,7 @@ const useBoardsContextState = () => {
setBoards,
selectedBoard,
setSelectedBoard,
refetchBoards,
};
};

View File

@ -1,12 +1,22 @@
// This file is auto-generated by @hey-api/openapi-ts
import { queryOptions } from "@tanstack/react-query";
import { queryOptions, type UseMutationOptions } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { client as _heyApiClient } from "../client.gen";
import { getBoards, getDeals, getProjects, type Options } from "../sdk.gen";
import {
getBoards,
getDeals,
getProjects,
updateBoard,
type Options,
} from "../sdk.gen";
import type {
GetBoardsData,
GetDealsData,
GetProjectsData,
UpdateBoardData,
UpdateBoardError,
UpdateBoardResponse2,
} from "../types.gen";
export type QueryKey<TOptions extends Options> = [
@ -87,6 +97,33 @@ export const getBoardsOptions = (options: Options<GetBoardsData>) => {
});
};
/**
* Update Board
*/
export const updateBoardMutation = (
options?: Partial<Options<UpdateBoardData>>
): UseMutationOptions<
UpdateBoardResponse2,
AxiosError<UpdateBoardError>,
Options<UpdateBoardData>
> => {
const mutationOptions: UseMutationOptions<
UpdateBoardResponse2,
AxiosError<UpdateBoardError>,
Options<UpdateBoardData>
> = {
mutationFn: async localOptions => {
const { data } = await updateBoard({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
export const getDealsQueryKey = (options: Options<GetDealsData>) =>
createQueryKey("getDeals", options);

View File

@ -11,6 +11,9 @@ import type {
GetDealsResponses,
GetProjectsData,
GetProjectsResponses,
UpdateBoardData,
UpdateBoardErrors,
UpdateBoardResponses,
} from "./types.gen";
export type Options<
@ -59,11 +62,32 @@ export const getBoards = <ThrowOnError extends boolean = false>(
ThrowOnError
>({
responseType: "json",
url: "/board/{project_id}",
url: "/board/{projectId}",
...options,
});
};
/**
* Update Board
*/
export const updateBoard = <ThrowOnError extends boolean = false>(
options: Options<UpdateBoardData, ThrowOnError>
) => {
return (options.client ?? _heyApiClient).patch<
UpdateBoardResponses,
UpdateBoardErrors,
ThrowOnError
>({
responseType: "json",
url: "/board/{boardId}",
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
});
};
/**
* Get Deals
*/
@ -76,7 +100,7 @@ export const getDeals = <ThrowOnError extends boolean = false>(
ThrowOnError
>({
responseType: "json",
url: "/deal/{board_id}",
url: "/deal/{boardId}",
...options,
});
};

View File

@ -116,6 +116,37 @@ export type StatusSchema = {
lexorank: string;
};
/**
* UpdateBoardRequest
*/
export type UpdateBoardRequest = {
board: UpdateBoardSchema;
};
/**
* UpdateBoardResponse
*/
export type UpdateBoardResponse = {
/**
* Message
*/
message: string;
};
/**
* UpdateBoardSchema
*/
export type UpdateBoardSchema = {
/**
* Name
*/
name?: string | null;
/**
* Lexorank
*/
lexorank?: string | null;
};
/**
* ValidationError
*/
@ -155,12 +186,12 @@ export type GetBoardsData = {
body?: never;
path: {
/**
* Project Id
* Projectid
*/
project_id: number;
projectId: number;
};
query?: never;
url: "/board/{project_id}";
url: "/board/{projectId}";
};
export type GetBoardsErrors = {
@ -181,16 +212,51 @@ export type GetBoardsResponses = {
export type GetBoardsResponse2 = GetBoardsResponses[keyof GetBoardsResponses];
export type UpdateBoardData = {
body: UpdateBoardRequest;
path: {
/**
* Boardid
*/
boardId: number;
};
query?: never;
url: "/board/{boardId}";
};
export type UpdateBoardErrors = {
/**
* Item not found
*/
404: unknown;
/**
* Validation Error
*/
422: HttpValidationError;
};
export type UpdateBoardError = UpdateBoardErrors[keyof UpdateBoardErrors];
export type UpdateBoardResponses = {
/**
* Successful Response
*/
200: UpdateBoardResponse;
};
export type UpdateBoardResponse2 =
UpdateBoardResponses[keyof UpdateBoardResponses];
export type GetDealsData = {
body?: never;
path: {
/**
* Board Id
* Boardid
*/
board_id: number;
boardId: number;
};
query?: never;
url: "/deal/{board_id}";
url: "/deal/{boardId}";
};
export type GetDealsErrors = {

View File

@ -11,7 +11,7 @@ const useBoardsList = ({ projectId }: Props) => {
const [boards, setBoards] = useState<BoardSchema[]>([]);
const { data, refetch, isLoading } = useQuery({
...getBoardsOptions({ path: { project_id: projectId! } }),
...getBoardsOptions({ path: { projectId: projectId! } }),
enabled: projectId !== undefined,
});

View File

@ -11,7 +11,7 @@ const useDealsList = ({ boardId }: Props) => {
const [deals, setDeals] = useState<DealSchema[]>([]);
const { data, refetch, isLoading } = useQuery({
...getDealsOptions({ path: { board_id: boardId! } }),
...getDealsOptions({ path: { boardId: boardId! } }),
enabled: boardId !== undefined,
});

3
src/types/ErrorBody.ts Normal file
View File

@ -0,0 +1,3 @@
export type ErrorBody = {
detail?: string;
};