import { useEffect, useState } from 'react'; import type { Particle } from '@/api/types'; import { apiClient } from '@/api/client'; import { Skeleton } from '@/components/ui/skeleton'; import { Video, Mic, CircleCheck, CalendarDays, BookOpen, FileIcon, FolderIcon, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { formatEventTime } from '@/lib/particle-display'; export function ParticlePreview({ particle }: { particle: Particle }) { switch (particle.type) { case 'text': return ; case 'media': return ; case 'task': return ; case 'event': return ; case 'paper': return ; case 'file': return ; case 'folder': return ; default: return ; } } function TextPreview({ particle, }: { particle: Extract; }) { const truncated = particle.properties.content.length > 30 ? particle.properties.content.slice(0, 30) + '...' : particle.properties.content; return (

{truncated}

); } function MediaPreview({ particle, }: { particle: Extract; }) { const { mime_type, duration_ms } = particle.properties; const isVideo = mime_type.startsWith('video'); const durationSec = Math.round(duration_ms / 1000); const durationLabel = `${Math.floor(durationSec / 60)}:${String(durationSec % 60).padStart(2, '0')}`; if (isVideo) { return ( ); } return (
{durationLabel}
); } function VideoThumbnail({ particleId, duration, }: { particleId: string; duration: string; }) { const [url, setUrl] = useState(null); const [error, setError] = useState(false); useEffect(() => { let cancelled = false; apiClient .getParticleDownloadUrl(particleId) .then((downloadUrl) => { if (!cancelled) setUrl(downloadUrl); }) .catch(() => { if (!cancelled) setError(true); }); return () => { cancelled = true; }; }, [particleId]); if (error) { return (
); } if (!url) { return ; } return (
); } function TaskPreview({ particle, }: { particle: Extract; }) { const { title, done } = particle.properties; return (

{title}

); } function EventPreview({ particle, }: { particle: Extract; }) { const { title, start_at, end_at } = particle.properties; return (

{title}

{formatEventTime(start_at, end_at)}
); } function PaperPreview({ particle, }: { particle: Extract; }) { return (

{particle.properties.title}

); } function FilePreview({ particle, }: { particle: Extract; }) { return (

{particle.properties.filename}

); } function FolderPreview({ particle, }: { particle: Extract; }) { return (

{particle.properties.name}

); } function EmptyPreview() { return (

No messages yet

); }