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:
@@ -11,6 +11,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
|||||||
import { useProcessStore } from '@/store/process-store'
|
import { useProcessStore } from '@/store/process-store'
|
||||||
import { useAuth } from '@/auth/AuthContext'
|
import { useAuth } from '@/auth/AuthContext'
|
||||||
import { formatPercent } from '@/lib/format'
|
import { formatPercent } from '@/lib/format'
|
||||||
|
import { supabaseAreaRepo } from '@/persistence/supabase/area-repo'
|
||||||
|
import type { Area } from '@/domain/types'
|
||||||
|
|
||||||
const CURRENCIES = [
|
const CURRENCIES = [
|
||||||
{ code: 'USD', label: 'USD — Dólar estadounidense' },
|
{ code: 'USD', label: 'USD — Dólar estadounidense' },
|
||||||
@@ -28,7 +30,9 @@ export function GlobalSettingsPanel() {
|
|||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
const isClientRole = user?.platformRole === 'client_editor' || user?.platformRole === 'client_viewer'
|
const isClientRole = user?.platformRole === 'client_editor' || user?.platformRole === 'client_viewer'
|
||||||
const [localName, setLocalName] = useState('')
|
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 [localCurrency, setLocalCurrency] = useState('USD')
|
||||||
const [localOverhead, setLocalOverhead] = useState(20)
|
const [localOverhead, setLocalOverhead] = useState(20)
|
||||||
const [localFrequency, setLocalFrequency] = useState(1000)
|
const [localFrequency, setLocalFrequency] = useState(1000)
|
||||||
@@ -39,7 +43,18 @@ export function GlobalSettingsPanel() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentProcess) return
|
if (!currentProcess) return
|
||||||
setLocalName(currentProcess.name)
|
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)
|
setLocalCurrency(currentProcess.currency)
|
||||||
setLocalOverhead(Math.round(currentProcess.overheadPercentage * 100))
|
setLocalOverhead(Math.round(currentProcess.overheadPercentage * 100))
|
||||||
setLocalFrequency(currentProcess.annualFrequency)
|
setLocalFrequency(currentProcess.annualFrequency)
|
||||||
@@ -54,7 +69,7 @@ export function GlobalSettingsPanel() {
|
|||||||
const clampedHorizon = Math.min(10, Math.max(1, localHorizon))
|
const clampedHorizon = Math.min(10, Math.max(1, localHorizon))
|
||||||
await updateProcess({
|
await updateProcess({
|
||||||
name: localName.trim() || 'Proceso sin nombre',
|
name: localName.trim() || 'Proceso sin nombre',
|
||||||
clientName: localClient.trim(),
|
areaId: localAreaId === '' ? null : localAreaId,
|
||||||
currency: localCurrency,
|
currency: localCurrency,
|
||||||
overheadPercentage: localOverhead / 100,
|
overheadPercentage: localOverhead / 100,
|
||||||
annualFrequency: Math.max(1, localFrequency),
|
annualFrequency: Math.max(1, localFrequency),
|
||||||
@@ -82,19 +97,35 @@ export function GlobalSettingsPanel() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Cliente */}
|
{/* Área */}
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-xs font-medium">Cliente</Label>
|
<Label className="text-xs font-medium">Área</Label>
|
||||||
{isClientRole ? (
|
{areasLoading ? (
|
||||||
<p className="text-sm text-slate-600 h-8 flex items-center px-1">{localClient || '—'}</p>
|
<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
|
<Select
|
||||||
id="client-name"
|
value={localAreaId}
|
||||||
value={localClient}
|
onValueChange={(v) => { setLocalAreaId(v); markDirty() }}
|
||||||
onChange={(e) => { setLocalClient(e.target.value); markDirty() }}
|
>
|
||||||
placeholder="ej. Empresa ABC"
|
<SelectTrigger className="h-8 text-xs">
|
||||||
className="h-8 text-sm"
|
<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>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user