chore: update empty states, fix: delete issue modal (#1743)

* chore: update empty states

* fix: delete issue modal

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
Nikhil 2023-08-01 13:58:58 +05:30 committed by GitHub
parent e48147f87e
commit 4e297d92f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 206 additions and 116 deletions

View File

@ -21,9 +21,9 @@ import {
GanttChartView,
} from "components/core";
// ui
import { EmptyState, SecondaryButton, Spinner } from "components/ui";
import { EmptyState, Spinner } from "components/ui";
// icons
import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
import { TrashIcon } from "@heroicons/react/24/outline";
// images
import emptyIssue from "public/empty-state/issue.svg";
import emptyIssueArchive from "public/empty-state/issue-archive.svg";
@ -39,6 +39,16 @@ type Props = {
addIssueToGroup: (groupTitle: string) => void;
disableUserActions: boolean;
dragDisabled?: boolean;
emptyState: {
title: string;
description?: string;
primaryButton?: {
icon: any;
text: string;
onClick: () => void;
};
secondaryButton?: React.ReactNode;
};
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
handleOnDragEnd: (result: DropResult) => Promise<void>;
openIssuesListModal: (() => void) | null;
@ -53,6 +63,7 @@ export const AllViews: React.FC<Props> = ({
addIssueToGroup,
disableUserActions,
dragDisabled = false,
emptyState,
handleIssueAction,
handleOnDragEnd,
openIssuesListModal,
@ -156,41 +167,28 @@ export const AllViews: React.FC<Props> = ({
title="Archived Issues will be shown here"
description="All the issues that have been in the completed or canceled groups for the configured period of time can be viewed here."
image={emptyIssueArchive}
buttonText="Go to Automation Settings"
onClick={() => {
primaryButton={{
text: "Go to Automation Settings",
onClick: () => {
router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`);
},
}}
/>
) : (
<EmptyState
title={
cycleId
? "Cycle issues will appear here"
: moduleId
? "Module issues will appear here"
: "Project issues will appear here"
}
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
title={emptyState.title}
description={emptyState.description}
image={emptyIssue}
buttonText="New Issue"
buttonIcon={<PlusIcon className="h-4 w-4" />}
secondaryButton={
cycleId || moduleId ? (
<SecondaryButton
className="flex items-center gap-1.5"
onClick={openIssuesListModal ?? (() => {})}
>
<PlusIcon className="h-4 w-4" />
Add an existing issue
</SecondaryButton>
) : null
primaryButton={
emptyState.primaryButton
? {
icon: emptyState.primaryButton.icon,
text: emptyState.primaryButton.text,
onClick: emptyState.primaryButton.onClick,
}
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
: undefined
}
secondaryButton={emptyState.secondaryButton}
/>
)
) : (

View File

@ -22,7 +22,7 @@ import { FiltersList, AllViews } from "components/core";
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
import { CreateUpdateViewModal } from "components/views";
// ui
import { PrimaryButton } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// helpers
@ -515,6 +515,35 @@ export const IssuesView: React.FC<Props> = ({
selectedGroup === "labels" ||
selectedGroup === "state_detail.group"
}
emptyState={{
title: cycleId
? "Cycle issues will appear here"
: moduleId
? "Module issues will appear here"
: "Project issues will appear here",
description:
"Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done.",
primaryButton: {
icon: <PlusIcon className="h-4 w-4" />,
text: "New Issue",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
},
},
secondaryButton:
cycleId || moduleId ? (
<SecondaryButton
className="flex items-center gap-1.5"
onClick={openIssuesListModal ?? (() => {})}
>
<PlusIcon className="h-4 w-4" />
Add an existing issue
</SecondaryButton>
) : null,
}}
handleOnDragEnd={handleOnDragEnd}
handleIssueAction={handleIssueAction}
openIssuesListModal={openIssuesListModal ? openIssuesListModal : null}

View File

@ -59,8 +59,9 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, u
};
const handleDeletion = async () => {
if (!workspaceSlug || !data) return;
setIsDeleteLoading(true);
if (!workspaceSlug || !projectId || !data) return;
await issueServices
.deleteIssue(workspaceSlug as string, data.project, data.id, user)
@ -112,7 +113,7 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, u
} else {
if (cycleId) mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
else if (moduleId) mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, params));
}
handleClose();

View File

@ -21,6 +21,7 @@ import { orderArrayBy } from "helpers/array.helper";
import { IIssue, IIssueFilterOptions } from "types";
// fetch-keys
import { USER_ISSUES, WORKSPACE_LABELS } from "constants/fetch-keys";
import { PlusIcon } from "@heroicons/react/24/outline";
type Props = {
openIssuesListModal?: () => void;
@ -262,6 +263,20 @@ export const MyIssuesView: React.FC<Props> = ({
addIssueToGroup={addIssueToGroup}
disableUserActions={disableUserActions}
dragDisabled={groupBy !== "priority"}
emptyState={{
title: "You don't have any issue assigned to you yet",
description: "Keep track of your work in a single place.",
primaryButton: {
icon: <PlusIcon className="h-4 w-4" />,
text: "New Issue",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
},
},
}}
handleOnDragEnd={handleOnDragEnd}
handleIssueAction={handleIssueAction}
openIssuesListModal={openIssuesListModal ? openIssuesListModal : null}

View File

@ -56,13 +56,15 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
title="Have your thoughts in place"
description="You can think of Pages as an AI-powered notepad."
image={emptyPage}
buttonText="New Page"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Page",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "d",
});
document.dispatchEvent(e);
},
}}
/>
)

View File

@ -260,13 +260,15 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
title="Have your thoughts in place"
description="You can think of Pages as an AI-powered notepad."
image={emptyPage}
buttonText="New Page"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Page",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "d",
});
document.dispatchEvent(e);
},
}}
/>
)}

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useState } from "react";
import { useRouter } from "next/router";
@ -140,10 +140,26 @@ export const ProfileIssuesView = () => {
]
);
const addIssueToGroup = useCallback((groupTitle: string) => {
const addIssueToGroup = useCallback(
(groupTitle: string) => {
setCreateIssueModal(true);
return;
}, []);
let preloadedValue: string | string[] = groupTitle;
if (groupByProperty === "labels") {
if (groupTitle === "None") preloadedValue = [];
else preloadedValue = [groupTitle];
}
if (groupByProperty)
setPreloadedData({
[groupByProperty]: preloadedValue,
actionType: "createIssue",
});
else setPreloadedData({ actionType: "createIssue" });
},
[setCreateIssueModal, setPreloadedData, groupByProperty]
);
const addIssueToDate = useCallback(
(date: string) => {
@ -250,6 +266,13 @@ export const ProfileIssuesView = () => {
addIssueToGroup={addIssueToGroup}
disableUserActions={false}
dragDisabled={groupByProperty !== "priority"}
emptyState={{
title: router.pathname.includes("assigned")
? `Issues assigned to ${user?.first_name} ${user?.last_name} will appear here`
: router.pathname.includes("created")
? `Issues created by ${user?.first_name} ${user?.last_name} will appear here`
: `Issues subscribed by ${user?.first_name} ${user?.last_name} will appear here`,
}}
handleOnDragEnd={handleOnDragEnd}
handleIssueAction={handleIssueAction}
openIssuesListModal={null}

View File

@ -9,10 +9,12 @@ type Props = {
title: string;
description: React.ReactNode | string;
image: any;
buttonText?: string;
buttonIcon?: any;
primaryButton?: {
icon?: any;
text: string;
onClick: () => void;
};
secondaryButton?: React.ReactNode;
onClick?: () => void;
isFullScreen?: boolean;
};
@ -20,9 +22,7 @@ export const EmptyState: React.FC<Props> = ({
title,
description,
image,
onClick,
buttonText,
buttonIcon,
primaryButton,
secondaryButton,
isFullScreen = true,
}) => (
@ -32,14 +32,14 @@ export const EmptyState: React.FC<Props> = ({
}`}
>
<div className="text-center flex flex-col items-center w-full">
<Image src={image} className="w-52 sm:w-60" alt={buttonText} />
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} />
<h6 className="text-xl font-semibold mt-6 sm:mt-8 mb-3">{title}</h6>
<p className="text-custom-text-300 mb-7 sm:mb-8">{description}</p>
<div className="flex items-center gap-4">
{buttonText && (
<PrimaryButton className="flex items-center gap-1.5" onClick={onClick}>
{buttonIcon}
{buttonText}
{primaryButton && (
<PrimaryButton className="flex items-center gap-1.5" onClick={primaryButton.onClick}>
{primaryButton.icon}
{primaryButton.text}
</PrimaryButton>
)}
{secondaryButton}

View File

@ -71,12 +71,14 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
title="No such project exists"
description="Try creating a new project"
image={emptyProject}
buttonText="Create Project"
onClick={() => {
primaryButton={{
text: "Create Project",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}}
/>
</div>

View File

@ -134,13 +134,15 @@ const Analytics = () => {
title="You can see your all projects' analytics here"
description="Let's create your first project and analyse the stats with various graphs."
image={emptyAnalytics}
buttonText="New Project"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Project",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}}
/>
)

View File

@ -121,13 +121,15 @@ const ProjectCycles: NextPage = () => {
title="Plan your project with cycles"
description="Cycle is a custom time period in which a team works to complete items on their backlog."
image={emptyCycle}
buttonText="New Cycle"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Cycle",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "q",
});
document.dispatchEvent(e);
},
}}
/>
</div>

View File

@ -146,13 +146,15 @@ const ProjectModules: NextPage = () => {
title="Manage your project with modules"
description="Modules are smaller, focused projects that help you group and organize issues."
image={emptyModule}
buttonText="New Module"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Module",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "m",
});
document.dispatchEvent(e);
},
}}
/>
)

View File

@ -166,11 +166,13 @@ const EstimatesSettings: NextPage = () => {
title="No estimates yet"
description="Estimates help you communicate the complexity of an issue."
image={emptyEstimate}
buttonText="Add Estimate"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "Add Estimate",
onClick: () => {
setEstimateToUpdate(undefined);
setEstimateFormOpen(true);
},
}}
/>
</div>

View File

@ -78,8 +78,10 @@ const ProjectIntegrations: NextPage = () => {
title="You haven't configured integrations"
description="Configure GitHub and other integrations to sync your project issues."
image={emptyIntegration}
buttonText="Configure now"
onClick={() => router.push(`/${workspaceSlug}/settings/integrations`)}
primaryButton={{
text: "Configure now",
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
}}
/>
)
) : (

View File

@ -181,8 +181,10 @@ const LabelsSettings: NextPage = () => {
title="No labels yet"
description="Create labels to help organize and filter issues in you project"
image={emptyLabel}
buttonText="Add label"
onClick={newLabel}
primaryButton={{
text: "Add label",
onClick: () => newLabel(),
}}
isFullScreen={false}
/>
)

View File

@ -118,13 +118,15 @@ const ProjectViews: NextPage = () => {
title="Get focused with views"
description="Views aid in saving your issues by applying various filters and grouping options."
image={emptyView}
buttonText="New View"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New View",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "v",
});
document.dispatchEvent(e);
},
}}
/>
)

View File

@ -111,13 +111,15 @@ const ProjectsPage: NextPage = () => {
image={emptyProject}
title="No projects yet"
description="Get started by creating your first project"
buttonText="New Project"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
primaryButton={{
icon: <PlusIcon className="h-4 w-4" />,
text: "New Project",
onClick: () => {
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}}
/>
)}

View File

@ -186,8 +186,10 @@ const OnBoard: NextPage = () => {
title="No pending invites"
description="You can see here if someone invites you to a workspace."
image={emptyInvitation}
buttonText="Back to Dashboard"
onClick={() => router.push("/")}
primaryButton={{
text: "Back to Dashboard",
onClick: () => router.push("/"),
}}
/>
</div>
)