refactor: reorganizar importaciones y eliminar componentes obsoletos en las páginas de proformas y facturas

This commit is contained in:
David Arranz 2026-09-04 11:53:59 +02:00
parent 3eb7c37a7b
commit 85d2f11bde
17 changed files with 287 additions and 321 deletions

View File

@ -1,4 +1,5 @@
import { Card, CardContent, RdxBadge } from "@repo/shadcn-ui/components"; import { RdxBadge } from "@repo/rdx-ui/components";
import { Card, CardContent } from "@repo/shadcn-ui/components";
import { CalendarClockIcon } from "lucide-react"; import { CalendarClockIcon } from "lucide-react";
import { useTranslation } from "../../../../i18n"; import { useTranslation } from "../../../../i18n";

View File

@ -1,6 +1,6 @@
import { PageErrorState } from "@erp/core/components"; import { PageErrorState } from "@erp/core/components";
import { RdxPageContainer } from "@repo/rdx-ui/components"; import { RdxBadge, RdxPageContainer } from "@repo/rdx-ui/components";
import { Button, Card, CardContent, RdxBadge } from "@repo/shadcn-ui/components"; import { Button, Card, CardContent } from "@repo/shadcn-ui/components";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
import { useTranslation } from "../../../../i18n"; import { useTranslation } from "../../../../i18n";

View File

