"use client"; import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; import { Controller, useForm } from "react-hook-form"; import { ChevronDown, CircleUserRound } from "lucide-react"; import { Disclosure, Transition } from "@headlessui/react"; import type { IUser, TUserProfile } from "@plane/types"; import { Button, CustomSelect, CustomSearchSelect, Input, TOAST_TYPE, setPromiseToast, setToast, Tooltip, } from "@plane/ui"; // components import { DeactivateAccountModal } from "@/components/account"; import { LogoSpinner } from "@/components/common"; import { ImagePickerPopover, UserImageUploadModal, PageHead } from "@/components/core"; import { TimezoneSelect } from "@/components/global"; import { ProfileSettingContentWrapper } from "@/components/profile"; // constants import { USER_ROLES } from "@/constants/workspace"; // helpers import { getFileURL } from "@/helpers/file.helper"; // hooks import { useUser, useUserProfile } from "@/hooks/store"; const defaultValues: Partial = { avatar_url: "", cover_image_url: "", first_name: "", last_name: "", display_name: "", email: "", role: "Product / Project Manager", user_timezone: "Asia/Kolkata", }; const ProfileSettingsPage = observer(() => { // states const [isLoading, setIsLoading] = useState(false); const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); const [deactivateAccountModal, setDeactivateAccountModal] = useState(false); // form info const { handleSubmit, reset, watch, control, setValue, formState: { errors }, } = useForm({ defaultValues }); // derived values const userAvatar = watch("avatar_url"); const userCover = watch("cover_image_url"); // store hooks const { data: currentUser, updateCurrentUser } = useUser(); const { updateUserProfile, data: currentUserProfile } = useUserProfile(); useEffect(() => { reset({ ...defaultValues, ...currentUser, ...currentUserProfile }); }, [currentUser, currentUserProfile, reset]); const onSubmit = async (formData: IUser) => { setIsLoading(true); const userPayload: Partial = { first_name: formData.first_name, last_name: formData.last_name, avatar_url: formData.avatar_url, display_name: formData?.display_name, user_timezone: formData.user_timezone, }; const userProfilePayload: Partial = { role: formData.role ?? undefined, }; // if unsplash or a pre-defined image is uploaded, delete the old uploaded asset if (formData.cover_image_url?.startsWith("http")) { userPayload.cover_image = formData.cover_image_url; userPayload.cover_image_asset = null; } const updateUser = Promise.all([updateCurrentUser(userPayload), updateUserProfile(userProfilePayload)]).finally( () => setIsLoading(false) ); setPromiseToast(updateUser, { loading: "Updating...", success: { title: "Success!", message: () => `Profile updated successfully.`, }, error: { title: "Error!", message: () => `There was some error in updating your profile. Please try again.`, }, }); }; const handleDelete = async (url: string | null | undefined) => { if (!url) return; await updateCurrentUser({ avatar_url: "", }) .then(() => { setToast({ type: TOAST_TYPE.SUCCESS, title: "Success!", message: "Profile picture deleted successfully.", }); setValue("avatar_url", ""); }) .catch(() => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "There was some error in deleting your profile picture. Please try again.", }); }) .finally(() => { setIsImageUploadModalOpen(false); }); }; if (!currentUser) return (
); return ( <> ( setIsImageUploadModalOpen(false)} handleRemove={async () => await handleDelete(currentUser?.avatar_url)} onSuccess={(url) => { onChange(url); handleSubmit(onSubmit)(); setIsImageUploadModalOpen(false); }} value={value && value.trim() !== "" ? value : null} /> )} /> 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")}

First name*

( )} /> {errors.first_name && {errors.first_name.message}}

Last name

( )} />

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 character 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 && ( {errors?.display_name?.message} )}

Email*

( )} />

Role*

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

Timezone*

( { onChange(value); }} error={Boolean(errors.user_timezone)} /> )} /> {errors.user_timezone && {errors.user_timezone.message}}

Language

{}} className="rounded-md bg-custom-background-90" input disabled />
{({ open }) => ( <> Deactivate account
When deactivating an account, all of the data and resources within that account will be permanently removed and cannot be recovered.
)}
); }); export default ProfileSettingsPage;