Resumen del fix — Prioridad 2:
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled

Cambios en WorkspacePage.tsx:

orgName ahora es string | null | undefined. undefined = query no completó aún, null = proceso sin org (o query sin resultado), string = nombre real.
Reemplazó .single() por .maybeSingle() — .single() lanzaba PGRST116 cuando el org no existía, data quedaba en null y setOrgName nunca se llamaba, dejando el estado indefinido.
setOrgName(data?.name ?? null) se llama siempre, sin condición if (data).
backLabel pasa de orgId ? (orgName ?? 'Volver') : 'Biblioteca' a simplemente orgName ?? 'Biblioteca' — el nombre real si cargó, o el fallback genérico en cualquier otro caso. Ya no depende de orgId para decidir el label.
handleBack() no cambió — sigue usando currentProcess?.orgId para construir el URL correcto a /library?org=xxx.
Listo para validación visual en workspace con un proceso de cliente que tenga org_id en la DB.
This commit is contained in:
2026-07-07 14:53:39 -03:00
parent f3f55a6857
commit 6fee592e40
3 changed files with 32 additions and 19 deletions

View File

@@ -1,4 +1,4 @@
import { createContext, useContext, useEffect, useState, useCallback, type ReactNode } from 'react'
import { createContext, useContext, useEffect, useRef, useState, useCallback, type ReactNode } from 'react'
import { SupabaseAuthService } from './SupabaseAuthService'
import { supabase } from '@/lib/supabase'
import type { AuthUser } from './types'
@@ -67,18 +67,30 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const [loading, setLoading] = useState(isOAuthRedirect)
const [pendingPasswordReset, setPendingPasswordReset] = useState(false)
const [isProfileLoaded, setIsProfileLoaded] = useState(false)
// Ref para comparar id entre eventos de auth y NO resetear isProfileLoaded en eventos
// como TOKEN_REFRESHED que llegan con el mismo usuario. Sin esto, si el evento llega
// después de que syncProfileFromDB completó, isProfileLoaded queda en false para siempre.
const lastSyncedUserIdRef = useRef<string | null>(
isOAuthRedirect ? null : (getUserFromStorage()?.id ?? null)
)
useEffect(() => {
// Verificar y sincronizar con Supabase en background.
// Si la sesión expiró o fue revocada, onAuthStateChange llamará callback(null)
// y el router redirigirá a /login.
const unsubscribe = authService.onAuthStateChange((u) => {
const prevId = lastSyncedUserIdRef.current
lastSyncedUserIdRef.current = u?.id ?? null
setUser(u)
setLoading(false)
// Si no hay usuario, no hay nada que sincronizar → marcar como cargado.
// Si hay usuario, la sincronización con DB reseteará a false → true al completar.
if (!u) setIsProfileLoaded(true)
else setIsProfileLoaded(false)
if (!u) {
// Logout → nada que sincronizar
setIsProfileLoaded(true)
} else if (u.id !== prevId) {
// Usuario diferente → requiere nueva sincronización con DB
setIsProfileLoaded(false)
}
// Mismo usuario (TOKEN_REFRESHED, INITIAL_SESSION, etc.) → preservar isProfileLoaded
})
return () => unsubscribe()
}, [])

View File

@@ -68,12 +68,17 @@ export function WorkspacePage() {
}
}, [user, processId, navigate])
// Nombre de la organización dueña del proceso (para el back button contextual)
const [orgName, setOrgName] = useState<string | null>(null)
// 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).single()
.then(({ data }) => { if (data) setOrgName(data.name as string) })
supabase
.from('organizations')
.select('name')
.eq('id', currentProcess.orgId)
.maybeSingle()
.then(({ data }) => setOrgName(data?.name ?? null))
}, [currentProcess?.orgId])
// Validación XOR: todos los gateways exclusivos deben sumar 1.0
@@ -196,9 +201,7 @@ export function WorkspacePage() {
const isClientRole = user?.platformRole === 'client_editor'
const backLabel = isClientRole
? 'Procesos'
: currentProcess.orgId
? (orgName ?? 'Volver')
: 'Biblioteca'
: orgName ?? 'Biblioteca'
function handleBack() {
const orgId = currentProcess?.orgId