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

@@ -9,6 +9,7 @@ import { supabaseProcessRepo } from '@/persistence/supabase/process-repo'
import type { Process, Activity, GatewayConfig } from '@/domain/types'
import { bpmnTypeToGatewayType } from '@/domain/types'
import { useToast } from '@/components/ui/use-toast'
import { useAuth } from '@/auth/AuthContext'
import { AppFooter } from '@/components/AppFooter'
import { AppHeader } from '@/components/AppHeader'
@@ -36,6 +37,7 @@ const SAMPLE_PROCESSES = [
export function ImportPage() {
const navigate = useNavigate()
const { toast } = useToast()
const { user } = useAuth()
const [isDragging, setIsDragging] = useState(false)
const [isProcessing, setIsProcessing] = useState(false)
const [loadingSampleId, setLoadingSampleId] = useState<string | null>(null)
@@ -113,7 +115,7 @@ export function ImportPage() {
})
await Promise.all([
supabaseProcessRepo.save(process),
supabaseProcessRepo.save(process, user!.id),
activityRepo.saveMany(activities),
gatewayRepo.saveMany(gateways),
])

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 ───────────────────────────────────────────────────────────────

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { Fragment, useEffect, useMemo, useRef, useState } from 'react'
import { ArrowUpDown, ArrowUp, ArrowDown, ChevronRight } from 'lucide-react'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { activityColor } from '@/lib/colors'
@@ -108,9 +108,8 @@ export function ActivitiesTable({ perActivity, pairedBreakdown, mode, currency,
const hasBreakdown = !(act.resourceCostBreakdown.length === 0 && act.expectedDirectCost === 0)
return (
<>
<Fragment key={act.activityId}>
<TableRow
key={act.activityId}
ref={(el) => { if (el) rowRefs.current.set(act.bpmnElementId, el) }}
onClick={() => onRowClick(act.bpmnElementId)}
className={`cursor-pointer ${isHighlighted ? 'bg-primary/5 ring-1 ring-inset ring-primary/20' : ''}`}
@@ -217,7 +216,7 @@ export function ActivitiesTable({ perActivity, pairedBreakdown, mode, currency,
</TableCell>
</TableRow>
)}
</>
</Fragment>
)
})}
</TableBody>

View File

@@ -151,9 +151,12 @@ export const HeatmapCanvas = forwardRef<HeatmapCanvasHandle, HeatmapCanvasProps>
setIsImported(false)
const eventBus = viewer.get('eventBus') as any
let cancelled = false
const onImportDone = () => {
eventBus.off('import.done', onImportDone)
// Si el viewer fue destruido y reemplazado (p.ej. React Strict Mode), ignorar
if (cancelled) return
const canvas = viewer.get('canvas') as any
try { canvas.zoom('fit-viewport', 'auto') } catch { /* canvas puede no estar listo */ }
isImportedRef.current = true
@@ -163,12 +166,14 @@ export const HeatmapCanvas = forwardRef<HeatmapCanvasHandle, HeatmapCanvasProps>
eventBus.on('import.done', onImportDone)
viewer.importXML(xml).catch((err: unknown) => {
if (cancelled) return
// Puede rechazar aunque el diagrama ya se haya renderizado (error de root layer en bpmn-js 18).
// 'import.done' ya habrá disparado antes de este catch, por lo que isImported ya es true.
console.warn('HeatmapCanvas importXML error (diagrama puede estar parcialmente renderizado):', err)
})
return () => {
cancelled = true
eventBus.off('import.done', onImportDone)
}
}, [xml])

View File

