Added routes
This commit is contained in:
128
apps/web/src/features/join/JoinGroupProvider.tsx
Normal file
128
apps/web/src/features/join/JoinGroupProvider.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { createContext, useContext, useState } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import type { GroupInviteInfoDto } from '@gruperly/shared'
|
||||
import { ApiError, getInviteInfo, joinViaInvite } from '../../lib/api'
|
||||
|
||||
type RegisteredAttendee = {
|
||||
fullName: string
|
||||
phone: string | null
|
||||
}
|
||||
|
||||
type JoinGroupContextValue = {
|
||||
token: string
|
||||
group: GroupInviteInfoDto | undefined
|
||||
invitePending: boolean
|
||||
inviteFailed: boolean
|
||||
firstName: string
|
||||
setFirstName: (value: string) => void
|
||||
lastName: string
|
||||
setLastName: (value: string) => void
|
||||
phone: string
|
||||
setPhone: (value: string) => void
|
||||
email: string
|
||||
setEmail: (value: string) => void
|
||||
errorMessage: string | null
|
||||
registeredAttendee: RegisteredAttendee | null
|
||||
waitlistMessage: string | null
|
||||
submit: () => void
|
||||
isSubmitting: boolean
|
||||
}
|
||||
|
||||
const JoinGroupContext = createContext<JoinGroupContextValue | null>(null)
|
||||
|
||||
export function JoinGroupProvider({ token, children }: { token: string; children: ReactNode }) {
|
||||
const [firstName, setFirstName] = useState('')
|
||||
const [lastName, setLastName] = useState('')
|
||||
const [phone, setPhone] = useState('')
|
||||
const [email, setEmail] = useState('')
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||
const [registeredAttendee, setRegisteredAttendee] = useState<RegisteredAttendee | null>(null)
|
||||
const [waitlistMessage, setWaitlistMessage] = useState<string | null>(null)
|
||||
|
||||
const inviteQuery = useQuery({
|
||||
queryKey: ['public-invite', token],
|
||||
queryFn: () => getInviteInfo(token),
|
||||
enabled: Boolean(token),
|
||||
retry: 1,
|
||||
})
|
||||
|
||||
const joinMutation = useMutation({
|
||||
mutationFn: () =>
|
||||
joinViaInvite(token, {
|
||||
firstName: firstName.trim(),
|
||||
lastName: lastName.trim(),
|
||||
phone: phone.trim(),
|
||||
email: email.trim() || undefined,
|
||||
}),
|
||||
onSuccess: (data) => {
|
||||
setErrorMessage(null)
|
||||
if (data.status === 'waitlisted') {
|
||||
setRegisteredAttendee(null)
|
||||
setWaitlistMessage(data.message)
|
||||
return
|
||||
}
|
||||
setWaitlistMessage(null)
|
||||
setRegisteredAttendee({
|
||||
fullName: data.attendee?.fullName ?? `${firstName.trim()} ${lastName.trim()}`.trim(),
|
||||
phone: data.attendee?.phone ?? null,
|
||||
})
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
if (error instanceof ApiError) {
|
||||
if (error.problem?.code === 'attendee_already_registered') {
|
||||
setErrorMessage(
|
||||
'Ya te encuentras registrado en este grupo con ese número de teléfono. El profesor ya tiene tus datos.',
|
||||
)
|
||||
return
|
||||
}
|
||||
setErrorMessage(error.message || 'Error al procesar la inscripción.')
|
||||
return
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
setErrorMessage(error.message)
|
||||
return
|
||||
}
|
||||
setErrorMessage('Ocurrió un error inesperado. Por favor, intenta de nuevo.')
|
||||
},
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
setErrorMessage(null)
|
||||
if (!firstName.trim() || !lastName.trim() || !phone.trim()) {
|
||||
setErrorMessage('Por favor completa los campos requeridos (Nombre, Apellido y Teléfono).')
|
||||
return
|
||||
}
|
||||
joinMutation.mutate()
|
||||
}
|
||||
|
||||
const value: JoinGroupContextValue = {
|
||||
token,
|
||||
group: inviteQuery.data,
|
||||
invitePending: inviteQuery.isPending,
|
||||
inviteFailed: inviteQuery.isError,
|
||||
firstName,
|
||||
setFirstName,
|
||||
lastName,
|
||||
setLastName,
|
||||
phone,
|
||||
setPhone,
|
||||
email,
|
||||
setEmail,
|
||||
errorMessage,
|
||||
registeredAttendee,
|
||||
waitlistMessage,
|
||||
submit,
|
||||
isSubmitting: joinMutation.isPending,
|
||||
}
|
||||
|
||||
return <JoinGroupContext.Provider value={value}>{children}</JoinGroupContext.Provider>
|
||||
}
|
||||
|
||||
export function useJoinGroup() {
|
||||
const context = useContext(JoinGroupContext)
|
||||
if (!context) {
|
||||
throw new Error('useJoinGroup debe usarse dentro de <JoinGroupProvider>')
|
||||
}
|
||||
return context
|
||||
}
|
||||
Reference in New Issue
Block a user