feat: quick-add placement in spreadsheet and gantt (#2259)

* feat: sticking quick-add at the bottom of the screen

fix: opening create issue modal instead of quick-add in draft-issues, my-issue and profile page

* fix: build error due to dynamic import
This commit is contained in:
Dakshesh Jain 2023-09-25 19:08:26 +05:30 committed by GitHub
parent de7a672b79
commit 5e8d523ed4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 121 additions and 95 deletions

View File

@ -63,6 +63,10 @@ export const SingleBoard: React.FC<Props> = (props) => {
const router = useRouter();
const { cycleId, moduleId } = router.query;
const isMyIssuesPage = router.pathname.split("/")[3] === "my-issues";
const isProfileIssuesPage = router.pathname.split("/")[2] === "profile";
const isDraftIssuesPage = router.pathname.split("/")[4] === "draft-issues";
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
// Check if it has at least 4 tickets since it is enough to accommodate the Calendar height
@ -214,7 +218,11 @@ export const SingleBoard: React.FC<Props> = (props) => {
<button
type="button"
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
onClick={() => onCreateClick()}
onClick={() => {
if (isDraftIssuesPage || isMyIssuesPage || isProfileIssuesPage) {
addIssueToGroup();
} else onCreateClick();
}}
>
<PlusIcon className="h-4 w-4" />
Add Issue

View File

@ -154,15 +154,6 @@ export const InlineCreateIssueFormWrapper: React.FC<Props> = (props) => {
if (!isOpen) reset({ ...defaultValues });
}, [isOpen, reset]);
useEffect(() => {
if (isSubmitting)
setToastAlert({
type: "info",
title: "Creating issue...",
message: "Please wait while we create your issue.",
});
}, [isSubmitting, setToastAlert]);
useEffect(() => {
if (!errors) return;

View File

@ -46,10 +46,17 @@ const InlineInput = () => {
};
export const ListInlineCreateIssueForm: React.FC<Props> = (props) => (
<InlineCreateIssueFormWrapper
className="flex py-3 px-4 items-center gap-x-5 bg-custom-background-100 shadow-custom-shadow-md"
{...props}
>
<InlineInput />
</InlineCreateIssueFormWrapper>
<>
<InlineCreateIssueFormWrapper
className="flex py-3 px-4 items-center gap-x-5 bg-custom-background-100 shadow-custom-shadow-md"
{...props}
>
<InlineInput />
</InlineCreateIssueFormWrapper>
{props.isOpen && (
<p className="text-xs ml-3 mt-3 italic text-custom-text-200">
Press {"'"}Enter{"'"} to add another issue
</p>
)}
</>
);

View File

@ -62,6 +62,7 @@ export const SingleList: React.FC<Props> = (props) => {
openIssuesListModal,
handleDraftIssueAction,
handleMyIssueOpen,
addIssueToGroup,
removeIssue,
disableUserActions,
disableAddIssueOption = false,
@ -75,6 +76,10 @@ export const SingleList: React.FC<Props> = (props) => {
const [isCreateIssueFormOpen, setIsCreateIssueFormOpen] = useState(false);
const isMyIssuesPage = router.pathname.split("/")[3] === "my-issues";
const isProfileIssuesPage = router.pathname.split("/")[2] === "profile";
const isDraftIssuesPage = router.pathname.split("/")[4] === "draft-issues";
const isArchivedIssues = router.pathname.includes("archived-issues");
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
@ -295,7 +300,7 @@ export const SingleList: React.FC<Props> = (props) => {
)}
<ListInlineCreateIssueForm
isOpen={isCreateIssueFormOpen}
isOpen={isCreateIssueFormOpen && !disableAddIssueOption}
handleClose={() => setIsCreateIssueFormOpen(false)}
prePopulatedData={{
...(cycleId && { cycle: cycleId.toString() }),
@ -304,11 +309,15 @@ export const SingleList: React.FC<Props> = (props) => {
}}
/>
{!isCreateIssueFormOpen && (
{!disableAddIssueOption && !isCreateIssueFormOpen && (
<div className="w-full bg-custom-background-100 px-6 py-3">
<button
type="button"
onClick={() => setIsCreateIssueFormOpen(true)}
onClick={() => {
if (isDraftIssuesPage || isMyIssuesPage || isProfileIssuesPage) {
addIssueToGroup();
} else setIsCreateIssueFormOpen(true);
}}
className="flex items-center gap-x-[6px] text-custom-primary-100 px-2 py-1 rounded-md"
>
<PlusIcon className="h-4 w-4" />

View File

@ -73,7 +73,7 @@ export const SpreadsheetView: React.FC<Props> = ({
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
</div>
{spreadsheetIssues ? (
<div className="flex flex-col h-full w-full bg-custom-background-100 rounded-sm ">
<div className="flex flex-col h-full w-full bg-custom-background-100 rounded-sm">
{spreadsheetIssues.map((issue: IIssue, index) => (
<SpreadsheetIssues
key={`${issue.id}_${index}`}
@ -90,59 +90,55 @@ export const SpreadsheetView: React.FC<Props> = ({
/>
))}
<ListInlineCreateIssueForm
isOpen={isInlineCreateIssueFormOpen}
handleClose={() => setIsInlineCreateIssueFormOpen(false)}
prePopulatedData={{
...(cycleId && { cycle: cycleId.toString() }),
...(moduleId && { module: moduleId.toString() }),
}}
/>
<div className="absolute bottom-0 left-0 z-10 group pb-2 hover:rounded-sm bg-custom-background-100 hover:bg-custom-background-80 border-b border-custom-border-200 w-full min-w-max">
<ListInlineCreateIssueForm
isOpen={isInlineCreateIssueFormOpen}
handleClose={() => setIsInlineCreateIssueFormOpen(false)}
prePopulatedData={{
...(cycleId && { cycle: cycleId.toString() }),
...(moduleId && { module: moduleId.toString() }),
}}
/>
<div
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-custom-background-80 border-b border-custom-border-200 w-full min-w-max"
style={{ gridTemplateColumns }}
>
{!isInlineCreateIssueFormOpen && (
<>
{type === "issue" ? (
{type === "issue"
? !disableUserActions &&
!isInlineCreateIssueFormOpen && (
<button
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-200 w-full"
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 border-custom-border-200 w-full"
onClick={() => setIsInlineCreateIssueFormOpen(true)}
>
<PlusIcon className="h-4 w-4" />
Add Issue
</button>
) : (
!disableUserActions && (
<CustomMenu
className="sticky left-0 z-[1]"
customButton={
<button
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-200 w-full"
type="button"
>
<PlusIcon className="h-4 w-4" />
Add Issue
</button>
}
position="left"
optionsClassName="left-5 !w-36"
noBorder
>
<CustomMenu.MenuItem onClick={() => setIsInlineCreateIssueFormOpen(true)}>
Create new
)
: !disableUserActions &&
!isInlineCreateIssueFormOpen && (
<CustomMenu
className="sticky left-0 z-[1]"
customButton={
<button
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 border-custom-border-200 w-full"
type="button"
>
<PlusIcon className="h-4 w-4" />
Add Issue
</button>
}
position="left"
verticalPosition="top"
optionsClassName="left-5 !w-36"
noBorder
>
<CustomMenu.MenuItem onClick={() => setIsInlineCreateIssueFormOpen(true)}>
Create new
</CustomMenu.MenuItem>
{openIssuesListModal && (
<CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
{openIssuesListModal && (
<CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
)}
</CustomMenu>
)
)}
</CustomMenu>
)}
</>
)}
</div>
</div>
) : (

View File

@ -155,31 +155,32 @@ export const GanttSidebar: React.FC<Props> = (props) => {
)}
{droppableProvided.placeholder}
</>
<GanttInlineCreateIssueForm
isOpen={isCreateIssueFormOpen}
handleClose={() => setIsCreateIssueFormOpen(false)}
prePopulatedData={{
start_date: new Date(Date.now()).toISOString().split("T")[0],
target_date: new Date(Date.now() + 86400000).toISOString().split("T")[0],
...(cycleId && { cycle: cycleId.toString() }),
...(moduleId && { module: moduleId.toString() }),
}}
/>
{!isCreateIssueFormOpen && (
<button
type="button"
onClick={() => setIsCreateIssueFormOpen(true)}
className="flex items-center gap-x-[6px] text-custom-primary-100 px-2 py-1 rounded-md mt-3"
>
<PlusIcon className="h-4 w-4" />
<span className="text-sm font-medium text-custom-primary-100">New Issue</span>
</button>
)}
</div>
)}
</StrictModeDroppable>
<div className="pl-2.5">
<GanttInlineCreateIssueForm
isOpen={isCreateIssueFormOpen}
handleClose={() => setIsCreateIssueFormOpen(false)}
prePopulatedData={{
start_date: new Date(Date.now()).toISOString().split("T")[0],
target_date: new Date(Date.now() + 86400000).toISOString().split("T")[0],
...(cycleId && { cycle: cycleId.toString() }),
...(moduleId && { module: moduleId.toString() }),
}}
/>
{!isCreateIssueFormOpen && (
<button
type="button"
onClick={() => setIsCreateIssueFormOpen(true)}
className="flex items-center gap-x-[6px] text-custom-primary-100 px-2 py-1 rounded-md mt-3"
>
<PlusIcon className="h-4 w-4" />
<span className="text-sm font-medium text-custom-primary-100">New Issue</span>
</button>
)}
</div>
</DragDropContext>
);
};

View File

@ -227,7 +227,8 @@ export const ProfileIssuesView = () => {
router.pathname.includes("my-issues")) ??
false;
const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues;
const disableAddIssueOption =
isSubscribedIssuesRoute || isMySubscribedIssues || user?.id !== userId;
return (
<>

View File

@ -1,3 +1,4 @@
import dynamic from "next/dynamic";
// hooks
import useTheme from "hooks/use-theme";
// components
@ -5,8 +6,18 @@ import {
WorkspaceHelpSection,
WorkspaceSidebarDropdown,
WorkspaceSidebarMenu,
WorkspaceSidebarQuickAction,
} from "components/workspace";
const WorkspaceSidebarQuickAction = dynamic<{}>(
() =>
import("components/workspace/sidebar-quick-action").then(
(mod) => mod.WorkspaceSidebarQuickAction
),
{
ssr: false,
}
);
import { ProjectSidebarList } from "components/project";
import { PublishProjectModal } from "components/project/publish-project/modal";
import { ConfirmProjectLeaveModal } from "components/project/confirm-project-leave-modal";

View File

@ -189,10 +189,12 @@ const SingleCycle: React.FC = () => {
{cycleStatus === "completed" && (
<TransferIssues handleClick={() => setTransferIssuesModal(true)} />
)}
<IssuesView
openIssuesListModal={openIssuesListModal}
disableUserActions={cycleStatus === "completed" ?? false}
/>
<div className="relative overflow-y-auto">
<IssuesView
openIssuesListModal={openIssuesListModal}
disableUserActions={cycleStatus === "completed" ?? false}
/>
</div>
</div>
<CycleDetailsSidebar
cycleStatus={cycleStatus}

View File

@ -181,9 +181,9 @@ const SingleModule: React.FC = () => {
onClose={() => setAnalyticsModal(false)}
/>
<div
className={`h-full flex flex-col ${moduleSidebar ? "mr-[24rem]" : ""} ${
analyticsModal ? "mr-[50%]" : ""
} duration-300`}
className={`relative overflow-y-auto h-full flex flex-col ${
moduleSidebar ? "mr-[24rem]" : ""
} ${analyticsModal ? "mr-[50%]" : ""} duration-300`}
>
<IssuesView openIssuesListModal={openIssuesListModal} />
</div>