Corrección 1 — Delete de proceso restaurado + Corrección 2 — Patrón userId en repos

This commit is contained in:
2026-05-28 01:13:28 -03:00
parent 1bc80e190f
commit 0a3c60cd09
26 changed files with 1650 additions and 25844 deletions

View File

@@ -3,8 +3,10 @@ import { useNavigate } from '@tanstack/react-router'
import {
Upload, Search, Plus, Building2, FolderX, GitBranch,
Clock, TrendingUp, BarChart2, FileX2, X, Settings,
MoreVertical, Trash2,
} from 'lucide-react'
import { useLibraryStore } from '@/store/library-store'
import { useAuth } from '@/auth/AuthContext'
import { formatCurrency } from '@/lib/format'
import type { Process, ProcessGroup, Simulation } from '@/domain/types'
import { AppHeader } from '@/components/AppHeader'
@@ -78,18 +80,31 @@ function KpiBadge({ process, simulation }: { process: Process; simulation: Simul
// ─── Process Card ─────────────────────────────────────────────────────────────
function ProcessCard({ process, simulation, showGroupChip, groupName }: {
function ProcessCard({ process, simulation, showGroupChip, groupName, onDelete }: {
process: Process
simulation: Simulation | null | undefined
showGroupChip?: boolean
groupName?: string
onDelete?: () => void
}) {
const navigate = useNavigate()
const [menuState, setMenuState] = useState<null | 'menu' | 'confirm'>(null)
// Cierra el menú al hacer click fuera de él
useEffect(() => {
if (!menuState) return
function handleDocClick() { setMenuState(null) }
document.addEventListener('click', handleDocClick)
return () => document.removeEventListener('click', handleDocClick)
}, [menuState])
return (
<div
className="flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card hover:border-border/80 hover:shadow-sm transition-all cursor-pointer"
onClick={() => navigate({ to: '/workspace/$processId', params: { processId: process.id } })}
className="flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card hover:border-border/80 hover:shadow-sm transition-all cursor-pointer group"
onClick={() => {
if (menuState) { setMenuState(null); return }
navigate({ to: '/workspace/$processId', params: { processId: process.id } })
}}
>
{/* Ícono */}
<div className="flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center"
@@ -125,6 +140,60 @@ function ProcessCard({ process, simulation, showGroupChip, groupName }: {
<div className="flex-shrink-0 min-w-[90px]">
<KpiBadge process={process} simulation={simulation} />
</div>
{/* Menú de opciones (⋮) — en el flujo flex, a la derecha del KPI */}
{onDelete && (
<div
className="relative flex-shrink-0"
onClick={(e) => e.stopPropagation()}
>
<button
className={`p-1 rounded hover:bg-secondary text-muted-foreground hover:text-foreground transition-all ${menuState === null ? 'opacity-0 group-hover:opacity-100' : 'opacity-100'}`}
onClick={(e) => { e.stopPropagation(); setMenuState(menuState === 'menu' ? null : 'menu') }}
title="Opciones"
>
<MoreVertical className="h-3.5 w-3.5" />
</button>
{menuState === 'menu' && (
<div
className="absolute right-0 top-7 z-20 bg-card border border-border rounded-lg shadow-lg py-1 min-w-[130px]"
onClick={(e) => e.stopPropagation()}
>
<button
className="flex items-center gap-2 w-full px-3 py-1.5 text-[12px] text-destructive hover:bg-destructive/10 transition-colors"
onClick={(e) => { e.stopPropagation(); setMenuState('confirm') }}
>
<Trash2 className="h-3.5 w-3.5" />
Eliminar
</button>
</div>
)}
{menuState === 'confirm' && (
<div
className="absolute right-0 top-6 z-20 bg-card border border-border rounded-lg shadow-lg p-3 min-w-[170px]"
onClick={(e) => e.stopPropagation()}
>
<p className="text-[12px] font-medium mb-2 text-foreground">¿Eliminar proceso?</p>
<p className="text-[11px] text-muted-foreground mb-3">Esta acción no se puede deshacer.</p>
<div className="flex gap-1.5">
<button
className="flex-1 text-[11px] px-2 py-1 rounded font-medium text-white transition-opacity hover:opacity-90"
style={{ background: '#ef4444' }}
onClick={(e) => { e.stopPropagation(); onDelete(); setMenuState(null) }}
>
Eliminar
</button>
<button
className="flex-1 text-[11px] px-2 py-1 rounded border border-border text-muted-foreground hover:bg-secondary transition-colors"
onClick={(e) => { e.stopPropagation(); setMenuState(null) }}
>
Cancelar
</button>
</div>
</div>
)}
</div>
)}
</div>
)
}
@@ -244,6 +313,7 @@ function HomeView({
onImport: (groupId?: string) => void
}) {
const { groups, processes, settings, createGroup } = useLibraryStore()
const { user } = useAuth()
const [search, setSearch] = useState('')
const [activeTags, setActiveTags] = useState<string[]>([])
@@ -402,7 +472,7 @@ function HomeView({
})}
<NewGroupCard
label={settings.groupLabel}
onCreate={(name) => createGroup(name)}
onCreate={(name) => createGroup(name, user!.id)}
/>
</div>
@@ -437,7 +507,7 @@ function ProcessCardWithSim({ process, showGroupChip, groupName }: {
showGroupChip?: boolean
groupName?: string
}) {
const { getLatestSimulation } = useLibraryStore()
const { getLatestSimulation, deleteProcess } = useLibraryStore()
const [simulation, setSimulation] = useState<Simulation | null | undefined>(undefined)
useEffect(() => {
@@ -448,7 +518,15 @@ function ProcessCardWithSim({ process, showGroupChip, groupName }: {
return () => { cancelled = true }
}, [process.id, getLatestSimulation])
return <ProcessCard process={process} simulation={simulation} showGroupChip={showGroupChip} groupName={groupName} />
return (
<ProcessCard
process={process}
simulation={simulation}
showGroupChip={showGroupChip}
groupName={groupName}
onDelete={() => deleteProcess(process.id)}
/>
)
}
// ─── Group View ───────────────────────────────────────────────────────────────