@ -2,10 +2,6 @@ import type { ModuleClientParams } from "@erp/core/client";
import { lazy } from "react"; import { lazy } from "react";
import { Outlet, type RouteObject } from "react-router-dom"; import { Outlet, type RouteObject } from "react-router-dom";
const RecurringProformaLayout = lazy(() =>
import("./recurring-proformas/shared/ui").then((m) => ({ default: m.RecurringProformaLayout }))
);
const ProformasListPage = lazy(() => const ProformasListPage = lazy(() =>
import("./proformas/list").then((m) => ({ default: m.ListProformasPage })) import("./proformas/list").then((m) => ({ default: m.ListProformasPage }))
); );
@ -42,10 +38,6 @@ const RecurringProformaDetailPage = lazy(() =>
import("./recurring-proformas").then((m) => ({ default: m.RecurringProformaDetailPage })) import("./recurring-proformas").then((m) => ({ default: m.RecurringProformaDetailPage }))
); );
const IssuedInvoicesLayout = lazy(() =>
import("./issued-invoices/shared/ui").then((m) => ({ default: m.IssuedInvoicesLayout }))
);
const IssuedInvoiceListPage = lazy(() => const IssuedInvoiceListPage = lazy(() =>
import("./issued-invoices/list").then((m) => ({ default: m.ListIssuedInvoicesPage })) import("./issued-invoices/list").then((m) => ({ default: m.ListIssuedInvoicesPage }))
); );
@ -119,11 +111,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-sidebar", layout: "app-sidebar",
protected: true, protected: true,
}, },
element: ( element: <RecurringProformasListPage />,
<RecurringProformaLayout>
<RecurringProformasListPage />
</RecurringProformaLayout>
),
}, },
{ {
path: "recurring-proformas/archived", path: "recurring-proformas/archived",
@ -131,11 +119,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-sidebar", layout: "app-sidebar",
protected: true, protected: true,
}, },
element: ( element: <RecurringProformasListPage />,
<RecurringProformaLayout>
<RecurringProformasListPage />
</RecurringProformaLayout>
),
}, },
{ {
path: "recurring-proformas/create", path: "recurring-proformas/create",
@ -143,11 +127,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-fullscreen", layout: "app-fullscreen",
protected: true, protected: true,
}, },
element: ( element: <RecurringProformaCreatePage />,
<RecurringProformaLayout>
<RecurringProformaCreatePage />
</RecurringProformaLayout>
),
}, },
{ {
path: "recurring-proformas/:recurring_proforma_id", path: "recurring-proformas/:recurring_proforma_id",
@ -155,11 +135,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-fullscreen", layout: "app-fullscreen",
protected: true, protected: true,
}, },
element: ( element: <RecurringProformaDetailPage />,
<RecurringProformaLayout>
<RecurringProformaDetailPage />
</RecurringProformaLayout>
),
}, },
{ {
@ -168,11 +144,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-sidebar", layout: "app-sidebar",
protected: true, protected: true,
}, },
element: ( element: <Outlet context={params} />,
<IssuedInvoicesLayout>
<Outlet context={params} />
</IssuedInvoicesLayout>
),
children: [ children: [
{ path: "", index: true, element: <IssuedInvoiceListPage /> }, // index { path: "", index: true, element: <IssuedInvoiceListPage /> }, // index
{ path: "list", element: <IssuedInvoiceListPage /> }, { path: "list", element: <IssuedInvoiceListPage /> },
@ -196,11 +168,7 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
layout: "app-fullscreen", layout: "app-fullscreen",
protected: true, protected: true,
}, },
element: ( element: <IssuedInvoiceDetailPage />,
<IssuedInvoicesLayout>
<IssuedInvoiceDetailPage />
</IssuedInvoicesLayout>
),
}, },
{ {
path: "settings/billing/verifactu", path: "settings/billing/verifactu",

View File

@ -10,7 +10,7 @@ export const IssuedInvoiceDetailContent = ({
inspector, inspector,
}: IssuedInvoiceDetailContentProps) => { }: IssuedInvoiceDetailContentProps) => {
return ( return (
<div className="min-h-0 flex-1 overflow-auto lg:overflow-hidden"> <div className="min-h-full lg:h-full lg:min-h-0 lg:overflow-hidden">
<div className="grid min-h-full grid-cols-1 lg:h-full lg:min-h-0 lg:grid-cols-[minmax(0,1fr)_340px] lg:overflow-hidden xl:grid-cols-[minmax(0,1fr)_380px]"> <div className="grid min-h-full grid-cols-1 lg:h-full lg:min-h-0 lg:grid-cols-[minmax(0,1fr)_340px] lg:overflow-hidden xl:grid-cols-[minmax(0,1fr)_380px]">
{documentPane} {documentPane}
{inspector} {inspector}

View File

@ -1,4 +1,5 @@
import { PageErrorState } from "@erp/core/components"; import { PageErrorState } from "@erp/core/components";
import { RdxPageContainer, RdxPageFrame } from "@repo/rdx-ui/components";
import { useTranslation } from "../../../../i18n"; import { useTranslation } from "../../../../i18n";
import { useIssuedInvoiceDetailPageController } from "../../controllers"; import { useIssuedInvoiceDetailPageController } from "../../controllers";
@ -20,8 +21,8 @@ export const IssuedInvoiceDetailPage = () => {
if (ctrl.state.pageError) { if (ctrl.state.pageError) {
return ( return (
<div className="p-4 sm:p-6"> <RdxPageFrame>
<div className="mx-auto w-full max-w-3xl"> <RdxPageContainer width="content">
<PageErrorState <PageErrorState
description={ctrl.state.pageError.description} description={ctrl.state.pageError.description}
primaryAction={ctrl.state.pageError.primaryAction} primaryAction={ctrl.state.pageError.primaryAction}
@ -30,15 +31,15 @@ export const IssuedInvoiceDetailPage = () => {
title={ctrl.state.pageError.title} title={ctrl.state.pageError.title}
variant={ctrl.state.pageError.variant} variant={ctrl.state.pageError.variant}
/> />
</div> </RdxPageContainer>
</div> </RdxPageFrame>
); );
} }
if (!(ctrl.header && ctrl.document && ctrl.general)) { if (!(ctrl.header && ctrl.document && ctrl.general)) {
return ( return (
<div className="p-4 sm:p-6"> <RdxPageFrame>
<div className="mx-auto w-full max-w-3xl"> <RdxPageContainer width="content">
<PageErrorState <PageErrorState
description={t("pages.issued_invoices.detail.page_error.inconsistent.description")} description={t("pages.issued_invoices.detail.page_error.inconsistent.description")}
secondaryAction={{ secondaryAction={{
@ -48,20 +49,23 @@ export const IssuedInvoiceDetailPage = () => {
title={t("pages.issued_invoices.detail.page_error.unknown.title")} title={t("pages.issued_invoices.detail.page_error.unknown.title")}
variant="unknown" variant="unknown"
/> />
</div> </RdxPageContainer>
</div> </RdxPageFrame>
); );
} }
return ( return (
<div className="flex h-full min-h-0 flex-col overflow-hidden"> <RdxPageFrame
<IssuedInvoiceDetailHeader contentClassName="lg:overflow-hidden"
actions={ctrl.actions} header={
header={ctrl.header} <IssuedInvoiceDetailHeader
onBack={ctrl.navigation.navigateBack} actions={ctrl.actions}
onExecuteAction={ctrl.handlers.executeAction} header={ctrl.header}
/> onBack={ctrl.navigation.navigateBack}
onExecuteAction={ctrl.handlers.executeAction}
/>
}
>
<IssuedInvoiceDetailContent <IssuedInvoiceDetailContent
documentPane={ documentPane={
<IssuedInvoiceDocumentPane <IssuedInvoiceDocumentPane
@ -80,6 +84,6 @@ export const IssuedInvoiceDetailPage = () => {
/> />
} }
/> />
</div> </RdxPageFrame>
); );
}; };

View File

@ -1,3 +1,4 @@
import { RdxBadge } from "@repo/rdx-ui/components";
import { ToggleGroup, ToggleGroupItem } from "@repo/shadcn-ui/components"; import { ToggleGroup, ToggleGroupItem } from "@repo/shadcn-ui/components";
import { cn } from "@repo/shadcn-ui/lib/utils"; import { cn } from "@repo/shadcn-ui/lib/utils";
import { import {

View File

@ -1,3 +1,4 @@
import { RdxBadge } from "@repo/rdx-ui/components";
import { Tooltip, TooltipContent, TooltipTrigger } from "@repo/shadcn-ui/components"; import { Tooltip, TooltipContent, TooltipTrigger } from "@repo/shadcn-ui/components";
import { cn } from "@repo/shadcn-ui/lib/utils"; import { cn } from "@repo/shadcn-ui/lib/utils";

View File

@ -1,6 +1,6 @@
import { ErrorAlert, PageErrorState, PageHeader, SimpleSearchInput } from "@erp/core/components"; import { ErrorAlert, PageErrorState, PageHeader, SimpleSearchInput } from "@erp/core/components";
import { useReturnToNavigation } from "@erp/core/hooks"; import { useReturnToNavigation } from "@erp/core/hooks";
import { LogoVerifactu } from "@repo/rdx-ui/components"; import { LogoVerifactu, RdxPageContainer, RdxPageFrame } from "@repo/rdx-ui/components";
import { Alert, AlertDescription, AlertTitle, Button } from "@repo/shadcn-ui/components"; import { Alert, AlertDescription, AlertTitle, Button } from "@repo/shadcn-ui/components";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
@ -58,8 +58,8 @@ export const ListIssuedInvoicesPage = () => {
if (hasBlockingError && pageError) { if (hasBlockingError && pageError) {
return ( return (
<div className="p-4 sm:p-6"> <RdxPageFrame>
<div className="mx-auto w-full max-w-3xl"> <RdxPageContainer width="content">
<PageErrorState <PageErrorState
description={pageError.description} description={pageError.description}
primaryAction={ primaryAction={
@ -88,46 +88,46 @@ export const ListIssuedInvoicesPage = () => {
title={pageError.title} title={pageError.title}
variant={pageError.variant} variant={pageError.variant}
/> />
</div> </RdxPageContainer>
</div> </RdxPageFrame>
); );
} }
return ( return (
<div className="p-6 space-y-6"> <RdxPageFrame>
<PageHeader <RdxPageContainer className="space-y-6" width="full">
description={t("pages.issued_invoices.list.description")} <PageHeader
rightSlot={ description={t("pages.issued_invoices.list.description")}
<Button rightSlot={
aria-label={t("pages.issued_invoices.create.title")} <Button
className="hidden" aria-label={t("pages.issued_invoices.create.title")}
onClick={() => navigate("/issued-invoices/create")} className="hidden"
> onClick={() => navigate("/issued-invoices/create")}
<PlusIcon aria-hidden className="mr-2 size-4" /> >
{t("pages.issued_invoices.create.title")} <PlusIcon aria-hidden className="mr-2 size-4" />
</Button> {t("pages.issued_invoices.create.title")}
} </Button>
title={t("pages.issued_invoices.list.title")} }
/> title={t("pages.issued_invoices.list.title")}
/>
<div className="mx-auto w-full space-y-4"> <div className="mx-auto w-full space-y-4">
{hasRefreshError && refreshError ? ( {hasRefreshError && refreshError ? (
<ErrorAlert message={refreshError.message} title={refreshError.title} /> <ErrorAlert message={refreshError.message} title={refreshError.title} />
) : null} ) : null}
<Alert className="bg-green-50 text-green-800 flex items-center justify-between gap-6"> <Alert className="bg-green-50 text-green-800 flex items-center justify-between gap-6">
<div> <div>
<AlertTitle className="font-semibold text-green-800">¡Atención!</AlertTitle> <AlertTitle className="font-semibold text-green-800">¡Atención!</AlertTitle>
<AlertDescription className="text-green-800"> <AlertDescription className="text-green-800">
Las facturas de esta pantalla son de solo lectura. Se generan automáticamente al Las facturas de esta pantalla son de solo lectura. Se generan automáticamente al
emitir una proforma aprobada y no se pueden modificar ni eliminar. Solo puedes emitir una proforma aprobada y no se pueden modificar ni eliminar. Solo puedes
descargar el PDF de cada factura. descargar el PDF de cada factura.
</AlertDescription> </AlertDescription>
</div> </div>
<LogoVerifactu className="text-green-800 w-50" color="" /> <LogoVerifactu className="text-green-800 w-50" color="" />
</Alert> </Alert>
<div className="min-h-0 flex-1 overflow-auto">
<IssuedInvoicesGrid <IssuedInvoicesGrid
columns={columns} columns={columns}
data={listCtrl.data} data={listCtrl.data}
@ -164,10 +164,10 @@ export const ListIssuedInvoicesPage = () => {
</div> </div>
} }
/> />
</div>
{listCtrl.data.totalItems === 0 ? <IssuedInvoicesEmptyGrid /> : null} {listCtrl.data.totalItems === 0 ? <IssuedInvoicesEmptyGrid /> : null}
</div> </div>
</div> </RdxPageContainer>
</RdxPageFrame>
); );
}; };

View File

@ -1 +0,0 @@
export * from "./issued-invoices-layout";

View File

@ -1,5 +0,0 @@
import type { PropsWithChildren } from "react";
export const IssuedInvoicesLayout = ({ children }: PropsWithChildren) => {
return <div className="space-y-4">{children}</div>;
};

View File

@ -1,6 +1,6 @@
import { PageFormHeader } from "@erp/core/components"; import { PageFormHeader } from "@erp/core/components";
import { useHookForm } from "@erp/core/hooks"; import { useHookForm } from "@erp/core/hooks";
import { RdxEditorPageLayout } from "@repo/rdx-ui/components"; import { RdxEditorLayout, RdxPageContainer, RdxPageFrame } from "@repo/rdx-ui/components";
import { import {
Button, Button,
Card, Card,
@ -50,35 +50,39 @@ export const RecurringProformaCreatePage = () => {
}); });
return ( return (
<div className="fixed inset-0 flex flex-col overflow-hidden"> <RdxPageFrame
<PageFormHeader contentClassName="bg-muted/20"
actions={ header={
<div className="flex items-center gap-3"> <PageFormHeader
<Button actions={
disabled={mutation.isPending} <div className="flex items-center gap-3">
onClick={() => navigate("/recurring-proformas")} <Button
type="button" disabled={mutation.isPending}
variant="outline" onClick={() => navigate("/recurring-proformas")}
> type="button"
{t("recurring_proformas.create.cancel")} variant="outline"
</Button> >
<Button {t("recurring_proformas.create.cancel")}
disabled={mutation.isPending} </Button>
form={RECURRING_PROFORMA_CREATE_FORM_ID} <Button
type="submit" disabled={mutation.isPending}
> form={RECURRING_PROFORMA_CREATE_FORM_ID}
{mutation.isPending type="submit"
? t("recurring_proformas.create.creating") >
: t("recurring_proformas.create.submit")} {mutation.isPending
</Button> ? t("recurring_proformas.create.creating")
</div> : t("recurring_proformas.create.submit")}
} </Button>
backLabel={t("recurring_proformas.create.cancel")} </div>
onBack={() => navigate("/recurring-proformas")} }
title={t("recurring_proformas.create.title")} backLabel={t("recurring_proformas.create.cancel")}
/> onBack={() => navigate("/recurring-proformas")}
<div className="flex-1 overflow-y-auto bg-muted/20"> title={t("recurring_proformas.create.title")}
<RdxEditorPageLayout width="simple"> />
}
>
<RdxPageContainer width="content">
<RdxEditorLayout>
<form <form
className="space-y-6" className="space-y-6"
id={RECURRING_PROFORMA_CREATE_FORM_ID} id={RECURRING_PROFORMA_CREATE_FORM_ID}
@ -129,8 +133,8 @@ export const RecurringProformaCreatePage = () => {
</CardContent> </CardContent>
</Card> </Card>
</form> </form>
</RdxEditorPageLayout> </RdxEditorLayout>
</div> </RdxPageContainer>
</div> </RdxPageFrame>
); );
}; };

View File

@ -1,10 +1,5 @@
import { PageErrorState } from "@erp/core/components"; import { PageErrorState } from "@erp/core/components";
import { import { RdxBadge, RdxPageContainer, RdxPageFrame, RdxPageStack } from "@repo/rdx-ui/components";
RdxBadge,
RdxEditorPageLayout,
RdxPageContainer,
RdxPageStack,
} from "@repo/rdx-ui/components";
import { Button, Card, CardContent, CardHeader, CardTitle } from "@repo/shadcn-ui/components"; import { Button, Card, CardContent, CardHeader, CardTitle } from "@repo/shadcn-ui/components";
import { ArrowLeftIcon } from "lucide-react"; import { ArrowLeftIcon } from "lucide-react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
@ -96,179 +91,181 @@ export const RecurringProformaDetailPage = () => {
}); });
return ( return (
<RdxPageStack className="fixed inset-0 min-h-0 overflow-hidden" spacing="none"> <RdxPageFrame
<ProformaPageHeader header={
actions={ <ProformaPageHeader
<RecurringProformaDetailHeaderActions actions={
actions={headerActions} <RecurringProformaDetailHeaderActions
isPending={actionMutation.isPending} actions={headerActions}
onExecuteAction={(action) => isPending={actionMutation.isPending}
actionMutation.mutate({ id: recurringProforma.id, action }) onExecuteAction={(action) =>
} actionMutation.mutate({ id: recurringProforma.id, action })
/> }
} />
backLabel={t("recurring_proformas.detail.back")} }
onBack={() => navigate("/recurring-proformas")} backLabel={t("recurring_proformas.detail.back")}
title={ onBack={() => navigate("/recurring-proformas")}
<div className="space-y-3"> title={
<span className="inline-flex max-w-full items-center gap-3"> <div className="space-y-3">
<span className="truncate">{mainView.name}</span> <span className="inline-flex max-w-full items-center gap-3">
<RdxBadge <span className="truncate">{mainView.name}</span>
className={`shrink-0 rounded-md px-4 py-3 ${getRecurringProformaStatusBadgeClassName(recurringProforma.status)}`} <RdxBadge
variant="secondary" className={`shrink-0 rounded-md px-4 py-3 ${getRecurringProformaStatusBadgeClassName(recurringProforma.status)}`}
> variant="secondary"
{t(mainView.statusKey)} >
</RdxBadge> {t(mainView.statusKey)}
<RdxBadge className="shrink-0 px-4 py-3 rounded-md" variant="secondary"> </RdxBadge>
{t( <RdxBadge className="shrink-0 px-4 py-3 rounded-md" variant="secondary">
recurringProforma.has_issue {t(
? "recurring_proformas.list.issues.issue" recurringProforma.has_issue
: "recurring_proformas.list.issues.none" ? "recurring_proformas.list.issues.issue"
)} : "recurring_proformas.list.issues.none"
</RdxBadge> )}
</span> </RdxBadge>
<p className="text-sm text-muted-foreground">{metadata}</p> </span>
</div> <p className="text-sm text-muted-foreground">{metadata}</p>
} </div>
/> }
/>
<RdxPageContainer className="min-h-0 flex-1 overflow-y-auto" padding="none" width="wide"> }
<RdxEditorPageLayout width="wide"> >
<RdxPageContainer width="wide">
<RdxPageStack spacing="default">
<RecurringProformaOperationalSummary <RecurringProformaOperationalSummary
locale={dateLocale} locale={dateLocale}
recurringProforma={recurringProforma} recurringProforma={recurringProforma}
/> />
</RdxEditorPageLayout>
<div className="grid gap-6 xl:grid-cols-2"> <div className="grid gap-6 xl:grid-cols-2">
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{t("recurring_proformas.detail.general.title")}</CardTitle> <CardTitle>{t("recurring_proformas.detail.general.title")}</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
{recurringProforma.description ? ( {recurringProforma.description ? (
<p className="text-sm leading-6 text-muted-foreground"> <p className="text-sm leading-6 text-muted-foreground">
{recurringProforma.description} {recurringProforma.description}
</p> </p>
) : null} ) : null}
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{t("recurring_proformas.detail.schedule.title")}</CardTitle> <CardTitle>{t("recurring_proformas.detail.schedule.title")}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
{schedule ? ( {schedule ? (
<dl className="space-y-3">
<DetailField
label={t("recurring_proformas.detail.schedule.interval")}
value={mainView.scheduleLabel}
/>
<DetailField
label={t("recurring_proformas.detail.schedule.start_date")}
value={formatRecurringProformaDateOnly(schedule.start_date)}
/>
<DetailField
label={t("recurring_proformas.detail.schedule.end_date")}
value={
schedule.end_date
? formatRecurringProformaDateOnly(schedule.end_date)
: t("recurring_proformas.detail.schedule.no_end_date")
}
/>
<DetailField
label={t("recurring_proformas.detail.schedule.monthly_rule")}
value={
schedule.monthly_rule
? t(`recurring_proformas.list.schedule.${schedule.monthly_rule}`)
: t("recurring_proformas.detail.schedule.not_applicable")
}
/>
</dl>
) : (
<p className="text-sm text-muted-foreground">
{t("recurring_proformas.list.schedule.none")}
</p>
)}
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>{t("recurring_proformas.detail.commercial.title")}</CardTitle>
</CardHeader>
<CardContent>
<dl className="space-y-3"> <dl className="space-y-3">
<DetailField <DetailField
label={t("recurring_proformas.detail.schedule.interval")} label={t("recurring_proformas.detail.commercial.payment_term")}
value={mainView.scheduleLabel} value={formatRecurringProformaOverride(recurringProforma.payment_term_id, t)}
/> />
<DetailField <DetailField
label={t("recurring_proformas.detail.schedule.start_date")} label={t("recurring_proformas.detail.commercial.payment_method")}
value={formatRecurringProformaDateOnly(schedule.start_date)} value={formatRecurringProformaOverride(recurringProforma.payment_method_id, t)}
/> />
<DetailField <DetailField
label={t("recurring_proformas.detail.schedule.end_date")} label={t("recurring_proformas.detail.commercial.language")}
value={ value={formatRecurringProformaOverride(recurringProforma.language, t)}
schedule.end_date
? formatRecurringProformaDateOnly(schedule.end_date)
: t("recurring_proformas.detail.schedule.no_end_date")
}
/> />
<DetailField <DetailField
label={t("recurring_proformas.detail.schedule.monthly_rule")} label={t("recurring_proformas.detail.commercial.currency")}
value={ value={formatRecurringProformaOverride(recurringProforma.currency, t)}
schedule.monthly_rule
? t(`recurring_proformas.list.schedule.${schedule.monthly_rule}`)
: t("recurring_proformas.detail.schedule.not_applicable")
}
/> />
<DetailField
label={t("recurring_proformas.detail.commercial.proforma_series")}
value={formatRecurringProformaOverride(recurringProforma.proforma_series, t)}
/>
<DetailField
label={t("recurring_proformas.detail.commercial.issued_invoice_series")}
value={formatRecurringProformaOverride(
recurringProforma.issued_invoice_series,
t
)}
/>
{discount ? (
<DetailField
label={t("recurring_proformas.detail.commercial.global_discount")}
value={discount}
/>
) : null}
</dl> </dl>
) : ( </CardContent>
<p className="text-sm text-muted-foreground"> </Card>
{t("recurring_proformas.list.schedule.none")}
</p>
)}
</CardContent>
</Card>
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{t("recurring_proformas.detail.commercial.title")}</CardTitle> <CardTitle>{t("recurring_proformas.detail.items.title")}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<dl className="space-y-3"> {recurringProforma.items.length === 0 ? (
<DetailField <p className="text-sm text-muted-foreground">
label={t("recurring_proformas.detail.commercial.payment_term")} {t("recurring_proformas.detail.items.empty")}
value={formatRecurringProformaOverride(recurringProforma.payment_term_id, t)} </p>
/> ) : (
<DetailField <ol className="space-y-3">
label={t("recurring_proformas.detail.commercial.payment_method")} {recurringProforma.items.map((item) => (
value={formatRecurringProformaOverride(recurringProforma.payment_method_id, t)} <li className="flex gap-3 text-sm" key={item.id}>
/> <span className="tabular-nums text-muted-foreground">{item.position}</span>
<DetailField <span>
label={t("recurring_proformas.detail.commercial.language")} {item.description ?? t("recurring_proformas.detail.items.no_description")}
value={formatRecurringProformaOverride(recurringProforma.language, t)} </span>
/> </li>
<DetailField ))}
label={t("recurring_proformas.detail.commercial.currency")} </ol>
value={formatRecurringProformaOverride(recurringProforma.currency, t)} )}
/> </CardContent>
<DetailField </Card>
label={t("recurring_proformas.detail.commercial.proforma_series")} </div>
value={formatRecurringProformaOverride(recurringProforma.proforma_series, t)}
/>
<DetailField
label={t("recurring_proformas.detail.commercial.issued_invoice_series")}
value={formatRecurringProformaOverride(
recurringProforma.issued_invoice_series,
t
)}
/>
{discount ? (
<DetailField
label={t("recurring_proformas.detail.commercial.global_discount")}
value={discount}
/>
) : null}
</dl>
</CardContent>
</Card>
<Card> <RecurringProformaOccurrencesSection recurringProformaId={recurringProforma.id} />
<CardHeader>
<CardTitle>{t("recurring_proformas.detail.items.title")}</CardTitle>
</CardHeader>
<CardContent>
{recurringProforma.items.length === 0 ? (
<p className="text-sm text-muted-foreground">
{t("recurring_proformas.detail.items.empty")}
</p>
) : (
<ol className="space-y-3">
{recurringProforma.items.map((item) => (
<li className="flex gap-3 text-sm" key={item.id}>
<span className="tabular-nums text-muted-foreground">{item.position}</span>
<span>
{item.description ?? t("recurring_proformas.detail.items.no_description")}
</span>
</li>
))}
</ol>
)}
</CardContent>
</Card>
</div>
<RecurringProformaOccurrencesSection recurringProformaId={recurringProforma.id} /> <Button onClick={() => navigate("/recurring-proformas")} type="button" variant="outline">
<ArrowLeftIcon aria-hidden className="size-4" />
<Button onClick={() => navigate("/recurring-proformas")} type="button" variant="outline"> {t("recurring_proformas.detail.back")}
<ArrowLeftIcon aria-hidden className="size-4" /> </Button>
{t("recurring_proformas.detail.back")} </RdxPageStack>
</Button>
</RdxPageContainer> </RdxPageContainer>
</RdxPageStack> </RdxPageFrame>
); );
}; };

View File

@ -124,6 +124,7 @@ mock.module("./controllers/use-list-recurring-proformas-page-controller", {
mock.module("@repo/rdx-ui/components", { mock.module("@repo/rdx-ui/components", {
namedExports: { namedExports: {
RdxPageContainer: ({ children }: { children: ReactNode }) => <div>{children}</div>, RdxPageContainer: ({ children }: { children: ReactNode }) => <div>{children}</div>,
RdxPageFrame: ({ children }: { children: ReactNode }) => <div>{children}</div>,
RdxPageStack: ({ children }: { children: ReactNode }) => <div>{children}</div>, RdxPageStack: ({ children }: { children: ReactNode }) => <div>{children}</div>,
RdxPageHeader: ({ RdxPageHeader: ({
title, title,

View File

@ -2,6 +2,7 @@ import { ErrorAlert } from "@erp/core/components";
import { import {
RdxPageActions, RdxPageActions,
RdxPageContainer, RdxPageContainer,
RdxPageFrame,
RdxPageHeader, RdxPageHeader,
RdxPageStack, RdxPageStack,
} from "@repo/rdx-ui/components"; } from "@repo/rdx-ui/components";
@ -28,20 +29,22 @@ export const ScopedListRecurringProformasPageView = ({
content, content,
}: ScopedListRecurringProformasPageViewProps) => { }: ScopedListRecurringProformasPageViewProps) => {
return ( return (
<RdxPageContainer width="full"> <RdxPageFrame>
<RdxPageStack spacing="default"> <RdxPageContainer width="full">
<RdxPageHeader <RdxPageStack spacing="default">
actions={primaryAction ? <RdxPageActions primary={primaryAction} /> : undefined} <RdxPageHeader
description={description} actions={primaryAction ? <RdxPageActions primary={primaryAction} /> : undefined}
title={title} description={description}
/> title={title}
/>
{refreshError ? ( {refreshError ? (
<ErrorAlert message={refreshError.message} title={refreshError.title} /> <ErrorAlert message={refreshError.message} title={refreshError.title} />
) : null} ) : null}
{content} {content}
</RdxPageStack> </RdxPageStack>
</RdxPageContainer> </RdxPageContainer>
</RdxPageFrame>
); );
}; };

View File

@ -1 +0,0 @@
export * from "./recurring-proforma-layout";

View File

@ -1,9 +0,0 @@
import type { PropsWithChildren } from "react";
export function RecurringProformaLayout({ children }: PropsWithChildren) {
return (
<div className="flex flex-col h-full w-full" id="recurring_proformas ">
{children}
</div>
);
}

View File

@ -21,12 +21,14 @@ const ASIDE_GRID_CLASSNAME: Record<RdxEditorWidth, string> = {
}; };
/** /**
* @deprecated
* Distribuye el contenido interno de un contenedor en: * Distribuye el contenido interno de un contenedor en:
* *
* - una región principal * - una región principal
* - un aside opcional. * - un aside opcional.
* *
* No controla padding, scroll ni estructura general de página. * No controla padding, scroll ni estructura general de página.
* Para nuevos consumidores usar RdxPageContainer + RdxEditorLayout.
*/ */
export const RdxEditorPageLayout = ({ export const RdxEditorPageLayout = ({