diff --git a/src/app/deals/components/Board/Board.tsx b/src/app/deals/components/Board/Board.tsx
index bb61c0d..df4863f 100644
--- a/src/app/deals/components/Board/Board.tsx
+++ b/src/app/deals/components/Board/Board.tsx
@@ -1,6 +1,6 @@
import React, { FC } from "react";
import { Box } from "@mantine/core";
-import { BoardSchema } from "@/types/BoardSchema";
+import { BoardSchema } from "@/client";
type Props = {
board: BoardSchema;
diff --git a/src/app/deals/components/Boards/Boards.tsx b/src/app/deals/components/Boards/Boards.tsx
index e570612..bd7e954 100644
--- a/src/app/deals/components/Boards/Boards.tsx
+++ b/src/app/deals/components/Boards/Boards.tsx
@@ -4,11 +4,11 @@ import React from "react";
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 SortableDnd from "@/components/SortableDnd";
-import { BoardSchema } from "@/types/BoardSchema";
const Boards = () => {
- const { boards } = useBoardsContext();
+ const { boards, setSelectedBoard } = useBoardsContext();
const renderBoard = (board: BoardSchema) => {
return ;
@@ -18,6 +18,11 @@ const Boards = () => {
console.log("onDragEnd:", itemId, newLexorank);
};
+ const selectBoard = (board: BoardSchema) => {
+ console.log("Board selecting:", board);
+ setSelectedBoard(board);
+ };
+
return (
{
initialItems={boards}
renderItem={renderBoard}
onDragEnd={onDragEnd}
+ onItemClick={selectBoard}
rowStyle={{ flexWrap: "nowrap" }}
/>
diff --git a/src/app/deals/components/DndOverlay/DndOverlay.tsx b/src/app/deals/components/DndOverlay/DndOverlay.tsx
index a431224..ba6006b 100644
--- a/src/app/deals/components/DndOverlay/DndOverlay.tsx
+++ b/src/app/deals/components/DndOverlay/DndOverlay.tsx
@@ -4,7 +4,7 @@ import DealCard from "@/app/deals/components/DealCard/DealCard";
import StatusColumn from "@/app/deals/components/StatusColumn/StatusColumn";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import { DealSchema } from "@/types/DealSchema";
-import { StatusSchema } from "@/types/StatusSchema";
+import { StatusSchema } from "@/client";
type Props = {
activeDeal: DealSchema | null;
diff --git a/src/app/deals/components/StatusColumn/StatusColumn.tsx b/src/app/deals/components/StatusColumn/StatusColumn.tsx
index d1199c2..380f3f3 100644
--- a/src/app/deals/components/StatusColumn/StatusColumn.tsx
+++ b/src/app/deals/components/StatusColumn/StatusColumn.tsx
@@ -6,8 +6,8 @@ import {
} from "@dnd-kit/sortable";
import { Box, Stack, Text } from "@mantine/core";
import DealContainer from "@/app/deals/components/DealContainer/DealContainer";
+import { StatusSchema } from "@/client";
import { DealSchema } from "@/types/DealSchema";
-import { StatusSchema } from "@/types/StatusSchema";
import { sortByLexorank } from "@/utils/lexorank";
type Props = {
diff --git a/src/app/deals/contexts/BoardsContext.tsx b/src/app/deals/contexts/BoardsContext.tsx
index afdc0e6..d913e61 100644
--- a/src/app/deals/contexts/BoardsContext.tsx
+++ b/src/app/deals/contexts/BoardsContext.tsx
@@ -8,8 +8,8 @@ import React, {
useState,
} from "react";
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
-import useBoards from "@/app/deals/hooks/useBoards";
-import { BoardSchema } from "@/types/BoardSchema";
+import { BoardSchema } from "@/client";
+import useBoardsList from "@/hooks/useBoardsList";
type BoardsContextState = {
boards: BoardSchema[];
@@ -21,11 +21,11 @@ type BoardsContextState = {
const BoardsContext = createContext(undefined);
const useBoardsContextState = () => {
- const { boards, setBoards } = useBoards();
+ const { selectedProject: project } = useProjectsContext();
+ const { boards, setBoards } = useBoardsList({ projectId: project?.id });
const [selectedBoard, setSelectedBoard] = useState(
null
);
- const { selectedProject: project } = useProjectsContext();
useEffect(() => {
if (boards.length > 0 && selectedBoard === null) {
diff --git a/src/app/deals/contexts/StatusesContext.tsx b/src/app/deals/contexts/StatusesContext.tsx
index 3d8f8a9..3693199 100644
--- a/src/app/deals/contexts/StatusesContext.tsx
+++ b/src/app/deals/contexts/StatusesContext.tsx
@@ -1,11 +1,16 @@
"use client";
-import React, { createContext, FC, useContext } from "react";
+import React, {
+ createContext,
+ FC,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import useDeals from "@/app/deals/hooks/useDeals";
-import useStatuses from "@/app/deals/hooks/useStatuses";
+import { StatusSchema } from "@/client";
import { DealSchema } from "@/types/DealSchema";
-import { StatusSchema } from "@/types/StatusSchema";
type StatusesContextState = {
statuses: StatusSchema[];
@@ -19,10 +24,14 @@ const StatusesContext = createContext(
);
const useStatusesContextState = () => {
- const { statuses, setStatuses } = useStatuses();
+ const [statuses, setStatuses] = useState([]);
const { deals, setDeals } = useDeals();
const { selectedBoard } = useBoardsContext();
+ useEffect(() => {
+ setStatuses(selectedBoard?.statuses ?? []);
+ }, [selectedBoard]);
+
return {
statuses,
setStatuses,
diff --git a/src/app/deals/hooks/useBoards.ts b/src/app/deals/hooks/useBoards.ts
index c8b69c8..b475145 100644
--- a/src/app/deals/hooks/useBoards.ts
+++ b/src/app/deals/hooks/useBoards.ts
@@ -1,19 +1,9 @@
-import { useEffect, useState } from "react";
-import { BoardSchema } from "@/types/BoardSchema";
+import { useState } from "react";
+import { BoardSchema } from "@/client";
const useBoards = () => {
const [boards, setBoards] = useState([]);
- useEffect(() => {
- setBoards([
- { id: 1, name: "1 Item", rank: "0|aaaaaa:" },
- { id: 2, name: "2 Item", rank: "0|gggggg:" },
- { id: 3, name: "3 Item", rank: "0|mmmmmm:" },
- { id: 4, name: "4 Item", rank: "0|ssssss:" },
- { id: 5, name: "5 Item", rank: "0|zzzzzz:" },
- ]);
- }, []);
-
return {
boards,
setBoards,
diff --git a/src/app/deals/hooks/useDeals.ts b/src/app/deals/hooks/useDeals.ts
index c1f59a7..3708b54 100644
--- a/src/app/deals/hooks/useDeals.ts
+++ b/src/app/deals/hooks/useDeals.ts
@@ -9,19 +9,19 @@ const useDeals = () => {
{
id: 1,
name: "Deal 1",
- rank: "0|gggggg:",
+ lexorank: "0|gggggg:",
statusId: 1,
},
{
id: 2,
name: "Deal 2",
- rank: "0|mmmmmm:",
+ lexorank: "0|mmmmmm:",
statusId: 1,
},
{
id: 3,
name: "Deal 3",
- rank: "0|ssssss:",
+ lexorank: "0|ssssss:",
statusId: 2,
},
];
diff --git a/src/app/deals/hooks/useDnd.ts b/src/app/deals/hooks/useDnd.ts
index 00d3206..d30e49f 100644
--- a/src/app/deals/hooks/useDnd.ts
+++ b/src/app/deals/hooks/useDnd.ts
@@ -4,8 +4,8 @@ import { throttle } from "lodash";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import useGetNewRank from "@/app/deals/hooks/useGetNewRank";
import { getStatusId, isStatusId } from "@/app/deals/utils/statusId";
+import { StatusSchema } from "@/client";
import { DealSchema } from "@/types/DealSchema";
-import { StatusSchema } from "@/types/StatusSchema";
import { sortByLexorank } from "@/utils/lexorank";
type Props = {
@@ -73,7 +73,7 @@ const useDnd = (props: Props) => {
? {
...deal,
statusId: overStatusId,
- rank: newLexorank || deal.rank,
+ lexorank: newLexorank || deal.lexorank,
}
: deal
)
@@ -100,7 +100,7 @@ const useDnd = (props: Props) => {
throttledSetStatuses(statuses =>
statuses.map(status =>
status.id === activeStatusId
- ? { ...status, rank: newRank }
+ ? { ...status, lexorank: newRank }
: status
)
);
diff --git a/src/app/deals/hooks/useGetNewRank.ts b/src/app/deals/hooks/useGetNewRank.ts
index da86b02..3067aff 100644
--- a/src/app/deals/hooks/useGetNewRank.ts
+++ b/src/app/deals/hooks/useGetNewRank.ts
@@ -20,10 +20,10 @@ const useGetNewRank = () => {
: [overDealIndex, overDealIndex + 1];
const leftLexorank =
- leftIndex >= 0 ? LexoRank.parse(deals[leftIndex].rank) : null;
+ leftIndex >= 0 ? LexoRank.parse(deals[leftIndex].lexorank) : null;
const rightLexorank =
rightIndex < deals.length
- ? LexoRank.parse(deals[rightIndex].rank)
+ ? LexoRank.parse(deals[rightIndex].lexorank)
: null;
return getNewLexorank(leftLexorank, rightLexorank).toString();
@@ -35,9 +35,11 @@ const useGetNewRank = () => {
) => {
const leftLexorank =
overDealIndex > 0
- ? LexoRank.parse(statusDeals[overDealIndex - 1].rank)
+ ? LexoRank.parse(statusDeals[overDealIndex - 1].lexorank)
: null;
- const rightLexorank = LexoRank.parse(statusDeals[overDealIndex].rank);
+ const rightLexorank = LexoRank.parse(
+ statusDeals[overDealIndex].lexorank
+ );
return getNewLexorank(leftLexorank, rightLexorank).toString();
};
@@ -59,10 +61,12 @@ const useGetNewRank = () => {
: [overIndex, overIndex + 1];
const leftLexorank =
- leftIndex >= 0 ? LexoRank.parse(statuses[leftIndex].rank) : null;
+ leftIndex >= 0
+ ? LexoRank.parse(statuses[leftIndex].lexorank)
+ : null;
const rightLexorank =
rightIndex < statuses.length
- ? LexoRank.parse(statuses[rightIndex].rank)
+ ? LexoRank.parse(statuses[rightIndex].lexorank)
: null;
return getNewLexorank(leftLexorank, rightLexorank).toString();
diff --git a/src/app/deals/hooks/useStatuses.ts b/src/app/deals/hooks/useStatuses.ts
deleted file mode 100644
index 7c3def4..0000000
--- a/src/app/deals/hooks/useStatuses.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { useEffect, useState } from "react";
-import { StatusSchema } from "@/types/StatusSchema";
-
-const useStatuses = () => {
- const [statuses, setStatuses] = useState([]);
-
- useEffect(() => {
- setStatuses([
- { id: 1, name: "Todo", rank: "0|aaaaaa:" },
- { id: 2, name: "In progress", rank: "0|gggggg:" },
- { id: 3, name: "Testing", rank: "0|mmmmmm:" },
- { id: 4, name: "Ready", rank: "0|ssssss:" },
- ]);
- }, []);
-
- return {
- statuses,
- setStatuses,
- };
-};
-
-export default useStatuses;
diff --git a/src/client/@tanstack/react-query.gen.ts b/src/client/@tanstack/react-query.gen.ts
index a630ccb..5ce22f1 100644
--- a/src/client/@tanstack/react-query.gen.ts
+++ b/src/client/@tanstack/react-query.gen.ts
@@ -2,8 +2,8 @@
import { queryOptions } from "@tanstack/react-query";
import { client as _heyApiClient } from "../client.gen";
-import { getProjects, type Options } from "../sdk.gen";
-import type { GetProjectsData } from "../types.gen";
+import { getBoards, getProjects, type Options } from "../sdk.gen";
+import type { GetBoardsData, GetProjectsData } from "../types.gen";
export type QueryKey = [
Pick & {
@@ -61,3 +61,24 @@ export const getProjectsOptions = (options?: Options) => {
queryKey: getProjectsQueryKey(options),
});
};
+
+export const getBoardsQueryKey = (options: Options) =>
+ createQueryKey("getBoards", options);
+
+/**
+ * Get Boards
+ */
+export const getBoardsOptions = (options: Options) => {
+ return queryOptions({
+ queryFn: async ({ queryKey, signal }) => {
+ const { data } = await getBoards({
+ ...options,
+ ...queryKey[0],
+ signal,
+ throwOnError: true,
+ });
+ return data;
+ },
+ queryKey: getBoardsQueryKey(options),
+ });
+};
diff --git a/src/client/sdk.gen.ts b/src/client/sdk.gen.ts
index 22a0ae4..6cada35 100644
--- a/src/client/sdk.gen.ts
+++ b/src/client/sdk.gen.ts
@@ -2,7 +2,13 @@
import type { Client, Options as ClientOptions, TDataShape } from "./client";
import { client as _heyApiClient } from "./client.gen";
-import type { GetProjectsData, GetProjectsResponses } from "./types.gen";
+import type {
+ GetBoardsData,
+ GetBoardsErrors,
+ GetBoardsResponses,
+ GetProjectsData,
+ GetProjectsResponses,
+} from "./types.gen";
export type Options<
TData extends TDataShape = TDataShape,
@@ -37,3 +43,20 @@ export const getProjects = (
...options,
});
};
+
+/**
+ * Get Boards
+ */
+export const getBoards = (
+ options: Options
+) => {
+ return (options.client ?? _heyApiClient).get<
+ GetBoardsResponses,
+ GetBoardsErrors,
+ ThrowOnError
+ >({
+ responseType: "json",
+ url: "/board/{project_id}",
+ ...options,
+ });
+};
diff --git a/src/client/types.gen.ts b/src/client/types.gen.ts
index 4ad913d..88f77d8 100644
--- a/src/client/types.gen.ts
+++ b/src/client/types.gen.ts
@@ -1,5 +1,37 @@
// This file is auto-generated by @hey-api/openapi-ts
+/**
+ * BoardSchema
+ */
+export type BoardSchema = {
+ /**
+ * Name
+ */
+ name: string;
+ /**
+ * Id
+ */
+ id: number;
+ /**
+ * Lexorank
+ */
+ lexorank: string;
+ /**
+ * Statuses
+ */
+ statuses: Array;
+};
+
+/**
+ * GetBoardsResponse
+ */
+export type GetBoardsResponse = {
+ /**
+ * Boards
+ */
+ boards: Array;
+};
+
/**
* GetProjectsResponse
*/
@@ -10,6 +42,16 @@ export type GetProjectsResponse = {
projects: Array;
};
+/**
+ * HTTPValidationError
+ */
+export type HttpValidationError = {
+ /**
+ * Detail
+ */
+ detail?: Array;
+};
+
/**
* ProjectSchema
*/
@@ -24,6 +66,42 @@ export type ProjectSchema = {
id: number;
};
+/**
+ * StatusSchema
+ */
+export type StatusSchema = {
+ /**
+ * Name
+ */
+ name: string;
+ /**
+ * Id
+ */
+ id: number;
+ /**
+ * Lexorank
+ */
+ lexorank: string;
+};
+
+/**
+ * ValidationError
+ */
+export type ValidationError = {
+ /**
+ * Location
+ */
+ loc: Array;
+ /**
+ * Message
+ */
+ msg: string;
+ /**
+ * Error Type
+ */
+ type: string;
+};
+
export type GetProjectsData = {
body?: never;
path?: never;
@@ -41,6 +119,36 @@ export type GetProjectsResponses = {
export type GetProjectsResponse2 =
GetProjectsResponses[keyof GetProjectsResponses];
+export type GetBoardsData = {
+ body?: never;
+ path: {
+ /**
+ * Project Id
+ */
+ project_id: number;
+ };
+ query?: never;
+ url: "/board/{project_id}";
+};
+
+export type GetBoardsErrors = {
+ /**
+ * Validation Error
+ */
+ 422: HttpValidationError;
+};
+
+export type GetBoardsError = GetBoardsErrors[keyof GetBoardsErrors];
+
+export type GetBoardsResponses = {
+ /**
+ * Successful Response
+ */
+ 200: GetBoardsResponse;
+};
+
+export type GetBoardsResponse2 = GetBoardsResponses[keyof GetBoardsResponses];
+
export type ClientOptions = {
baseURL: "http://localhost:8000" | (string & {});
};
diff --git a/src/components/SortableDnd/SortableDnd.tsx b/src/components/SortableDnd/SortableDnd.tsx
index 5de115d..bc08877 100644
--- a/src/components/SortableDnd/SortableDnd.tsx
+++ b/src/components/SortableDnd/SortableDnd.tsx
@@ -7,34 +7,25 @@ import React, {
useMemo,
useState,
} from "react";
-import {
- Active,
- DndContext,
- DragEndEvent,
- KeyboardSensor,
- PointerSensor,
- useSensor,
- useSensors,
-} from "@dnd-kit/core";
-import {
- SortableContext,
- sortableKeyboardCoordinates,
-} from "@dnd-kit/sortable";
+import { Active, DndContext, DragEndEvent } from "@dnd-kit/core";
+import { SortableContext } from "@dnd-kit/sortable";
import { LexoRank } from "lexorank";
-import { Group } from "@mantine/core";
+import { Box, Group } from "@mantine/core";
+import useDndSensors from "@/app/deals/hooks/useSensors";
import { SortableItem } from "@/components/SortableDnd/SortableItem";
import { SortableOverlay } from "@/components/SortableDnd/SortableOverlay";
import { getNewLexorank, sortByLexorank } from "@/utils/lexorank";
type BaseItem = {
id: number;
- rank: string;
+ lexorank: string;
};
type Props = {
initialItems: T[];
renderItem: (item: T) => ReactNode;
onDragEnd: (itemId: number, newLexorank: string) => void;
+ onItemClick: (item: T) => void;
rowStyle?: CSSProperties;
itemStyle?: CSSProperties;
};
@@ -43,6 +34,7 @@ const SortableDnd = ({
initialItems,
renderItem,
onDragEnd,
+ onItemClick,
rowStyle,
itemStyle,
}: Props) => {
@@ -57,12 +49,7 @@ const SortableDnd = ({
setItems(sortByLexorank(initialItems));
}, [initialItems]);
- const sensors = useSensors(
- useSensor(PointerSensor),
- useSensor(KeyboardSensor, {
- coordinateGetter: sortableKeyboardCoordinates,
- })
- );
+ const sensors = useDndSensors();
const onDragEndLocal = ({ active, over }: DragEndEvent) => {
if (over && active.id !== over?.id && activeItem) {
@@ -81,10 +68,12 @@ const SortableDnd = ({
}
const leftLexorank: LexoRank | null =
- leftIndex >= 0 ? LexoRank.parse(items[leftIndex].rank) : null;
+ leftIndex >= 0
+ ? LexoRank.parse(items[leftIndex].lexorank)
+ : null;
const rightLexorank: LexoRank | null =
rightIndex < items.length
- ? LexoRank.parse(items[rightIndex].rank)
+ ? LexoRank.parse(items[rightIndex].lexorank)
: null;
const newLexorank = getNewLexorank(
@@ -92,7 +81,7 @@ const SortableDnd = ({
rightLexorank
).toString();
- items[activeIndex].rank = newLexorank;
+ items[activeIndex].lexorank = newLexorank;
onDragEnd(items[activeIndex].id, newLexorank);
const sortedItems = sortByLexorank(items);
setItems([...sortedItems]);
@@ -112,12 +101,19 @@ const SortableDnd = ({
style={rowStyle}
role="application">
{items.map((item, index) => (
-
- {renderItem(item)}
-
+ onClick={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ onItemClick(item);
+ }}>
+
+ {renderItem(item)}
+
+
))}
diff --git a/src/components/SortableDnd/SortableItem.tsx b/src/components/SortableDnd/SortableItem.tsx
index 2f3e3c5..8504db5 100644
--- a/src/components/SortableDnd/SortableItem.tsx
+++ b/src/components/SortableDnd/SortableItem.tsx
@@ -9,7 +9,11 @@ type Props = {
itemStyle?: CSSProperties;
};
-export const SortableItem = ({ children, id }: PropsWithChildren) => {
+export const SortableItem = ({
+ children,
+ itemStyle,
+ id,
+}: PropsWithChildren) => {
const {
attributes,
isDragging,
@@ -33,6 +37,7 @@ export const SortableItem = ({ children, id }: PropsWithChildren) => {
opacity: isDragging ? 0.4 : undefined,
transform: CSS.Translate.toString(transform),
transition,
+ ...itemStyle,
};
return (
diff --git a/src/hooks/useBoardsList.ts b/src/hooks/useBoardsList.ts
new file mode 100644
index 0000000..6b4cb00
--- /dev/null
+++ b/src/hooks/useBoardsList.ts
@@ -0,0 +1,29 @@
+import { useEffect, useState } from "react";
+import { useQuery } from "@tanstack/react-query";
+import { BoardSchema } from "@/client";
+import { getBoardsOptions } from "@/client/@tanstack/react-query.gen";
+
+type Props = {
+ projectId?: number;
+};
+
+const useBoardsList = ({ projectId }: Props) => {
+ const [boards, setBoards] = useState([]);
+
+ const { data, refetch, isLoading } = useQuery({
+ ...getBoardsOptions({ path: { project_id: projectId! } }),
+ enabled: projectId !== undefined,
+ });
+
+ useEffect(() => {
+ if (projectId === undefined) {
+ setBoards([]);
+ } else if (data?.boards) {
+ setBoards(data.boards);
+ }
+ }, [data?.boards, projectId]);
+
+ return { boards, setBoards, refetch, isLoading };
+};
+
+export default useBoardsList;
diff --git a/src/types/BoardSchema.ts b/src/types/BoardSchema.ts
deleted file mode 100644
index 021f1fc..0000000
--- a/src/types/BoardSchema.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export type BoardSchema = {
- id: number;
- name: string;
- rank: string;
-};
diff --git a/src/types/DealSchema.ts b/src/types/DealSchema.ts
index a4f7656..f1c6c54 100644
--- a/src/types/DealSchema.ts
+++ b/src/types/DealSchema.ts
@@ -1,6 +1,6 @@
export type DealSchema = {
id: number;
name: string;
- rank: string;
+ lexorank: string;
statusId: number;
};
diff --git a/src/types/StatusSchema.ts b/src/types/StatusSchema.ts
deleted file mode 100644
index 1f44b73..0000000
--- a/src/types/StatusSchema.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export type StatusSchema = {
- id: number;
- name: string;
- rank: string;
-};
diff --git a/src/utils/lexorank.ts b/src/utils/lexorank.ts
index 8909ada..d201a46 100644
--- a/src/utils/lexorank.ts
+++ b/src/utils/lexorank.ts
@@ -1,17 +1,17 @@
import { LexoRank } from "lexorank";
type LexorankSortable = {
- rank: string;
+ lexorank: string;
};
export function compareByLexorank(
a: T,
b: T
): -1 | 1 | 0 {
- if (a.rank < b.rank) {
+ if (a.lexorank < b.lexorank) {
return -1;
}
- if (a.rank > b.rank) {
+ if (a.lexorank > b.lexorank) {
return 1;
}
return 0;