Backend:
- Nuevo modelo Prisma ClientInvitation con token unico, expiracion
y estados (pending/accepted/expired).
- Migracion: 20260511213955_add_client_invitations
- Service client-invitations.service.ts: crear invitacion,
validar token, registrar desde invitacion (reutiliza logica
de creacion de tenant + usuario de despacho.service).
- Controller + routes: POST /invitations/client (admin),
GET /invitations/client/validate/:token (publico),
POST /invitations/client/register/:token (publico),
GET /invitations/client (admin).
- Email template client-invitation.ts con link a
/invitacion/registro/{token}.
- Agregado sendClientInvitation a email.service.
Frontend:
- Pagina /invitacion/registro/[token] para que el invitado
complete registro (nombre, password, despacho, RFC, perfil).
- Pagina /admin/invitar-cliente para que admin global envie
invitaciones y vea el historial.
- Hooks useCreateInvitation, useValidateInvitationToken,
useRegisterFromInvitation, useClientInvitations.
- API client lib/api/client-invitations.ts.
Infra:
- PM2 ecosystem.config.js: usa node --import tsx con
kill_timeout aumentado a 15s para evitar EADDRINUSE.
- React Query retry=2 con delay exponencial para resiliencia.
Refs: docs/CAMBIOS-2026-05-09.md
34 lines
965 B
TypeScript
34 lines
965 B
TypeScript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import * as api from '@/lib/api/client-invitations';
|
|
|
|
export function useCreateInvitation() {
|
|
const qc = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: api.createInvitation,
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: ['client-invitations'] }),
|
|
});
|
|
}
|
|
|
|
export function useValidateInvitationToken(token: string) {
|
|
return useQuery({
|
|
queryKey: ['invitation-token', token],
|
|
queryFn: () => api.validateInvitationToken(token),
|
|
enabled: !!token,
|
|
retry: false,
|
|
});
|
|
}
|
|
|
|
export function useRegisterFromInvitation() {
|
|
return useMutation({
|
|
mutationFn: ({ token, data }: { token: string; data: Parameters<typeof api.registerFromInvitation>[1] }) =>
|
|
api.registerFromInvitation(token, data),
|
|
});
|
|
}
|
|
|
|
export function useClientInvitations() {
|
|
return useQuery({
|
|
queryKey: ['client-invitations'],
|
|
queryFn: api.getClientInvitations,
|
|
});
|
|
}
|