import { useState, useEffect, useCallback } from 'react' import { Link, useNavigate } from 'react-router-dom' import { Globe, Users, Copy, Check, ExternalLink, Trash2, ArrowLeft } from 'lucide-react' import { PageMeta } from '@/components/common/PageMeta' import { Button } from '@/components/ui/Button' import { Spinner } from '@/components/common/Spinner' import { EmptyState } from '@/components/common/EmptyState' import { ShareIllustration } from '@/components/common/EmptyStateIllustrations' import { ConfirmDialog } from '@/components/common/ConfirmDialog' import { cn } from '@/lib/utils' import { toast } from '@/lib/toast' import { sessionsApi } from '@/api/sessions' import { buildSessionShareUrl } from '@/lib/sessionShare' import type { SessionShare } from '@/types' function formatRelativeTime(dateString: string): string { const date = new Date(dateString) const now = new Date() const diffMs = now.getTime() - date.getTime() const diffMinutes = Math.floor(diffMs / 60000) const diffHours = Math.floor(diffMs / 3600000) const diffDays = Math.floor(diffMs / 86400000) if (diffMinutes < 1) return 'just now' if (diffHours < 1) return `${diffMinutes} minute${diffMinutes === 1 ? '' : 's'} ago` if (diffDays < 1) return `${diffHours} hour${diffHours === 1 ? '' : 's'} ago` if (diffDays < 30) return `${diffDays} day${diffDays === 1 ? '' : 's'} ago` const diffMonths = Math.floor(diffDays / 30) return `${diffMonths} month${diffMonths === 1 ? '' : 's'} ago` } function formatExpiration(expiresAt: string | null): { text: string; isExpired: boolean } { if (!expiresAt) return { text: 'No expiration', isExpired: false } const expiry = new Date(expiresAt) const now = new Date() const diffMs = expiry.getTime() - now.getTime() if (diffMs <= 0) return { text: 'Expired', isExpired: true } const diffMinutes = Math.floor(diffMs / 60000) const diffHours = Math.floor(diffMs / 3600000) const diffDays = Math.floor(diffMs / 86400000) if (diffHours < 1) return { text: `Expires in ${diffMinutes} minute${diffMinutes === 1 ? '' : 's'}`, isExpired: false } if (diffDays < 1) return { text: `Expires in ${diffHours} hour${diffHours === 1 ? '' : 's'}`, isExpired: false } return { text: `Expires in ${diffDays} day${diffDays === 1 ? '' : 's'}`, isExpired: false } } export default function MySharesPage() { const navigate = useNavigate() const [shares, setShares] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [copiedId, setCopiedId] = useState(null) const [revokeTarget, setRevokeTarget] = useState(null) const fetchShares = useCallback(async () => { try { setLoading(true) setError(null) const data = await sessionsApi.listMyShares() setShares(data) } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load shares') } finally { setLoading(false) } }, []) useEffect(() => { fetchShares() }, [fetchShares]) const handleCopyLink = async (share: SessionShare) => { try { const url = buildSessionShareUrl(share) await navigator.clipboard.writeText(url) setCopiedId(share.id) toast.success('Link copied') setTimeout(() => setCopiedId(null), 2000) } catch { toast.error('Failed to copy link') } } const handleRevoke = async () => { if (!revokeTarget) return try { await sessionsApi.revokeShare(revokeTarget.id) setShares((prev) => prev.filter((s) => s.id !== revokeTarget.id)) toast.success('Share link revoked') } catch { toast.error('Failed to revoke share link') } finally { setRevokeTarget(null) } } // Loading state if (loading) { return (
) } // Error state if (error) { return (

{error}

) } return (
{/* Back link */} Back to sessions {/* Header */}

My Shared Sessions

Manage your session share links

{/* Empty state */} {shares.length === 0 ? ( } title="Share session results with your team" description="Create shareable links to completed sessions for knowledge sharing and client communication." action={ } learnMoreLink="/guides/sharing-exports" /> ) : (
{shares.map((share) => { const expiration = formatExpiration(share.expires_at) const isCopied = copiedId === share.id return (
{/* Top row: badge + name */}
{share.visibility === 'public' ? ( ) : ( )} {share.visibility === 'public' ? 'Public' : 'Account Only'} {share.share_name || 'Untitled share'}
{/* Session info */}

Session ID: {share.session_id.slice(0, 8)}...

{/* Meta row */}
Created {formatRelativeTime(share.created_at)} · {share.view_count > 0 ? `${share.view_count} view${share.view_count === 1 ? '' : 's'}` : 'Not viewed yet'} · {expiration.text}
{/* Actions */}
View Session
) })}
)} setRevokeTarget(null)} onConfirm={handleRevoke} title="Revoke Share Link" message="Revoke this share link? Anyone with the link will no longer be able to access the session." confirmLabel="Revoke" />
) }