plane/web/components/core/views/board-view/single-board.tsx
sriram veeraghanta 1e152c666c
New Directory Setup (#2065)
* chore: moved app & space from apps to root

* chore: modified workspace configuration

* chore: modified dockerfiles for space and web

* chore: modified icons for space

* feat: updated files for new svg icons supported by next-images

* chore: added /spaces base path for next

* chore: added compose config for space

* chore: updated husky configuration

* chore: updated workflows for new configuration

* chore: changed app name to web

* fix: resolved build errors with web

* chore: reset file tracing root for both projects

* chore: added nginx config for deploy

* fix: eslint and tsconfig settings for space app

* husky setup fixes based on new dir

* eslint fixes

* prettier formatting

---------

Co-authored-by: Henit Chobisa <chobisa.henit@gmail.com>
2023-09-03 18:50:30 +05:30

200 lines
7.4 KiB
TypeScript

import { useState } from "react";
import { useRouter } from "next/router";
// react-beautiful-dnd
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
import { Draggable } from "react-beautiful-dnd";
// components
import { BoardHeader, SingleBoardIssue } from "components/core";
// ui
import { CustomMenu } from "components/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types
import { ICurrentUserResponse, IIssue, IIssueViewProps, IState, UserAuth } from "types";
type Props = {
addIssueToGroup: () => void;
currentState?: IState | null;
disableUserActions: boolean;
dragDisabled: boolean;
groupTitle: string;
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
handleTrashBox: (isDragging: boolean) => void;
openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth;
viewProps: IIssueViewProps;
};
export const SingleBoard: React.FC<Props> = ({
addIssueToGroup,
currentState,
groupTitle,
disableUserActions,
dragDisabled,
handleIssueAction,
handleTrashBox,
openIssuesListModal,
removeIssue,
user,
userAuth,
viewProps,
}) => {
// collapse/expand
const [isCollapsed, setIsCollapsed] = useState(true);
const { groupedIssues, groupByProperty: selectedGroup, orderBy, properties } = viewProps;
const router = useRouter();
const { cycleId, moduleId } = router.query;
const isSubscribedIssues = router.pathname.includes("subscribed");
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
// Check if it has at least 4 tickets since it is enough to accommodate the Calendar height
const issuesLength = groupedIssues?.[groupTitle].length;
const hasMinimumNumberOfCards = issuesLength ? issuesLength >= 4 : false;
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions;
return (
<div className={`flex-shrink-0 ${!isCollapsed ? "" : "flex h-full flex-col w-96"}`}>
<BoardHeader
addIssueToGroup={addIssueToGroup}
currentState={currentState}
groupTitle={groupTitle}
isCollapsed={isCollapsed}
setIsCollapsed={setIsCollapsed}
disableUserActions={disableUserActions}
disableAddIssue={isSubscribedIssues}
viewProps={viewProps}
/>
{isCollapsed && (
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
{(provided, snapshot) => (
<div
className={`relative h-full ${
orderBy !== "sort_order" && snapshot.isDraggingOver
? "bg-custom-background-100/20"
: ""
} ${!isCollapsed ? "hidden" : "flex flex-col"}`}
ref={provided.innerRef}
{...provided.droppableProps}
>
{orderBy !== "sort_order" && (
<>
<div
className={`absolute ${
snapshot.isDraggingOver ? "block" : "hidden"
} pointer-events-none top-0 left-0 z-[99] h-full w-full bg-custom-background-90 opacity-50`}
/>
<div
className={`absolute ${
snapshot.isDraggingOver ? "block" : "hidden"
} pointer-events-none top-1/2 left-1/2 z-[99] -translate-y-1/2 -translate-x-1/2 whitespace-nowrap rounded bg-custom-background-100 p-2 text-xs`}
>
This board is ordered by{" "}
{replaceUnderscoreIfSnakeCase(
orderBy ? (orderBy[0] === "-" ? orderBy.slice(1) : orderBy) : "created_at"
)}
</div>
</>
)}
<div
className={`pt-3 ${
hasMinimumNumberOfCards ? "overflow-hidden overflow-y-scroll" : ""
} `}
>
{groupedIssues?.[groupTitle].map((issue, index) => (
<Draggable
key={issue.id}
draggableId={issue.id}
index={index}
isDragDisabled={isNotAllowed || dragDisabled}
>
{(provided, snapshot) => (
<SingleBoardIssue
key={index}
provided={provided}
snapshot={snapshot}
type={type}
index={index}
issue={issue}
groupTitle={groupTitle}
editIssue={() => handleIssueAction(issue, "edit")}
makeIssueCopy={() => handleIssueAction(issue, "copy")}
handleDeleteIssue={() => handleIssueAction(issue, "delete")}
handleTrashBox={handleTrashBox}
removeIssue={() => {
if (removeIssue && issue.bridge_id)
removeIssue(issue.bridge_id, issue.id);
}}
disableUserActions={disableUserActions}
user={user}
userAuth={userAuth}
viewProps={viewProps}
/>
)}
</Draggable>
))}
<span
style={{
display: orderBy === "sort_order" ? "inline" : "none",
}}
>
{provided.placeholder}
</span>
</div>
{selectedGroup !== "created_by" && (
<div>
{type === "issue"
? !isSubscribedIssues && (
<button
type="button"
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
onClick={addIssueToGroup}
>
<PlusIcon className="h-4 w-4" />
Add Issue
</button>
)
: !disableUserActions && (
<CustomMenu
customButton={
<button
type="button"
className="flex items-center gap-2 font-medium text-custom-primary outline-none whitespace-nowrap"
>
<PlusIcon className="h-4 w-4" />
Add Issue
</button>
}
position="left"
noBorder
>
<CustomMenu.MenuItem onClick={addIssueToGroup}>
Create new
</CustomMenu.MenuItem>
{openIssuesListModal && (
<CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
)}
</CustomMenu>
)}
</div>
)}
</div>
)}
</StrictModeDroppable>
)}
</div>
);
};