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,4 +1,3 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
Form,
@@ -9,6 +8,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { UserAvatar } from '@/components/user-avatar';
import { apiClient } from '@/lib/api-client';
import { useAuth } from '@/lib/auth';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -38,7 +38,7 @@ type UpdateProfileForm = z.infer<typeof updateProfileSchema>;
type UpdatePasswordForm = z.infer<typeof updatePasswordSchema>;
export function ProfilePage() {
const { user, displayName, initials, avatarUrl, isAuthenticated, updateProfile, updatePassword } =
const { user, displayName, avatarUrl, isAuthenticated, updateProfile, updatePassword } =
useAuth();
const queryClient = useQueryClient();
const profileQuery = useQuery({
@@ -119,13 +119,12 @@ export function ProfilePage() {
<div className="w-full max-w-3xl space-y-6">
<section className="rounded-xl border bg-card p-6 text-card-foreground shadow-sm">
<div className="flex items-center gap-3">
<Avatar size="lg">
<AvatarImage
src={profileQuery.data?.avatarUrl ?? avatarUrl ?? undefined}
alt={displayName}
/>
<AvatarFallback>{initials}</AvatarFallback>
</Avatar>
<UserAvatar
src={profileQuery.data?.avatarUrl ?? avatarUrl}
alt={displayName}
fallbackText={displayName}
size="lg"
/>
<div>
<h1 className="text-2xl font-semibold">{displayName}</h1>
<p className="text-sm text-muted-foreground">