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>
This commit is contained in:
@@ -7,6 +7,7 @@ interface AuthContextValue {
|
||||
loading: boolean
|
||||
signIn: () => Promise<void>
|
||||
signOut: () => Promise<void>
|
||||
updateUser: (updates: Partial<Pick<AuthUser, 'name' | 'company'>>) => void
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextValue | null>(null)
|
||||
@@ -78,8 +79,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
setUser(null)
|
||||
}, [])
|
||||
|
||||
const updateUser = useCallback((updates: Partial<Pick<AuthUser, 'name' | 'company'>>) => {
|
||||
setUser((prev) => prev ? { ...prev, ...updates } : prev)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, loading, signIn, signOut }}>
|
||||
<AuthContext.Provider value={{ user, loading, signIn, signOut, updateUser }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
)
|
||||
|
||||
@@ -60,8 +60,19 @@ export class SupabaseAuthService implements AuthService {
|
||||
if (upsertError) console.error('Error al crear usuario en DB:', upsertError)
|
||||
}
|
||||
|
||||
// buildAuthUser es sincrónico — sin DB query, usa metadatos de la sesión
|
||||
const user = this.buildAuthUser(session.user)
|
||||
// Leer company y name editado desde la tabla users (pueden diferir del user_metadata de Google)
|
||||
const { data: userRow } = await supabase
|
||||
.from('users')
|
||||
.select('company, name')
|
||||
.eq('id', session.user.id)
|
||||
.maybeSingle()
|
||||
|
||||
const base = this.buildAuthUser(session.user)
|
||||
const user: AuthUser = {
|
||||
...base,
|
||||
company: (userRow?.company as string | null) ?? undefined,
|
||||
name: (userRow?.name as string | null) ?? base.name,
|
||||
}
|
||||
callback(user)
|
||||
} catch (err) {
|
||||
console.error('Error en onAuthStateChange:', err)
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface AuthUser {
|
||||
name: string
|
||||
avatarUrl?: string
|
||||
platformRole: 'platform_admin' | 'member' | 'guest'
|
||||
company?: string
|
||||
}
|
||||
|
||||
export interface AuthService {
|
||||
|
||||
Reference in New Issue
Block a user