chore: update profile settings layout (#2925)

* chore: update profile layout

* fix: multiple workspaces

* chore: removed breadcrumbs

* chore: fix sidebar collapsed state
This commit is contained in:
Aaryan Khandelwal 2023-11-29 13:48:07 +05:30 committed by Aaryan Khandelwal
parent a184b72056
commit 66bc1cb167
12 changed files with 176 additions and 284 deletions

View File

@ -25,7 +25,7 @@
"clsx": "^2.0.0", "clsx": "^2.0.0",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lowlight": "^2.9.0", "lowlight": "^2.9.0",
"lucide-react": "^0.263.1", "lucide-react": "^0.293.0",
"mobx": "^6.10.0", "mobx": "^6.10.0",
"mobx-react-lite": "^4.0.3", "mobx-react-lite": "^4.0.3",
"next": "12.3.2", "next": "12.3.2",

View File

@ -1,3 +1,2 @@
export * from "./layout"; export * from "./layout";
export * from "./settings-sidebar";
export * from "./sidebar"; export * from "./sidebar";

View File

@ -1,13 +1,13 @@
import { FC, ReactNode } from "react"; import { FC, ReactNode } from "react";
// layout // layout
import { UserAuthWrapper } from "layouts/auth-layout"; import { UserAuthWrapper } from "layouts/auth-layout";
import { ProfileLayoutSidebar } from "layouts/settings-layout";
// components // components
import { ProfileLayoutSidebar, ProfileSettingsSidebar } from "layouts/settings-layout";
import { CommandPalette } from "components/command-palette"; import { CommandPalette } from "components/command-palette";
interface IProfileSettingsLayout { interface IProfileSettingsLayout {
children: ReactNode; children: ReactNode;
header: ReactNode; header?: ReactNode;
} }
export const ProfileSettingsLayout: FC<IProfileSettingsLayout> = (props) => { export const ProfileSettingsLayout: FC<IProfileSettingsLayout> = (props) => {
@ -21,12 +21,7 @@ export const ProfileSettingsLayout: FC<IProfileSettingsLayout> = (props) => {
<ProfileLayoutSidebar /> <ProfileLayoutSidebar />
<main className="relative flex flex-col h-full w-full overflow-hidden bg-custom-background-100"> <main className="relative flex flex-col h-full w-full overflow-hidden bg-custom-background-100">
{header} {header}
<div className="flex gap-2 h-full w-full overflow-x-hidden overflow-y-scroll"> <div className="h-full w-full overflow-x-hidden overflow-y-scroll">{children}</div>
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
<ProfileSettingsSidebar />
</div>
{children}
</div>
</main> </main>
</div> </div>
</UserAuthWrapper> </UserAuthWrapper>

View File

@ -1,75 +0,0 @@
import React from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { observer } from "mobx-react-lite";
// mobx
import { useMobxStore } from "lib/mobx/store-provider";
const PROFILE_LINKS: Array<{
key: string;
label: string;
href: string;
}> = [
{
key: "profile",
label: "Profile",
href: `/profile`,
},
{
key: "change-password",
label: "Change password",
href: `/profile/change-password`,
},
{
key: "activity",
label: "Activity",
href: `/profile/activity`,
},
{
key: "preferences",
label: "Preferences",
href: `/profile/preferences`,
},
];
export const ProfileSettingsSidebar = observer(() => {
const router = useRouter();
const {
appConfig: { envConfig },
} = useMobxStore();
const enableEmailPassword =
envConfig &&
(envConfig?.email_password_login ||
!(
envConfig?.email_password_login ||
envConfig?.magic_login ||
envConfig?.google_client_id ||
envConfig?.github_client_id
));
return (
<div className="flex flex-col gap-2 w-80 px-5">
<span className="text-xs text-custom-sidebar-text-400 font-semibold">My Account</span>
<div className="flex flex-col gap-1 w-full">
{PROFILE_LINKS.map((link) => {
if (link.key === "change-password" && !enableEmailPassword) return;
return (
<Link key={link.key} href={link.href}>
<a>
<div
className={`px-4 py-2 text-sm font-medium rounded-md ${
router.asPath === link.href
? "bg-custom-primary-100/10 text-custom-primary-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
}`}
>
{link.label}
</div>
</a>
</Link>
);
})}
</div>
</div>
);
});

View File

@ -1,50 +1,73 @@
import { Fragment, useEffect, useRef, useState } from "react";
import { mutate } from "swr"; import { mutate } from "swr";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { Menu, Transition } from "@headlessui/react"; import { Activity, ChevronLeft, CircleUser, KeyRound, LogOut, MoveLeft, Plus, Settings2, UserPlus } from "lucide-react";
// icons
import { LogIn, LogOut, MoveLeft, Plus, User, UserPlus } from "lucide-react";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// ui // ui
import { Avatar, Tooltip } from "@plane/ui"; import { Tooltip } from "@plane/ui";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import { useState } from "react";
const SIDEBAR_LINKS = [ const PROFILE_ACTION_LINKS = [
{
key: "profile",
label: "Profile",
href: `/profile`,
Icon: CircleUser,
},
{
key: "change-password",
label: "Change password",
href: `/profile/change-password`,
Icon: KeyRound,
},
{
key: "activity",
label: "Activity",
href: `/profile/activity`,
Icon: Activity,
},
{
key: "preferences",
label: "Preferences",
href: `/profile/preferences`,
Icon: Settings2,
},
];
const WORKSPACE_ACTION_LINKS = [
{ {
key: "create-workspace", key: "create-workspace",
Icon: Plus, Icon: Plus,
name: "Create workspace", label: "Create workspace",
href: "/create-workspace", href: "/create-workspace",
}, },
{ {
key: "invitations", key: "invitations",
Icon: UserPlus, Icon: UserPlus,
name: "Invitations", label: "Invitations",
href: "/invitations", href: "/invitations",
}, },
]; ];
export const ProfileLayoutSidebar = observer(() => { export const ProfileLayoutSidebar = observer(() => {
// states // states
const [isScrolled, setIsScrolled] = useState(false); // scroll animation state const [isSigningOut, setIsSigningOut] = useState(false);
// refs // router
const containerRef = useRef<HTMLDivElement | null>(null);
const router = useRouter(); const router = useRouter();
// next themes
const { setTheme } = useTheme(); const { setTheme } = useTheme();
// toast
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { const {
theme: { sidebarCollapsed, toggleSidebar }, theme: { sidebarCollapsed, toggleSidebar },
workspace: { workspaces }, workspace: { workspaces },
user: { currentUser, currentUserSettings, isUserInstanceAdmin, signOut }, user: { currentUser, currentUserSettings, signOut },
} = useMobxStore(); } = useMobxStore();
// redirect url for normal mode // redirect url for normal mode
@ -54,6 +77,8 @@ export const ProfileLayoutSidebar = observer(() => {
""; "";
const handleSignOut = async () => { const handleSignOut = async () => {
setIsSigningOut(true);
await signOut() await signOut()
.then(() => { .then(() => {
mutate("CURRENT_USER_DETAILS", null); mutate("CURRENT_USER_DETAILS", null);
@ -66,144 +91,67 @@ export const ProfileLayoutSidebar = observer(() => {
title: "Error!", title: "Error!",
message: "Failed to sign out. Please try again.", message: "Failed to sign out. Please try again.",
}) })
); )
.finally(() => setIsSigningOut(false));
}; };
/**
* Implementing scroll animation styles based on the scroll length of the container
*/
useEffect(() => {
const handleScroll = () => {
if (containerRef.current) {
const scrollTop = containerRef.current.scrollTop;
setIsScrolled(scrollTop > 0);
}
};
const currentContainerRef = containerRef.current;
if (currentContainerRef) {
currentContainerRef.addEventListener("scroll", handleScroll);
}
return () => {
if (currentContainerRef) {
currentContainerRef.removeEventListener("scroll", handleScroll);
}
};
}, []);
return ( return (
<div <div
className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 duration-300 ${ className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 duration-300 ${
sidebarCollapsed ? "" : "md:w-[280px]" sidebarCollapsed ? "" : "md:w-[280px]"
} ${sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`} } ${sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`}
> >
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col gap-y-4">
<div className="flex items-center gap-x-3 gap-y-2 px-4 pt-4">
<div className="w-full h-full truncate">
<div <div
className={`flex flex-grow items-center gap-x-2 rounded p-1 truncate ${ className={`flex-shrink-0 flex items-center gap-2 px-4 pt-4 truncate ${
sidebarCollapsed ? "justify-center" : "" sidebarCollapsed ? "justify-center" : ""
}`} }`}
> >
<div
className={`flex-shrink-0 flex items-center justify-center h-6 w-6 bg-custom-sidebar-background-80 rounded`}
>
<User className="h-5 w-5 text-custom-text-200" />
</div>
{!sidebarCollapsed && <h4 className="text-custom-text-200 font-medium text-base truncate">My Profile</h4>}
</div>
</div>
{!sidebarCollapsed && (
<Tooltip position="bottom-left" tooltipContent="Go back to your workspace">
<div className="flex-shrink-0">
<Link href={`/${redirectWorkspaceSlug}`}> <Link href={`/${redirectWorkspaceSlug}`}>
<a> <a className="flex-shrink-0 grid place-items-center h-5 w-5">
<LogIn className="h-5 w-5 text-custom-text-200 rotate-180" /> <ChevronLeft className="h-5 w-5" strokeWidth={1} />
</a> </a>
</Link> </Link>
</div>
</Tooltip>
)}
{!sidebarCollapsed && ( {!sidebarCollapsed && (
<Menu as="div" className="relative flex-shrink-0 "> <h4 className="text-custom-text-200 font-semibold text-lg truncate">Profile settings</h4>
<Menu.Button className="flex gap-4 place-items-center outline-none">
<Avatar
name={currentUser?.display_name}
src={currentUser?.avatar}
size={24}
shape="square"
className="!text-base"
/>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute left-0 z-20 mt-1 w-52 rounded-md border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 shadow-custom-shadow-rg text-xs space-y-2 outline-none">
<span className="px-2 text-custom-sidebar-text-200">{currentUser?.email}</span>
<Menu.Item
as="button"
type="button"
className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80"
onClick={handleSignOut}
>
<LogOut className="h-4 w-4 stroke-[1.5]" />
Sign out
</Menu.Item>
{isUserInstanceAdmin && (
<div className="p-2 pb-0 border-t border-custom-border-100">
<Menu.Item as="button" type="button" className="w-full">
<Link href="/god-mode">
<a className="flex w-full items-center justify-center rounded px-2 py-1 text-sm font-medium text-custom-primary-100 hover:text-custom-primary-200 bg-custom-primary-100/20 hover:bg-custom-primary-100/30">
Enter God Mode
</a>
</Link>
</Menu.Item>
</div>
)}
</Menu.Items>
</Transition>
</Menu>
)} )}
</div> </div>
<div className="flex-shrink-0 flex flex-col overflow-x-hidden px-4">
{!sidebarCollapsed && (
<h6 className="rounded text-custom-sidebar-text-400 px-1.5 text-sm font-semibold">Your account</h6>
)}
<div className="space-y-1.5 mt-2 h-full overflow-y-auto">
{PROFILE_ACTION_LINKS.map((link) => {
if (link.key === "change-password" && currentUser?.is_password_autoset) return null;
<div className="w-full cursor-pointer space-y-1 p-4 flex-shrink-0"> return (
{SIDEBAR_LINKS.map((link) => (
<Link key={link.key} href={link.href}> <Link key={link.key} href={link.href}>
<a className="block w-full"> <a className="block w-full">
<Tooltip tooltipContent={link.name} position="right" className="ml-2" disabled={!sidebarCollapsed}> <Tooltip tooltipContent={link.label} position="right" className="ml-2" disabled={!sidebarCollapsed}>
<div <div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80 ${ className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
sidebarCollapsed ? "justify-center" : "" router.pathname === link.href
}`} ? "bg-custom-primary-100/10 text-custom-primary-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
} ${sidebarCollapsed ? "justify-center" : ""}`}
> >
{<link.Icon className="h-4 w-4" />} {<link.Icon className="h-4 w-4" />}
{!sidebarCollapsed && link.name} {!sidebarCollapsed && link.label}
</div> </div>
</Tooltip> </Tooltip>
</a> </a>
</Link> </Link>
))} );
})}
</div> </div>
{workspaces && workspaces.length > 0 && ( </div>
<div className="flex flex-col h-full overflow-x-hidden px-4"> <div className="flex flex-col overflow-x-hidden px-4">
{!sidebarCollapsed && ( {!sidebarCollapsed && (
<div className="rounded text-custom-sidebar-text-400 px-1.5 text-sm font-semibold">Your workspaces</div> <h6 className="rounded text-custom-sidebar-text-400 px-1.5 text-sm font-semibold">Workspaces</h6>
)} )}
<div {workspaces && workspaces.length > 0 && (
ref={containerRef} <div className="space-y-1.5 mt-2 h-full overflow-y-auto">
className={`space-y-2 mt-2 pt-2 h-full overflow-y-auto ${
isScrolled ? "border-t border-custom-sidebar-border-300" : ""
}`}
>
{workspaces.map((workspace) => ( {workspaces.map((workspace) => (
<Link <Link
key={workspace.id} key={workspace.id}
@ -213,7 +161,7 @@ export const ProfileLayoutSidebar = observer(() => {
}`} }`}
> >
<a <a
className={`flex items-center flex-grow w-full truncate gap-x-2 px-2 py-1 hover:bg-custom-sidebar-background-80 rounded-md ${ className={`flex items-center flex-grow w-full truncate gap-x-2 px-3 py-1 hover:bg-custom-sidebar-background-80 rounded-md ${
sidebarCollapsed ? "justify-center" : "" sidebarCollapsed ? "justify-center" : ""
}`} }`}
> >
@ -239,9 +187,41 @@ export const ProfileLayoutSidebar = observer(() => {
</Link> </Link>
))} ))}
</div> </div>
</div>
)} )}
<div className="flex-grow flex items-end px-4 py-2 border-t border-custom-border-200"> <div className="mt-1.5">
{WORKSPACE_ACTION_LINKS.map((link) => (
<Link key={link.key} href={link.href}>
<a className="block w-full">
<Tooltip tooltipContent={link.label} position="right" className="ml-2" disabled={!sidebarCollapsed}>
<div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80 ${
sidebarCollapsed ? "justify-center" : ""
}`}
>
{<link.Icon className="h-4 w-4" />}
{!sidebarCollapsed && link.label}
</div>
</Tooltip>
</a>
</Link>
))}
</div>
</div>
<div className="flex-shrink-0 flex-grow flex items-end px-6 py-2">
<div
className={`flex w-full ${
sidebarCollapsed ? "flex-col justify-center gap-2" : "items-center justify-between gap-2"
}`}
>
<button
type="button"
onClick={handleSignOut}
className="text-sm text-red-500 flex items-center justify-center gap-2 font-medium"
disabled={isSigningOut}
>
<LogOut className="h-3.5 w-3.5" />
{!sidebarCollapsed && <span>{isSigningOut ? "Signing out..." : "Sign out"}</span>}
</button>
<button <button
type="button" type="button"
className="grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none md:hidden" className="grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none md:hidden"
@ -261,5 +241,6 @@ export const ProfileLayoutSidebar = observer(() => {
</div> </div>
</div> </div>
</div> </div>
</div>
); );
}); });

View File

@ -39,7 +39,7 @@
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lucide-react": "^0.274.0", "lucide-react": "^0.293.0",
"mobx": "^6.10.0", "mobx": "^6.10.0",
"mobx-react-lite": "^4.0.3", "mobx-react-lite": "^4.0.3",
"next": "12.3.2", "next": "12.3.2",

View File

@ -9,7 +9,6 @@ import { ProfileSettingsLayout } from "layouts/settings-layout";
// components // components
import { ActivityIcon, ActivityMessage } from "components/core"; import { ActivityIcon, ActivityMessage } from "components/core";
import { RichReadOnlyEditor } from "@plane/rich-text-editor"; import { RichReadOnlyEditor } from "@plane/rich-text-editor";
import { ProfileSettingsHeader } from "components/headers";
// icons // icons
import { History, MessageSquare } from "lucide-react"; import { History, MessageSquare } from "lucide-react";
// ui // ui
@ -30,12 +29,12 @@ const ProfileActivityPage: NextPageWithLayout = () => {
const { data: userActivity } = useSWR(USER_ACTIVITY, () => userService.getUserActivity()); const { data: userActivity } = useSWR(USER_ACTIVITY, () => userService.getUserActivity());
return ( return (
<section className="pr-9 py-8 w-full overflow-y-auto"> <section className="h-full w-full lg:w-3/5 mx-auto px-8 pb-8 mt-16 flex flex-col overflow-hidden">
<div className="flex items-center py-3.5 border-b border-custom-border-100"> <div className="flex items-center pb-3.5 border-b border-custom-border-100">
<h3 className="text-xl font-medium">Activity</h3> <h3 className="text-xl font-medium">Activity</h3>
</div> </div>
{userActivity ? ( {userActivity ? (
<div className="flex flex-col gap-2 pb-4 w-full"> <div className="flex flex-col gap-2 h-full w-full overflow-y-auto">
<ul role="list" className="-mb-4"> <ul role="list" className="-mb-4">
{userActivity.results.map((activityItem: any) => { {userActivity.results.map((activityItem: any) => {
if (activityItem.field === "comment") { if (activityItem.field === "comment") {
@ -191,7 +190,7 @@ const ProfileActivityPage: NextPageWithLayout = () => {
}; };
ProfileActivityPage.getLayout = function getLayout(page: ReactElement) { ProfileActivityPage.getLayout = function getLayout(page: ReactElement) {
return <ProfileSettingsLayout header={<ProfileSettingsHeader title="Activity" />}>{page}</ProfileSettingsLayout>; return <ProfileSettingsLayout>{page}</ProfileSettingsLayout>;
}; };
export default ProfileActivityPage; export default ProfileActivityPage;

View File

@ -10,8 +10,6 @@ import { UserService } from "services/user.service";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// layout // layout
import { ProfileSettingsLayout } from "layouts/settings-layout"; import { ProfileSettingsLayout } from "layouts/settings-layout";
// components
import { ProfileSettingsHeader } from "components/headers";
// ui // ui
import { Button, Input, Spinner } from "@plane/ui"; import { Button, Input, Spinner } from "@plane/ui";
// types // types
@ -99,7 +97,11 @@ const ChangePasswordPage: NextPageWithLayout = observer(() => {
); );
return ( return (
<form onSubmit={handleSubmit(handleChangePassword)} className="flex flex-col gap-8 my-10 w-full mr-9"> <form
onSubmit={handleSubmit(handleChangePassword)}
className="flex flex-col gap-8 h-full w-full lg:w-3/5 mx-auto px-8 pb-8 mt-16"
>
<h3 className="text-xl font-medium">Change password</h3>
<div className="grid grid-col grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 items-center justify-between gap-10 w-full"> <div className="grid grid-col grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 items-center justify-between gap-10 w-full">
<div className="flex flex-col gap-1 "> <div className="flex flex-col gap-1 ">
<h4 className="text-sm">Current password</h4> <h4 className="text-sm">Current password</h4>
@ -181,9 +183,7 @@ const ChangePasswordPage: NextPageWithLayout = observer(() => {
}); });
ChangePasswordPage.getLayout = function getLayout(page: ReactElement) { ChangePasswordPage.getLayout = function getLayout(page: ReactElement) {
return ( return <ProfileSettingsLayout>{page}</ProfileSettingsLayout>;
<ProfileSettingsLayout header={<ProfileSettingsHeader title="Change Password" />}>{page}</ProfileSettingsLayout>
);
}; };
export default ChangePasswordPage; export default ChangePasswordPage;

View File

@ -11,7 +11,6 @@ import useToast from "hooks/use-toast";
import { ProfileSettingsLayout } from "layouts/settings-layout"; import { ProfileSettingsLayout } from "layouts/settings-layout";
// components // components
import { ImagePickerPopover, UserImageUploadModal } from "components/core"; import { ImagePickerPopover, UserImageUploadModal } from "components/core";
import { ProfileSettingsHeader } from "components/headers";
import { DeactivateAccountModal } from "components/account"; import { DeactivateAccountModal } from "components/account";
// ui // ui
import { Button, CustomSelect, CustomSearchSelect, Input, Spinner } from "@plane/ui"; import { Button, CustomSelect, CustomSearchSelect, Input, Spinner } from "@plane/ui";
@ -169,10 +168,10 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
)} )}
/> />
<DeactivateAccountModal isOpen={deactivateAccountModal} onClose={() => setDeactivateAccountModal(false)} /> <DeactivateAccountModal isOpen={deactivateAccountModal} onClose={() => setDeactivateAccountModal(false)} />
<div className="h-full w-full flex flex-col py-9 pr-9 space-y-10 overflow-y-auto"> <div className="h-full w-full lg:w-3/5 mx-auto flex flex-col px-8 pb-8 mt-16 space-y-10 overflow-y-auto">
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col gap-8 w-full"> <div className="flex flex-col gap-8 w-full">
<div className="relative h-44 w-full mt-6"> <div className="relative h-44 w-full">
<img <img
src={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"} src={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"}
className="h-44 w-full rounded-lg object-cover" className="h-44 w-full rounded-lg object-cover"
@ -236,7 +235,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
<div className="grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-6 px-8"> <div className="grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-6 px-8">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<h4 className="text-sm">First Name</h4> <h4 className="text-sm">First name</h4>
<Controller <Controller
control={control} control={control}
name="first_name" name="first_name"
@ -250,14 +249,14 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
ref={ref} ref={ref}
hasError={Boolean(errors.first_name)} hasError={Boolean(errors.first_name)}
placeholder="Enter your first name" placeholder="Enter your first name"
className="rounded-md font-medium w-full" className="rounded-md w-full"
/> />
)} )}
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<h4 className="text-sm">Last Name</h4> <h4 className="text-sm">Last name</h4>
<Controller <Controller
control={control} control={control}
@ -272,7 +271,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
ref={ref} ref={ref}
hasError={Boolean(errors.last_name)} hasError={Boolean(errors.last_name)}
placeholder="Enter your last name" placeholder="Enter your last name"
className="rounded-md font-medium w-full" className="rounded-md w-full"
/> />
)} )}
/> />
@ -292,8 +291,8 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
onChange={onChange} onChange={onChange}
ref={ref} ref={ref}
hasError={Boolean(errors.email)} hasError={Boolean(errors.email)}
placeholder="Enter your last name" placeholder="Enter your email"
className="rounded-md font-medium w-full" className="rounded-md w-full"
disabled disabled
/> />
)} )}
@ -312,7 +311,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
onChange={onChange} onChange={onChange}
label={value ? value.toString() : "Select your role"} label={value ? value.toString() : "Select your role"}
buttonClassName={errors.role ? "border-red-500 bg-red-500/10" : "border-none"} buttonClassName={errors.role ? "border-red-500 bg-red-500/10" : "border-none"}
className="rounded-md border !border-custom-border-200" className="rounded-md border-[0.5px] !border-custom-border-200"
width="w-full" width="w-full"
input input
> >
@ -328,7 +327,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<h4 className="text-sm">Display name </h4> <h4 className="text-sm">Display name</h4>
<Controller <Controller
control={control} control={control}
name="display_name" name="display_name"
@ -365,7 +364,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<h4 className="text-sm">Timezone </h4> <h4 className="text-sm">Timezone</h4>
<Controller <Controller
name="user_timezone" name="user_timezone"
@ -378,8 +377,8 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
options={timeZoneOptions} options={timeZoneOptions}
onChange={onChange} onChange={onChange}
optionsClassName="w-full" optionsClassName="w-full"
buttonClassName={"border-none"} buttonClassName="border-none"
className="rounded-md border !border-custom-border-200" className="rounded-md border-[0.5px] !border-custom-border-200"
input input
/> />
)} )}
@ -389,7 +388,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
<div className="flex items-center justify-between py-2"> <div className="flex items-center justify-between py-2">
<Button variant="primary" type="submit" loading={isSubmitting}> <Button variant="primary" type="submit" loading={isSubmitting}>
{isSubmitting ? "Updating Profile..." : "Update Profile"} {isSubmitting ? "Saving..." : "Save changes"}
</Button> </Button>
</div> </div>
</div> </div>
@ -399,8 +398,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
{({ open }) => ( {({ open }) => (
<> <>
<Disclosure.Button as="button" type="button" className="flex items-center justify-between w-full py-4"> <Disclosure.Button as="button" type="button" className="flex items-center justify-between w-full py-4">
<span className="text-lg tracking-tight">Deactivate Account</span> <span className="text-lg tracking-tight">Deactivate account</span>
{/* <Icon iconName={open ? "expand_less" : "expand_more"} className="!text-2xl" /> */}
<ChevronDown className={`h-5 w-5 transition-all ${open ? "rotate-180" : ""}`} /> <ChevronDown className={`h-5 w-5 transition-all ${open ? "rotate-180" : ""}`} />
</Disclosure.Button> </Disclosure.Button>
@ -437,7 +435,7 @@ const ProfileSettingsPage: NextPageWithLayout = () => {
}; };
ProfileSettingsPage.getLayout = function getLayout(page: ReactElement) { ProfileSettingsPage.getLayout = function getLayout(page: ReactElement) {
return <ProfileSettingsLayout header={<ProfileSettingsHeader title="Settings" />}>{page}</ProfileSettingsLayout>; return <ProfileSettingsLayout>{page}</ProfileSettingsLayout>;
}; };
export default ProfileSettingsPage; export default ProfileSettingsPage;

View File

@ -8,7 +8,6 @@ import useToast from "hooks/use-toast";
import { ProfileSettingsLayout } from "layouts/settings-layout"; import { ProfileSettingsLayout } from "layouts/settings-layout";
// components // components
import { CustomThemeSelector, ThemeSwitch } from "components/core"; import { CustomThemeSelector, ThemeSwitch } from "components/core";
import { ProfileSettingsHeader } from "components/headers";
// ui // ui
import { Spinner } from "@plane/ui"; import { Spinner } from "@plane/ui";
// constants // constants
@ -50,8 +49,8 @@ const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
return ( return (
<> <>
{currentUser ? ( {currentUser ? (
<div className="pr-9 py-8 w-full overflow-y-auto"> <div className="h-full w-full lg:w-3/5 mx-auto px-8 pb-8 mt-16 overflow-y-auto">
<div className="flex items-center py-3.5 border-b border-custom-border-100"> <div className="flex items-center pb-3.5 border-b border-custom-border-100">
<h3 className="text-xl font-medium">Preferences</h3> <h3 className="text-xl font-medium">Preferences</h3>
</div> </div>
<div className="grid grid-cols-12 gap-4 sm:gap-16 py-6"> <div className="grid grid-cols-12 gap-4 sm:gap-16 py-6">
@ -75,7 +74,7 @@ const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
}); });
ProfilePreferencesPage.getLayout = function getLayout(page: ReactElement) { ProfilePreferencesPage.getLayout = function getLayout(page: ReactElement) {
return <ProfileSettingsLayout header={<ProfileSettingsHeader title="Preferences" />}>{page}</ProfileSettingsLayout>; return <ProfileSettingsLayout>{page}</ProfileSettingsLayout>;
}; };
export default ProfilePreferencesPage; export default ProfilePreferencesPage;

View File

@ -14,6 +14,7 @@ export interface IUser {
is_email_verified: boolean; is_email_verified: boolean;
is_managed: boolean; is_managed: boolean;
is_onboarded: boolean; is_onboarded: boolean;
is_password_autoset: boolean;
is_tour_completed: boolean; is_tour_completed: boolean;
mobile_number: string | null; mobile_number: string | null;
role: string | null; role: string | null;

View File

@ -6049,15 +6049,10 @@ lucide-react@^0.244.0:
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.244.0.tgz#9626f44881830280012dad23afda7ddbcffff24b" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.244.0.tgz#9626f44881830280012dad23afda7ddbcffff24b"
integrity sha512-PeDVbx5PlIRrVvdxiuSxPfBo7sK5qrL3LbvvRoGVNiHYRAkBm/48lKqoioxcmp0bgsyJs9lMw7CdtGFvnMJbVg== integrity sha512-PeDVbx5PlIRrVvdxiuSxPfBo7sK5qrL3LbvvRoGVNiHYRAkBm/48lKqoioxcmp0bgsyJs9lMw7CdtGFvnMJbVg==
lucide-react@^0.263.1: lucide-react@^0.293.0:
version "0.263.1" version "0.293.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.263.1.tgz#a456ee0d171aa373929bd3ee20d6f9fb4429c301" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.293.0.tgz#02703dbcc56bb38779f4e576cc03be8cc0046fcc"
integrity sha512-keqxAx97PlaEN89PXZ6ki1N8nRjGWtDa4021GFYLNj0RgruM5odbpl8GHTExj0hhPq3sF6Up0gnxt6TSHu+ovw== integrity sha512-g3AN0EYITCpAjNgLHrKrFWvIJzZy0Y9OPBaonyKw1cM+nZE6piOM+TiuQdYfha7oa76TMiDaWXQHE44CEqsrzw==
lucide-react@^0.274.0:
version "0.274.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.274.0.tgz#d3b54dcb972b12f1292061448d61d422ef2e269d"
integrity sha512-qiWcojRXEwDiSimMX1+arnxha+ROJzZjJaVvCC0rsG6a9pUPjZePXSq7em4ZKMp0NDm1hyzPNkM7UaWC3LU2AA==
magic-string@^0.25.0, magic-string@^0.25.7: magic-string@^0.25.0, magic-string@^0.25.7:
version "0.25.9" version "0.25.9"