Ship the full Communication portal (real SMS API, feature-locked future channels), BFF proxy, docs, snapshot, and phase handover. Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
2.6 KiB
TypeScript
54 lines
2.6 KiB
TypeScript
"use client";
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import { communicationApi } from "@/modules/communication/services/communication-api";
|
||
import { useTenantId } from "@/hooks/useTenantId";
|
||
import { useCommunicationMonitoring } from "@/modules/communication/hooks/useCommunicationCapabilities";
|
||
import { CommunicationPageLoader, CommunicationPageError } from "@/modules/communication/pages/shared";
|
||
import { PageHeader, StatCard, Card, CardContent } from "@/components/ds";
|
||
import { CommunicationBreadcrumbs } from "@/modules/communication/components/CommunicationBreadcrumbs";
|
||
import { CommunicationStatusChip } from "@/modules/communication/design-system";
|
||
|
||
export function ProviderDashboard() {
|
||
const { tenantId } = useTenantId();
|
||
const monitoring = useCommunicationMonitoring(tenantId);
|
||
const statusQ = useQuery({
|
||
queryKey: ["communication", tenantId, "provider-status"],
|
||
queryFn: () => communicationApi.providers.status(tenantId!),
|
||
enabled: !!tenantId,
|
||
});
|
||
|
||
if (!tenantId || statusQ.isLoading) return <CommunicationPageLoader />;
|
||
if (statusQ.error) return <CommunicationPageError error={statusQ.error} onRetry={() => statusQ.refetch()} />;
|
||
|
||
const rows = statusQ.data ?? [];
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<CommunicationBreadcrumbs current="داشبورد ارائهدهندگان" parent={{ href: "/communication/sms/providers", label: "SMS" }} />
|
||
<PageHeader title="داشبورد ارائهدهندگان" description="سلامت circuit، balance و failover" />
|
||
<div className="grid gap-4 sm:grid-cols-3">
|
||
<StatCard label="کل" value={String(rows.length)} />
|
||
<StatCard label="سالم" value={String(rows.filter((r) => r.healthy).length)} />
|
||
<StatCard label="Deferrals" value={String(monitoring.data?.rate_limit_deferrals ?? 0)} />
|
||
</div>
|
||
<Card>
|
||
<CardContent className="divide-y divide-[var(--border)] p-0">
|
||
{rows.map((p) => (
|
||
<div key={String(p.id)} className="flex flex-wrap items-center justify-between gap-2 p-4 text-sm">
|
||
<div>
|
||
<p className="font-medium">{String(p.name)}</p>
|
||
<p className="text-xs text-[var(--muted)]">{String(p.provider_kind)} · {String(p.channel)}</p>
|
||
</div>
|
||
<CommunicationStatusChip status={String(p.status)} />
|
||
</div>
|
||
))}
|
||
{rows.length === 0 ? <p className="p-4 text-sm text-[var(--muted)]">ارائهدهندهای ثبت نشده</p> : null}
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default ProviderDashboard;
|