import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Select } from '@/components/ui/select'; import { ConfirmationDialog } from '@/components/ui/confirmation-dialog'; import { Share2, Copy, Check, Trash2, Plus, ExternalLink, Calendar, Eye, Loader2, } from 'lucide-react'; import { useToast } from '@/hooks/useToast'; import { formatDistanceToNow, format } from 'date-fns'; import { fr } from 'date-fns/locale'; import { cn } from '@/lib/utils'; /** * FE-COMP-013: Share link generation and management UI component */ export interface ShareLink { id: string; share_token: string; expires_at?: string; access_count?: number; created_at: string; permissions?: string; } export interface ShareLinkManagerProps { resourceId: string; resourceType: 'track' | 'playlist'; onCreateShare: ( resourceId: string, options: CreateShareOptions, ) => Promise; onRevokeShare?: (shareId: string) => Promise; getShareUrl: (token: string) => string; className?: string; } export interface CreateShareOptions { expires_in_days?: number; is_public?: boolean; permissions?: string; } /** * Share link manager component for creating and managing share links */ export function ShareLinkManager({ resourceId, resourceType, onCreateShare, onRevokeShare, getShareUrl, className, }: ShareLinkManagerProps) { const { success: showSuccess, error: showError } = useToast(); const queryClient = useQueryClient(); const [isCreating, setIsCreating] = useState(false); const [showCreateForm, setShowCreateForm] = useState(false); const [expiresIn, setExpiresIn] = useState(7); const [isPublic, setIsPublic] = useState(true); const [shareLinks, setShareLinks] = useState([]); const [copiedToken, setCopiedToken] = useState(null); const [shareToRevoke, setShareToRevoke] = useState(null); // Create share mutation const createShareMutation = useMutation({ mutationFn: (options: CreateShareOptions) => onCreateShare(resourceId, options), onSuccess: (newShare) => { setShareLinks((prev) => [newShare, ...prev]); setShowCreateForm(false); showSuccess('Lien de partage créé avec succès'); queryClient.invalidateQueries({ queryKey: [`${resourceType}ShareLinks`, resourceId], }); }, onError: (error: any) => { showError(error.message || 'Erreur lors de la création du lien'); }, }); // Revoke share mutation const revokeShareMutation = useMutation({ mutationFn: (shareId: string) => { if (onRevokeShare) { return onRevokeShare(shareId); } throw new Error('Revoke function not provided'); }, onSuccess: () => { if (shareToRevoke) { setShareLinks((prev) => prev.filter((s) => s.id !== shareToRevoke)); setShareToRevoke(null); showSuccess('Lien de partage révoqué'); queryClient.invalidateQueries({ queryKey: [`${resourceType}ShareLinks`, resourceId], }); } }, onError: (error: any) => { showError(error.message || 'Erreur lors de la révocation'); }, }); const handleCreateShare = async () => { setIsCreating(true); try { await createShareMutation.mutateAsync({ expires_in_days: expiresIn, is_public: isPublic, }); } finally { setIsCreating(false); } }; const handleCopy = async (token: string) => { const shareUrl = getShareUrl(token); try { await navigator.clipboard.writeText(shareUrl); setCopiedToken(token); showSuccess('Lien copié dans le presse-papiers'); setTimeout(() => setCopiedToken(null), 2000); } catch (err) { showError('Erreur lors de la copie'); } }; const handleRevoke = (shareId: string) => { setShareToRevoke(shareId); }; const confirmRevoke = () => { if (shareToRevoke) { revokeShareMutation.mutate(shareToRevoke); } }; const isExpired = (expiresAt?: string) => { if (!expiresAt) return false; return new Date(expiresAt) < new Date(); }; return (
Liens de partage
{/* Create Form */} {showCreateForm && (
setIsPublic(e.target.checked)} className="rounded" />
)} {/* Share Links List */} {shareLinks.length === 0 && !showCreateForm ? (

Aucun lien de partage créé

Créez un lien pour partager ce{' '} {resourceType === 'track' ? 'morceau' : 'playlist'}

) : (
{shareLinks.map((share) => { const shareUrl = getShareUrl(share.share_token); const expired = isExpired(share.expires_at); const isCopied = copiedToken === share.share_token; return (
{share.expires_at && (
{expired ? ( Expiré le{' '} {format( new Date(share.expires_at), 'dd/MM/yyyy', { locale: fr }, )} ) : ( Expire{' '} {formatDistanceToNow( new Date(share.expires_at), { addSuffix: true, locale: fr }, )} )}
)} {share.access_count !== undefined && (
{share.access_count} accès
)}
Créé{' '} {formatDistanceToNow(new Date(share.created_at), { addSuffix: true, locale: fr, })}
{onRevokeShare && ( )}
); })}
)}
{/* Revoke Confirmation Dialog */} {onRevokeShare && ( setShareToRevoke(null)} onConfirm={confirmRevoke} title="Révoquer le lien de partage" description="Êtes-vous sûr de vouloir révoquer ce lien ? Il ne sera plus accessible." confirmLabel="Révoquer" cancelLabel="Annuler" variant="destructive" /> )}
); }