import { createResource, createSignal, Show, For } from 'solid-js'; import AdminShell from '~/components/AdminShell'; const API = '/api/gateway'; type Package = { id: string; name: string; role: string; tracecoin_amount: number; price_inr: number; bonus_percentage?: number; is_active: boolean; }; const ROLES = [ 'company', 'customer', 'job_seeker', 'photographer', 'video_editor', 'graphic_designer', 'social_media_manager', 'fitness_trainer', 'catering_services', 'makeup_artist', 'tutor', 'developer', ]; async function loadPackages(): Promise { try { const res = await fetch(`${API}/api/admin/tracecoin-packages`); if (!res.ok) throw new Error('Failed to load'); const data = await res.json(); return Array.isArray(data) ? data : (data.packages || []); } catch { return []; } } export default function PricingPage() { const [packages, { refetch }] = createResource(loadPackages); const [view, setView] = createSignal<'packages' | 'create'>('packages'); // Inline edit state const [editingId, setEditingId] = createSignal(''); const [editName, setEditName] = createSignal(''); const [editTracecoins, setEditTracecoins] = createSignal(''); const [editPrice, setEditPrice] = createSignal(''); const [editSaving, setEditSaving] = createSignal(false); const [editError, setEditError] = createSignal(''); // Toggle active state const [togglingId, setTogglingId] = createSignal(''); // Create form state const [cName, setCName] = createSignal(''); const [cRole, setCRole] = createSignal(ROLES[0]); const [cTracecoins, setCTracecoins] = createSignal(''); const [cPrice, setCPrice] = createSignal(''); const [cBonus, setCBonus] = createSignal(''); const [cSaving, setCsaving] = createSignal(false); const [cError, setCError] = createSignal(''); const startEdit = (pkg: Package) => { setEditingId(pkg.id); setEditName(pkg.name); setEditTracecoins(String(pkg.tracecoin_amount)); setEditPrice(String(pkg.price_inr)); setEditError(''); }; const cancelEdit = () => { setEditingId(''); setEditError(''); }; const saveEdit = async (id: string) => { try { setEditSaving(true); setEditError(''); const res = await fetch(`${API}/api/admin/tracecoin-packages/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: editName(), tracecoin_amount: Number(editTracecoins()), price_inr: Number(editPrice()), }), }); if (!res.ok) throw new Error('Failed to save'); setEditingId(''); refetch(); } catch (err: any) { setEditError(err.message || 'Failed to save'); } finally { setEditSaving(false); } }; const toggleActive = async (pkg: Package) => { try { setTogglingId(pkg.id); const res = await fetch(`${API}/api/admin/tracecoin-packages/${pkg.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ is_active: !pkg.is_active }), }); if (!res.ok) throw new Error('Failed to update'); refetch(); } catch { // ignore } finally { setTogglingId(''); } }; const handleCreate = async (e: Event) => { e.preventDefault(); try { setCsaving(true); setCError(''); const body: Record = { name: cName(), role: cRole(), tracecoin_amount: Number(cTracecoins()), price_inr: Number(cPrice()), }; if (cBonus()) body.bonus_percentage = Number(cBonus()); const res = await fetch(`${API}/api/admin/tracecoin-packages`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) throw new Error('Failed to create package'); setCName(''); setCRole(ROLES[0]); setCTracecoins(''); setCPrice(''); setCBonus(''); setView('packages'); refetch(); } catch (err: any) { setCError(err.message || 'Failed to create'); } finally { setCsaving(false); } }; return (

Pricing Management

Create and manage TraceCoin packages

{/* Tabs */}
{/* Packages list tab */}
0}> {(pkg) => ( <> )}
Name Role TraceCoins Price (₹) Bonus (%) Status Actions
Loading...
Failed to load. Is the backend running?
No packages found.
{pkg.name} {pkg.role} {pkg.tracecoin_amount} ₹{(pkg.price_inr / 100).toFixed(2)} {pkg.bonus_percentage != null ? `${pkg.bonus_percentage}%` : '—'} {pkg.is_active ? 'Active' : 'Inactive'}
{editError()}
setEditName(e.currentTarget.value)} style="padding:7px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:13px;width:180px" />
setEditTracecoins(e.currentTarget.value)} style="padding:7px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:13px;width:110px" />
setEditPrice(e.currentTarget.value)} style="padding:7px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:13px;width:110px" />
{/* Create Package tab */}

New Package

{cError()}
setCName(e.currentTarget.value)} required placeholder="e.g. Starter Pack" style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" />
setCTracecoins(e.currentTarget.value)} required min="1" placeholder="e.g. 100" style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" />
setCPrice(e.currentTarget.value)} required min="1" placeholder="e.g. 49900" style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" />
setCBonus(e.currentTarget.value)} min="0" placeholder="e.g. 10" style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" />
); }