- Added Spanish translations for home page components. - Created API endpoints for fetching home-related data (customers, proformas, issued invoices). - Developed hooks for managing home page data queries. - Implemented home page layout with KPI cards, attention panels, monthly billing summary, and recent activity sections. - Added error handling and loading states for improved user experience.
113 lines
3.8 KiB
TypeScript
113 lines
3.8 KiB
TypeScript
import { PageErrorState } from "@erp/core/components";
|
|
import { RdxPageContainer, RdxPageHeader, RdxPageStack } from "@repo/rdx-ui/components";
|
|
import { Skeleton } from "@repo/shadcn-ui/components";
|
|
import { Link, useNavigate } from "react-router-dom";
|
|
|
|
import { useAppTranslation } from "@/locales/i18n";
|
|
|
|
import { useHomePageController } from "../../controllers/use-home-page-controller";
|
|
import { HomeAttentionPanel } from "../blocks/home-attention-panel";
|
|
import { HomeKpiCard } from "../blocks/home-kpi-card";
|
|
import { HomeMonthlyBillingSummary } from "../blocks/home-monthly-billing-summary";
|
|
import { HomeProformaStatusSummary } from "../blocks/home-proforma-status-summary";
|
|
import { HomeRecentActivity } from "../blocks/home-recent-activity";
|
|
|
|
const HomeKpisSkeleton = () => {
|
|
return (
|
|
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
{Array.from({ length: 4 }).map((_, index) => (
|
|
<div className="rounded-xl border border-border/70 bg-background p-5" key={index}>
|
|
<div className="space-y-3">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="h-9 w-16" />
|
|
<Skeleton className="h-4 w-20" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const HomePage = () => {
|
|
const { t } = useAppTranslation();
|
|
const navigate = useNavigate();
|
|
const ctrl = useHomePageController();
|
|
|
|
if (ctrl.hasBlockingError && ctrl.pageError) {
|
|
return (
|
|
<RdxPageContainer width="full">
|
|
<div className="mx-auto w-full max-w-3xl">
|
|
<PageErrorState
|
|
description={ctrl.pageError.description}
|
|
primaryAction={{
|
|
label: t("web.actions.retry"),
|
|
onClick: ctrl.retry,
|
|
}}
|
|
secondaryAction={{
|
|
label: t("web.actions.goHome"),
|
|
onClick: () => navigate("/proformas"),
|
|
}}
|
|
title={ctrl.pageError.title}
|
|
variant="server"
|
|
/>
|
|
</div>
|
|
</RdxPageContainer>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<RdxPageContainer width="full">
|
|
<RdxPageStack spacing="default">
|
|
<RdxPageHeader
|
|
description={t("web.home.header.description")}
|
|
title={t("web.home.header.title")}
|
|
/>
|
|
|
|
{ctrl.customersTotalQuery.isLoading ||
|
|
ctrl.proformasOverviewQuery.isLoading ||
|
|
ctrl.monthlyBillingQuery.isLoading ? (
|
|
<HomeKpisSkeleton />
|
|
) : (
|
|
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
{ctrl.kpis.map((kpi) => (
|
|
<HomeKpiCard item={kpi} key={kpi.id} />
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<div className="grid gap-4 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
|
|
<HomeAttentionPanel
|
|
hasError={ctrl.proformasOverviewQuery.isError}
|
|
items={ctrl.attentionItems}
|
|
/>
|
|
<HomeProformaStatusSummary
|
|
hasError={ctrl.proformasOverviewQuery.isError}
|
|
items={ctrl.proformaStatusSummary}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-4 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
|
|
<HomeRecentActivity
|
|
hasPartialError={ctrl.recentActivityQuery.hasPartialError}
|
|
items={ctrl.recentActivityQuery.items}
|
|
/>
|
|
<HomeMonthlyBillingSummary
|
|
data={ctrl.monthlyBillingQuery.data}
|
|
hasError={ctrl.monthlyBillingQuery.isError}
|
|
/>
|
|
</div>
|
|
|
|
<p className="text-xs text-muted-foreground">
|
|
{t("web.home.footer.note")}{" "}
|
|
<Link
|
|
className="underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
to="/customer-invoices"
|
|
>
|
|
{t("web.home.footer.link")}
|
|
</Link>
|
|
</p>
|
|
</RdxPageStack>
|
|
</RdxPageContainer>
|
|
);
|
|
};
|