diff --git a/web/app/profile/activity/page.tsx b/web/app/profile/activity/page.tsx index ad70c7df8f..afc9b29bf8 100644 --- a/web/app/profile/activity/page.tsx +++ b/web/app/profile/activity/page.tsx @@ -6,9 +6,12 @@ import { observer } from "mobx-react"; import { Button } from "@plane/ui"; // components import { PageHead } from "@/components/core"; -import { SidebarHamburgerToggle } from "@/components/core/sidebar"; import { EmptyState } from "@/components/empty-state"; -import { ProfileActivityListPage } from "@/components/profile"; +import { + ProfileActivityListPage, + ProfileSettingContentHeader, + ProfileSettingContentWrapper, +} from "@/components/profile"; // constants import { EmptyStateType } from "@/constants/empty-state"; @@ -51,22 +54,17 @@ const ProfileActivityPage = observer(() => { return ( <> -
-
- -

Activity

-
-
- {activityPages} - {isLoadMoreVisible && ( -
- -
- )} -
-
+ + + {activityPages} + {isLoadMoreVisible && ( +
+ +
+ )} +
); }); diff --git a/web/app/profile/appearance/page.tsx b/web/app/profile/appearance/page.tsx index e34fe8cdd7..4a4c85d2f1 100644 --- a/web/app/profile/appearance/page.tsx +++ b/web/app/profile/appearance/page.tsx @@ -7,7 +7,8 @@ import { useTheme } from "next-themes"; import { setPromiseToast } from "@plane/ui"; // components import { LogoSpinner } from "@/components/common"; -import { CustomThemeSelector, ThemeSwitch, PageHead, SidebarHamburgerToggle } from "@/components/core"; +import { CustomThemeSelector, ThemeSwitch, PageHead } from "@/components/core"; +import { ProfileSettingContentHeader, ProfileSettingContentWrapper } from "@/components/profile"; // constants import { I_THEME_OPTION, THEME_OPTIONS } from "@/constants/themes"; // hooks @@ -50,11 +51,8 @@ const ProfileAppearancePage = observer(() => { <> {userProfile ? ( -
-
- -

Appearance

-
+ +

Theme

