- Remove .prettierrc (dead config, Biome replaces Prettier) - Rename lighthouserc.json to lighthouserc.cjs with module.exports for ESM compat - Add logger.warn to empty catch blocks in auth, register, site-settings, prisma-cache, redis, security, rate-limit - Unify ActionResult type: action-helper.ts uses 'ok' consistent with safe-action-shared.ts - Add noUnusedLocals + noUnusedParameters to tsconfig + fix 25 pre-existing unused vars - Replace barrel export src/types/index.ts with direct @/types/common imports - Make trustHost conditional (development only) in auth.ts - Add pre-flight URL validation to update-Nitrov3.sh to catch image.library.url misconfigurations - Improve NITRO_IMAGE_LIBRARY_URL content validation in pre-flight & post-compute checks
91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useTranslations } from "next-intl";
|
|
import { DataTable } from "@/components/admin/data-table";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import type { DataTableColumn, PaginatedResult } from "@/types/common";
|
|
|
|
export interface TransactionRow {
|
|
id: number;
|
|
payer: string;
|
|
payerId: number;
|
|
amount: string;
|
|
package: string;
|
|
status: string;
|
|
statusKind: "ok" | "danger" | "neutral";
|
|
transactionId: string;
|
|
date: string;
|
|
}
|
|
|
|
function statusVariant(
|
|
kind: TransactionRow["statusKind"],
|
|
): "default" | "destructive" | "secondary" {
|
|
if (kind === "ok") return "default";
|
|
if (kind === "danger") return "destructive";
|
|
return "secondary";
|
|
}
|
|
|
|
export function TransactionsTable({
|
|
data,
|
|
}: {
|
|
data: PaginatedResult<TransactionRow>;
|
|
}) {
|
|
const t = useTranslations("pages.admin.transactions");
|
|
|
|
const columns: DataTableColumn<TransactionRow>[] = [
|
|
{ key: "id", label: t("colId"), sortable: true },
|
|
{
|
|
key: "payer",
|
|
label: t("colPayer"),
|
|
sortable: true,
|
|
render: (_value, row) => (
|
|
<Link
|
|
href={`/admin/users/${row.payerId}`}
|
|
className="font-medium hover:underline"
|
|
>
|
|
{row.payer}
|
|
</Link>
|
|
),
|
|
},
|
|
{ key: "amount", label: t("colAmount"), sortable: true },
|
|
{ key: "package", label: t("colPackage"), sortable: true },
|
|
{
|
|
key: "status",
|
|
label: t("colStatus"),
|
|
sortable: true,
|
|
filterKey: "filter_status",
|
|
filterOptions: [
|
|
{ label: t("statusCompleted"), value: "paid" },
|
|
{ label: t("statusPending"), value: "pending" },
|
|
{ label: t("statusFailed"), value: "failed" },
|
|
],
|
|
render: (_value, row) =>
|
|
row.status ? (
|
|
<Badge
|
|
variant={statusVariant(row.statusKind)}
|
|
className="font-mono text-[0.7rem]"
|
|
>
|
|
{row.status}
|
|
</Badge>
|
|
) : (
|
|
<span className="text-muted-foreground">—</span>
|
|
),
|
|
},
|
|
{ key: "transactionId", label: t("colTransaction") },
|
|
{ key: "date", label: t("colDate"), sortable: true },
|
|
];
|
|
|
|
return (
|
|
<DataTable
|
|
data={data}
|
|
columns={columns}
|
|
searchPlaceholder={t("searchPlaceholder")}
|
|
presets={[
|
|
{ label: t("presetPaid"), params: { filter_status: "paid" } },
|
|
{ label: t("presetFailed"), params: { filter_status: "failed" } },
|
|
]}
|
|
/>
|
|
);
|
|
}
|