TorbatYar/frontend/modules/payment/features/monitoring.tsx
Mortezakoohjani 4451b32a33 feat(payment-frontend): ship Torbat Pay admin portal for MVP 14.0-14.5
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>
2026-07-27 18:35:07 +03:30

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;