import { MeVariables } from "@hey/data/constants"; import { ERRORS } from "@hey/data/errors"; import { Regex } from "@hey/data/regex"; import { useMeLazyQuery, useSetAccountMetadataMutation } from "@hey/indexer"; import type { ApolloClientError } from "@hey/types/errors"; import { account as accountMetadata } from "@lens-protocol/metadata"; import { useCallback, useState } from "react"; import { toast } from "sonner"; import { z } from "zod"; import AvatarUpload from "@/components/Shared/AvatarUpload"; import BackButton from "@/components/Shared/BackButton"; import CoverUpload from "@/components/Shared/CoverUpload"; import { Button, Card, CardHeader, Form, Input, TextArea, useZodForm } from "@/components/Shared/UI"; import errorToast from "@/helpers/errorToast"; import getAccountAttribute from "@/helpers/getAccountAttribute"; import prepareAccountMetadata from "@/helpers/prepareAccountMetadata"; import uploadMetadata from "@/helpers/uploadMetadata"; import useTransactionLifecycle from "@/hooks/useTransactionLifecycle"; import useWaitForTransactionToComplete from "@/hooks/useWaitForTransactionToComplete"; import { useAccountStore } from "@/store/persisted/useAccountStore"; const ValidationSchema = z.object({ bio: z.string().max(260, { message: "Bio should not exceed 260 characters" }), location: z.string().max(100, { message: "Location should not exceed 100 characters" }), name: z .string() .max(100, { message: "Name should not exceed 100 characters" }) .regex(Regex.accountNameValidator, { message: "Account name must not contain restricted symbols" }), website: z.union([ z.string().regex(Regex.url, { message: "Invalid website" }), z.string().max(0) ]), x: z.string().max(100, { message: "X handle must not exceed 100 characters" }) }); const PersonalizeSettingsForm = () => { const { currentAccount, setCurrentAccount } = useAccountStore(); const [isSubmitting, setIsSubmitting] = useState(false); const [avatarUrl, setAvatarUrl] = useState( currentAccount?.metadata?.picture ); const [coverUrl, setCoverUrl] = useState( currentAccount?.metadata?.coverPicture ); const handleTransactionLifecycle = useTransactionLifecycle(); const waitForTransactionToComplete = useWaitForTransactionToComplete(); const [getCurrentAccountDetails] = useMeLazyQuery({ fetchPolicy: "no-cache", variables: MeVariables }); const onCompleted = async (hash: string) => { await waitForTransactionToComplete(hash); const accountData = await getCurrentAccountDetails(); setCurrentAccount(accountData?.data?.me.loggedInAs.account); setIsSubmitting(false); toast.success("Account updated"); }; const onError = useCallback((error: ApolloClientError) => { setIsSubmitting(false); errorToast(error); }, []); const [setAccountMetadata] = useSetAccountMetadataMutation({ onCompleted: async ({ setAccountMetadata }) => { if (setAccountMetadata.__typename === "SetAccountMetadataResponse") { return onCompleted(setAccountMetadata.hash); } return await handleTransactionLifecycle({ onCompleted, onError, transactionData: setAccountMetadata }); }, onError }); const form = useZodForm({ defaultValues: { bio: currentAccount?.metadata?.bio || "", location: getAccountAttribute( "location", currentAccount?.metadata?.attributes ), name: currentAccount?.metadata?.name || "", website: getAccountAttribute( "website", currentAccount?.metadata?.attributes ), x: getAccountAttribute( "x", currentAccount?.metadata?.attributes )?.replace(/(https:\/\/)?x\.com\//, "") }, schema: ValidationSchema }); const updateAccount = async ( data: z.infer, avatarUrl: string | undefined, coverUrl: string | undefined ) => { if (!currentAccount) { return toast.error(ERRORS.SignWallet); } setIsSubmitting(true); const preparedAccountMetadata = prepareAccountMetadata(currentAccount, { attributes: { location: data.location, website: data.website, x: data.x }, bio: data.bio, coverPicture: coverUrl, name: data.name, picture: avatarUrl }); const metadataUri = await uploadMetadata( accountMetadata(preparedAccountMetadata) ); return await setAccountMetadata({ variables: { request: { metadataUri } } }); }; const onSetAvatar = async (src: string | undefined) => { setAvatarUrl(src); return await updateAccount({ ...form.getValues() }, src, coverUrl); }; const onSetCover = async (src: string | undefined) => { setCoverUrl(src); return await updateAccount({ ...form.getValues() }, avatarUrl, src); }; return ( } title="Personalize" />
updateAccount(data, avatarUrl, coverUrl)} >