Antes de la última revisión de etapa 4. Sprint 1. Previo al ajuste de look n feel de app, reportes, nombre y colores.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { PlusCircle, Trash2, Info } from 'lucide-react'
|
||||
import { PlusCircle, Trash2, Info, AlertTriangle } from 'lucide-react'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -7,6 +7,8 @@ import { Slider } from '@/components/ui/slider'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { useProcessStore } from '@/store/process-store'
|
||||
import { formatCurrency } from '@/lib/format'
|
||||
import type { Activity } from '@/domain/types'
|
||||
@@ -226,6 +228,101 @@ export function ActivityPanel({ selectedElementId }: ActivityPanelProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ── Sección: Automatización ──────────────────────────────────── */}
|
||||
<div>
|
||||
<Separator className="mb-4" />
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Automatización</p>
|
||||
|
||||
{/* Toggle */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="automatable-toggle" className="text-xs font-medium cursor-pointer">
|
||||
¿Es automatizable?
|
||||
</Label>
|
||||
<Switch
|
||||
id="automatable-toggle"
|
||||
checked={localActivity.automatable}
|
||||
onCheckedChange={(v) => handleChange('automatable', v)}
|
||||
aria-label="Marcar actividad como automatizable"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Campos — aparecen con transición suave cuando toggle=ON */}
|
||||
<div className={`space-y-3 overflow-hidden transition-all duration-200 ${localActivity.automatable ? 'max-h-80 opacity-100' : 'max-h-0 opacity-0'}`}>
|
||||
|
||||
{/* Costo automatizado */}
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Label htmlFor="automated-cost" className="text-xs font-medium">
|
||||
Costo automatizado
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Info className="h-3 w-3 text-slate-400 cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-56 text-xs">
|
||||
Costo recurrente por ejecución automatizada. No incluye la inversión inicial del proyecto.
|
||||
Ver METHODOLOGY_AUTOMATED_COST.md para la guía de cálculo.
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input
|
||||
id="automated-cost"
|
||||
type="number"
|
||||
min={0}
|
||||
step={1}
|
||||
value={localActivity.automatedCostFixed === 0 ? '' : localActivity.automatedCostFixed}
|
||||
onChange={(e) => handleChange('automatedCostFixed', Math.max(0, parseFloat(e.target.value) || 0))}
|
||||
className="font-mono h-8 text-sm"
|
||||
placeholder="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Tiempo automatizado */}
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="automated-time" className="text-xs font-medium">
|
||||
Tiempo automatizado (min)
|
||||
</Label>
|
||||
<Input
|
||||
id="automated-time"
|
||||
type="number"
|
||||
min={0}
|
||||
step={1}
|
||||
value={localActivity.automatedTimeMinutes === 0 ? '' : localActivity.automatedTimeMinutes}
|
||||
onChange={(e) => handleChange('automatedTimeMinutes', Math.max(0, parseFloat(e.target.value) || 0))}
|
||||
className="font-mono h-8 text-sm"
|
||||
placeholder="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Helper ámbar — siempre en el DOM para que la transición funcione
|
||||
al tipear un valor (no desaparece instantáneo sino con fade).
|
||||
La condición controla opacity + max-h, no mount/unmount. */}
|
||||
{(() => {
|
||||
const showHelper = localActivity.automatable
|
||||
&& localActivity.automatedCostFixed === 0
|
||||
&& localActivity.automatedTimeMinutes === 0
|
||||
return (
|
||||
<div
|
||||
aria-hidden={!showHelper}
|
||||
className={`overflow-hidden transition-all duration-150 ease-out ${
|
||||
showHelper ? 'opacity-100 max-h-20' : 'opacity-0 max-h-0'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-2 rounded-lg bg-amber-50 border border-amber-200 px-3 py-2">
|
||||
<AlertTriangle className="h-3.5 w-3.5 text-amber-600 shrink-0 mt-0.5" />
|
||||
<p className="text-xs text-amber-700 leading-snug">
|
||||
Esta actividad aparecerá en "Transparencia metodológica" del reporte hasta que cargues valores.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Guardar */}
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user