fix(workspace): obtener orgName via JOIN en getById, eliminar fetch separado con race condition
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
This commit is contained in:
@@ -21,6 +21,7 @@ export interface Process {
|
||||
ownerId: string // 🆕 Sprint 4 — owner del proceso (auth.uid() al crear)
|
||||
updatedBy: string // 🆕 Sprint 4 — UUID del usuario que hizo el último update
|
||||
orgId: string | null // 🆕 Sprint 7 — organización dueña del proceso (null = proceso interno InQ)
|
||||
orgName?: string | null // 🆕 Sprint 7 — nombre de la org (poblado por getById via JOIN, no se persiste)
|
||||
}
|
||||
|
||||
export type ActivityType = 'task' | 'subprocess'
|
||||
|
||||
@@ -22,7 +22,6 @@ import { useLibraryStore } from '@/store/library-store'
|
||||
import { useAuth } from '@/auth/AuthContext'
|
||||
import { AppHeader } from '@/components/AppHeader'
|
||||
import { ErrorBoundary } from '@/components/ErrorBoundary'
|
||||
import { supabase } from '@/lib/supabase'
|
||||
|
||||
type SelectedCategory = 'activity' | 'gateway' | null
|
||||
|
||||
@@ -68,18 +67,7 @@ export function WorkspacePage() {
|
||||
}
|
||||
}, [user, processId, navigate])
|
||||
|
||||
// Nombre de la organización dueña del proceso (para el back button contextual).
|
||||
// undefined = todavía cargando, null = cargado sin resultado, string = nombre real.
|
||||
const [orgName, setOrgName] = useState<string | null | undefined>(undefined)
|
||||
useEffect(() => {
|
||||
if (!currentProcess?.orgId) { setOrgName(null); return }
|
||||
supabase
|
||||
.from('organizations')
|
||||
.select('name')
|
||||
.eq('id', currentProcess.orgId)
|
||||
.maybeSingle()
|
||||
.then(({ data }) => setOrgName(data?.name ?? null))
|
||||
}, [currentProcess?.orgId])
|
||||
// orgName viene directamente del proceso cargado via JOIN en getById (sin fetch separado)
|
||||
|
||||
// Validación XOR: todos los gateways exclusivos deben sumar 1.0
|
||||
const xorValidation = useMemo(() => {
|
||||
@@ -198,10 +186,12 @@ export function WorkspacePage() {
|
||||
}
|
||||
|
||||
// client_viewer ya fue redirigido antes de este punto; solo verificamos client_editor aquí
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[WorkspacePage] currentProcess:', { id: currentProcess.id, orgId: currentProcess.orgId })
|
||||
const isClientRole = user?.platformRole === 'client_editor'
|
||||
const backLabel = isClientRole
|
||||
? 'Procesos'
|
||||
: orgName ?? 'Biblioteca'
|
||||
: currentProcess.orgName ?? 'Biblioteca'
|
||||
|
||||
function handleBack() {
|
||||
const orgId = currentProcess?.orgId
|
||||
|
||||
@@ -23,6 +23,8 @@ function toRow(process: Process, userId: string) {
|
||||
}
|
||||
|
||||
function fromRow(row: Record<string, unknown>): Process {
|
||||
// org puede estar presente si el query hizo JOIN con organizations (getById lo incluye)
|
||||
const org = row.org as { name: string } | null
|
||||
return {
|
||||
id: row.id as string,
|
||||
name: row.name as string,
|
||||
@@ -40,6 +42,7 @@ function fromRow(row: Record<string, unknown>): Process {
|
||||
ownerId: (row.owner_id as string) ?? '',
|
||||
updatedBy: (row.updated_by as string) ?? '',
|
||||
orgId: (row.org_id as string | null) ?? null,
|
||||
orgName: org?.name ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,13 +99,14 @@ export const supabaseProcessRepo = {
|
||||
},
|
||||
|
||||
async getById(id: string): Promise<Process | undefined> {
|
||||
// JOIN con organizations para obtener orgName en una sola query (evita fetch separado y race conditions)
|
||||
const { data, error } = await supabase
|
||||
.from('processes')
|
||||
.select('*')
|
||||
.select('*, org:organizations!org_id(name)')
|
||||
.eq('id', id)
|
||||
.single()
|
||||
if (error) return undefined
|
||||
return fromRow(data)
|
||||
return fromRow(data as Record<string, unknown>)
|
||||
},
|
||||
|
||||
// JOIN con users para resolver owner/updater en una sola query (evita N+1).
|
||||
|
||||
Reference in New Issue
Block a user