@@ -65,7 +63,7 @@ const ProfileAppearancePage = observer(() => {
{userProfile?.theme?.theme === "custom" && } -
+ ) : (
@@ -75,4 +73,4 @@ const ProfileAppearancePage = observer(() => { ); }); -export default ProfileAppearancePage; \ No newline at end of file +export default ProfileAppearancePage; diff --git a/web/app/profile/notifications/page.tsx b/web/app/profile/notifications/page.tsx index 76f1bf3d6a..f6bb1e4e51 100644 --- a/web/app/profile/notifications/page.tsx +++ b/web/app/profile/notifications/page.tsx @@ -1,17 +1,14 @@ "use client"; import useSWR from "swr"; -// layouts -import { PageHead, SidebarHamburgerToggle } from "@/components/core"; +// components +import { PageHead } from "@/components/core"; +import { ProfileSettingContentHeader, ProfileSettingContentWrapper } from "@/components/profile"; import { EmailNotificationForm } from "@/components/profile/notification"; import { EmailSettingsLoader } from "@/components/ui"; -// ui -// components // services import { UserService } from "@/services/user.service"; -// type -// services const userService = new UserService(); export default function ProfileNotificationPage() { @@ -27,18 +24,13 @@ export default function ProfileNotificationPage() { return ( <> -
-
- -
-
Email notifications
-
- Stay in the loop on Issues you are subscribed to. Enable this to get notified. -
-
-
+ + -
+ ); } diff --git a/web/app/profile/page.tsx b/web/app/profile/page.tsx index 66a2a7b54f..c0eba78e7d 100644 --- a/web/app/profile/page.tsx +++ b/web/app/profile/page.tsx @@ -17,8 +17,8 @@ import { ImagePickerPopover, UserImageUploadModal, PageHead } from "@/components // ui // icons // components -import { SidebarHamburgerToggle } from "@/components/core/sidebar"; // constants +import { ProfileSettingContentWrapper } from "@/components/profile"; import { TIME_ZONES } from "@/constants/timezones"; import { USER_ROLES } from "@/constants/workspace"; // hooks @@ -137,322 +137,309 @@ const ProfileSettingsPage = observer(() => { return ( <> -
-
- -
-
- ( - setIsImageUploadModalOpen(false)} - isRemoving={isRemoving} - handleDelete={() => handleDelete(currentUser?.avatar, true)} - onSuccess={(url) => { - onChange(url); - handleSubmit(onSubmit)(); - setIsImageUploadModalOpen(false); - }} - value={value && value.trim() !== "" ? value : null} + + ( + setIsImageUploadModalOpen(false)} + isRemoving={isRemoving} + handleDelete={() => handleDelete(currentUser?.avatar, true)} + onSuccess={(url) => { + onChange(url); + handleSubmit(onSubmit)(); + setIsImageUploadModalOpen(false); + }} + value={value && value.trim() !== "" ? value : null} + /> + )} + /> + setDeactivateAccountModal(false)} /> +
+
+
+ {currentUser?.first_name - )} - /> - setDeactivateAccountModal(false)} /> -
- -
-
- {currentUser?.first_name -
-
-
- -
-
-
- -
- ( - onChange(imageUrl)} - control={control} - value={value ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"} - isProfileCover - /> +
+
+
+
+
-
-
-
- {`${watch("first_name")} ${watch("last_name")}`} -
- {watch("email")} -
+
+ ( + onChange(imageUrl)} + control={control} + value={value ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"} + isProfileCover + /> + )} + /> +
+
- {/* +
+
+
+ {`${watch("first_name")} ${watch("last_name")}`} +
+ {watch("email")} +
+ + {/* Activity Overview */} -
+
-
-
-

- First name* -

- +
+

+ First name* +

+ ( + ( - - )} + type="text" + value={value} + onChange={onChange} + ref={ref} + hasError={Boolean(errors.first_name)} + placeholder="Enter your first name" + className={`w-full rounded-md ${errors.first_name ? "border-red-500" : ""}`} + maxLength={24} /> - {errors.first_name && Please enter first name} -
- -
-

Last name

- - ( - - )} - /> -
- -
-

- Email* -

- ( - - )} - /> -
- -
-

- Role* -

- ( - - {USER_ROLES.map((item) => ( - - {item.label} - - ))} - - )} - /> - {errors.role && Please select a role} -
- -
-

- Display name* -

- { - if (value.trim().length < 1) return "Display name can't be empty."; - - if (value.split(" ").length > 1) return "Display name can't have two consecutive spaces."; - - if (value.replace(/\s/g, "").length < 1) - return "Display name must be at least 1 characters long."; - - if (value.replace(/\s/g, "").length > 20) - return "Display name must be less than 20 characters long."; - - return true; - }, - }} - render={({ field: { value, onChange, ref } }) => ( - - )} - /> - {errors?.display_name && Please enter display name} -
- -
-

- Timezone* -

- - ( - t.value === value)?.label ?? value : "Select a timezone" - } - options={timeZoneOptions} - onChange={onChange} - optionsClassName="w-full" - buttonClassName={errors.user_timezone ? "border-red-500" : "border-none"} - className="rounded-md border-[0.5px] !border-custom-border-200" - input - /> - )} - /> - {errors.role && Please select a time zone} -
- -
- -
-
+ )} + /> + {errors.first_name && Please enter first name}
- - - {({ open }) => ( - <> - - Deactivate account - - - - -
- - The danger zone of the profile page is a critical area that requires careful consideration and - attention. When deactivating an account, all of the data and resources within that account - will be permanently removed and cannot be recovered. - -
- -
-
-
-
- - )} -
+ +
+

Last name

+ + ( + + )} + /> +
+ +
+

+ Email* +

+ ( + + )} + /> +
+ +
+

+ Role* +

+ ( + + {USER_ROLES.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.role && Please select a role} +
+ +
+

+ Display name* +

+ { + if (value.trim().length < 1) return "Display name can't be empty."; + + if (value.split(" ").length > 1) return "Display name can't have two consecutive spaces."; + + if (value.replace(/\s/g, "").length < 1) + return "Display name must be at least 1 characters long."; + + if (value.replace(/\s/g, "").length > 20) + return "Display name must be less than 20 characters long."; + + return true; + }, + }} + render={({ field: { value, onChange, ref } }) => ( + + )} + /> + {errors?.display_name && Please enter display name} +
+ +
+

