Add payment module, BFF proxy, hub/dashboard/ops/PSP/merchant screens wired to real APIs, and mark payment-frontend complete in project status. Co-authored-by: Cursor <cursoragent@cursor.com>
78 lines
3.0 KiB
TypeScript
78 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { useTenantId } from "@/hooks/useTenantId";
|
|
import { paymentApi } from "@/modules/payment/services/payment-api";
|
|
import { usePaymentHealth, usePaymentMetrics } from "@/modules/payment/hooks/usePaymentCapabilities";
|
|
import { PaymentPageLoader, PaymentPageError } from "@/modules/payment/pages/shared";
|
|
import { PageHeader, Card, CardContent, Badge } from "@/components/ds";
|
|
import { PaymentStatCards } from "@/modules/payment/components/PaymentCharts";
|
|
|
|
export const PaymentMonitoring = function PaymentMonitoringPage() {
|
|
const { tenantId } = useTenantId();
|
|
const health = usePaymentHealth();
|
|
const metrics = usePaymentMetrics();
|
|
|
|
const opsQ = useQuery({
|
|
queryKey: ["payment", tenantId, "monitoring"],
|
|
queryFn: async () => {
|
|
const [requests, transactions] = await Promise.all([
|
|
paymentApi.requests.list(tenantId!),
|
|
paymentApi.transactions.list(tenantId!),
|
|
]);
|
|
const failed = requests.filter((r) => r.status === "failed").length;
|
|
const pending = requests.filter((r) =>
|
|
["pending", "redirect_issued"].includes(String(r.status))
|
|
).length;
|
|
return { failed, pending, requests: requests.length, transactions: transactions.length };
|
|
},
|
|
enabled: !!tenantId,
|
|
refetchInterval: 30_000,
|
|
});
|
|
|
|
if (!tenantId || health.isLoading || metrics.isLoading || opsQ.isLoading) {
|
|
return <PaymentPageLoader label="در حال بارگذاری مانیتورینگ…" />;
|
|
}
|
|
if (opsQ.error) return <PaymentPageError error={opsQ.error} onRetry={() => opsQ.refetch()} />;
|
|
|
|
const ops = opsQ.data!;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<PageHeader
|
|
title="مانیتورینگ"
|
|
description="سلامت سرویس و شاخصهای عملیاتی real-time."
|
|
actions={
|
|
<Badge tone={health.data?.status === "ok" ? "success" : "warning"}>
|
|
{health.data?.status ?? "—"}
|
|
</Badge>
|
|
}
|
|
/>
|
|
<PaymentStatCards
|
|
items={[
|
|
{ label: "وضعیت سرویس", value: health.data?.status ?? "—" },
|
|
{ label: "درخواستهای باز", value: ops.pending },
|
|
{ label: "ناموفق", value: ops.failed },
|
|
{ label: "تراکنش", value: ops.transactions },
|
|
]}
|
|
/>
|
|
<div className="grid gap-4 lg:grid-cols-2">
|
|
<Card>
|
|
<CardContent className="p-4 text-sm">
|
|
<h3 className="mb-2 font-semibold">Health</h3>
|
|
<pre className="text-xs">{JSON.stringify(health.data, null, 2)}</pre>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardContent className="p-4 text-sm">
|
|
<h3 className="mb-2 font-semibold">Metrics</h3>
|
|
<pre className="text-xs">{JSON.stringify(metrics.data?.metrics ?? {}, null, 2)}</pre>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PaymentMonitoring;
|