152 lines
5.0 KiB
TypeScript
152 lines
5.0 KiB
TypeScript
import { Button } from "@repo/shadcn-ui/components/button";
|
|
import { Card, CardContent } from "@repo/shadcn-ui/components/card";
|
|
import { FormDialog } from "@repo/shadcn-ui/components/form-dialog";
|
|
import { Input } from "@repo/shadcn-ui/components/input";
|
|
import { Label } from "@repo/shadcn-ui/components/label";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@repo/shadcn-ui/components/table";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import type { ColumnDef } from "@tanstack/react-table";
|
|
import { getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table";
|
|
import { useId, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import type { CompanySummaryDTO } from "../../common";
|
|
import { companyApi, companyKeys } from "../api/company-api";
|
|
|
|
import { CompanyDetail } from "./company-detail";
|
|
import { CompanyFeedback } from "./company-feedback";
|
|
import { CompanyForm } from "./company-form";
|
|
|
|
const EMPTY_COMPANIES: CompanySummaryDTO[] = [];
|
|
const COMPANY_COLUMNS: ColumnDef<CompanySummaryDTO>[] = [
|
|
{ accessorKey: "name" },
|
|
{ accessorKey: "active", enableGlobalFilter: false },
|
|
];
|
|
|
|
export function CompaniesPage({
|
|
csrfToken,
|
|
onSelectCompany,
|
|
}: {
|
|
csrfToken: string;
|
|
onSelectCompany?: (id: string) => void;
|
|
}) {
|
|
const { t } = useTranslation("companies");
|
|
const query = useQuery({ queryKey: companyKeys.list, queryFn: companyApi.list });
|
|
const [selectedId, setSelectedId] = useState<string | undefined>();
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
const [search, setSearch] = useState("");
|
|
const id = useId();
|
|
const table = useReactTable({
|
|
data: query.data?.companies ?? EMPTY_COMPANIES,
|
|
columns: COMPANY_COLUMNS,
|
|
getCoreRowModel: getCoreRowModel(),
|
|
getFilteredRowModel: getFilteredRowModel(),
|
|
state: { globalFilter: search.trim() },
|
|
globalFilterFn: "includesString",
|
|
});
|
|
const selectCompany = onSelectCompany ?? setSelectedId;
|
|
if (selectedId && !onSelectCompany) {
|
|
return (
|
|
<CompanyDetail
|
|
csrfToken={csrfToken}
|
|
id={selectedId}
|
|
key={selectedId}
|
|
onBack={() => setSelectedId(undefined)}
|
|
/>
|
|
);
|
|
}
|
|
const companies = table.getRowModel().rows.map((row) => row.original);
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex flex-wrap items-start justify-between gap-4">
|
|
<div>
|
|
<h1 className="text-2xl font-semibold">{t("title")}</h1>
|
|
<p className="mt-2 text-muted-foreground">{t("help")}</p>
|
|
</div>
|
|
<Button onClick={() => setCreateOpen(true)}>{t("newCompany")}</Button>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor={id}>{t("search")}</Label>
|
|
<Input
|
|
className="max-w-md"
|
|
id={id}
|
|
onChange={(event) => setSearch(event.target.value)}
|
|
placeholder={t("searchPlaceholder")}
|
|
value={search}
|
|
/>
|
|
</div>
|
|
{query.isPending && <p role="status">{t("loading")}</p>}
|
|
<CompanyFeedback error={query.error} />
|
|
{query.isError && (
|
|
<Button
|
|
onClick={() => {
|
|
query.refetch().catch(() => undefined);
|
|
}}
|
|
variant="outline"
|
|
>
|
|
{t("retry")}
|
|
</Button>
|
|
)}
|
|
{query.data && (
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
{companies.length === 0 ? (
|
|
<p className="text-muted-foreground">{t(search ? "noResults" : "empty")}</p>
|
|
) : (
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>{t("name")}</TableHead>
|
|
<TableHead>{t("status")}</TableHead>
|
|
<TableHead>{t("actions")}</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{companies.map((company) => (
|
|
<TableRow key={company.id}>
|
|
<TableCell className="font-medium">{company.name}</TableCell>
|
|
<TableCell>{t(company.active ? "active" : "inactive")}</TableCell>
|
|
<TableCell>
|
|
<Button
|
|
onClick={() => selectCompany(company.id)}
|
|
size="sm"
|
|
variant="outline"
|
|
>
|
|
{t("open")}
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
<FormDialog
|
|
cancelLabel={t("cancel")}
|
|
formActions
|
|
onOpenChange={setCreateOpen}
|
|
open={createOpen}
|
|
title={t("newCompany")}
|
|
>
|
|
<CompanyForm
|
|
csrfToken={csrfToken}
|
|
onCreated={(companyId) => {
|
|
setCreateOpen(false);
|
|
selectCompany(companyId);
|
|
}}
|
|
showTitle={false}
|
|
/>
|
|
</FormDialog>
|
|
</div>
|
|
);
|
|
}
|