feat: add complex user invitation and management features

- Implemented complex member and invitation schemas using Zod for validation.
- Created new API endpoints for inviting, accepting, revoking, and canceling complex user invitations.
- Developed handlers for managing complex users, including listing, inviting, revoking, and canceling invitations.
- Added frontend components for displaying and managing complex users and invitations.
- Introduced session storage management for pending invitations.
- Integrated Gravatar for user avatars based on email.
- Created database migration for complex invitations table.
This commit is contained in:
Jose Selesan
2026-04-22 15:30:04 -03:00
parent 5f2a7fd494
commit 6ad4fc9ee9
37 changed files with 1935 additions and 78 deletions

View File

@@ -1,8 +1,15 @@
import type {
AcceptComplexInvitationsInput,
AcceptComplexInvitationsResponse,
CancelComplexInvitationResponse,
Complex,
ComplexUsersOverview,
ComplexWithRole,
CreateComplexPayload,
CreateComplexResponse,
InviteComplexUserInput,
InviteComplexUserResponse,
RevokeComplexUserInput,
SelectComplexInput,
UpdateComplexPayload,
UpdateComplexResponse,
@@ -49,3 +56,47 @@ export async function select(payload: SelectComplexInput) {
);
return response.data;
}
export async function listUsers(id: string) {
const response = await http.get<ComplexUsersOverview>(`/api/complexes/${id}/users`);
return response.data;
}
export async function inviteUser(id: string, payload: InviteComplexUserInput) {
const response = await http.post<InviteComplexUserResponse>(
`/api/complexes/${id}/users`,
JSON.stringify(payload),
{ headers: { 'Content-Type': 'application/json' } }
);
return response.data;
}
export async function revokeUser(id: string, payload: RevokeComplexUserInput) {
const response = await http.delete<{ ok: boolean }>(
`/api/complexes/${id}/users/${payload.userId}`
);
return response.data;
}
export async function acceptPendingInvitations(payload: AcceptComplexInvitationsInput = {}) {
const response = await http.post<AcceptComplexInvitationsResponse>(
'/api/complexes/accept-pending',
JSON.stringify(payload),
{ headers: { 'Content-Type': 'application/json' } }
);
return response.data;
}
export async function resendInvitation(id: string, invitationId: string) {
const response = await http.post<InviteComplexUserResponse>(
`/api/complexes/${id}/invitations/${invitationId}/resend`
);
return response.data;
}
export async function cancelInvitation(id: string, invitationId: string) {
const response = await http.delete<CancelComplexInvitationResponse>(
`/api/complexes/${id}/invitations/${invitationId}`
);
return response.data;
}