style: rediseno de layout profesional en las 7 apps

Headers sticky con marca y acciones, contenedores max-w-[1280px],
grids de contenido con rails laterales sticky (cotizador, mi-dia,
detalle de cobranza), stepper vertical en el wizard de alta, toolbar+
tabla unificadas en cobranza, tabs como segmented control en
dashboards, chat con barra de entrada fija y preguntas sugeridas,
landing con navbar + hero + grid de modulos + footer.
This commit is contained in:
2026-09-03 04:28:56 +00:00
parent 599dce2629
commit d59c8c0d7e
39 changed files with 1622 additions and 1235 deletions

View File

@@ -7,6 +7,13 @@ import type { Mensaje } from '../types'
let contadorLocal = 0
const idLocal = () => `local-${++contadorLocal}`
const PREGUNTAS_SUGERIDAS = [
'¿Qué incluye la propuesta del cotizador DIAGONAL?',
'¿Cuáles son los pasos del proceso de venta?',
'¿Qué políticas de Frasa debo conocer?',
'¿Qué modelos hay en el catálogo DIAGONAL?',
]
export default function ChatPage() {
const [sessionId, setSessionId] = useState<string | null>(null)
const [mensajes, setMensajes] = useState<Mensaje[]>([])
@@ -70,8 +77,8 @@ export default function ChatPage() {
return (
<div className="flex min-h-screen flex-col bg-[#F8FAFC] text-[#111827]">
<header className="border-b border-[#E5E7EB] bg-white">
<div className="mx-auto flex w-full max-w-3xl items-center justify-between px-4 py-4">
<header className="sticky top-0 z-10 border-b border-[#E5E7EB] bg-white/95 backdrop-blur">
<div className="mx-auto flex h-14 w-full max-w-3xl items-center justify-between px-4 sm:px-6">
<span className="text-sm tracking-wide">
<span className="font-bold">FRASA</span>
<span className="text-[#F97316]"> · </span>
@@ -80,14 +87,14 @@ export default function ChatPage() {
<button
type="button"
onClick={nuevaConversacion}
className="rounded-lg border border-[#D1D5DB] bg-white px-5 py-2.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
>
Nueva conversación
</button>
</div>
</header>
<main className="mx-auto flex w-full max-w-3xl flex-1 flex-col px-4 py-8">
<main className="mx-auto flex w-full max-w-3xl flex-1 flex-col px-4 py-8 sm:px-6">
{sinConexion && (
<p className="mb-6 rounded-lg bg-amber-50 px-4 py-3 text-xs font-medium text-amber-700">
Sin conexión al API del asistente. Revisa que el servicio esté disponible e inténtalo de
@@ -101,60 +108,76 @@ export default function ChatPage() {
)}
{mensajes.length === 0 && !escribiendo ? (
<div className="flex flex-1 flex-col items-center justify-center gap-4 text-center">
<p className="text-xs font-semibold uppercase tracking-wider text-[#64748B]">
Asistente interno
</p>
<p className="max-w-md text-2xl font-light text-[#111827]">
Pregunta sobre el catálogo DIAGONAL, las propuestas del cotizador, el proceso de venta
o las políticas de Frasa.
</p>
<div className="flex flex-1 flex-col items-center justify-center">
<div className="w-full max-w-lg rounded-xl border border-[#E5E7EB] bg-white p-6 text-center shadow-sm">
<p className="text-xs font-semibold uppercase tracking-wider text-[#64748B]">
Asistente interno
</p>
<p className="mt-3 text-xl font-light leading-relaxed text-[#111827]">
Pregunta sobre el catálogo DIAGONAL, las propuestas del cotizador, el proceso de
venta o las políticas de Frasa.
</p>
<div className="mt-6 grid gap-2 sm:grid-cols-2">
{PREGUNTAS_SUGERIDAS.map((pregunta) => (
<button
key={pregunta}
type="button"
onClick={() => setEntrada(pregunta)}
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-2.5 text-left text-xs font-medium text-[#374151] transition-colors hover:border-accent hover:text-accent"
>
{pregunta}
</button>
))}
</div>
</div>
</div>
) : (
<div className="flex flex-1 flex-col gap-6">
{mensajes.map((m) => (
<Burbuja key={m.id} mensaje={m} />
))}
{escribiendo && (
<div className="flex justify-start">
<p className="rounded-full bg-white px-4 py-2 text-xs font-medium text-[#64748B] shadow-sm">
Escribiendo…
</p>
</div>
)}
<div ref={finalRef} />
</div>
)}
</main>
<footer className="border-t border-[#E5E7EB] bg-white">
<form
className="mx-auto flex w-full max-w-3xl items-stretch gap-4 px-4 py-4"
onSubmit={(e) => {
e.preventDefault()
void enviar()
}}
>
<label htmlFor="entrada-chat" className="sr-only">
Escribe tu mensaje
</label>
<input
id="entrada-chat"
type="text"
value={entrada}
onChange={(e) => setEntrada(e.target.value)}
placeholder="Escribe tu pregunta…"
autoComplete="off"
className="flex-1 rounded-lg border border-[#D1D5DB] bg-white px-4 py-3 text-sm placeholder:text-[#94A3B8] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20"
/>
<button
type="submit"
disabled={escribiendo || entrada.trim().length === 0}
className="rounded-lg bg-accent px-6 py-3 text-sm font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-40"
<footer className="sticky bottom-0 border-t border-[#E5E7EB] bg-white">
<div className="relative mx-auto w-full max-w-3xl px-4 sm:px-6">
{escribiendo && (
<div className="pointer-events-none absolute -top-11 left-4 sm:left-6">
<p className="rounded-full border border-[#E5E7EB] bg-white px-4 py-2 text-xs font-medium text-[#64748B] shadow-md">
Escribiendo…
</p>
</div>
)}
<form
className="flex items-stretch gap-3 py-4"
onSubmit={(e) => {
e.preventDefault()
void enviar()
}}
>
Enviar
</button>
</form>
<label htmlFor="entrada-chat" className="sr-only">
Escribe tu mensaje
</label>
<input
id="entrada-chat"
type="text"
value={entrada}
onChange={(e) => setEntrada(e.target.value)}
placeholder="Escribe tu pregunta…"
autoComplete="off"
className="flex-1 rounded-lg border border-[#D1D5DB] bg-white px-4 py-3 text-sm placeholder:text-[#94A3B8] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20"
/>
<button
type="submit"
disabled={escribiendo || entrada.trim().length === 0}
className="rounded-lg bg-accent px-6 py-3 text-sm font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-40"
>
Enviar
</button>
</form>
</div>
</footer>
</div>
)