feat(ui): actualizar la estructura de RdxPageContent en varias páginas y componentes para mejorar la jerarquía y la semántica
This commit is contained in:
parent
450cc8d7bd
commit
b6aa20e52b
@ -82,7 +82,7 @@ RdxPageContent
|
||||
→ composición de los hijos principales
|
||||
```
|
||||
|
||||
Regla: Las Pages no deben reconstruir estas responsabilidades con wrappers HTML locales.
|
||||
Regla: Las Pages no deben reconstruir estas responsabilidades con wrappers HTML locales. En Create/Update, la composición canónica es RdxPageFrame → RdxPageContainer → RdxPageContent: los errores inline y el editor son hijos directos de RdxPageContent; los dialogs son hermanos del frame; RdxPanel se reserva para secciones semánticas reales.
|
||||
|
||||
## 6. Identity y sesión
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@ El controller de página concentra URL, filtros, consulta, estados y navegación
|
||||
|
||||
## 2. Create / Update
|
||||
|
||||
Estructura canónica: providers → RdxPageFrame (header/content/footer) → un único RdxPageContainer → un único RdxPageContent; los dialogs son hermanos del frame.
|
||||
|
||||
```tsx
|
||||
<RdxPageFrame
|
||||
header={<RdxEditorHeader />}
|
||||
@ -53,6 +55,7 @@ Los errores inline no definen su propio spacing estructural. Participan del spac
|
||||
Footer y aside son opcionales. `content` es adecuado para formularios focalizados; `full` para editores documentales amplios. Create y Update deben compartir geometría cuando solo cambian defaults, submit o navegación.
|
||||
|
||||
Loading y error bloqueante usan también `RdxPageFrame` y `RdxPageContainer`; no reconstruyen el viewport.
|
||||
El error bloqueante conserva la misma jerarquía: RdxPageFrame → RdxPageContainer → RdxPageContent → PageErrorState.
|
||||
|
||||
## 3. Detail
|
||||
|
||||
|
||||
@ -108,6 +108,7 @@ Agrupa una sección con título, descripción, icono, acciones y contenido:
|
||||
|
||||
- `variant="plain"`: sección plana con divisor; valor predeterminado.
|
||||
- `variant="card"`: superficie independiente.
|
||||
RdxPanel no sustituye un div estructural: solo representa una sección con identidad semántica, como fiscalidad, dirección o preferencias.
|
||||
|
||||
### `RdxFormGrid`
|
||||
|
||||
@ -157,7 +158,7 @@ Los avisos, errores inline, secciones y contenido funcional deben ser hijos dire
|
||||
<Editor />
|
||||
</RdxPageContent>
|
||||
```
|
||||
No deben introducirse wrappers adicionales únicamente para controlar gap, ancho, padding o centrado.
|
||||
No deben introducirse wrappers adicionales únicamente para controlar gap, ancho, padding o centrado. No se anidan RdxPageContainer ni RdxPageContent salvo razón arquitectónica explícita. Los errores inline participan como hijos directos del spacing estándar de RdxPageContent; no crean su propio layout.
|
||||
|
||||
## 8. Responsive y accesibilidad
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ Se adoptan de Customer:
|
||||
|
||||
- manifest y rutas lazy por módulo;
|
||||
- páginas de listado con `RdxPageContainer`, `RdxPageHeader`, búsqueda con debounce y `DataTable`;
|
||||
- editores fullscreen con `RdxEditorPageLayout`, header persistente, protección de cambios sin guardar y secciones Rdx;
|
||||
- editores fullscreen con `RdxPageFrame`, header persistente, protección de cambios sin guardar y secciones Rdx;
|
||||
- `PageErrorState`, skeletons, alertas y toasts del sistema;
|
||||
- React Hook Form con validación Zod;
|
||||
- queries y mutations encapsuladas en hooks y adapters de transporte.
|
||||
@ -119,9 +119,9 @@ Todos los textos visibles pertenecen al namespace `Suppliers`. Se mantienen recu
|
||||
## 17. Componentes reutilizados
|
||||
|
||||
- `RdxPageContainer`, `RdxPageContent`, `RdxPageHeader`, `RdxPageActions`;
|
||||
- `RdxEditorPageLayout`, `RdxPanel`, `RdxFormGrid`;
|
||||
- `RdxPageFrame`, `RdxPanel`, `RdxFormGrid`;
|
||||
- `DataTable`, `SkeletonDataTable`, `DataTableColumnHeader`, `RdxRowActions`;
|
||||
- `TextField`, `SelectField`, `PageFormHeader`, `FormActionsBar`;
|
||||
- `TextField`, `SelectField`, `RdxEditorHeader`, `FormActionsBar`;
|
||||
- `SimpleSearchInput`, `PageErrorState`, `ErrorAlert`;
|
||||
- `UnsavedChangesProvider` y `useReturnToNavigation`.
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ export const ProformaCreatePage = () => {
|
||||
}
|
||||
>
|
||||
<RdxPageContainer width="content">
|
||||
<RdxPageContent spacing="default">
|
||||
<RdxPageContent>
|
||||
{createCtrl.isCreateError && (
|
||||
<ErrorAlert
|
||||
message={
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
import { ErrorAlert } from "@erp/core/components";
|
||||
import { useHookForm } from "@erp/core/hooks";
|
||||
import {
|
||||
RdxEditorHeader,
|
||||
RdxPageContainer,
|
||||
RdxPageContent,
|
||||
RdxPageFrame,
|
||||
RdxPanel,
|
||||
} from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Input,
|
||||
Label,
|
||||
Textarea,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { Button, Input, Label, Textarea } from "@repo/shadcn-ui/components";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
@ -89,6 +82,7 @@ export const RecurringProformaCreatePage = () => {
|
||||
>
|
||||
<RdxPageContainer width="content">
|
||||
<RdxPageContent>
|
||||
{submitError ? <ErrorAlert message={submitError} /> : null}
|
||||
<form
|
||||
className="space-y-6"
|
||||
id={RECURRING_PROFORMA_CREATE_FORM_ID}
|
||||
@ -98,19 +92,8 @@ export const RecurringProformaCreatePage = () => {
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("recurring_proformas.create.description")}
|
||||
</p>
|
||||
{submitError ? (
|
||||
<p
|
||||
className="rounded-md border border-destructive/30 p-3 text-sm text-destructive"
|
||||
role="alert"
|
||||
>
|
||||
{submitError}
|
||||
</p>
|
||||
) : null}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("recurring_proformas.create.form_title")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-5">
|
||||
<RdxPanel title={t("recurring_proformas.create.form_title")}>
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="recurring-proforma-name">
|
||||
{t("recurring_proformas.create.name")}
|
||||
@ -136,8 +119,8 @@ export const RecurringProformaCreatePage = () => {
|
||||
{...form.register("description")}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</RdxPanel>
|
||||
</form>
|
||||
</RdxPageContent>
|
||||
</RdxPageContainer>
|
||||
|
||||
@ -47,7 +47,7 @@ export const CustomerCreatePage = () => {
|
||||
}
|
||||
>
|
||||
<RdxPageContainer width="content">
|
||||
<RdxPageContent spacing="default">
|
||||
<RdxPageContent>
|
||||
{createCtrl.isCreateError ? (
|
||||
<ErrorAlert
|
||||
message={(createCtrl.createError as Error)?.message ?? t("create.errors.message")}
|
||||
|
||||
@ -40,21 +40,17 @@ export const SupplierCreatePage = () => {
|
||||
>
|
||||
<RdxPageContainer width="content">
|
||||
<RdxPageContent>
|
||||
<div className="rounded-2xl border border-border/60 bg-background p-4 shadow-xs md:p-6">
|
||||
<div className="flex min-w-0 flex-col gap-6">
|
||||
{controller.mutation.isError ? (
|
||||
<ErrorAlert
|
||||
message={controller.mutation.error.message || t("create.error")}
|
||||
title={t("create.error")}
|
||||
/>
|
||||
) : null}
|
||||
<SupplierEditorForm
|
||||
formId={controller.formId}
|
||||
isSubmitting={controller.mutation.isPending}
|
||||
onSubmit={controller.onSubmit}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{controller.mutation.isError ? (
|
||||
<ErrorAlert
|
||||
message={controller.mutation.error.message || t("create.error")}
|
||||
title={t("create.error")}
|
||||
/>
|
||||
) : null}
|
||||
<SupplierEditorForm
|
||||
formId={controller.formId}
|
||||
isSubmitting={controller.mutation.isPending}
|
||||
onSubmit={controller.onSubmit}
|
||||
/>
|
||||
</RdxPageContent>
|
||||
</RdxPageContainer>
|
||||
</RdxPageFrame>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { RdxPageContainer, RdxPageFrame } from "@repo/rdx-ui/components";
|
||||
import { RdxPageContainer, RdxPageContent, RdxPageFrame } from "@repo/rdx-ui/components";
|
||||
|
||||
import { useTranslation } from "../../i18n";
|
||||
|
||||
@ -19,15 +19,17 @@ export const SupplierEditorSkeleton = () => {
|
||||
return (
|
||||
<RdxPageFrame>
|
||||
<RdxPageContainer width="content">
|
||||
<div aria-hidden className="space-y-6">
|
||||
<div className="h-10 w-64 animate-pulse rounded-md bg-muted" />
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{SKELETON_FIELDS.map((field) => (
|
||||
<div className="h-16 animate-pulse rounded-md bg-muted" key={field} />
|
||||
))}
|
||||
<RdxPageContent>
|
||||
<div aria-hidden className="space-y-6">
|
||||
<div className="h-10 w-64 animate-pulse rounded-md bg-muted" />
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{SKELETON_FIELDS.map((field) => (
|
||||
<div className="h-16 animate-pulse rounded-md bg-muted" key={field} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="sr-only">{t("common.loading")}</span>
|
||||
<span className="sr-only">{t("common.loading")}</span>
|
||||
</RdxPageContent>
|
||||
</RdxPageContainer>
|
||||
</RdxPageFrame>
|
||||
);
|
||||
|
||||
@ -32,18 +32,20 @@ export const SupplierUpdatePage = () => {
|
||||
return (
|
||||
<RdxPageFrame>
|
||||
<RdxPageContainer width="content">
|
||||
<PageErrorState
|
||||
description={t("detail.error.description")}
|
||||
primaryAction={{
|
||||
label: t("common.actions.retry"),
|
||||
onClick: async () => {
|
||||
await controller.query.refetch();
|
||||
},
|
||||
}}
|
||||
secondaryAction={{ label: t("common.actions.back"), onClick: navigateBack }}
|
||||
title={t("detail.error.title")}
|
||||
variant="notFound"
|
||||
/>
|
||||
<RdxPageContent>
|
||||
<PageErrorState
|
||||
description={t("detail.error.description")}
|
||||
primaryAction={{
|
||||
label: t("common.actions.retry"),
|
||||
onClick: async () => {
|
||||
await controller.query.refetch();
|
||||
},
|
||||
}}
|
||||
secondaryAction={{ label: t("common.actions.back"), onClick: navigateBack }}
|
||||
title={t("detail.error.title")}
|
||||
variant="notFound"
|
||||
/>
|
||||
</RdxPageContent>
|
||||
</RdxPageContainer>
|
||||
</RdxPageFrame>
|
||||
);
|
||||
@ -66,21 +68,17 @@ export const SupplierUpdatePage = () => {
|
||||
>
|
||||
<RdxPageContainer width="content">
|
||||
<RdxPageContent>
|
||||
<div className="rounded-2xl border border-border/60 bg-background p-4 shadow-xs md:p-6">
|
||||
<div className="flex min-w-0 flex-col gap-6">
|
||||
{controller.mutation.isError ? (
|
||||
<ErrorAlert
|
||||
message={controller.mutation.error.message || t("update.error")}
|
||||
title={t("update.error")}
|
||||
/>
|
||||
) : null}
|
||||
<SupplierEditorForm
|
||||
formId={controller.formId}
|
||||
isSubmitting={controller.mutation.isPending}
|
||||
onSubmit={controller.onSubmit}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{controller.mutation.isError ? (
|
||||
<ErrorAlert
|
||||
message={controller.mutation.error.message || t("update.error")}
|
||||
title={t("update.error")}
|
||||
/>
|
||||
) : null}
|
||||
<SupplierEditorForm
|
||||
formId={controller.formId}
|
||||
isSubmitting={controller.mutation.isPending}
|
||||
onSubmit={controller.onSubmit}
|
||||
/>
|
||||
</RdxPageContent>
|
||||
</RdxPageContainer>
|
||||
</RdxPageFrame>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user