import { useCallback, useState } from 'react'; import { getSikshyaApi, SIKSHYA_ENDPOINTS } from '../api'; import { EmbeddableShell } from '../components/shared/EmbeddableShell'; import { ApiErrorPanel } from '../components/shared/ApiErrorPanel'; import { ButtonPrimary } from '../components/shared/buttons'; import { useSikshyaDialog } from '../components/shared/SikshyaDialogContext'; import { TopRightToast, useTopRightToast } from '../components/shared/TopRightToast'; import type { SikshyaReactConfig } from '../types'; import { __ } from '../lib/i18n'; type ToolsTab = 'status' | 'export' | 'maintenance'; function downloadJson(filename: string, data: unknown) { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } const TAB_BTN = 'rounded-xl px-4 py-2.5 text-sm font-semibold transition-colors border border-transparent'; const TAB_ACTIVE = 'bg-brand-600 text-white shadow-sm dark:bg-brand-500'; const TAB_IDLE = 'bg-slate-100 text-slate-700 hover:bg-slate-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700'; export function ToolsPage(props: { config: SikshyaReactConfig; title: string; embedded?: boolean }) { const { config, title, embedded } = props; const { confirm } = useSikshyaDialog(); const [tab, setTab] = useState('status'); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const toast = useTopRightToast(); const [systemRows, setSystemRows] = useState | null>(null); const [exportKind, setExportKind] = useState< 'settings' | 'courses' | 'certificates' | 'lessons' | 'quizzes' | 'assignments' | 'questions' | 'chapters' >('settings'); const [importText, setImportText] = useState(''); const [importOverwrite, setImportOverwrite] = useState(false); const runTool = useCallback(async (body: Record) => { setBusy(true); setError(null); toast.clear(); try { const res = await getSikshyaApi().post<{ success?: boolean; message?: string; data?: unknown; }>(SIKSHYA_ENDPOINTS.admin.tools, body); if (!res?.success) { throw new Error(res?.message || 'Request failed'); } return res; } catch (e) { setError(e); throw e; } finally { setBusy(false); } }, []); const loadSystemInfo = () => { void runTool({ action_type: 'system_info' }) .then((res) => { const data = res.data as Record | undefined; if (data && typeof data === 'object') { setSystemRows(data); } toast.success(__('Done', 'sikshya'), res.message ?? 'System information loaded.'); }) .catch(() => void 0); }; const clearCache = () => { void runTool({ action_type: 'clear_cache' }) .then((res) => toast.success(__('Done', 'sikshya'), res.message ?? 'Done.')) .catch(() => void 0); }; const importSampleLms = () => { void (async () => { const ok = await confirm({ title: __('Import sample courses?', 'sikshya'), message: __('This creates published sample courses, chapters, lessons, quizzes, and questions from the bundled JSON pack. Safe to run on a staging site; avoid duplicates on production if you already imported once.', 'sikshya'), variant: 'default', confirmLabel: __('Import sample data', 'sikshya'), }); if (!ok) { return; } void runTool({ action_type: 'import_sample_data', pack: 'default' }) .then((res) => { const data = res.data as { counts?: Record } | undefined; const c = data?.counts; const bits = c ? Object.entries(c) .map(([k, v]) => `${k}: ${v}`) .join(', ') : ''; toast.success(__('Done', 'sikshya'), bits ? `${res.message ?? 'Done.'} (${bits})` : (res.message ?? 'Done.')); }) .catch(() => void 0); })(); }; const resetPluginSettings = () => { void (async () => { const ok = await confirm({ title: __('Reset all settings?', 'sikshya'), message: __('Reset every Sikshya setting to its default? This cannot be undone.', 'sikshya'), variant: 'danger', confirmLabel: __('Reset everything', 'sikshya'), }); if (!ok) { return; } void runTool({ action_type: 'reset_settings' }) .then((res) => toast.success(__('Done', 'sikshya'), res.message ?? 'Done.')) .catch(() => void 0); })(); }; const exportPayload = () => { if (exportKind === 'settings') { void runTool({ action_type: 'export_settings' }) .then((res) => { downloadJson(`sikshya-settings-${new Date().toISOString().slice(0, 10)}.json`, res.data ?? {}); toast.success(__('Download started', 'sikshya'), res.message ?? 'Download started.'); }) .catch(() => void 0); return; } void runTool({ action_type: 'export_data', export_type: exportKind }) .then((res) => { downloadJson(`sikshya-export-${exportKind}-${new Date().toISOString().slice(0, 10)}.json`, { export_type: exportKind, exported_at: new Date().toISOString(), items: res.data ?? [], }); toast.success(__('Download started', 'sikshya'), res.message ?? 'Download started.'); }) .catch(() => void 0); }; const importSettings = () => { let parsed: unknown; try { parsed = JSON.parse(importText.trim()); } catch { setError(new Error('Invalid JSON. Paste a settings export file.')); return; } if (!parsed || typeof parsed !== 'object') { setError(new Error('Settings JSON must be an object.')); return; } void runTool({ action_type: 'import_settings', settings: parsed, overwrite: importOverwrite, }) .then((res) => toast.success(__('Import finished', 'sikshya'), res.message ?? 'Import finished.')) .catch(() => void 0); }; return ( {config.setupWizardUrl ? (

{__('Setup wizard', 'sikshya')}

Configure storefront permalinks and learning URL style. You can return here anytime from Tools.

) : null}
{( [ ['status', 'System status'], ['export', 'Export / import'], ['maintenance', 'Maintenance'], ] as const ).map(([id, label]) => ( ))}
{error ? (
setError(null)} />
) : null} {tab === 'status' ? (

{__('Environment', 'sikshya')}

Load WordPress, PHP, database, and theme summary. Nothing is changed until you run a maintenance action.

loadSystemInfo()}> {busy ? __('Loading…', 'sikshya') : __('Load system info', 'sikshya')}
{systemRows ? (
{Object.entries(systemRows).map(([k, v]) => (
{k.replace(/_/g, ' ')}
{String(v)}
))}
) : null}
) : null} {tab === 'export' ? (

{__('Export', 'sikshya')}

Download JSON for backups or staging. Content exports include titles, HTML bodies, and Sikshya meta keys.

exportPayload()}> Download JSON

{__('Import settings', 'sikshya')}

Paste JSON from a settings export. Empty values are only overwritten when you enable the option below.