@@ -10,6 +10,7 @@ import { ScrollArea } from '@/components/ui/scroll-area'
import { Switch } from '@/components/ui/switch'
import { Separator } from '@/components/ui/separator'
import { useProcessStore } from '@/store/process-store'
import { useAuth } from '@/auth/AuthContext'
import { formatCurrency } from '@/lib/format'
import type { Activity } from '@/domain/types'
@@ -19,6 +20,7 @@ interface ActivityPanelProps {
export function ActivityPanel({ selectedElementId }: ActivityPanelProps) {
const { activities, resources, updateActivity, currentProcess } = useProcessStore()
const { user } = useAuth()
const [localActivity, setLocalActivity] = useState<Activity | null>(null)
const [isDirty, setIsDirty] = useState(false)
@@ -42,7 +44,7 @@ export function ActivityPanel({ selectedElementId }: ActivityPanelProps) {
async function handleSave() {
if (!localActivity) return
await updateActivity(localActivity)
await updateActivity(localActivity, user!.id)
setIsDirty(false)
}

View File

@@ -110,12 +110,17 @@ export function BpmnCanvas({
if (!viewer || !xml) return
isImportedRef.current = false
viewer.importXML(xml).then(({ warnings }) => {
// Si el viewer fue destruido y reemplazado (p.ej. React Strict Mode), ignorar
if (viewerRef.current !== viewer) return
if (warnings.length) console.warn('bpmn-js warnings:', warnings)
const canvas = viewer.get('canvas') as any
canvas.zoom('fit-viewport', 'auto')
isImportedRef.current = true
syncAutomationOverlays()
}).catch((err: Error) => console.error('Error cargando BPMN:', err))
}).catch((err: Error) => {
if (viewerRef.current !== viewer) return
console.error('Error cargando BPMN:', err)
})
}, [xml, syncAutomationOverlays])
// ─── Re-sincronizar overlays cuando cambia la lista de automatizables ─────

View File

@@ -6,6 +6,7 @@ import { Slider } from '@/components/ui/slider'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { ScrollArea } from '@/components/ui/scroll-area'
import { useProcessStore } from '@/store/process-store'
import { useAuth } from '@/auth/AuthContext'
import { parseBpmnXml } from '@/domain/bpmn-parser'
import { formatPercent } from '@/lib/format'
import type { GatewayConfig } from '@/domain/types'
@@ -28,6 +29,7 @@ export function isXorSumValid(gw: GatewayConfig): boolean {
export function GatewayPanel({ selectedElementId }: GatewayPanelProps) {
const { gateways, currentProcess, updateGateway, activities } = useProcessStore()
const { user } = useAuth()
const [localGw, setLocalGw] = useState<GatewayConfig | null>(null)
const [isDirty, setIsDirty] = useState(false)
@@ -82,7 +84,7 @@ export function GatewayPanel({ selectedElementId }: GatewayPanelProps) {
async function handleSave() {
if (!localGw) return
await updateGateway(localGw)
await updateGateway(localGw, user!.id)
setIsDirty(false)
}

View File

@@ -9,6 +9,7 @@ import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { useProcessStore } from '@/store/process-store'
import { useAuth } from '@/auth/AuthContext'
import { formatPercent } from '@/lib/format'
const CURRENCIES = [
@@ -24,6 +25,7 @@ const CURRENCIES = [
export function GlobalSettingsPanel() {
const { currentProcess, updateProcess } = useProcessStore()
const { user } = useAuth()
const [localName, setLocalName] = useState('')
const [localClient, setLocalClient] = useState('')
const [localCurrency, setLocalCurrency] = useState('USD')
@@ -57,7 +59,7 @@ export function GlobalSettingsPanel() {
annualFrequency: Math.max(1, localFrequency),
analysisHorizonYears: clampedHorizon,
automationInvestment: Math.max(0, localInvestment),
})
}, user!.id)
setLocalHorizon(clampedHorizon)
setIsDirty(false)
}

View File

@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { ScrollArea } from '@/components/ui/scroll-area'
import { useProcessStore } from '@/store/process-store'
import { useAuth } from '@/auth/AuthContext'
import { formatCurrency } from '@/lib/format'
import type { Resource, ResourceType } from '@/domain/types'
@@ -36,6 +37,7 @@ const EMPTY_FORM: ResourceFormState = { name: '', type: 'role', costPerHour: ''
export function ResourcesPanel() {
const { currentProcess, resources, addResource, updateResource, deleteResource } = useProcessStore()
const { user } = useAuth()
const [showForm, setShowForm] = useState(false)
const [editingId, setEditingId] = useState<string | null>(null)
const [form, setForm] = useState<ResourceFormState>(EMPTY_FORM)
@@ -65,7 +67,7 @@ export function ResourcesPanel() {
if (editingId) {
const existing = resources.find((r) => r.id === editingId)
if (!existing) return
await updateResource({ ...existing, name: form.name.trim(), type: form.type, costPerHour })
await updateResource({ ...existing, name: form.name.trim(), type: form.type, costPerHour }, user!.id)
} else {
const newResource: Resource = {
id: uuidv4(),
@@ -74,7 +76,7 @@ export function ResourcesPanel() {
type: form.type,
costPerHour,
}
await addResource(newResource)
await addResource(newResource, user!.id)
}
cancelForm()
}
@@ -186,7 +188,7 @@ export function ResourcesPanel() {
variant="ghost"
size="icon"
className="h-6 w-6 text-slate-400 hover:text-destructive"
onClick={() => deleteResource(resource.id)}
onClick={() => deleteResource(resource.id, user!.id)}
>
<Trash2 className="h-3 w-3" />
</Button>

View File

@@ -19,6 +19,7 @@ import { useProcessStore } from '@/store/process-store'
import { useSimulationStore } from '@/store/simulation-store'
import { useSimulate } from '../simulation/useSimulate'
import { useLibraryStore } from '@/store/library-store'
import { useAuth } from '@/auth/AuthContext'
import { AppHeader } from '@/components/AppHeader'
type SelectedCategory = 'activity' | 'gateway' | null
@@ -30,6 +31,7 @@ export function WorkspacePage() {
const { isRunning, resultActual, error: simError, selectActivity, loadLatestForProcess, lastPersistedExecutedAt } = useSimulationStore()
const { simulate } = useSimulate()
const { toast } = useToast()
const { user } = useAuth()
const [sidebarOpen, setSidebarOpen] = useState(true)
const [selectedElementId, setSelectedElementId] = useState<string | null>(null)
@@ -122,12 +124,12 @@ export function WorkspacePage() {
if (field === 'name') {
const trimmed = editValue.trim()
if (trimmed && trimmed !== currentProcess?.name) {
await updateProcess({ name: trimmed })
await updateProcess({ name: trimmed }, user!.id)
}
} else {
const trimmed = editValue.trim()
if (trimmed !== (currentProcess?.clientName ?? '')) {
await updateProcess({ clientName: trimmed })
await updateProcess({ clientName: trimmed }, user!.id)
}
}
setEditingField(null)
@@ -141,14 +143,14 @@ export function WorkspacePage() {
if (!normalized) return
const current = currentProcess?.tags ?? []
if (current.some((t) => t === normalized)) return
updateProcess({ tags: [...current, normalized] })
updateProcess({ tags: [...current, normalized] }, user!.id)
setTagInput('')
setShowTagSuggestions(false)
}
function removeTag(tag: string) {
const current = currentProcess?.tags ?? []
updateProcess({ tags: current.filter((t) => t !== tag) })
updateProcess({ tags: current.filter((t) => t !== tag) }, user!.id)
}
function handleTagKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {

View File

@@ -1,12 +1,6 @@
import { supabase } from '@/lib/supabase'
import type { ProcessGroup } from '@/domain/types'
async function getCurrentUserId(): Promise<string> {
const { data: { session } } = await supabase.auth.getSession()
if (!session?.user) throw new Error('Usuario no autenticado')
return session.user.id
}
function fromRow(row: Record<string, unknown>): ProcessGroup {
return {
id: row.id as string,
@@ -17,8 +11,7 @@ function fromRow(row: Record<string, unknown>): ProcessGroup {
}
export const supabaseGroupRepo = {
async save(group: ProcessGroup): Promise<void> {
const userId = await getCurrentUserId()
async save(group: ProcessGroup, userId: string): Promise<void> {
const { error } = await supabase.from('process_groups').upsert({
id: group.id,
name: group.name,

View File

@@ -2,12 +2,6 @@ import { supabase } from '@/lib/supabase'
import { db } from '@/persistence/db'
import type { Process } from '@/domain/types'
async function getCurrentUserId(): Promise<string> {
const { data: { session } } = await supabase.auth.getSession()
if (!session?.user) throw new Error('Usuario no autenticado')
return session.user.id
}
function toRow(process: Process, userId: string) {
return {
id: process.id,
@@ -47,8 +41,7 @@ function fromRow(row: Record<string, unknown>): Process {
}
export const supabaseProcessRepo = {
async save(process: Process): Promise<void> {
const userId = await getCurrentUserId()
async save(process: Process, userId: string): Promise<void> {
const { error } = await supabase.from('processes').upsert(toRow(process, userId))
if (error) throw error
},

View File

@@ -14,12 +14,12 @@ interface LibraryState {
load: () => Promise<void>
createGroup: (name: string) => Promise<ProcessGroup>
createGroup: (name: string, userId: string) => Promise<ProcessGroup>
deleteGroup: (id: string) => Promise<void>
deleteProcess: (id: string) => Promise<void>
assignProcessToGroup: (processId: string, groupId: string | null) => Promise<void>
assignProcessToGroup: (processId: string, groupId: string | null, userId: string) => Promise<void>
getProcessesByGroup: (groupId: string | null) => Process[]
getLatestSimulation: (processId: string) => Promise<Simulation | undefined>
@@ -51,15 +51,15 @@ export const useLibraryStore = create<LibraryState>((set, get) => ({
}
},
createGroup: async (name: string) => {
createGroup: async (name, userId) => {
const now = Date.now()
const group: ProcessGroup = { id: uuidv4(), name, createdAt: now, updatedAt: now }
await supabaseGroupRepo.save(group)
await supabaseGroupRepo.save(group, userId)
set((state) => ({ groups: [...state.groups, group].sort((a, b) => a.name.localeCompare(b.name)) }))
return group
},
deleteGroup: async (id: string) => {
deleteGroup: async (id) => {
await supabaseGroupRepo.delete(id)
set((state) => ({
groups: state.groups.filter((g) => g.id !== id),
@@ -67,29 +67,29 @@ export const useLibraryStore = create<LibraryState>((set, get) => ({
}))
},
deleteProcess: async (id: string) => {
deleteProcess: async (id) => {
await supabaseProcessRepo.delete(id)
set((state) => ({ processes: state.processes.filter((p) => p.id !== id) }))
},
assignProcessToGroup: async (processId: string, groupId: string | null) => {
assignProcessToGroup: async (processId, groupId, userId) => {
const process = get().processes.find((p) => p.id === processId)
if (!process) return
const updated = { ...process, groupId, updatedAt: Date.now() }
await supabaseProcessRepo.save(updated)
await supabaseProcessRepo.save(updated, userId)
set((state) => ({
processes: state.processes.map((p) => p.id === processId ? updated : p),
}))
},
getProcessesByGroup: (groupId: string | null) => {
getProcessesByGroup: (groupId) => {
const processes = get().processes
return groupId === null
? processes.filter((p) => p.groupId == null)
: processes.filter((p) => p.groupId === groupId)
},
getLatestSimulation: (processId: string) => {
getLatestSimulation: (processId) => {
return simulationRepo.getLatestByProcess(processId)
},

View File

@@ -12,13 +12,13 @@ interface ProcessState {
error: string | null
loadProcess: (processId: string) => Promise<void>
setCurrentProcess: (process: Process) => Promise<void>
updateProcess: (updates: Partial<Process>) => Promise<void>
updateActivity: (activity: Activity) => Promise<void>
updateGateway: (gateway: GatewayConfig) => Promise<void>
addResource: (resource: Resource) => Promise<void>
updateResource: (resource: Resource) => Promise<void>
deleteResource: (resourceId: string) => Promise<void>
setCurrentProcess: (process: Process, userId: string) => Promise<void>
updateProcess: (updates: Partial<Process>, userId: string) => Promise<void>
updateActivity: (activity: Activity, userId: string) => Promise<void>
updateGateway: (gateway: GatewayConfig, userId: string) => Promise<void>
addResource: (resource: Resource, userId: string) => Promise<void>
updateResource: (resource: Resource, userId: string) => Promise<void>
deleteResource: (resourceId: string, userId: string) => Promise<void>
reset: () => void
}
@@ -46,8 +46,8 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
}
},
setCurrentProcess: async (process) => {
await supabaseProcessRepo.save(process)
setCurrentProcess: async (process, userId) => {
await supabaseProcessRepo.save(process, userId)
const [activities, gateways, resources] = await Promise.all([
activityRepo.getByProcess(process.id),
gatewayRepo.getByProcess(process.id),
@@ -56,20 +56,20 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
set({ currentProcess: process, activities, gateways, resources })
},
updateProcess: async (updates) => {
updateProcess: async (updates, userId) => {
const current = get().currentProcess
if (!current) return
const updated: Process = { ...current, ...updates, updatedAt: Date.now() }
await supabaseProcessRepo.save(updated)
await supabaseProcessRepo.save(updated, userId)
set({ currentProcess: updated })
},
updateActivity: async (activity) => {
updateActivity: async (activity, userId) => {
await activityRepo.save(activity)
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await supabaseProcessRepo.save(updatedProcess)
await supabaseProcessRepo.save(updatedProcess, userId)
set((state) => ({
activities: state.activities.map((a) => (a.id === activity.id ? activity : a)),
currentProcess: updatedProcess,
@@ -81,12 +81,12 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
}
},
updateGateway: async (gateway) => {
updateGateway: async (gateway, userId) => {
await gatewayRepo.save(gateway)
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await supabaseProcessRepo.save(updatedProcess)
await supabaseProcessRepo.save(updatedProcess, userId)
set((state) => ({
gateways: state.gateways.map((g) => (g.id === gateway.id ? gateway : g)),
currentProcess: updatedProcess,
@@ -98,24 +98,24 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
}
},
addResource: async (resource) => {
addResource: async (resource, userId) => {
await resourceRepo.save(resource)
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await supabaseProcessRepo.save(updatedProcess)
await supabaseProcessRepo.save(updatedProcess, userId)
set((state) => ({ resources: [...state.resources, resource], currentProcess: updatedProcess }))
} else {
set((state) => ({ resources: [...state.resources, resource] }))
}
},
updateResource: async (resource) => {
updateResource: async (resource, userId) => {
await resourceRepo.save(resource)
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await supabaseProcessRepo.save(updatedProcess)
await supabaseProcessRepo.save(updatedProcess, userId)
set((state) => ({
resources: state.resources.map((r) => (r.id === resource.id ? resource : r)),
currentProcess: updatedProcess,
@@ -127,12 +127,12 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
}
},
deleteResource: async (resourceId) => {
deleteResource: async (resourceId, userId) => {
await resourceRepo.delete(resourceId)
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await supabaseProcessRepo.save(updatedProcess)
await supabaseProcessRepo.save(updatedProcess, userId)
set((state) => ({
resources: state.resources.filter((r) => r.id !== resourceId),
currentProcess: updatedProcess,