feat(workspace): selector de área en GlobalSettingsPanel reemplaza campo libre "Cliente"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 21:06:39 -03:00
parent de00e3a902
commit e0b4607603

View File

@@ -11,6 +11,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { useProcessStore } from '@/store/process-store'
import { useAuth } from '@/auth/AuthContext'
import { formatPercent } from '@/lib/format'
import { supabaseAreaRepo } from '@/persistence/supabase/area-repo'
import type { Area } from '@/domain/types'
const CURRENCIES = [
{ code: 'USD', label: 'USD — Dólar estadounidense' },
@@ -28,7 +30,9 @@ export function GlobalSettingsPanel() {
const { user } = useAuth()
const isClientRole = user?.platformRole === 'client_editor' || user?.platformRole === 'client_viewer'
const [localName, setLocalName] = useState('')
const [localClient, setLocalClient] = useState('')
const [localAreaId, setLocalAreaId] = useState<string>('')
const [areas, setAreas] = useState<Area[]>([])
const [areasLoading, setAreasLoading] = useState(false)
const [localCurrency, setLocalCurrency] = useState('USD')
const [localOverhead, setLocalOverhead] = useState(20)
const [localFrequency, setLocalFrequency] = useState(1000)
@@ -39,7 +43,18 @@ export function GlobalSettingsPanel() {
useEffect(() => {
if (!currentProcess) return
setLocalName(currentProcess.name)
setLocalClient(currentProcess.clientName)
setLocalAreaId(currentProcess.areaId ?? '')
// Cargar áreas de la org del proceso
if (currentProcess.orgId) {
setAreasLoading(true)
supabaseAreaRepo.getByOrg(currentProcess.orgId)
.then(setAreas)
.catch(() => setAreas([]))
.finally(() => setAreasLoading(false))
} else {
setAreas([])
}
setLocalCurrency(currentProcess.currency)
setLocalOverhead(Math.round(currentProcess.overheadPercentage * 100))
setLocalFrequency(currentProcess.annualFrequency)
@@ -54,7 +69,7 @@ export function GlobalSettingsPanel() {
const clampedHorizon = Math.min(10, Math.max(1, localHorizon))
await updateProcess({
name: localName.trim() || 'Proceso sin nombre',
clientName: localClient.trim(),
areaId: localAreaId === '' ? null : localAreaId,
currency: localCurrency,
overheadPercentage: localOverhead / 100,
annualFrequency: Math.max(1, localFrequency),
@@ -82,19 +97,35 @@ export function GlobalSettingsPanel() {
/>
</div>
{/* Cliente */}
{/* Área */}
<div className="space-y-1.5">
<Label className="text-xs font-medium">Cliente</Label>
{isClientRole ? (
<p className="text-sm text-slate-600 h-8 flex items-center px-1">{localClient || '—'}</p>
<Label className="text-xs font-medium">Área</Label>
{areasLoading ? (
<div className="h-8 bg-slate-100 animate-pulse rounded-md" />
) : !currentProcess.orgId ? (
<p className="text-sm text-slate-400 h-8 flex items-center px-1 italic">Sin organización asignada</p>
) : isClientRole && user?.platformRole === 'client_viewer' ? (
<p className="text-sm text-slate-600 h-8 flex items-center px-1">{currentProcess.areaName || '—'}</p>
) : (
<Input
id="client-name"
value={localClient}
onChange={(e) => { setLocalClient(e.target.value); markDirty() }}
placeholder="ej. Empresa ABC"
className="h-8 text-sm"
/>
<Select
value={localAreaId}
onValueChange={(v) => { setLocalAreaId(v); markDirty() }}
>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="Sin área" />
</SelectTrigger>
<SelectContent>
<SelectItem value="" className="text-xs text-slate-400 italic">Sin área</SelectItem>
{areas.map((a) => (
<SelectItem key={a.id} value={a.id} className="text-xs">{a.name}</SelectItem>
))}
{areas.length === 0 && (
<div className="px-2 py-1.5 text-xs text-slate-400">
No hay áreas en esta organización
</div>
)}
</SelectContent>
</Select>
)}
</div>