'use client' import { useState, useEffect, useCallback } from 'react' import { createPortal } from 'react-dom' import { createShareRequest, removeCollaborator, getNoteCollaborators } from '@/app/actions/notes' import { toast } from 'sonner' import { X, UserPlus, Users, Mail, Trash2, Loader2, Share2, Check } from 'lucide-react' import { cn } from '@/lib/utils' interface Collaborator { id: string name: string | null email: string | null image: string | null } interface NoteShareDialogProps { noteId: string noteTitle: string onClose: () => void } export function NoteShareDialog({ noteId, noteTitle, onClose }: NoteShareDialogProps) { const [email, setEmail] = useState('') const [permission, setPermission] = useState<'view' | 'edit'>('view') const [collaborators, setCollaborators] = useState([]) const [loading, setLoading] = useState(true) const [sending, setSending] = useState(false) const [removingId, setRemovingId] = useState(null) const [sent, setSent] = useState(false) const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) // Close on Escape const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) return () => document.removeEventListener('keydown', onKey) }, [onClose]) const loadCollaborators = useCallback(async () => { try { const list = await getNoteCollaborators(noteId) setCollaborators(list as Collaborator[]) } catch { // owner-only view — silently ignore } finally { setLoading(false) } }, [noteId]) useEffect(() => { loadCollaborators() }, [loadCollaborators]) const handleInvite = async (e: React.FormEvent) => { e.preventDefault() const trimmed = email.trim() if (!trimmed) return setSending(true) try { await createShareRequest(noteId, trimmed, permission) setSent(true) setEmail('') toast.success(`Invitation envoyée à ${trimmed}`) setTimeout(() => setSent(false), 2000) loadCollaborators() } catch (err: any) { const msg = err?.message || 'Erreur lors du partage' if (msg.includes('not found')) toast.error('Aucun compte trouvé avec cet email.') else if (msg.includes('already shared')) toast.error('Cette note est déjà partagée avec cet utilisateur.') else toast.error(msg) } finally { setSending(false) } } const handleRemove = async (collaboratorId: string, collaboratorEmail: string | null) => { setRemovingId(collaboratorId) try { await removeCollaborator(noteId, collaboratorId) setCollaborators(prev => prev.filter(c => c.id !== collaboratorId)) toast.success(`Accès retiré à ${collaboratorEmail || "l'utilisateur"}`) } catch { toast.error("Impossible de retirer l'accès.") } finally { setRemovingId(null) } } if (!mounted) return null return createPortal(
{ if (e.target === e.currentTarget) onClose() }} >
e.stopPropagation()} > {/* Header */}

Partager

{/* Invite form */}
setEmail(e.target.value)} required autoFocus className="w-full pl-9 pr-3 py-2.5 text-[13px] rounded-xl border border-black/15 dark:border-white/15 bg-transparent outline-none focus:ring-2 ring-[#75B2D6]/30 focus:border-[#75B2D6] transition-all placeholder:text-foreground/30" />
{/* Permission toggle */}
{(['view', 'edit'] as const).map(p => ( ))}
{/* Collaborators list */}
Accès partagé
{loading ? (
) : collaborators.length === 0 ? (

Aucun collaborateur pour l'instant.

) : (
    {collaborators.map(c => (
  • {c.image ? {c.name : {(c.name || c.email || '?')[0].toUpperCase()} }

    {c.name || 'Utilisateur'}

    {c.email}

  • ))}
)}
, document.body ) }