FactuGES_ERP/apps/web/src/home/controllers/use-home-page-controller.ts
david ef2ae58046 feat(home): implement home page with KPIs, recent activity, and attention items
- 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.
2026-08-13 11:04:57 +02:00

183 lines
5.7 KiB
TypeScript

import { useIdentityAuthSession } from "@erp/identity/client";
import { useCallback, useMemo } from "react";
import { useAppTranslation } from "@/locales/i18n";
import type {
HomeAttentionItem,
HomeKpi,
HomeProformaStatusSummaryItem,
} from "../entities/home.entity";
import { useHomeCustomersTotalQuery } from "../hooks/use-home-customers-total-query";
import { useHomeMonthlyBillingQuery } from "../hooks/use-home-monthly-billing-query";
import { useHomeProformasOverviewQuery } from "../hooks/use-home-proformas-overview-query";
import { useHomeRecentActivityQuery } from "../hooks/use-home-recent-activity-query";
export const useHomePageController = () => {
const { t, i18n } = useAppTranslation();
const { activeCompany, account } = useIdentityAuthSession();
const customersTotalQuery = useHomeCustomersTotalQuery();
const proformasOverviewQuery = useHomeProformasOverviewQuery();
const monthlyBillingQuery = useHomeMonthlyBillingQuery();
const recentActivityQuery = useHomeRecentActivityQuery();
const kpis = useMemo<HomeKpi[]>(() => {
const monthlyInvoiceCount = monthlyBillingQuery.data?.invoiceCount ?? 0;
const openProformasCount = proformasOverviewQuery.data?.openCount ?? 0;
const readyToIssueCount = proformasOverviewQuery.data?.readyToIssueCount ?? 0;
const customersTotal = customersTotalQuery.data ?? 0;
return [
{
id: "customers",
label: t("web.home.kpis.customers.label"),
value: new Intl.NumberFormat(i18n.language).format(customersTotal),
href: "/customers",
ctaLabel: t("web.home.kpis.customers.cta"),
},
{
id: "open-proformas",
label: t("web.home.kpis.openProformas.label"),
value: new Intl.NumberFormat(i18n.language).format(openProformasCount),
href: "/proformas",
ctaLabel: t("web.home.kpis.openProformas.cta"),
},
{
id: "ready-to-issue",
label: t("web.home.kpis.readyToIssue.label"),
value: new Intl.NumberFormat(i18n.language).format(readyToIssueCount),
href: "/proformas?status=approved",
ctaLabel: t("web.home.kpis.readyToIssue.cta"),
},
{
id: "monthly-issued-invoices",
label: t("web.home.kpis.monthlyIssuedInvoices.label"),
value: new Intl.NumberFormat(i18n.language).format(monthlyInvoiceCount),
href: "/customer-invoices",
ctaLabel: t("web.home.kpis.monthlyIssuedInvoices.cta"),
},
];
}, [
customersTotalQuery.data,
i18n.language,
monthlyBillingQuery.data?.invoiceCount,
proformasOverviewQuery.data?.openCount,
proformasOverviewQuery.data?.readyToIssueCount,
t,
]);
const attentionItems = useMemo<HomeAttentionItem[]>(() => {
const statusCounts = proformasOverviewQuery.data?.statusCounts;
if (!statusCounts) {
return [];
}
return [
{
id: "approved",
count: statusCounts.approved,
href: "/proformas?status=approved",
title: t("web.home.attention.readyToIssue.title"),
description: t("web.home.attention.readyToIssue.description"),
},
{
id: "sent",
count: statusCounts.sent,
href: "/proformas?status=sent",
title: t("web.home.attention.sent.title"),
description: t("web.home.attention.sent.description"),
},
{
id: "draft",
count: statusCounts.draft,
href: "/proformas?status=draft",
title: t("web.home.attention.draft.title"),
description: t("web.home.attention.draft.description"),
},
].filter((item) => item.count > 0);
}, [proformasOverviewQuery.data?.statusCounts, t]);
const proformaStatusSummary = useMemo<HomeProformaStatusSummaryItem[]>(() => {
const statusCounts = proformasOverviewQuery.data?.statusCounts;
if (!statusCounts) {
return [];
}
return [
{
id: "draft",
label: t("web.home.proformas.status.draft"),
count: statusCounts.draft,
href: "/proformas?status=draft",
},
{
id: "sent",
label: t("web.home.proformas.status.sent"),
count: statusCounts.sent,
href: "/proformas?status=sent",
},
{
id: "approved",
label: t("web.home.proformas.status.approved"),
count: statusCounts.approved,
href: "/proformas?status=approved",
},
{
id: "rejected",
label: t("web.home.proformas.status.rejected"),
count: statusCounts.rejected,
href: "/proformas?status=rejected",
},
{
id: "issued",
label: t("web.home.proformas.status.issued"),
count: statusCounts.issued,
href: "/proformas?status=issued",
},
];
}, [proformasOverviewQuery.data?.statusCounts, t]);
const hasBlockingError =
customersTotalQuery.isError &&
proformasOverviewQuery.isError &&
monthlyBillingQuery.isError &&
recentActivityQuery.isError;
const retry = useCallback(async () => {
await Promise.all([
customersTotalQuery.refetch(),
proformasOverviewQuery.refetch(),
monthlyBillingQuery.refetch(),
recentActivityQuery.refetch(),
]);
}, [customersTotalQuery, monthlyBillingQuery, proformasOverviewQuery, recentActivityQuery]);
const pageError = useMemo(() => {
if (!hasBlockingError) {
return null;
}
return {
title: t("web.home.errors.blocking.title"),
description: t("web.home.errors.blocking.description"),
};
}, [hasBlockingError, t]);
return {
account,
activeCompany,
kpis,
attentionItems,
proformaStatusSummary,
customersTotalQuery,
proformasOverviewQuery,
monthlyBillingQuery,
recentActivityQuery,
hasBlockingError,
pageError,
retry,
};
};