metis-desk/modules/companies/src/web/infrastructure/shared/ui/asset-printer-usage.tsx
2026-10-25 01:19:17 +02:00

134 lines
5.4 KiB
TypeScript

import { inventoryApi, inventoryKeys } from "@metis/assets/client";
import { BrowserLink, useEntryState, useListQuery } from "@metis/core/client";
import { EntityListStatus } from "@repo/rdx-ui/components/entity-list-status";
import { useRef } from "react";
import { useTranslation } from "react-i18next";
import { z } from "zod/v4";
import type { CompanyDTO } from "../../../../common";
import { printerApi, printerKeys } from "../../../printer-configurations/shared/api";
import { useCompanyListState } from "../../../shared/hooks/use-company-list-state";
import { profileApi, profileKeys } from "../../../work-profiles/shared/api";
import { printerUsage } from "../helpers/printer-usage";
const HistorySchema = z.boolean();
export function AssetPrinterUsage({ company, assetId }: { company: CompanyDTO; assetId: string }) {
const { t } = useTranslation("companies");
const printers = useListQuery({
queryKey: printerKeys.company(company.id),
queryFn: () => printerApi.get(company.id),
});
const profiles = useListQuery({
queryKey: profileKeys.company(company.id),
queryFn: () => profileApi.get(company.id),
});
const inventory = useListQuery({
queryKey: inventoryKeys.company(company.id),
queryFn: () => inventoryApi.get(company.id),
});
const rootRef = useRef<HTMLDivElement>(null);
const [historyOpen, setHistoryOpen] = useEntryState({
scope: `/companies/${company.id}/assets/${assetId}`,
key: "printer-usage-history",
schema: HistorySchema,
initialValue: false,
});
const { state, denied } = useCompanyListState([printers, profiles, inventory]);
const available = state.status !== "loading" && state.status !== "unavailable";
const usage = printerUsage(
assetId,
printers.data?.configurations ?? [],
profiles.data?.profiles ?? [],
inventory.data?.assets ?? []
);
return (
<div className="min-w-0 space-y-3" ref={rootRef} tabIndex={-1}>
<EntityListStatus
onRetry={
denied
? undefined
: () => Promise.all([printers.refetch(), profiles.refetch(), inventory.refetch()])
}
retryFocus={() => rootRef.current}
retryLabel={t("retry")}
state={state}
/>
{available && (
<>
{!usage.groups.length && (
<p className="text-sm text-muted-foreground">{t("infrastructureUsage.empty")}</p>
)}
{usage.unresolved.length > 0 && <p role="alert">{t("infrastructureUsage.incomplete")}</p>}
<ul className="space-y-3">
{usage.groups.map((group) => (
<li
className="min-w-0 rounded-md border p-3 text-sm [overflow-wrap:anywhere]"
data-entity-id={group.id}
key={group.id}
>
<BrowserLink
className="font-medium"
href={`/companies/${company.id}/assets/${group.id}`}
>
{group.name}
</BrowserLink>
<ul className="mt-2 space-y-2">
{group.configurations.map(({ profile, configuration }) => (
<li data-entity-id={configuration.id} key={configuration.id}>
<BrowserLink href={`/companies/${company.id}/work-profiles/${profile.id}`}>
{profile.values.name}
</BrowserLink>{" "}
·{" "}
{company.people.find((person) => person.id === profile.values.personId)
?.name ?? "—"}
<p className="text-muted-foreground">
{t(`mail.${configuration.values.state}`)} ·{" "}
{t(`printers.${configuration.values.connection}`)}
{configuration.values.isDefault
? ` · ${t("infrastructureUsage.default")}`
: ""}
</p>
{(!profile.values.active || configuration.needsReview) && (
<p className="text-amber-700 dark:text-amber-400">
{t("infrastructureUsage.review")}
</p>
)}
</li>
))}
</ul>
</li>
))}
</ul>
{usage.history.length > 0 && (
<details
onToggle={(event) => setHistoryOpen(event.currentTarget.open)}
open={historyOpen}
>
<summary className="cursor-pointer text-sm">
{t("infrastructureUsage.history", { count: usage.history.length })}
</summary>
<ul className="mt-2 space-y-2">
{usage.history.map((item) => (
<li className="text-sm" data-entity-id={item.id} key={item.id}>
<BrowserLink
href={`/companies/${company.id}/work-profiles/${item.values.profileId}`}
>
{profiles.data?.profiles.find(
(profile) => profile.id === item.values.profileId
)?.values.name ?? "—"}
</BrowserLink>{" "}
· {t(`mail.${item.values.state}`)}
</li>
))}
</ul>
</details>
)}
</>
)}
<p className="text-xs text-muted-foreground">{t("infrastructureUsage.notice")}</p>
</div>
);
}