import { useCallback, useState } from 'react'; import { getSikshyaApi, SIKSHYA_ENDPOINTS } from '../api'; import { EmbeddableShell } from '../components/shared/EmbeddableShell'; import { ApiErrorPanel } from '../components/shared/ApiErrorPanel'; import { ListPanel } from '../components/shared/list/ListPanel'; import { ListEmptyState } from '../components/shared/list/ListEmptyState'; import { RowActionsMenu, type RowActionItem } from '../components/shared/list/RowActionsMenu'; import { ButtonPrimary } from '../components/shared/buttons'; import { useSikshyaDialog } from '../components/shared/SikshyaDialogContext'; import { appViewHref } from '../lib/appUrl'; import { formatPostDate } from '../lib/formatPostDate'; import { useAsyncData } from '../hooks/useAsyncData'; import type { SikshyaReactConfig } from '../types'; import { __ } from '../lib/i18n'; type CertRow = { id: number; user_id: number; course_id: number; certificate_number: string; issued_date: string; status: string; verification_code: string; template_post_id: number | null; verify_url?: string; document_url?: string; }; type ListResponse = { ok?: boolean; certificates?: CertRow[]; page?: number; per_page?: number; }; export function IssuedCertificatesPage(props: { config: SikshyaReactConfig; title: string; embedded?: boolean }) { const { config, title, embedded } = props; const { confirm } = useSikshyaDialog(); const adminBase = config.adminUrl.replace(/\/?$/, '/'); const [page] = useState(1); const loader = useCallback(async () => { const q = new URLSearchParams({ page: String(page), per_page: '50' }); return getSikshyaApi().get(`${SIKSHYA_ENDPOINTS.admin.issuedCertificates}?${q.toString()}`); }, [page]); const { loading, data, error, refetch } = useAsyncData(loader, [page]); const rows = data?.certificates ?? []; const revoke = async (id: number) => { const ok = await confirm({ title: __('Revoke certificate?', 'sikshya'), message: __('This certificate will no longer verify publicly.', 'sikshya'), variant: 'danger', confirmLabel: __('Revoke', 'sikshya'), }); if (!ok) { return; } await getSikshyaApi().post(SIKSHYA_ENDPOINTS.admin.issuedCertificatesRevoke, { id }); refetch(); }; return ( refetch()}> Refresh } > {error ? (
refetch()} />
) : null} {loading ? (
{__('Loading…', 'sikshya')}
) : rows.length === 0 ? ( ) : (
{rows.map((r) => ( ))}
{__('Issued', 'sikshya')} {__('Learner', 'sikshya')} {__('Course', 'sikshya')} {__('Number', 'sikshya')} {__('Verification', 'sikshya')} {__('Status', 'sikshya')} {__('Actions', 'sikshya')}
{formatPostDate(r.issued_date)} User #{r.user_id} {`Course #${r.course_id}`} {r.certificate_number} {r.verify_url ? ( {r.verify_url} ) : r.verification_code ? ( {r.verification_code} ) : ( '—' )} {r.status} {r.status === 'active' ? ( revoke(r.id), danger: true, } satisfies RowActionItem, ]} ariaLabel={__('Certificate actions', 'sikshya')} /> ) : ( )}
)}
); }