refactoring
This commit is contained in:
@@ -18,8 +18,8 @@
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.board-during-dnd {
|
||||
background-color: var(--color-gray-10);
|
||||
.no-transition {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.board::after {
|
||||
|
||||
@@ -5,31 +5,30 @@ import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react";
|
||||
import classNames from "classnames";
|
||||
import styles from "./Board.module.scss";
|
||||
import useStatus from "../../Statuses/Status/hooks/useStatus.tsx";
|
||||
import { useDndContext } from "../../../../pages/CardsPage/contexts/DndContext.tsx";
|
||||
import DragState from "../../../../pages/CardsPage/enums/DragState.ts";
|
||||
import { useBoardsContext } from "../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
board: BoardSchema;
|
||||
selectedBoard: BoardSchema | null;
|
||||
setSelectedBoard: (board: BoardSchema) => void;
|
||||
onEditBoardClick: (board: BoardSchema) => void;
|
||||
onDeleteBoardClick: (board: BoardSchema) => void;
|
||||
isBoardDragEnded: boolean;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const Board = ({
|
||||
board,
|
||||
selectedBoard,
|
||||
setSelectedBoard,
|
||||
onEditBoardClick,
|
||||
onDeleteBoardClick,
|
||||
isBoardDragEnded,
|
||||
refetch,
|
||||
}: Props) => {
|
||||
const Board = ({ board }: Props) => {
|
||||
const {
|
||||
selectedBoard,
|
||||
setSelectedBoard,
|
||||
onEditBoardClick,
|
||||
onDeleteBoardClick,
|
||||
} = useBoardsContext();
|
||||
|
||||
const { dragState } = useDndContext();
|
||||
|
||||
const { showContextMenu } = useContextMenu();
|
||||
|
||||
const { onCreateStatusClick } = useStatus({ refetch });
|
||||
const { onCreateStatusClick } = useStatus();
|
||||
|
||||
const isDropDisabled = dragState !== DragState.DRAG_BOARD;
|
||||
|
||||
const contextMenu = (board: BoardSchema) => showContextMenu([
|
||||
{
|
||||
@@ -54,16 +53,22 @@ const Board = ({
|
||||
|
||||
return (
|
||||
<Droppable
|
||||
droppableId={board.id.toString()}
|
||||
droppableId={"board-" + board.id.toString()}
|
||||
direction={"horizontal"}
|
||||
isDropDisabled={isDropDisabled}
|
||||
>
|
||||
{provided => (
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
onMouseEnter={() => {
|
||||
if (dragState === DragState.DRAG_CARD) {
|
||||
setSelectedBoard(board);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Draggable
|
||||
draggableId={board.id.toString()}
|
||||
draggableId={"board-" + board.id.toString()}
|
||||
index={board.ordinalNumber}
|
||||
>
|
||||
{(provided) => (
|
||||
@@ -77,7 +82,6 @@ const Board = ({
|
||||
board.id === selectedBoard?.id ?
|
||||
styles["selected-board"] :
|
||||
styles["board"],
|
||||
!isBoardDragEnded && styles["board-during-dnd"],
|
||||
)}
|
||||
|
||||
onClick={() => setSelectedBoard(board)}
|
||||
|
||||
@@ -1,88 +1,66 @@
|
||||
import { Box, Center, Group, Stack } from "@mantine/core";
|
||||
import { DragDropContext } from "@hello-pangea/dnd";
|
||||
import { BoardSchema, CardSummary } from "../../../../client";
|
||||
import { BoardSchema } from "../../../../client";
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import useBoards from "./hooks/useBoards.tsx";
|
||||
import Statuses from "../../Statuses/Statuses/Statuses.tsx";
|
||||
import Board from "../Board/Board.tsx";
|
||||
import useBoardsDnd from "./hooks/useBoardsDnd.tsx";
|
||||
import PrefillCardsWithExcelDrawer
|
||||
from "../../../../pages/CardsPage/drawers/PrefillCardWithExcelDrawer/PrefillCardsWithExcelDrawer.tsx";
|
||||
import { useDndContext } from "../../../../pages/CardsPage/contexts/DndContext.tsx";
|
||||
import { useBoardsContext } from "../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
summariesRaw: CardSummary[];
|
||||
refetchSummaries: () => void;
|
||||
boards: BoardSchema[];
|
||||
refetchBoards: () => void;
|
||||
}
|
||||
|
||||
const Boards = (props: Props) => {
|
||||
const Boards = () => {
|
||||
const {
|
||||
boards,
|
||||
selectedBoard,
|
||||
setSelectedBoard,
|
||||
onCreateBoardClick,
|
||||
onEditBoardClick,
|
||||
onDeleteBoardClick,
|
||||
} = useBoards(props);
|
||||
} = useBoardsContext();
|
||||
|
||||
const {
|
||||
onBoardDragEnd,
|
||||
isBoardDragEnded,
|
||||
setIsBoardDragEnded,
|
||||
} = useBoardsDnd(props);
|
||||
onDragEnd,
|
||||
onDragStart,
|
||||
} = useDndContext();
|
||||
|
||||
const getBoardsTabs = () => {
|
||||
return (
|
||||
<DragDropContext
|
||||
onDragStart={() => {
|
||||
setIsBoardDragEnded(false);
|
||||
}}
|
||||
onDragEnd={onBoardDragEnd}
|
||||
<Group
|
||||
mx={"3%"}
|
||||
mb={"md"}
|
||||
gap={0}
|
||||
align={"end"}
|
||||
wrap={"nowrap"}
|
||||
>
|
||||
<Group
|
||||
mx={"3%"}
|
||||
mb={"md"}
|
||||
gap={0}
|
||||
align={"end"}
|
||||
wrap={"nowrap"}
|
||||
{boards.map((board: BoardSchema) => (
|
||||
<Board
|
||||
key={board.id}
|
||||
board={board}
|
||||
/>
|
||||
))}
|
||||
<Center
|
||||
px={"md"}
|
||||
py={"xs"}
|
||||
style={{ cursor: "pointer", borderBottom: "solid gray 1px" }}
|
||||
onClick={onCreateBoardClick}
|
||||
>
|
||||
{props.boards.map((board: BoardSchema) => (
|
||||
<Board
|
||||
key={board.id}
|
||||
|
||||
board={board}
|
||||
selectedBoard={selectedBoard}
|
||||
setSelectedBoard={setSelectedBoard}
|
||||
onEditBoardClick={onEditBoardClick}
|
||||
onDeleteBoardClick={onDeleteBoardClick}
|
||||
isBoardDragEnded={isBoardDragEnded}
|
||||
refetch={props.refetchBoards}
|
||||
/>
|
||||
))}
|
||||
<Center
|
||||
px={"md"}
|
||||
py={"xs"}
|
||||
style={{ cursor: "pointer", borderBottom: "solid gray 1px" }}
|
||||
onClick={onCreateBoardClick}
|
||||
>
|
||||
<IconPlus />
|
||||
</Center>
|
||||
<Box w={"100%"} style={{ borderBottom: "solid gray 1px" }}></Box>
|
||||
</Group>
|
||||
</DragDropContext>
|
||||
<IconPlus />
|
||||
</Center>
|
||||
<Box w={"100%"} style={{ borderBottom: "solid gray 1px" }}></Box>
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{getBoardsTabs()}
|
||||
<Statuses
|
||||
selectedBoard={selectedBoard}
|
||||
{...props}
|
||||
/>
|
||||
<PrefillCardsWithExcelDrawer board={selectedBoard} />
|
||||
</Stack>
|
||||
<DragDropContext
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
>
|
||||
<Stack>
|
||||
{getBoardsTabs()}
|
||||
<Statuses />
|
||||
<PrefillCardsWithExcelDrawer board={selectedBoard} />
|
||||
</Stack>
|
||||
</DragDropContext>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { DropResult } from "@hello-pangea/dnd";
|
||||
import { BoardSchema, BoardService } from "../../../../../client";
|
||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||
import { useState } from "react";
|
||||
import { useBoardsContext } from "../../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
boards: BoardSchema[];
|
||||
refetchBoards: () => void;
|
||||
}
|
||||
|
||||
const useBoardsDnd = ({ boards, refetchBoards }: Props) => {
|
||||
const [isBoardDragEnded, setIsBoardDragEnded] = useState(true);
|
||||
const useBoardsDnd = () => {
|
||||
const {
|
||||
boards,
|
||||
refetchBoards,
|
||||
} = useBoardsContext();
|
||||
|
||||
const updateBoardOrder = (board: BoardSchema, newOrdinalNumber: number) => {
|
||||
BoardService.updateBoardOrder({
|
||||
@@ -18,22 +16,21 @@ const useBoardsDnd = ({ boards, refetchBoards }: Props) => {
|
||||
projectId: board.projectId,
|
||||
boardId: board.id,
|
||||
newOrdinalNumber,
|
||||
}
|
||||
},
|
||||
})
|
||||
.then(({ ok, message }) => {
|
||||
if (!ok) notifications.error({ message });
|
||||
refetchBoards();
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const onBoardDragEnd = async (result: DropResult) => {
|
||||
setIsBoardDragEnded(true);
|
||||
|
||||
// If there is no changes
|
||||
if (!result.destination || result.destination == result.source) return;
|
||||
|
||||
// Checking for valid cardId
|
||||
const boardId = parseInt(result.draggableId);
|
||||
const boardIdStr = result.draggableId.replace("board-", "");
|
||||
const boardId = parseInt(boardIdStr);
|
||||
if (isNaN(boardId)) return;
|
||||
|
||||
// Checking for valid card
|
||||
@@ -45,8 +42,6 @@ const useBoardsDnd = ({ boards, refetchBoards }: Props) => {
|
||||
|
||||
return {
|
||||
onBoardDragEnd,
|
||||
isBoardDragEnded,
|
||||
setIsBoardDragEnded,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export const CardsDndColumn: FC<Props> = ({
|
||||
}) => {
|
||||
const { selectedProject } = useProjectsContext();
|
||||
const isCreatingDealFromFileEnabled = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, selectedProject);
|
||||
const isDropDisabled = dragState === DragState.DRAG_STATUS;
|
||||
const isDropDisabled = dragState !== DragState.DRAG_CARD;
|
||||
const droppableId = status.id.toString();
|
||||
|
||||
const isGroup = (obj: GroupWithCards | CardSummary): obj is GroupWithCards => {
|
||||
|
||||
@@ -9,7 +9,7 @@ type Props = {
|
||||
}
|
||||
|
||||
const CardsDndFooter = ({ dragState }: Props) => {
|
||||
const isDealDragEnded = dragState === DragState.DRAG_ENDED;
|
||||
const isDealDragEnded = dragState !== DragState.DRAG_CARD;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import styles from "../../../../pages/CardsPage/ui/CardsPage.module.css";
|
||||
import { Divider, Stack, Text, Title } from "@mantine/core";
|
||||
import getColumnColor from "../../Cards/CardsDndColumn/utils/getColumnColor.ts";
|
||||
import { BoardSchema, CardSummary, StatusSchema } from "../../../../client";
|
||||
import { CardSummary, StatusSchema } from "../../../../client";
|
||||
import { getPluralForm } from "../../../../shared/lib/utils.ts";
|
||||
import { sum } from "lodash";
|
||||
import { Draggable, Droppable } from "@hello-pangea/dnd";
|
||||
@@ -11,20 +11,23 @@ import { IconEdit, IconTrash } from "@tabler/icons-react";
|
||||
import useStatus from "./hooks/useStatus.tsx";
|
||||
import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
|
||||
import { useEqualHeightsContext } from "./contexts/EqualHeightContext.tsx";
|
||||
import { useBoardsContext } from "../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
status: StatusSchema;
|
||||
board: BoardSchema | null;
|
||||
index: number;
|
||||
summaries: CardSummary[];
|
||||
dragState: DragState;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const Status = ({ summaries, status, board, dragState, index, refetch }: Props) => {
|
||||
const isDropDisabled = dragState === DragState.DRAG_CARD;
|
||||
const isServicesAndProductsIncluded = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, board?.project);
|
||||
const Status = ({ summaries, status, dragState, index }: Props) => {
|
||||
const {
|
||||
selectedBoard,
|
||||
} = useBoardsContext();
|
||||
|
||||
const isDropDisabled = dragState !== DragState.DRAG_STATUS;
|
||||
const isServicesAndProductsIncluded = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, selectedBoard?.project);
|
||||
|
||||
const {
|
||||
divRefs,
|
||||
@@ -33,7 +36,7 @@ const Status = ({ summaries, status, board, dragState, index, refetch }: Props)
|
||||
const {
|
||||
onEditStatusClick,
|
||||
onDeleteStatusClick,
|
||||
} = useStatus({ refetch });
|
||||
} = useStatus();
|
||||
|
||||
const getDealsText = () => {
|
||||
const pluralForm = getPluralForm(
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { BoardSchema, StatusSchema, StatusService } from "../../../../../client";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||
import { useBoardsContext } from "../../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
refetch: () => void;
|
||||
}
|
||||
const useStatus = () => {
|
||||
const {
|
||||
refetchBoards: refetch,
|
||||
} = useBoardsContext();
|
||||
|
||||
const useStatus = ({ refetch }: Props) => {
|
||||
const onEditStatusClick = (status: StatusSchema) => {
|
||||
modals.openContextModal({
|
||||
modal: "statusModal",
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
import { BoardSchema, CardSummary, StatusSchema } from "../../../../client";
|
||||
import { StatusSchema } from "../../../../client";
|
||||
import CardsDndColumn from "../../Cards/CardsDndColumn/CardsDndColumn.tsx";
|
||||
import styles from "../../../../pages/CardsPage/ui/CardsPage.module.css";
|
||||
import CardsDndFooter from "../../Cards/CardsDndFooter/CardsDndFooter.tsx";
|
||||
import { Flex, rem, Stack } from "@mantine/core";
|
||||
import { DragDropContext } from "@hello-pangea/dnd";
|
||||
import useDnd from "../../../../pages/CardsPage/hooks/useDnd.tsx";
|
||||
import Status from "../Status/Status.tsx";
|
||||
import { EqualHeightsContextProvider } from "../Status/contexts/EqualHeightContext.tsx";
|
||||
import { useBoardsContext } from "../../../../contexts/BoardsContext.tsx";
|
||||
import { useDndContext } from "../../../../pages/CardsPage/contexts/DndContext.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
selectedBoard: BoardSchema | null;
|
||||
summariesRaw: CardSummary[];
|
||||
refetchSummaries: () => void;
|
||||
refetchBoards: () => void;
|
||||
}
|
||||
const Statuses = () => {
|
||||
const { selectedBoard } = useBoardsContext();
|
||||
|
||||
const Statuses = ({
|
||||
selectedBoard,
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
refetchBoards,
|
||||
}: Props) => {
|
||||
const {
|
||||
summaries,
|
||||
dragState,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
} = useDnd({
|
||||
selectedBoard,
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
refetchBoards,
|
||||
});
|
||||
} = useDndContext();
|
||||
|
||||
const statusDndColumn = (status: StatusSchema, index: number) => {
|
||||
const filteredSummaries = summaries.filter(
|
||||
@@ -45,9 +28,7 @@ const Statuses = ({
|
||||
summaries={filteredSummaries}
|
||||
index={index}
|
||||
status={status}
|
||||
board={selectedBoard}
|
||||
dragState={dragState}
|
||||
refetch={refetchBoards}
|
||||
/>
|
||||
<CardsDndColumn
|
||||
withCreateButton={index === 0}
|
||||
@@ -64,26 +45,21 @@ const Statuses = ({
|
||||
.sort((a, b) => a.ordinalNumber - b.ordinalNumber) ?? [];
|
||||
|
||||
return (
|
||||
<DragDropContext
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
>
|
||||
<EqualHeightsContextProvider statuses={statuses}>
|
||||
<Flex
|
||||
justify={"space-between"}
|
||||
direction={"column"}
|
||||
>
|
||||
<Flex className={styles["statuses"]}>
|
||||
{selectedBoard &&
|
||||
statuses.map(((status: StatusSchema, index: number) => {
|
||||
return statusDndColumn(status, index);
|
||||
}))
|
||||
}
|
||||
</Flex>
|
||||
<CardsDndFooter dragState={dragState} />
|
||||
<EqualHeightsContextProvider statuses={statuses}>
|
||||
<Flex
|
||||
justify={"space-between"}
|
||||
direction={"column"}
|
||||
>
|
||||
<Flex className={styles["statuses"]}>
|
||||
{selectedBoard &&
|
||||
statuses.map(((status: StatusSchema, index: number) => {
|
||||
return statusDndColumn(status, index);
|
||||
}))
|
||||
}
|
||||
</Flex>
|
||||
</EqualHeightsContextProvider>
|
||||
</DragDropContext>
|
||||
<CardsDndFooter dragState={dragState} />
|
||||
</Flex>
|
||||
</EqualHeightsContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { DropResult } from "@hello-pangea/dnd";
|
||||
import { BoardSchema, StatusSchema, StatusService } from "../../../../../client";
|
||||
import { StatusSchema, StatusService } from "../../../../../client";
|
||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||
import { useBoardsContext } from "../../../../../contexts/BoardsContext.tsx";
|
||||
|
||||
type Props = {
|
||||
board: BoardSchema | null;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const useStatusesDnd = ({ refetch, board }: Props) => {
|
||||
const useStatusesDnd = () => {
|
||||
const {
|
||||
refetchBoards,
|
||||
selectedBoard: board,
|
||||
} = useBoardsContext();
|
||||
|
||||
const updateStatusOrder = (status: StatusSchema, newOrdinalNumber: number) => {
|
||||
if (!board) return;
|
||||
|
||||
@@ -20,7 +22,7 @@ const useStatusesDnd = ({ refetch, board }: Props) => {
|
||||
})
|
||||
.then(({ ok, message }) => {
|
||||
if (!ok) notifications.error({ message });
|
||||
refetch();
|
||||
refetchBoards();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { BoardSchema, BoardService } from "../../../../../client";
|
||||
import React, { createContext, FC, useContext, useEffect, useState } from "react";
|
||||
import { BoardSchema, BoardService } from "../client";
|
||||
import { useProjectsContext } from "./ProjectsContext.tsx";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||
import { useProjectsContext } from "../../../../../contexts/ProjectsContext.tsx";
|
||||
import { notifications } from "../shared/lib/notifications.ts";
|
||||
import useBoards from "../pages/CardsPage/hooks/useBoards.tsx";
|
||||
|
||||
type Props = {
|
||||
boards: BoardSchema[];
|
||||
refetchBoards: () => void;
|
||||
}
|
||||
type BoardsContextState = {
|
||||
boards: BoardSchema[],
|
||||
refetchBoards: () => void,
|
||||
selectedBoard: BoardSchema | null,
|
||||
setSelectedBoard: React.Dispatch<React.SetStateAction<BoardSchema | null>>,
|
||||
onCreateBoardClick: () => void,
|
||||
onEditBoardClick: (board: BoardSchema) => void,
|
||||
onDeleteBoardClick: (board: BoardSchema) => void,
|
||||
};
|
||||
|
||||
const useBoards = ({ boards, refetchBoards }: Props) => {
|
||||
const BoardsContext = createContext<BoardsContextState | undefined>(undefined);
|
||||
|
||||
const useBoardsContextState = () => {
|
||||
const { boards, refetchBoards } = useBoards();
|
||||
const [selectedBoard, setSelectedBoard] = useState<BoardSchema | null>(null);
|
||||
const { selectedProject: project } = useProjectsContext();
|
||||
|
||||
@@ -20,7 +29,6 @@ const useBoards = ({ boards, refetchBoards }: Props) => {
|
||||
}
|
||||
|
||||
if (selectedBoard) {
|
||||
// Update selected board after changing all boards
|
||||
let newBoard = boards.find(board => board.id === selectedBoard.id);
|
||||
|
||||
if (!newBoard && boards.length > 0) {
|
||||
@@ -73,6 +81,8 @@ const useBoards = ({ boards, refetchBoards }: Props) => {
|
||||
};
|
||||
|
||||
return {
|
||||
boards,
|
||||
refetchBoards,
|
||||
selectedBoard,
|
||||
setSelectedBoard,
|
||||
onCreateBoardClick,
|
||||
@@ -81,4 +91,26 @@ const useBoards = ({ boards, refetchBoards }: Props) => {
|
||||
};
|
||||
};
|
||||
|
||||
export default useBoards;
|
||||
type BoardsContextProviderProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const BoardsContextProvider: FC<BoardsContextProviderProps> = ({ children }) => {
|
||||
const state = useBoardsContextState();
|
||||
|
||||
return (
|
||||
<BoardsContext.Provider value={state}>
|
||||
{children}
|
||||
</BoardsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useBoardsContext = () => {
|
||||
const context = useContext(BoardsContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useBoardsContext must be used within a BoardsContextProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
11
src/main.tsx
11
src/main.tsx
@@ -25,6 +25,7 @@ import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
|
||||
import { ContextMenuProvider } from "mantine-contextmenu";
|
||||
import { ProjectsContextProvider } from "./contexts/ProjectsContext.tsx";
|
||||
import { ModulesContextProvider } from "./modules/context/ModulesContext.tsx";
|
||||
import { BoardsContextProvider } from "./contexts/BoardsContext.tsx";
|
||||
|
||||
// Configuring router
|
||||
const router = createRouter({ routeTree });
|
||||
@@ -57,10 +58,12 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<DatesProvider settings={{ locale: "ru" }}>
|
||||
<TasksProvider>
|
||||
<ProjectsContextProvider>
|
||||
<ModulesContextProvider>
|
||||
<RouterProvider router={router} />
|
||||
<Notifications />
|
||||
</ModulesContextProvider>
|
||||
<BoardsContextProvider>
|
||||
<ModulesContextProvider>
|
||||
<RouterProvider router={router} />
|
||||
<Notifications />
|
||||
</ModulesContextProvider>
|
||||
</BoardsContextProvider>
|
||||
</ProjectsContextProvider>
|
||||
</TasksProvider>
|
||||
</DatesProvider>
|
||||
|
||||
@@ -19,9 +19,7 @@ type CardPageContextStateProps = {
|
||||
|
||||
const useCardPageContextState = (props: CardPageContextStateProps) => {
|
||||
const { refetchCards, defaultCardId } = props;
|
||||
const [selectedCard, setSelectedCard] = useState<CardSchema | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [selectedCard, setSelectedCard] = useState<CardSchema | undefined>(undefined);
|
||||
|
||||
const refetchCard = () => {
|
||||
const cardId = selectedCard?.id ?? defaultCardId;
|
||||
|
||||
91
src/pages/CardsPage/contexts/DndContext.tsx
Normal file
91
src/pages/CardsPage/contexts/DndContext.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React, { createContext, FC, useContext, useState } from "react";
|
||||
import { CardSummary } from "../../../client";
|
||||
import DragState from "../enums/DragState.ts";
|
||||
import useCardsDnd from "../../../components/Dnd/Cards/CardsDndColumn/hooks/useCardsDnd.tsx";
|
||||
import useStatusesDnd from "../../../components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx";
|
||||
import { DragStart, DropResult } from "@hello-pangea/dnd";
|
||||
import useBoardsDnd from "../../../components/Dnd/Boards/Boards/hooks/useBoardsDnd.tsx";
|
||||
|
||||
type DndContextState = {
|
||||
summaries: CardSummary[],
|
||||
dragState: DragState,
|
||||
onDragStart: (start: DragStart) => void,
|
||||
onDragEnd: (result: DropResult) => Promise<void>,
|
||||
};
|
||||
|
||||
const DndContext = createContext<DndContextState | undefined>(undefined);
|
||||
|
||||
type DndContextProps = {
|
||||
summariesRaw: CardSummary[];
|
||||
refetchSummaries: () => void;
|
||||
}
|
||||
|
||||
const useDndContextState = ({
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
}: DndContextProps) => {
|
||||
const [dragState, setDragState] = useState<DragState>(DragState.DRAG_ENDED);
|
||||
|
||||
const {
|
||||
summaries,
|
||||
onCardDragEnd,
|
||||
} = useCardsDnd({
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
});
|
||||
|
||||
const { onStatusDragEnd } = useStatusesDnd();
|
||||
|
||||
const { onBoardDragEnd } = useBoardsDnd();
|
||||
|
||||
const onDragEnd = async (result: DropResult) => {
|
||||
setDragState(DragState.DRAG_ENDED);
|
||||
if (result.draggableId.includes("status")) {
|
||||
return onStatusDragEnd(result);
|
||||
}
|
||||
if (result.draggableId.includes("board")) {
|
||||
return onBoardDragEnd(result);
|
||||
}
|
||||
return onCardDragEnd(result);
|
||||
};
|
||||
|
||||
const onDragStart = (start: DragStart) => {
|
||||
if (start.source.droppableId.includes("status")) {
|
||||
setDragState(DragState.DRAG_STATUS);
|
||||
} else if (start.source.droppableId.includes("board")) {
|
||||
setDragState(DragState.DRAG_BOARD);
|
||||
} else {
|
||||
setDragState(DragState.DRAG_CARD);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
summaries,
|
||||
dragState,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
};
|
||||
};
|
||||
|
||||
type DndContextProviderProps = {
|
||||
children: React.ReactNode;
|
||||
} & DndContextProps;
|
||||
|
||||
export const DndContextProvider: FC<DndContextProviderProps> = ({ children, ...props }) => {
|
||||
const state = useDndContextState(props);
|
||||
return (
|
||||
<DndContext.Provider value={state}>
|
||||
{children}
|
||||
</DndContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useDndContext = () => {
|
||||
const context = useContext(DndContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useDndContext must be used within a DndContextProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -2,6 +2,7 @@ enum DragState {
|
||||
DRAG_ENDED,
|
||||
DRAG_CARD,
|
||||
DRAG_STATUS,
|
||||
DRAG_BOARD,
|
||||
}
|
||||
|
||||
export default DragState;
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { BoardSchema, CardSummary } from "../../../client";
|
||||
import { DragStart, DropResult } from "@hello-pangea/dnd";
|
||||
import { useState } from "react";
|
||||
import DragState from "../enums/DragState.ts";
|
||||
import useCardsDnd from "../../../components/Dnd/Cards/CardsDndColumn/hooks/useCardsDnd.tsx";
|
||||
import useStatusesDnd from "../../../components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx";
|
||||
|
||||
|
||||
type Props = {
|
||||
selectedBoard: BoardSchema | null;
|
||||
summariesRaw: CardSummary[];
|
||||
refetchSummaries: () => void;
|
||||
refetchBoards: () => void;
|
||||
}
|
||||
|
||||
const useDnd = ({
|
||||
selectedBoard,
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
refetchBoards,
|
||||
}: Props) => {
|
||||
const [dragState, setDragState] = useState<DragState>(DragState.DRAG_ENDED);
|
||||
|
||||
const {
|
||||
summaries,
|
||||
onCardDragEnd,
|
||||
} = useCardsDnd({
|
||||
summariesRaw,
|
||||
refetchSummaries,
|
||||
})
|
||||
|
||||
const {
|
||||
onStatusDragEnd,
|
||||
} = useStatusesDnd({
|
||||
board: selectedBoard,
|
||||
refetch: refetchBoards,
|
||||
});
|
||||
|
||||
const onDragEnd = async (result: DropResult) => {
|
||||
setDragState(DragState.DRAG_ENDED);
|
||||
if (result.draggableId.includes("status")) {
|
||||
return onStatusDragEnd(result);
|
||||
}
|
||||
return onCardDragEnd(result);
|
||||
}
|
||||
|
||||
const onDragStart = (start: DragStart) => {
|
||||
if (start.source.droppableId.includes("status")) {
|
||||
setDragState(DragState.DRAG_STATUS);
|
||||
} else {
|
||||
setDragState(DragState.DRAG_CARD);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
summaries,
|
||||
dragState,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDnd;
|
||||
@@ -13,37 +13,30 @@ import { useParams } from "@tanstack/react-router";
|
||||
import { PrefillCardsWithExcelContextProvider } from "../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import DisplayMode from "../enums/DisplayMode.ts";
|
||||
import CardsPageHeader from "../components/CardsPageHeader/CardsPageHeader.tsx";
|
||||
import Boards from "../../../components/Dnd/Boards/Boards/Boards.tsx";
|
||||
import useBoards from "../hooks/useBoards.tsx";
|
||||
import { ProjectsEditorContextProvider } from "../contexts/ProjectsEditorContext.tsx";
|
||||
import ProjectEditDrawer from "../drawers/ProjectEditDrawer/ProjectEditDrawer.tsx";
|
||||
import Boards from "../../../components/Dnd/Boards/Boards/Boards.tsx";
|
||||
import { DndContextProvider } from "../contexts/DndContext.tsx";
|
||||
|
||||
export const CardsPage: FC = () => {
|
||||
const { data, form } = useCardsPageState();
|
||||
const { boards, refetchBoards } = useBoards();
|
||||
const { dealId } = useParams({ strict: false });
|
||||
const { summariesRaw, refetch: refetchSummaries } = useCardSummaries();
|
||||
|
||||
const [displayMode, setDisplayMode] = useState<DisplayMode>(
|
||||
DisplayMode.BOARD,
|
||||
const [displayMode, setDisplayMode] = useState<DisplayMode>(DisplayMode.BOARD);
|
||||
|
||||
const tableBody = (
|
||||
<CardsTable items={data} />
|
||||
);
|
||||
|
||||
const getTableBody = () => {
|
||||
return (
|
||||
<CardsTable items={data} />
|
||||
);
|
||||
};
|
||||
|
||||
const getBoardsBody = () => {
|
||||
return (
|
||||
<Boards
|
||||
summariesRaw={summariesRaw}
|
||||
refetchSummaries={refetchSummaries}
|
||||
boards={boards}
|
||||
refetchBoards={refetchBoards}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const boardsBody = (
|
||||
<DndContextProvider
|
||||
summariesRaw={summariesRaw}
|
||||
refetchSummaries={refetchSummaries}
|
||||
>
|
||||
<Boards />
|
||||
</DndContextProvider>
|
||||
);
|
||||
|
||||
const getBody = () => {
|
||||
return (
|
||||
@@ -53,8 +46,8 @@ export const CardsPage: FC = () => {
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}>
|
||||
{displayMode === DisplayMode.TABLE
|
||||
? getTableBody()
|
||||
: getBoardsBody()
|
||||
? tableBody
|
||||
: boardsBody
|
||||
}
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user