/ src / components / agents / trash-list.tsx
trash-list.tsx
  1  'use client'
  2  
  3  import { useEffect, useState } from 'react'
  4  import type { Agent } from '@/types'
  5  import { useAppStore } from '@/stores/use-app-store'
  6  import { api } from '@/lib/app/api-client'
  7  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
  8  
  9  export function TrashList() {
 10    const trashedAgents = useAppStore((s) => s.trashedAgents)
 11    const loadTrashedAgents = useAppStore((s) => s.loadTrashedAgents)
 12    const loadAgents = useAppStore((s) => s.loadAgents)
 13    const [confirmPermanent, setConfirmPermanent] = useState<Agent | null>(null)
 14  
 15    useEffect(() => { loadTrashedAgents() }, [loadTrashedAgents])
 16  
 17    const handleRestore = async (id: string) => {
 18      await api('POST', '/agents/trash', { id })
 19      await Promise.all([loadTrashedAgents(), loadAgents()])
 20    }
 21  
 22    const handlePermanentDelete = async (id: string) => {
 23      await api('DELETE', '/agents/trash', { id })
 24      await loadTrashedAgents()
 25      setConfirmPermanent(null)
 26    }
 27  
 28    const agents = Object.values(trashedAgents).sort(
 29      (a, b) => (b.trashedAt ?? 0) - (a.trashedAt ?? 0),
 30    )
 31  
 32    if (!agents.length) {
 33      return (
 34        <div className="flex-1 flex flex-col items-center justify-center gap-3 text-text-3 p-8 text-center">
 35          <div className="w-12 h-12 rounded-[14px] bg-white/[0.03] flex items-center justify-center">
 36            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-text-3/50">
 37              <polyline points="3 6 5 6 21 6" />
 38              <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
 39            </svg>
 40          </div>
 41          <p className="text-[13px] text-text-3/50">Trash is empty</p>
 42        </div>
 43      )
 44    }
 45  
 46    return (
 47      <div className="flex-1 overflow-y-auto">
 48        <div className="flex flex-col gap-1 px-2 pb-4 pt-2">
 49          {agents.map((agent) => (
 50            <div
 51              key={agent.id}
 52              className="py-3 px-4 rounded-[14px] border border-white/[0.04] bg-white/[0.02]"
 53            >
 54              <div className="flex items-center gap-2.5">
 55                <span className="font-display text-[14px] font-600 truncate flex-1 tracking-[-0.01em] text-text-2/70">
 56                  {agent.name}
 57                </span>
 58              </div>
 59              <div className="text-[12px] text-text-3/50 mt-1 truncate">{agent.description}</div>
 60              {agent.trashedAt && (
 61                <div className="text-[11px] text-text-3/40 mt-1">
 62                  Trashed {formatRelative(agent.trashedAt)}
 63                </div>
 64              )}
 65              <div className="flex items-center gap-2 mt-2.5">
 66                <button
 67                  onClick={() => handleRestore(agent.id)}
 68                  className="px-3 py-1.5 rounded-[8px] border border-white/[0.08] bg-transparent text-[12px] font-600
 69                    text-accent-bright cursor-pointer hover:bg-accent-soft transition-all"
 70                  style={{ fontFamily: 'inherit' }}
 71                >
 72                  Restore
 73                </button>
 74                <button
 75                  onClick={() => setConfirmPermanent(agent)}
 76                  className="px-3 py-1.5 rounded-[8px] border border-white/[0.08] bg-transparent text-[12px] font-600
 77                    text-red-400 cursor-pointer hover:bg-red-400/10 transition-all"
 78                  style={{ fontFamily: 'inherit' }}
 79                >
 80                  Delete Forever
 81                </button>
 82              </div>
 83            </div>
 84          ))}
 85        </div>
 86  
 87        <ConfirmDialog
 88          open={!!confirmPermanent}
 89          title="Permanently Delete"
 90          message={`Permanently delete "${confirmPermanent?.name}"? This cannot be undone.`}
 91          confirmLabel="Delete Forever"
 92          danger
 93          onConfirm={() => confirmPermanent && handlePermanentDelete(confirmPermanent.id)}
 94          onCancel={() => setConfirmPermanent(null)}
 95        />
 96      </div>
 97    )
 98  }
 99  
100  function formatRelative(ts: number): string {
101    const diff = Date.now() - ts
102    const mins = Math.floor(diff / 60_000)
103    if (mins < 1) return 'just now'
104    if (mins < 60) return `${mins}m ago`
105    const hours = Math.floor(mins / 60)
106    if (hours < 24) return `${hours}h ago`
107    const days = Math.floor(hours / 24)
108    return `${days}d ago`
109  }