feat: updated cuenta page

This commit is contained in:
2024-02-06 20:19:02 -06:00
parent 820865ac79
commit 7f758d9d0b
6 changed files with 204 additions and 11 deletions
+76
View File
@@ -0,0 +1,76 @@
'use client'
import Button from '@/components/ui/Button'
import ButtonGroup from '@/components/ui/ButtonGroup'
import useSession from '@/hooks/useSession'
import { css } from '@/styled-system/css'
import { AnimatePresence, motion } from 'framer-motion'
import { useState, type FC } from 'react'
import UpdateEmail from './UpdateEmail'
import UpdatePassword from './UpdatePassword'
import UpdateUserName from './UpdateUserName'
import UpdateUserPreferences from './UpdateUserPreferences'
type Tab = 'perfil' | 'login'
const CuentaTabs: FC = () => {
useSession('/login')
const [currentTab, setCurrentTab] = useState<Tab>('perfil')
return (
<>
<ButtonGroup
fullWidth={true}
>
<Button
fullWidth
onClick={() => { setCurrentTab('perfil') }}
disabled={currentTab === 'perfil'}
>
Perfil
</Button>
<Button
fullWidth
onClick={() => { setCurrentTab('login') }}
disabled={currentTab === 'login'}
>
Login
</Button>
</ButtonGroup>
<div
className={css({
overflow: 'hidden',
marginTop: 'medium'
})}
>
<AnimatePresence
mode='wait'
>
{currentTab === 'login' && (
<motion.div
transition={{ duration: 0.15, ease: 'easeInOut' }}
initial={{ opacity: 0, x: '-100%' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '100%' }}
key="login">
<UpdateEmail />
<UpdatePassword />
</motion.div>
)}
{currentTab === 'perfil' && (
<motion.div
transition={{ duration: 0.15, ease: 'easeInOut' }}
initial={{ opacity: 0, x: '-100%' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '100%' }}
key="perfil">
<UpdateUserName />
<UpdateUserPreferences />
</motion.div>
)}
</AnimatePresence>
</div>
</>
)
}
export default CuentaTabs
+1 -1
View File
@@ -61,7 +61,7 @@ const UpdateEmail: FC = () => {
}
},
validationSchema: updateEmailSchema,
isInitialValid: false
validateOnMount: true
})
if (status !== 'idle' || session === undefined) {
+1 -1
View File
@@ -68,7 +68,7 @@ const UpdatePassword: FC = () => {
}
},
validationSchema: updatePasswordSchema,
isInitialValid: false
validateOnMount: true
})
if (status !== 'idle' || session === undefined) {
+13 -3
View File
@@ -10,7 +10,7 @@ import { nanoid } from '@reduxjs/toolkit'
import { AppwriteException } from 'appwrite'
import { updateName } from 'entgamers-database/frontend/session'
import { useFormik } from 'formik'
import { type FC } from 'react'
import { useEffect, type FC } from 'react'
import { object, string } from 'yup'
interface UpdateUserNameData {
@@ -22,7 +22,7 @@ const UpdateUserNameSchema = object({
})
const UpdateUserName: FC = () => {
const { status, session } = useSession('/login')
const { status, session, user } = useSession('/login')
const dispatch = useAppDispatch()
const formik = useFormik<UpdateUserNameData>({
@@ -57,9 +57,19 @@ const UpdateUserName: FC = () => {
}
},
validationSchema: UpdateUserNameSchema,
isInitialValid: false
validateOnMount: true,
initialTouched: { name: true }
})
useEffect(() => {
if (status !== 'idle' && session !== undefined) {
formik.setValues({
name: user?.name ?? ''
})
.catch(console.error)
}
}, [status, session])
if (status !== 'idle' || session === undefined) {
// TODO: Replace with Skeleton
return null
+106
View File
@@ -0,0 +1,106 @@
'use client'
import Button from '@/components/ui/Button'
import Typography from '@/components/ui/Typography'
import FormGroup from '@/components/ui/form/FormGroup'
import TextArea from '@/components/ui/form/TextArea'
import { useAppDispatch } from '@/hooks/useAppDispatch'
import useManageError from '@/hooks/useManageError'
import useSession from '@/hooks/useSession'
import { setCurrentUser } from '@/state/sessionSlice'
import { updatePreferences, type UserPreferences } from 'entgamers-database/frontend/session'
import { useFormik } from 'formik'
import { useEffect, type FC } from 'react'
import { array, object, string, type ObjectSchema } from 'yup'
const socialLinksSchema: ObjectSchema<UserPreferences> = object({
bio: string().max(280, 'La descripción debe tener menos de 280 caracteres'),
profilePicture: string().url('La imagen debe ser una URL'),
socialLinks: array().of(
object({
label: string().required('La etiqueta es requerida'),
url: string().url('La URL debe ser una URL').required('La URL es requerida')
})
).min(0)
})
const UpdateUserPreferences: FC = () => {
const { status, session, user } = useSession('/login')
const dispatch = useAppDispatch()
const { manageError } = useManageError()
const formik = useFormik<UserPreferences>({
initialValues: {
bio: '',
profilePicture: '',
socialLinks: []
},
onSubmit: async ({ bio, profilePicture, socialLinks }) => {
try {
const updatedUserWithPreferences = await updatePreferences({ bio, profilePicture, socialLinks })
dispatch(setCurrentUser(updatedUserWithPreferences))
} catch (error) {
manageError(error, 'Error mientras se actualizaba las preferencias', ' Error desconocido mientras se actualizaba las preferencias', 'error')
}
},
validationSchema: socialLinksSchema,
validateOnMount: true
})
useEffect(() => {
if (status === 'idle' && session !== undefined) {
formik.setValues({
bio: user?.prefs.bio ?? '',
profilePicture: user?.prefs.profilePicture ?? '',
socialLinks: user?.prefs.socialLinks ?? []
})
.catch(console.error)
}
}, [status, session])
if (status !== 'idle' || session === undefined) {
// TODO: Replace with Skeleton
return null
}
return (
<>
<Typography
variant='h3'
>
Preferencias
</Typography>
<form
onSubmit={formik.handleSubmit}
>
<FormGroup>
<label
htmlFor='bio'
>
Biografia
</label>
<TextArea
id='bio'
name='bio'
value={formik.values.bio}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
disabled={formik.isSubmitting}
status={formik.touched.bio !== undefined && formik.errors.bio !== undefined ? 'danger' : undefined}
/>
</FormGroup>
{/* TODO: Add Profile Picture and Social Links fields */}
<FormGroup>
<Button
type='submit'
disabled={formik.isSubmitting || !formik.isValid}
fullWidth
>
Actualizar
</Button>
</FormGroup>
</form>
</>
)
}
export default UpdateUserPreferences
+7 -6
View File
@@ -1,17 +1,18 @@
import UpdateEmail from '@/app/cuenta/UpdateEmail'
import UpdatePassword from '@/app/cuenta/UpdatePassword'
import UpdateUserName from '@/app/cuenta/UpdateUserName'
import Typography from '@/components/ui/Typography'
import { Container } from '@/styled-system/jsx'
import { type FC } from 'react'
import CuentaTabs from './CuentaTabs'
const CuentaPage: FC = () => {
return (
<Container>
<Typography variant="h1" align="center">Cuenta</Typography>
<UpdateUserName />
<UpdatePassword />
<UpdateEmail />
<Typography variant="body1">
Aquí puedes actualizar el nombre de usuario de tu cuenta.
</Typography>
<CuentaTabs
/>
</Container>
)
}