+ Timezone* +

+ + ( + t.value === value)?.label ?? value : "Select a timezone"} + options={timeZoneOptions} + onChange={onChange} + optionsClassName="w-full" + buttonClassName={errors.user_timezone ? "border-red-500" : "border-none"} + className="rounded-md border-[0.5px] !border-custom-border-200" + input + /> + )} + /> + {errors.role && Please select a time zone} +
+ +
+ +
+
-
-
+ + + {({ open }) => ( + <> + + Deactivate account + + + + +
+ + The danger zone of the profile page is a critical area that requires careful consideration and + attention. When deactivating an account, all of the data and resources within that account will be + permanently removed and cannot be recovered. + +
+ +
+
+
+
+ + )} +
+ ); }); diff --git a/web/app/profile/security/page.tsx b/web/app/profile/security/page.tsx index 4ae11c8e37..a404db1c35 100644 --- a/web/app/profile/security/page.tsx +++ b/web/app/profile/security/page.tsx @@ -11,7 +11,7 @@ import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; import { PasswordStrengthMeter } from "@/components/account"; import { LogoSpinner } from "@/components/common"; import { PageHead } from "@/components/core"; -import { SidebarHamburgerToggle } from "@/components/core/sidebar"; +import { ProfileSettingContentHeader, ProfileSettingContentWrapper } from "@/components/profile"; // helpers import { authErrorHandler } from "@/helpers/authentication.helper"; import { getPasswordStrength } from "@/helpers/password.helper"; @@ -130,15 +130,9 @@ const SecurityPage = observer(() => { return ( <> -
-
- -
-
-

Change password

+ + +

Current password

@@ -262,7 +256,7 @@ const SecurityPage = observer(() => {
-
+
); }); diff --git a/web/core/components/profile/index.ts b/web/core/components/profile/index.ts index dac5f5641d..d0d33af96a 100644 --- a/web/core/components/profile/index.ts +++ b/web/core/components/profile/index.ts @@ -3,3 +3,5 @@ export * from "./overview"; export * from "./profile-issues-filter"; export * from "./sidebar"; export * from "./time"; +export * from "./profile-setting-content-wrapper" +export * from "./profile-setting-content-header" \ No newline at end of file diff --git a/web/core/components/profile/notification/email-notification-form.tsx b/web/core/components/profile/notification/email-notification-form.tsx index 1b78e19afa..4166634a9d 100644 --- a/web/core/components/profile/notification/email-notification-form.tsx +++ b/web/core/components/profile/notification/email-notification-form.tsx @@ -59,7 +59,7 @@ export const EmailNotificationForm: FC = (props) => return ( <> -
Notify me when:
+
Notify me when:
{/* Notification Settings */}
diff --git a/web/core/components/profile/profile-setting-content-header.tsx b/web/core/components/profile/profile-setting-content-header.tsx new file mode 100644 index 0000000000..ee1b220bd1 --- /dev/null +++ b/web/core/components/profile/profile-setting-content-header.tsx @@ -0,0 +1,17 @@ +"use client"; +import React, { FC } from "react"; + +type Props = { + title: string; + description?: string; +}; + +export const ProfileSettingContentHeader: FC = (props) => { + const { title, description } = props; + return ( +
+
{title}
+ {description &&
{description}
} +
+ ); +}; diff --git a/web/core/components/profile/profile-setting-content-wrapper.tsx b/web/core/components/profile/profile-setting-content-wrapper.tsx new file mode 100644 index 0000000000..c9741ca5d3 --- /dev/null +++ b/web/core/components/profile/profile-setting-content-wrapper.tsx @@ -0,0 +1,30 @@ +"use client"; +import React, { FC } from "react"; +// helpers +import { cn } from "@/helpers/common.helper"; +import { SidebarHamburgerToggle } from "../core"; + +type Props = { + children: React.ReactNode; + className?: string; +}; + +export const ProfileSettingContentWrapper: FC = (props) => { + const { children, className = "" } = props; + return ( +
+
+ +
+ +
+ {children} +
+
+ ); +};