Se establecieron limites en la cantidad de caracteres y de digitos de los inputs de los wizards #84

Merged
Guillermo.Arrieta merged 1 commits from hotfix/limite-de-caracteres-y-de-numeros into main 2026-02-06 18:26:56 +00:00
6 changed files with 64 additions and 39 deletions
Showing only changes of commit 6fc1677654 - Show all commits

View File

@@ -27,14 +27,25 @@ export function PasoBasicosForm({
const [creditosInput, setCreditosInput] = useState<string>(() => { const [creditosInput, setCreditosInput] = useState<string>(() => {
const c = Number(wizard.datosBasicos.creditos ?? 0) const c = Number(wizard.datosBasicos.creditos ?? 0)
return c > 0 ? c.toFixed(2) : '' let newC = c
console.log('antes', newC)
if (Number.isFinite(c) && c > 999) {
newC = 999
}
console.log('desp', newC)
return newC > 0 ? newC.toFixed(2) : ''
}) })
const [creditosFocused, setCreditosFocused] = useState(false) const [creditosFocused, setCreditosFocused] = useState(false)
useEffect(() => { useEffect(() => {
if (creditosFocused) return if (creditosFocused) return
const c = Number(wizard.datosBasicos.creditos ?? 0) const c = Number(wizard.datosBasicos.creditos ?? 0)
setCreditosInput(c > 0 ? c.toFixed(2) : '') let newC = c
if (Number.isFinite(c) && c > 999) {
newC = 999
}
setCreditosInput(newC > 0 ? newC.toFixed(2) : '')
}, [wizard.datosBasicos.creditos, creditosFocused]) }, [wizard.datosBasicos.creditos, creditosFocused])
return ( return (
@@ -44,6 +55,7 @@ export function PasoBasicosForm({
<Input <Input
id="nombre" id="nombre"
placeholder="Ej. Matemáticas Discretas" placeholder="Ej. Matemáticas Discretas"
maxLength={200}
value={wizard.datosBasicos.nombre} value={wizard.datosBasicos.nombre}
onChange={(e) => onChange={(e) =>
onChange( onChange(
@@ -67,6 +79,7 @@ export function PasoBasicosForm({
<Input <Input
id="codigo" id="codigo"
placeholder="Ej. MAT-101" placeholder="Ej. MAT-101"
maxLength={200}
value={wizard.datosBasicos.codigo || ''} value={wizard.datosBasicos.codigo || ''}
onChange={(e) => onChange={(e) =>
onChange( onChange(
@@ -123,6 +136,7 @@ export function PasoBasicosForm({
id="creditos" id="creditos"
type="text" type="text"
inputMode="decimal" inputMode="decimal"
maxLength={6}
pattern="^\\d*(?:[.,]\\d{0,2})?$" pattern="^\\d*(?:[.,]\\d{0,2})?$"
value={creditosInput} value={creditosInput}
onKeyDown={(e) => { onKeyDown={(e) => {
@@ -191,6 +205,42 @@ export function PasoBasicosForm({
/> />
</div> </div>
<div className="grid gap-1">
<Label htmlFor="estructura">Estructura de la asignatura</Label>
<Select
value={wizard.datosBasicos.estructuraId as string}
onValueChange={(val) =>
onChange(
(w): NewSubjectWizardState => ({
...w,
datosBasicos: { ...w.datosBasicos, estructuraId: val },
}),
)
}
>
<SelectTrigger
id="estructura"
className="w-full min-w-0 [&>span]:block! [&>span]:truncate!"
>
<SelectValue placeholder="Selecciona plantilla..." />
</SelectTrigger>
<SelectContent>
{estructuras?.map(
(
e: Database['public']['Tables']['estructuras_asignatura']['Row'],
) => (
<SelectItem key={e.id} value={e.id}>
{e.nombre}
</SelectItem>
),
)}
</SelectContent>
</Select>
<p className="text-muted-foreground text-xs">
Define los campos requeridos (ej. Objetivos, Temario, Evaluación).
</p>
</div>
<div className="grid gap-1"> <div className="grid gap-1">
<Label htmlFor="horasAcademicas"> <Label htmlFor="horasAcademicas">
Horas Académicas Horas Académicas
@@ -202,6 +252,7 @@ export function PasoBasicosForm({
id="horasAcademicas" id="horasAcademicas"
type="number" type="number"
min={1} min={1}
max={999}
step={1} step={1}
inputMode="numeric" inputMode="numeric"
pattern="[0-9]*" pattern="[0-9]*"
@@ -246,6 +297,7 @@ export function PasoBasicosForm({
id="horasIndependientes" id="horasIndependientes"
type="number" type="number"
min={1} min={1}
max={999}
step={1} step={1}
inputMode="numeric" inputMode="numeric"
pattern="[0-9]*" pattern="[0-9]*"
@@ -278,42 +330,6 @@ export function PasoBasicosForm({
placeholder="Ej. 24" placeholder="Ej. 24"
/> />
</div> </div>
<div className="grid gap-1">
<Label htmlFor="estructura">Estructura de la asignatura</Label>
<Select
value={wizard.datosBasicos.estructuraId as string}
onValueChange={(val) =>
onChange(
(w): NewSubjectWizardState => ({
...w,
datosBasicos: { ...w.datosBasicos, estructuraId: val },
}),
)
}
>
<SelectTrigger
id="estructura"
className="w-full min-w-0 [&>span]:block! [&>span]:truncate!"
>
<SelectValue placeholder="Selecciona plantilla..." />
</SelectTrigger>
<SelectContent>
{estructuras?.map(
(
e: Database['public']['Tables']['estructuras_asignatura']['Row'],
) => (
<SelectItem key={e.id} value={e.id}>
{e.nombre}
</SelectItem>
),
)}
</SelectContent>
</Select>
<p className="text-muted-foreground text-xs">
Define los campos requeridos (ej. Objetivos, Temario, Evaluación).
</p>
</div>
</div> </div>
) )
} }

View File

@@ -56,6 +56,7 @@ export function PasoDetallesPanel({
<Label>Descripción del enfoque académico</Label> <Label>Descripción del enfoque académico</Label>
<Textarea <Textarea
placeholder="Describe el enfoque, alcance y público objetivo. Ej.: Teórica-práctica enfocada en patrones de diseño, con proyectos semanales." placeholder="Describe el enfoque, alcance y público objetivo. Ej.: Teórica-práctica enfocada en patrones de diseño, con proyectos semanales."
maxLength={7000}
value={wizard.iaConfig?.descripcionEnfoqueAcademico} value={wizard.iaConfig?.descripcionEnfoqueAcademico}
onChange={(e) => onChange={(e) =>
onChange( onChange(
@@ -80,6 +81,7 @@ export function PasoDetallesPanel({
</Label> </Label>
<Textarea <Textarea
placeholder="Opcional: restricciones y preferencias. Ej.: incluye bibliografía en español, evita contenido avanzado, prioriza evaluación por proyectos." placeholder="Opcional: restricciones y preferencias. Ej.: incluye bibliografía en español, evita contenido avanzado, prioriza evaluación por proyectos."
maxLength={7000}
value={wizard.iaConfig?.instruccionesAdicionalesIA} value={wizard.iaConfig?.instruccionesAdicionalesIA}
onChange={(e) => onChange={(e) =>
onChange( onChange(

View File

@@ -50,6 +50,7 @@ export function PasoBasicosForm({
id="nombrePlan" id="nombrePlan"
placeholder="Ej. Ingeniería en Sistemas (2026)" placeholder="Ej. Ingeniería en Sistemas (2026)"
value={wizard.datosBasicos.nombrePlan} value={wizard.datosBasicos.nombrePlan}
maxLength={200}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChange( onChange(
(w): NewPlanWizardState => ({ (w): NewPlanWizardState => ({
@@ -228,6 +229,7 @@ export function PasoBasicosForm({
id="numCiclos" id="numCiclos"
type="number" type="number"
min={1} min={1}
max={99}
step={1} step={1}
inputMode="numeric" inputMode="numeric"
pattern="[0-9]*" pattern="[0-9]*"

View File

@@ -49,6 +49,7 @@ export function PasoDetallesPanel({
id="desc" id="desc"
className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none" className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
placeholder="Describe el enfoque del programa…" placeholder="Describe el enfoque del programa…"
maxLength={7000}
value={wizard.iaConfig?.descripcionEnfoqueAcademico || ''} value={wizard.iaConfig?.descripcionEnfoqueAcademico || ''}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
onChange((w) => ({ onChange((w) => ({
@@ -73,6 +74,7 @@ export function PasoDetallesPanel({
id="notas" id="notas"
className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none" className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
placeholder="Lineamientos institucionales, restricciones, etc." placeholder="Lineamientos institucionales, restricciones, etc."
maxLength={7000}
value={wizard.iaConfig?.instruccionesAdicionalesIA || ''} value={wizard.iaConfig?.instruccionesAdicionalesIA || ''}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
onChange((w) => ({ onChange((w) => ({

View File

@@ -93,6 +93,7 @@ export type Database = {
asignatura_hash: string | null asignatura_hash: string | null
codigo: string | null codigo: string | null
contenido_tematico: Json contenido_tematico: Json
conversation_id: string | null
creado_en: string creado_en: string
creado_por: string | null creado_por: string | null
creditos: number creditos: number
@@ -116,6 +117,7 @@ export type Database = {
asignatura_hash?: string | null asignatura_hash?: string | null
codigo?: string | null codigo?: string | null
contenido_tematico?: Json contenido_tematico?: Json
conversation_id?: string | null
creado_en?: string creado_en?: string
creado_por?: string | null creado_por?: string | null
creditos: number creditos: number
@@ -139,6 +141,7 @@ export type Database = {
asignatura_hash?: string | null asignatura_hash?: string | null
codigo?: string | null codigo?: string | null
contenido_tematico?: Json contenido_tematico?: Json
conversation_id?: string | null
creado_en?: string creado_en?: string
creado_por?: string | null creado_por?: string | null
creditos?: number creditos?: number

View File

@@ -1 +1 @@
v2.67.1 v2.75.0