Commit Graph

12 Commits

Author SHA1 Message Date
1c5329915a fix(sprint-5/etapa-4f): || fallback en name vacío — botón Guardar habilitado cuando Google devuelve full_name: ""
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
El operador ?? solo hace fallback con null/undefined, no con cadena vacía.
Si Google devuelve user_metadata.full_name: "", la cadena de propagación es:
  buildAuthUser → name=""  →  upsertUserOnLogin inserta ""  →  syncProfileFromDB
  devuelve ""  →  AuthContext setUser → "" ?? prev.name = ""  →  ProfileSheet
  setName("") → name.trim() === '' → botón disabled → click no hace nada.

Fix: cambiar ?? por || en todos los puntos donde full_name o name de DB
se propagan al estado: buildAuthUser, syncProfileFromDB, getUserFromStorage,
useEffect IIFE en AuthContext. Agregar fallback a email en ProfileSheet
setName() para usuarios cuya fila en DB ya tiene name="" de sesiones anteriores.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 19:06:30 -03:00
602957b6c9 fix(sprint-5/etapa-4b): timeout AbortController en sync de perfil al login
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
upsertUserOnLogin y syncProfileFromDB adquieren el processLock de Supabase para
leer/escribir la sesión. Si el servidor GoTrue está lento (token refresh), ese
lock puede quedar ocupado varios segundos bloqueando loads de biblioteca/workspace.

Agrega AbortController con timeout de 6s a las dos queries de auth sync en
AuthContext. Si el servidor no responde a tiempo, la señal de abort cancela
el fetch, postgrest-js lanza AbortError, el lock se libera, y el IIFE termina
silenciosamente. El profile save ya usa fetch nativo (no le afecta el lock).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 02:13:53 -03:00
496c227c88 fix(sprint-5/etapa-4d): mover queries DB fuera de onAuthStateChange — corta deadlock lockAcquired permanente
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
El callback de onAuthStateChange en GoTrueClient adquiere un lock interno (lockAcquired=true).
Hacer await supabase.from('users').select() dentro de ese callback genera un deadlock circular:
el select necesita getSession() → _acquireLock() → lockAcquired=true → espera al callback →
callback espera al select → deadlock permanente. Toda query posterior a Supabase cuelga.

Fix: el callback de onAuthStateChange pasa a ser síncrono y solo llama buildAuthUser() (sin
queries). El upsert y la lectura de company/name se mueven a un useEffect([user?.id]) en
AuthContext, que corre FUERA del lock de auth y solo se dispara al cambiar de usuario real
(distinto id), no en cada updateUser() local.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 01:28:26 -03:00
735294db06 fix(sprint-5/etapa-4b): prevenir loop en onAuthStateChange al guardar perfil
- SupabaseAuthService: solo leer company/name de DB en INITIAL_SESSION y SIGNED_IN;
  ignorar TOKEN_REFRESHED y USER_UPDATED para no sobreescribir ediciones locales
- ProfileSheet: useEffect con solo [open] como dep — inicializa el form al abrir
  el sheet, sin resetearlo en cada cambio del objeto user durante la edición

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 00:35:01 -03:00
6d14e64f33 feat(sprint-5/etapa-4): procesos por recurso + campo empresa en perfil
Feature A — Ver procesos asociados a un recurso:
- resource-repo.ts: getProcessCountsPerResource() (una query, N+1 evitado)
- resource-repo.ts: getProcessesForResource() (on-demand al expandir)
- ResourceCatalogPage: carga conteos en paralelo, columna "Procesos" con
  badge naranja clicable, fila expandida con links a /workspace/:id

Feature B — Campo empresa en perfil:
- 013_add_company_to_users.sql: ALTER TABLE users ADD COLUMN IF NOT EXISTS company text
- AuthUser: agrega company? opcional
- SupabaseAuthService: lee company y name de tabla users en onAuthStateChange
- AuthContext: agrega updateUser() para reflejar cambios sin recargar
- ProfileSheet.tsx: Sheet con nombre/empresa editables, email read-only
- AppHeader: muestra empresa en dropdown + item "Editar perfil"

528 tests Vitest verdes. Build limpio.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 19:56:13 -03:00
a2763ab755 Sprint 5. Etapa 1.
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
2026-06-19 15:31:03 -03:00
c738bc5489 Sprint 4 — Etapa 7B completada.
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
2026-06-19 00:20:27 -03:00
33b1d47229 fix: detectar OAuth callback para no cortar sesión en redirect 2026-06-03 00:19:14 -03:00
2955399ade Corrección 1 — Delete de proceso restaurado + 2026-05-29 18:45:48 -03:00
1bc80e190f fix: timeout 10s en AuthProvider — spinner no queda bloqueado si Supabase no responde
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:43:28 -03:00
180ba2abe7 fix: try-catch en onAuthStateChange — loading nunca queda bloqueado en error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:37:55 -03:00
78e776df6b feat(sprint-4/etapa-1): Supabase auth + Google OAuth + LoginPage + rutas protegidas
- Cliente Supabase singleton en src/lib/supabase.ts
- Interfaces AuthUser / AuthService en src/auth/types.ts
- SupabaseAuthService: signInWithGoogle, signOut, getCurrentUser, onAuthStateChange
  con upsert a tabla users (platform_admin para @inquality.com.py, guest resto)
- AuthProvider (React Context) wrappea toda la app; expone user, loading, signIn, signOut
- LoginPage /login: logo InQuality color, título, fade-in, botón Google naranja #F59845
- RootComponent del router guarda todas las rutas — sin sesión → /login, con sesión + /login → /
- Script SQL: supabase/migrations/001_create_users.sql (tabla users + RLS)
- AppHeader: <Link> → <a href="/"> para evitar dependencia de RouterContext en tests
- 561/561 tests verdes, build sin errores TS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:53:12 -03:00