mango-v4-ui/components/profile/EditProfileForm.tsx

218 lines
6.7 KiB
TypeScript
Raw Normal View History

2022-09-23 03:57:19 -07:00
import Input from '@components/forms/Input'
import Label from '@components/forms/Label'
import Button, { IconButton } from '@components/shared/Button'
import InlineNotification from '@components/shared/InlineNotification'
import Loading from '@components/shared/Loading'
2022-11-13 03:44:08 -08:00
import {
ExclamationCircleIcon,
PencilIcon,
PlusIcon,
} from '@heroicons/react/20/solid'
2022-09-23 03:57:19 -07:00
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes'
import { useWallet } from '@solana/wallet-adapter-react'
import mangoStore from '@store/mangoStore'
2022-12-05 18:53:51 -08:00
import startCase from 'lodash/startCase'
2022-09-23 03:57:19 -07:00
import { useTranslation } from 'next-i18next'
import { ChangeEvent, useState } from 'react'
import { MANGO_DATA_API_URL } from 'utils/constants'
2022-09-23 03:57:19 -07:00
import { notify } from 'utils/notifications'
import ProfileImage from './ProfileImage'
const EditProfileForm = ({
onFinish,
onEditProfileImage,
2022-11-13 03:44:08 -08:00
onboarding = false,
2022-09-23 03:57:19 -07:00
}: {
onFinish: () => void
onEditProfileImage: () => void
2022-11-13 03:44:08 -08:00
onboarding?: boolean
2022-09-23 03:57:19 -07:00
}) => {
2022-11-13 03:44:08 -08:00
const { t } = useTranslation(['profile', 'onboarding'])
2022-09-23 03:57:19 -07:00
const profile = mangoStore((s) => s.profile.details)
const { publicKey, signMessage } = useWallet()
const [profileName, setProfileName] = useState(
startCase(profile?.profile_name) || ''
)
2022-09-23 06:37:44 -07:00
const [inputError, setInputError] = useState('')
2022-09-23 03:57:19 -07:00
const [loadUniquenessCheck, setLoadUniquenessCheck] = useState(false)
const [loadUpdateProfile, setLoadUpdateProfile] = useState(false)
const [updateError, setUpdateError] = useState('')
2023-01-03 14:20:00 -08:00
const actions = mangoStore.getState().actions
2022-09-23 03:57:19 -07:00
2022-09-23 06:37:44 -07:00
const validateProfileNameUniqueness = async (name: string) => {
2022-09-23 03:57:19 -07:00
try {
setLoadUniquenessCheck(true)
const response = await fetch(
`${MANGO_DATA_API_URL}/user-data/check-profile-name-unique?profile-name=${name}`
2022-09-23 03:57:19 -07:00
)
const uniquenessCheck = await response.json()
2022-09-23 06:37:44 -07:00
if (uniquenessCheck) {
return true
} else {
setInputError(t('profile:uniqueness-fail'))
return false
2022-09-23 03:57:19 -07:00
}
} catch {
2022-09-23 06:37:44 -07:00
setInputError(t('profile:uniqueness-api-fail'))
return false
2022-09-23 03:57:19 -07:00
} finally {
setLoadUniquenessCheck(false)
}
}
const onChangeNameInput = (name: string) => {
setProfileName(name)
const re = /^[a-zA-Z0-9 ]*$/gm
2022-09-23 06:37:44 -07:00
if (!re.test(name)) {
setInputError(t('profile:invalid-characters'))
} else {
setInputError('')
}
2022-09-23 03:57:19 -07:00
}
const saveProfile = async () => {
setUpdateError('')
const name = profileName.trim().toLowerCase()
2022-09-23 03:57:19 -07:00
if (profile?.profile_name === name) {
onFinish()
return
}
2022-09-23 06:37:44 -07:00
const isUnique = await validateProfileNameUniqueness(name)
if (!inputError && isUnique) {
2022-09-23 03:57:19 -07:00
setLoadUpdateProfile(true)
try {
if (!publicKey) throw new Error('Wallet not connected!')
if (!signMessage)
throw new Error('Wallet does not support message signing!')
const messageString = JSON.stringify({
profile_name: name,
trader_category: profile?.trader_category,
profile_image_url: profile?.profile_image_url || '',
2022-09-23 03:57:19 -07:00
})
const message = new TextEncoder().encode(messageString)
const signature = await signMessage(message)
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet_pk: publicKey.toString(),
message: messageString,
signature: bs58.encode(signature),
}),
}
const response = await fetch(
`${MANGO_DATA_API_URL}/user-data/profile-details`,
2022-09-23 03:57:19 -07:00
requestOptions
)
if (response.status === 200) {
setLoadUpdateProfile(false)
await actions.fetchProfileDetails(publicKey.toString())
onFinish()
notify({
type: 'success',
title: t('profile:profile-update-success'),
})
}
} catch {
setLoadUpdateProfile(false)
setUpdateError(t('profile:profile-update-fail'))
}
}
}
return (
<>
{updateError ? (
<div className="py-3">
<InlineNotification type="error" desc={updateError} />
</div>
) : null}
{!profile ? (
<div className="py-3">
<InlineNotification
type="error"
desc={t('profile:profile-api-error')}
/>
</div>
) : null}
2022-09-23 03:57:19 -07:00
<div className="my-6 flex justify-center">
<div className="relative ">
<IconButton
2022-12-18 21:00:06 -08:00
className="absolute -top-2 -right-2 bg-th-button md:hover:bg-th-button-hover"
2022-09-23 03:57:19 -07:00
size="small"
onClick={onEditProfileImage}
disabled={!profile}
2022-09-23 03:57:19 -07:00
>
2022-11-13 03:44:08 -08:00
{profile?.profile_image_url ? (
<PencilIcon className="h-4 w-4" />
) : (
<PlusIcon className="h-4 w-4" />
)}
2022-09-23 03:57:19 -07:00
</IconButton>
<ProfileImage imageSize="80" placeholderSize="48" isOwnerProfile />
</div>
</div>
2022-11-13 03:44:08 -08:00
<div className={onboarding ? 'pb-10' : 'pb-6'}>
2022-09-23 03:57:19 -07:00
<Label text={t('profile:profile-name')} />
<Input
type="text"
2023-04-14 04:48:09 -07:00
hasError={!!inputError.length}
2022-09-23 03:57:19 -07:00
value={profileName}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
onChangeNameInput(e.target.value)
}
2023-01-25 01:19:12 -08:00
maxLength={20}
2022-09-23 03:57:19 -07:00
/>
2022-09-23 06:37:44 -07:00
{inputError ? (
2022-09-23 03:57:19 -07:00
<div className="mt-1.5 flex items-center space-x-1">
2022-11-30 19:32:32 -08:00
<ExclamationCircleIcon className="h-4 w-4 text-th-down" />
<p className="mb-0 text-xs text-th-down">{inputError}</p>
2022-09-23 03:57:19 -07:00
</div>
) : null}
</div>
{/* <div className="pb-6">
<Label text={t('profile:trader-category')} />
<Select
value={t(`profile:${traderCategory}`)}
onChange={(cat) => setTraderCategory(cat)}
className="w-full"
>
{TRADER_CATEGORIES.map((cat) => (
<Select.Option key={cat} value={cat}>
<div className="flex w-full items-center justify-between">
{t(`profile:${cat}`)}
</div>
</Select.Option>
))}
</Select>
</div> */}
<Button
2022-11-13 03:44:08 -08:00
className={`flex ${
onboarding ? 'w-44' : 'w-full'
} items-center justify-center`}
2022-09-23 03:57:19 -07:00
disabled={
2022-09-23 06:37:44 -07:00
!!Object.keys(inputError).length ||
2022-09-23 03:57:19 -07:00
loadUniquenessCheck ||
!profileName ||
!profile
2022-09-23 03:57:19 -07:00
}
onClick={saveProfile}
size="large"
>
{loadUniquenessCheck || loadUpdateProfile ? (
<Loading />
2022-11-13 03:44:08 -08:00
) : onboarding ? (
t('onboarding:save-finish')
2022-09-23 03:57:19 -07:00
) : (
t('profile:save-profile')
)}
</Button>
</>
)
}
export default EditProfileForm