diff --git a/apps/app/components/core/views/all-views.tsx b/apps/app/components/core/views/all-views.tsx index 60d3c88f6..4a757649c 100644 --- a/apps/app/components/core/views/all-views.tsx +++ b/apps/app/components/core/views/all-views.tsx @@ -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; openIssuesListModal: (() => void) | null; @@ -53,6 +63,7 @@ export const AllViews: React.FC = ({ addIssueToGroup, disableUserActions, dragDisabled = false, + emptyState, handleIssueAction, handleOnDragEnd, openIssuesListModal, @@ -156,41 +167,28 @@ export const AllViews: React.FC = ({ 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={() => { - router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`); + primaryButton={{ + text: "Go to Automation Settings", + onClick: () => { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`); + }, }} /> ) : ( } - secondaryButton={ - cycleId || moduleId ? ( - {})} - > - - Add an existing issue - - ) : null + primaryButton={ + emptyState.primaryButton + ? { + icon: emptyState.primaryButton.icon, + text: emptyState.primaryButton.text, + onClick: emptyState.primaryButton.onClick, + } + : undefined } - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "c", - }); - document.dispatchEvent(e); - }} + secondaryButton={emptyState.secondaryButton} /> ) ) : ( diff --git a/apps/app/components/core/views/issues-view.tsx b/apps/app/components/core/views/issues-view.tsx index 96b7e395c..d3d76f805 100644 --- a/apps/app/components/core/views/issues-view.tsx +++ b/apps/app/components/core/views/issues-view.tsx @@ -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 = ({ 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: , + text: "New Issue", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "c", + }); + document.dispatchEvent(e); + }, + }, + secondaryButton: + cycleId || moduleId ? ( + {})} + > + + Add an existing issue + + ) : null, + }} handleOnDragEnd={handleOnDragEnd} handleIssueAction={handleIssueAction} openIssuesListModal={openIssuesListModal ? openIssuesListModal : null} diff --git a/apps/app/components/issues/delete-issue-modal.tsx b/apps/app/components/issues/delete-issue-modal.tsx index 9a4725ae2..f46dae9aa 100644 --- a/apps/app/components/issues/delete-issue-modal.tsx +++ b/apps/app/components/issues/delete-issue-modal.tsx @@ -59,8 +59,9 @@ export const DeleteIssueModal: React.FC = ({ 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 = ({ 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(); diff --git a/apps/app/components/issues/my-issues/my-issues-view.tsx b/apps/app/components/issues/my-issues/my-issues-view.tsx index 695c36374..a30c7092c 100644 --- a/apps/app/components/issues/my-issues/my-issues-view.tsx +++ b/apps/app/components/issues/my-issues/my-issues-view.tsx @@ -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 = ({ 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: , + text: "New Issue", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "c", + }); + document.dispatchEvent(e); + }, + }, + }} handleOnDragEnd={handleOnDragEnd} handleIssueAction={handleIssueAction} openIssuesListModal={openIssuesListModal ? openIssuesListModal : null} diff --git a/apps/app/components/pages/pages-list/recent-pages-list.tsx b/apps/app/components/pages/pages-list/recent-pages-list.tsx index 2a4942564..34199b279 100644 --- a/apps/app/components/pages/pages-list/recent-pages-list.tsx +++ b/apps/app/components/pages/pages-list/recent-pages-list.tsx @@ -56,13 +56,15 @@ export const RecentPagesList: React.FC = ({ viewType }) => { title="Have your thoughts in place" description="You can think of Pages as an AI-powered notepad." image={emptyPage} - buttonText="New Page" - buttonIcon={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "d", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Page", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "d", + }); + document.dispatchEvent(e); + }, }} /> ) diff --git a/apps/app/components/pages/pages-view.tsx b/apps/app/components/pages/pages-view.tsx index c08d09241..8178460e1 100644 --- a/apps/app/components/pages/pages-view.tsx +++ b/apps/app/components/pages/pages-view.tsx @@ -260,13 +260,15 @@ export const PagesView: React.FC = ({ 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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "d", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Page", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "d", + }); + document.dispatchEvent(e); + }, }} /> )} diff --git a/apps/app/components/profile/profile-issues-view.tsx b/apps/app/components/profile/profile-issues-view.tsx index b87f9f06e..64632f0b9 100644 --- a/apps/app/components/profile/profile-issues-view.tsx +++ b/apps/app/components/profile/profile-issues-view.tsx @@ -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) => { - setCreateIssueModal(true); - return; - }, []); + const addIssueToGroup = useCallback( + (groupTitle: string) => { + setCreateIssueModal(true); + + 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} diff --git a/apps/app/components/ui/empty-state.tsx b/apps/app/components/ui/empty-state.tsx index a13e59679..26b621d98 100644 --- a/apps/app/components/ui/empty-state.tsx +++ b/apps/app/components/ui/empty-state.tsx @@ -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 = ({ title, description, image, - onClick, - buttonText, - buttonIcon, + primaryButton, secondaryButton, isFullScreen = true, }) => ( @@ -32,14 +32,14 @@ export const EmptyState: React.FC = ({ }`} >
- {buttonText} + {primaryButton?.text}
{title}

{description}

- {buttonText && ( - - {buttonIcon} - {buttonText} + {primaryButton && ( + + {primaryButton.icon} + {primaryButton.text} )} {secondaryButton} diff --git a/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx b/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx index a9c9fec1f..66f4693af 100644 --- a/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx +++ b/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx @@ -71,12 +71,14 @@ const ProjectAuthorizationWrapped: React.FC = ({ title="No such project exists" description="Try creating a new project" image={emptyProject} - buttonText="Create Project" - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "p", - }); - document.dispatchEvent(e); + primaryButton={{ + text: "Create Project", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "p", + }); + document.dispatchEvent(e); + }, }} />
diff --git a/apps/app/pages/[workspaceSlug]/analytics.tsx b/apps/app/pages/[workspaceSlug]/analytics.tsx index 493e708aa..945b27c4e 100644 --- a/apps/app/pages/[workspaceSlug]/analytics.tsx +++ b/apps/app/pages/[workspaceSlug]/analytics.tsx @@ -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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "p", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Project", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "p", + }); + document.dispatchEvent(e); + }, }} /> ) diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 0ea9e73e3..7633d41bd 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "q", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Cycle", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "q", + }); + document.dispatchEvent(e); + }, }} />
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index b5b1e3806..fb0811ffc 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "m", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Module", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "m", + }); + document.dispatchEvent(e); + }, }} /> ) diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx index 7c82f7dd4..f61bd24d8 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx @@ -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={} - onClick={() => { - setEstimateToUpdate(undefined); - setEstimateFormOpen(true); + primaryButton={{ + icon: , + text: "Add Estimate", + onClick: () => { + setEstimateToUpdate(undefined); + setEstimateFormOpen(true); + }, }} /> diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx index 0ede7d216..9c5fdecfc 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx @@ -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`), + }} /> ) ) : ( diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index d8c425ee5..3f4495ef5 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -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} /> ) diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx index 1034b741d..9a5511037 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx @@ -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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "v", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New View", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "v", + }); + document.dispatchEvent(e); + }, }} /> ) diff --git a/apps/app/pages/[workspaceSlug]/projects/index.tsx b/apps/app/pages/[workspaceSlug]/projects/index.tsx index 5f3fbcc07..6c60d4abd 100644 --- a/apps/app/pages/[workspaceSlug]/projects/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/index.tsx @@ -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={} - onClick={() => { - const e = new KeyboardEvent("keydown", { - key: "p", - }); - document.dispatchEvent(e); + primaryButton={{ + icon: , + text: "New Project", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "p", + }); + document.dispatchEvent(e); + }, }} /> )} diff --git a/apps/app/pages/invitations.tsx b/apps/app/pages/invitations.tsx index 40a687ff6..34aeca8f3 100644 --- a/apps/app/pages/invitations.tsx +++ b/apps/app/pages/invitations.tsx @@ -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("/"), + }} /> )