"use client"; import { useState } from 'react'; import { Clip } from '@/app/account/page'; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, DialogClose } from '@/components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog'; import { supabase } from '@/integrations/supabase/client'; import { toast } from 'sonner'; import { Toaster } from '@/components/ui/sonner'; import { formatDistanceToNow } from 'date-fns'; import { MoreVertical, Edit, Trash2, Loader2, Copy, Check } from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; import Link from 'next/link'; import Image from 'next/image'; type UserClipsProps = { clips: Clip[]; onClipDeleted: (clipId: string) => void; onClipUpdated: (clip: Clip) => void; }; export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProps) { const [clipToEdit, setClipToEdit] = useState(null); const [newTitle, setNewTitle] = useState(''); const [isSaving, setIsSaving] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [hasCopied, setHasCopied] = useState(null); const handleEditClick = (clip: Clip) => { setClipToEdit(clip); setNewTitle(clip.title); }; const handleSaveChanges = async () => { if (!clipToEdit || !newTitle.trim()) return; setIsSaving(true); try { const { data, error } = await supabase .from('clips') .update({ title: newTitle.trim() }) .eq('id', clipToEdit.id) .select() .single(); if (error) throw error; onClipUpdated(data as Clip); toast.success('Title updated successfully!'); setClipToEdit(null); } catch (error) { toast.error('Failed to update title.'); console.error(error); } finally { setIsSaving(false); } }; const handleDeleteClip = async (clip: Clip) => { setIsDeleting(true); try { const pathsToRemove = [clip.storage_path]; if (clip.thumbnail_storage_path) { pathsToRemove.push(clip.thumbnail_storage_path); } const { error: storageError } = await supabase.storage.from('clips').remove(pathsToRemove); if (storageError) throw storageError; const { error: dbError } = await supabase.from('clips').delete().eq('id', clip.id); if (dbError) throw dbError; onClipDeleted(clip.id); toast.success('Clip deleted successfully!'); } catch (error) { toast.error('Failed to delete clip.'); console.error(error); } finally { setIsDeleting(false); } }; const copyToClipboard = (shortId: string) => { const link = `${window.location.origin}/clips/${shortId}`; navigator.clipboard.writeText(link); setHasCopied(shortId); setTimeout(() => setHasCopied(null), 2000); }; const getThumbnailUrl = (path: string) => { const { data } = supabase.storage.from('clips').getPublicUrl(path); return data.publicUrl; } return ( <>
{clips.map((clip) => ( {clip.title || 'Untitled Clip'} handleEditClick(clip)}> Edit Title Delete
{clip.thumbnail_storage_path ? ( {clip.title ) : (
No thumbnail
)}
{formatDistanceToNow(new Date(clip.created_at), { addSuffix: true })} {/* Delete Confirmation Dialog */} Are you sure? This action cannot be undone. This will permanently delete your clip and its thumbnail from our servers. Cancel handleDeleteClip(clip)} disabled={isDeleting} className="bg-destructive hover:bg-destructive/90"> {isDeleting && } Delete
))}
{/* Edit Title Dialog */} !isOpen && setClipToEdit(null)}> Edit Clip Title
setNewTitle(e.target.value)} className="col-span-3" />
); }