plane/web/components/onboarding/onboarding-sidebar.tsx

292 lines
9.2 KiB
TypeScript

import React, { useEffect } from "react";
import Image from "next/image";
import { useTheme } from "next-themes";
import { Control, Controller, UseFormSetValue, UseFormWatch } from "react-hook-form";
import {
BarChart2,
Briefcase,
CheckCircle,
ChevronDown,
ContrastIcon,
FileText,
LayersIcon,
PenSquare,
Search,
Settings,
Bell,
Home,
} from "lucide-react";
import { IWorkspace } from "@plane/types";
import { Avatar, DiceIcon, PhotoFilterIcon } from "@plane/ui";
// hooks
import { useUser, useWorkspace } from "@/hooks/store";
// types
import projectEmoji from "public/emoji/project-emoji.svg";
// assets
const workspaceLinks = [
{
Icon: Home,
name: "Home",
},
{
Icon: BarChart2,
name: "Analytics",
},
{
Icon: Briefcase,
name: "Projects",
},
{
Icon: CheckCircle,
name: "All Issues",
},
{
Icon: Bell,
name: "Notifications",
},
];
const projectLinks = [
{
name: "Issues",
Icon: LayersIcon,
},
{
name: "Cycles",
Icon: ContrastIcon,
},
{
name: "Modules",
Icon: DiceIcon,
},
{
name: "Views",
Icon: PhotoFilterIcon,
},
{
name: "Pages",
Icon: FileText,
},
{
name: "Settings",
Icon: Settings,
},
];
type Props = {
workspaceName: string;
showProject: boolean;
control?: Control<IWorkspace, any>;
setValue?: UseFormSetValue<IWorkspace>;
watch?: UseFormWatch<IWorkspace>;
userFullName?: string;
};
let timer: number = 0;
let lastWorkspaceName: string = "";
export const OnboardingSidebar: React.FC<Props> = (props) => {
const { workspaceName, showProject, control, setValue, watch, userFullName } = props;
// store hooks
const { currentUser } = useUser();
const { workspaces } = useWorkspace();
const workspaceDetails = Object.values(workspaces ?? {})?.[0];
const { resolvedTheme } = useTheme();
const handleZoomWorkspace = (value: string) => {
if (lastWorkspaceName === value) return;
lastWorkspaceName = value;
if (timer > 0) {
timer += 2;
timer = Math.min(timer, 2);
} else {
timer = 2;
timer = Math.min(timer, 2);
const interval = setInterval(() => {
if (timer < 0) {
setValue!("name", lastWorkspaceName);
clearInterval(interval);
}
timer--;
}, 1000);
}
};
useEffect(() => {
if (watch) {
watch("name");
}
});
return (
<div className="relative h-full border-r border-onboarding-border-100 ">
<div>
{control && setValue ? (
<Controller
control={control}
name="name"
render={({ field: { value } }) => {
if (value.length > 0) {
handleZoomWorkspace(value);
} else {
lastWorkspaceName = "";
}
return timer > 0 ? (
<div
className={`top-3 ml-6 mt-4 flex w-full max-w-screen-sm items-center border-[6px] bg-onboarding-background-200 transition-all ${
resolvedTheme == "dark" ? "border-onboarding-background-100" : "border-custom-primary-20"
} rounded-xl`}
>
<div className="w-full rounded-lg border border-onboarding-background-400 py-6 pl-4">
<div
className={`${
resolvedTheme == "light" ? "bg-[#F5F5F5]" : "bg-[#363A40]"
} flex w-full items-center p-1`}
>
<div className="flex flex-shrink-0">
<Avatar
name={value.length > 0 ? value : "New Workspace"}
src={""}
size={30}
shape="square"
fallbackBackgroundColor="black"
className="!text-base capitalize"
/>
</div>
<span className="ml-2 truncate text-xl font-medium text-onboarding-text-100">{value}</span>
</div>
</div>
</div>
) : (
<div className="flex w-full items-center gap-y-2 truncate border border-transparent px-4 pt-6 transition-all">
<div className="flex flex-shrink-0">
<Avatar
name={value.length > 0 ? value : workspaceDetails ? workspaceDetails.name : "New Workspace"}
src={""}
size={24}
shape="square"
fallbackBackgroundColor="black"
className="!text-base capitalize"
/>
</div>
<div className="mx-2 flex w-full flex-shrink items-center justify-between truncate">
<h4 className="truncate text-base font-medium text-custom-text-100">{workspaceName}</h4>
<ChevronDown className={`mx-1 h-4 w-4 flex-shrink-0 text-custom-sidebar-text-400 duration-300`} />
</div>
<div className="flex flex-shrink-0">
<Avatar
name={currentUser?.email}
src={currentUser?.avatar}
size={24}
shape="square"
fallbackBackgroundColor="#FCBE1D"
className="!text-base capitalize"
/>
</div>
</div>
);
}}
/>
) : (
<div className="flex w-full items-center gap-y-2 truncate px-4 pt-6 transition-all">
<div className="flex flex-shrink-0">
<Avatar
name={workspaceDetails ? workspaceDetails.name : "New Workspace"}
src={""}
size={24}
shape="square"
fallbackBackgroundColor="black"
className="!text-base capitalize"
/>
</div>
<div className="mx-2 flex w-full flex-shrink items-center justify-between truncate">
<h4 className="truncate text-base font-medium text-custom-text-100">{workspaceName}</h4>
<ChevronDown className={`mx-1 h-4 w-4 flex-shrink-0 text-custom-sidebar-text-400 duration-300`} />
</div>
<div className="flex flex-shrink-0">
<Avatar
name={userFullName ?? currentUser?.email}
src={currentUser?.avatar}
size={24}
shape="square"
fallbackBackgroundColor="#FCBE1D"
className="!text-base capitalize"
/>
</div>
</div>
)}
</div>
<div className={`space-y-1 p-4`}>
<div className={`mb-3 mt-4 flex w-full items-center justify-between gap-2 px-1 `}>
<div
className={`group relative flex w-full items-center justify-between gap-1 rounded border border-onboarding-border-100 px-3 shadow-custom-shadow-2xs`}
>
<div className={`relative flex flex-shrink-0 flex-grow items-center gap-2 rounded py-1.5 outline-none`}>
<PenSquare className="h-4 w-4 text-custom-sidebar-text-300" />
{<span className="text-sm font-medium">New Issue</span>}
</div>
</div>
<div
className={`flex flex-shrink-0 items-center justify-center rounded border border-onboarding-border-100
p-2 shadow-custom-shadow-2xs outline-none
`}
>
<Search className="h-4 w-4 text-onboarding-text-200" />
</div>
</div>
{workspaceLinks.map((link) => (
<a className="block w-full" key={link.name}>
<div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-base font-medium text-onboarding-text-200
outline-none focus:bg-custom-sidebar-background-80
`}
>
{<link.Icon className="h-4 w-4" />}
{link.name}
</div>
</a>
))}
</div>
{showProject && (
<div className="px-4 pt-4">
<p className="pb-4 text-base font-semibold text-custom-text-300">Projects</p>
<div className="px-3">
{" "}
<div className="mb-3 flex w-4/5 items-center justify-between text-base font-medium text-custom-text-200">
<div className="flex items-center gap-x-2">
<Image src={projectEmoji} alt="Plane Logo" className="h-4 w-4" />
<span> Plane</span>
</div>
<ChevronDown className="h-4 w-4" />
</div>
{projectLinks.map((link) => (
<a className="ml-6 block w-full" key={link.name}>
<div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-base font-medium text-custom-sidebar-text-200
outline-none focus:bg-custom-sidebar-background-80
`}
>
{<link.Icon className="h-4 w-4" />}
{link.name}
</div>
</a>
))}
</div>
</div>
)}
</div>
);
};