Files
inq-roi-simulador-web/src/components/ProfileSheet.tsx
Marcos Benítez 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

92 lines
2.8 KiB
TypeScript

import { useEffect, useState } from 'react'
import { Check } from 'lucide-react'
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { supabase } from '@/lib/supabase'
import { useAuth } from '@/auth/AuthContext'
interface ProfileSheetProps {
open: boolean
onOpenChange: (open: boolean) => void
}
export function ProfileSheet({ open, onOpenChange }: ProfileSheetProps) {
const { user, updateUser } = useAuth()
const [name, setName] = useState('')
const [company, setCompany] = useState('')
const [saving, setSaving] = useState(false)
useEffect(() => {
if (open && user) {
setName(user.name)
setCompany(user.company ?? '')
}
}, [open, user])
async function handleSave() {
if (!user || !name.trim()) return
setSaving(true)
try {
const { error } = await supabase
.from('users')
.update({ name: name.trim(), company: company.trim() || null })
.eq('id', user.id)
if (error) throw error
updateUser({ name: name.trim(), company: company.trim() || undefined })
onOpenChange(false)
} catch (err) {
console.error('Error al guardar perfil:', err)
} finally {
setSaving(false)
}
}
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent>
<SheetHeader>
<SheetTitle>Editar perfil</SheetTitle>
</SheetHeader>
<div className="space-y-4 mt-6">
<div className="space-y-1.5">
<Label className="text-xs">Nombre</Label>
<Input
autoFocus
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Tu nombre"
/>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Empresa</Label>
<Input
value={company}
onChange={(e) => setCompany(e.target.value)}
placeholder="InQuality"
/>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Email</Label>
<Input value={user?.email ?? ''} readOnly className="bg-muted text-muted-foreground cursor-not-allowed" />
</div>
</div>
<SheetFooter className="mt-6 flex gap-2">
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={saving}>
Cancelar
</Button>
<Button onClick={handleSave} disabled={!name.trim() || saving} className="gap-1.5">
<Check className="h-4 w-4" />
Guardar
</Button>
</SheetFooter>
</SheetContent>
</Sheet>
)
}