chore: workspace active cycles upgrade page implementation (#3454)

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2024-01-24 19:37:49 +05:30 committed by GitHub
parent a2f34e9573
commit 9d9d703c62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 211 additions and 2 deletions

View File

@ -20,3 +20,4 @@ export * from "./project-archived-issue-details";
export * from "./project-archived-issues";
export * from "./project-issue-details";
export * from "./user-profile";
export * from "./workspace-active-cycles";

View File

@ -0,0 +1,22 @@
import { observer } from "mobx-react-lite";
// ui
import { Breadcrumbs, ContrastIcon } from "@plane/ui";
// icons
import { Crown } from "lucide-react";
export const WorkspaceActiveCycleHeader = observer(() => (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2">
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
icon={<ContrastIcon className="h-4 w-4 text-custom-text-300 rotate-180" />}
label="Active Cycles"
/>
</Breadcrumbs>
<Crown className="h-3.5 w-3.5 text-amber-400" />
</div>
</div>
</div>
));

View File

@ -8,3 +8,4 @@ export * from "./send-workspace-invitation-modal";
export * from "./sidebar-dropdown";
export * from "./sidebar-menu";
export * from "./sidebar-quick-action";
export * from "./workspace-active-cycles-upgrade";

View File

@ -8,9 +8,12 @@ import { useApplication, useUser } from "hooks/store";
import { NotificationPopover } from "components/notifications";
// ui
import { Tooltip } from "@plane/ui";
import { Crown } from "lucide-react";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { SIDEBAR_MENU_ITEMS } from "constants/dashboard";
// helper
import { cn } from "helpers/common.helper";
export const WorkspaceSidebarMenu = observer(() => {
// store hooks
@ -44,8 +47,17 @@ export const WorkspaceSidebarMenu = observer(() => {
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
>
{<link.Icon className="h-4 w-4" />}
{
<link.Icon
className={cn("h-4 w-4", {
"rotate-180": link.key === "active-cycles",
})}
/>
}
{!themeStore?.sidebarCollapsed && link.label}
{!themeStore?.sidebarCollapsed && link.key === "active-cycles" && (
<Crown className="h-3.5 w-3.5 text-amber-400" />
)}
</div>
</Tooltip>
</span>

View File

@ -0,0 +1,100 @@
import React from "react";
import Image from "next/image";
import { observer } from "mobx-react";
// hooks
import { useUser } from "hooks/store";
// ui
import { getButtonStyling } from "@plane/ui";
// icons
import { Crown } from "lucide-react";
// helper
import { cn } from "helpers/common.helper";
// constants
import { WORKSPACE_ACTIVE_CYCLES_DETAILS } from "constants/cycle";
export const WorkspaceActiveCyclesUpgrade = observer(() => {
// store hooks
const { currentUser } = useUser();
const isDarkMode = currentUser?.theme.theme === "dark";
return (
<div className="flex flex-col gap-10 p-8 rounded-xl">
<div
className={cn("flex item-center justify-between rounded-xl min-h-[25rem]", {
"bg-gradient-to-l from-[#CFCFCF] to-[#212121]": currentUser?.theme.theme === "dark",
"bg-gradient-to-l from-[#3b5ec6] to-[#f5f7fe]": currentUser?.theme.theme === "light",
})}
>
<div className="relative px-14 flex flex-col gap-7 justify-center lg:w-1/2">
<div className="flex flex-col gap-2 max-w-64">
<h2 className="text-2xl font-semibold">On-demand snapshots of all your cycles</h2>
<p className="text-base font-medium text-custom-text-300">
Monitor cycles across projects, track high-priority issues, and zoom in cycles that need attention.
</p>
</div>
<div className="flex items-center gap-3">
<a
className={`${getButtonStyling("primary", "md")} cursor-pointer`}
href="https://plane.so/pricing"
target="_blank"
rel="noreferrer"
>
<Crown className="h-3.5 w-3.5" />
Upgrade
</a>
<a
className={cn("text-sm underline", {
"text-white": currentUser?.theme.theme === "dark",
"text-blue-600": currentUser?.theme.theme === "light",
})}
href="https://plane.so/pricing"
target="_blank"
rel="noreferrer"
>
Talk custom pricing
</a>
</div>
<span className="absolute left-0 top-0">
<Image
src={`/workspace-active-cycles/cta-l-1-${isDarkMode ? "dark" : "light"}.webp`}
height={125}
width={125}
className="rounded-xl"
alt="l-1"
/>
</span>
</div>
<div className="relative w-1/2 hidden lg:block">
<span className="absolute right-0 bottom-0">
<Image
src={`/workspace-active-cycles/cta-r-1-${isDarkMode ? "dark" : "light"}.webp`}
height={420}
width={500}
alt="r-1"
/>
</span>
<span className="absolute right-1/2 -bottom-16 rounded-xl">
<Image
src={`/workspace-active-cycles/cta-r-2-${isDarkMode ? "dark" : "light"}.webp`}
height={210}
width={280}
alt="r-2"
/>
</span>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-5">
{WORKSPACE_ACTIVE_CYCLES_DETAILS.map((item) => (
<div className="flex flex-col gap-2 p-4 min-h-32 w-full bg-custom-background-80 rounded-md">
<div className="flex items-center gap-2">
<h3 className="font-medium">{item.title}</h3>
<item.icon className="text-blue-500 h-4 w-4" />
</div>
<span className="text-sm text-custom-text-300">{item.description}</span>
</div>
))}
</div>
</div>
);
});

View File

@ -1,4 +1,15 @@
import { GanttChartSquare, LayoutGrid, List } from "lucide-react";
import {
GanttChartSquare,
LayoutGrid,
List,
AlertOctagon,
BarChart4,
CircleDashed,
Folder,
Microscope,
Search,
} from "lucide-react";
// types
import { TCycleLayout, TCycleView } from "@plane/types";
@ -115,6 +126,43 @@ export const CYCLE_STATE_GROUPS_DETAILS = [
},
];
export const WORKSPACE_ACTIVE_CYCLES_DETAILS = [
{
title: "10,000-feet view of all active cycles.",
description:
"Zoom out to see running cycles across all your projects at once instead of going from Cycle to Cycle in each project.",
icon: Folder,
},
{
title: "Get a snapshot of each active cycle.",
description:
"Track high-level metrics for all active cycles, see their state of progress, and get a sense of scope against deadlines.",
icon: CircleDashed,
},
{
title: "Compare burndowns.",
description: "Monitor how each of your teams are performing with a peek into each cycles burndown report.",
icon: BarChart4,
},
{
title: "Quickly see make-or-break issues. ",
description:
"Preview high-priority issues for each cycle against due dates. See all of them per cycle in one click.",
icon: AlertOctagon,
},
{
title: "Zoom into cycles that need attention. ",
description: "Investigate the state of any cycle that doesnt conform to expectations in one click.",
icon: Search,
},
{
title: "Stay ahead of blockers.",
description:
"Spot challenges from one project to another and see inter-cycle dependencies that arent obvious from any other view.",
icon: Microscope,
},
];
export const CYCLE_EMPTY_STATE_DETAILS = {
active: {
key: "active",

View File

@ -19,6 +19,7 @@ import { Props } from "components/icons/types";
import { EUserWorkspaceRoles } from "./workspace";
// icons
import { BarChart2, Briefcase, CheckCircle, LayoutGrid } from "lucide-react";
import { ContrastIcon } from "@plane/ui";
// gradients for issues by priority widget graph bars
export const PRIORITY_GRAPH_GRADIENTS = [
@ -292,4 +293,12 @@ export const SIDEBAR_MENU_ITEMS: {
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/workspace-views/all-issues`,
Icon: CheckCircle,
},
{
key: "active-cycles",
label: "Active Cycles",
href: `/active-cycles`,
access: EUserWorkspaceRoles.GUEST,
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/active-cycles`,
Icon: ContrastIcon,
},
];

View File

@ -0,0 +1,16 @@
import { ReactElement } from "react";
// components
import { WorkspaceActiveCycleHeader } from "components/headers";
import { WorkspaceActiveCyclesUpgrade } from "components/workspace";
// layouts
import { AppLayout } from "layouts/app-layout";
// types
import { NextPageWithLayout } from "lib/types";
const WorkspaceActiveCyclesPage: NextPageWithLayout = () => <WorkspaceActiveCyclesUpgrade />;
WorkspaceActiveCyclesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceActiveCycleHeader />}>{page}</AppLayout>;
};
export default WorkspaceActiveCyclesPage;

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB