diff --git a/src/routes/admin/coupon.tsx b/src/routes/admin/coupon.tsx index 895fba9..0ba539a 100644 --- a/src/routes/admin/coupon.tsx +++ b/src/routes/admin/coupon.tsx @@ -142,194 +142,196 @@ export default function CouponPage() { return ( -
-
-

Coupon Management

-

Reusable coupon codes for package checkout

+
+
+

Coupon Management

+

Reusable coupon codes for package checkout

+
+ + {/* Tabs */} +
+ + +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => ( + + + + + + + + + + )} + + + +
CodeTitleTypeValueMax UsesStatusActions
Loading...
Failed to load. Is the backend running?
No coupons found.
{item.code}{item.title || '—'}{item.type}{item.type === 'PERCENT' ? `${item.value}%` : `₹${item.value}`}{item.usage_limit != null ? item.usage_limit : '—'} + + {item.is_active ? 'Active' : 'Inactive'} + + +
+ + +
+
+
+
+
+ + +
+

{form().id ? 'Edit Coupon' : 'Create Coupon'}

+ +
{formError()}
+
+
+
+ + setForm({ ...form(), code: e.currentTarget.value.toUpperCase() })} + required + placeholder="e.g. SAVE10" + style="text-transform:uppercase" + /> +
+
+ + setForm({ ...form(), title: e.currentTarget.value })} + required + placeholder="e.g. 10% off for companies" + /> +
+
+
+ + +
+
+ + setForm({ ...form(), value: Number(e.currentTarget.value) })} + required + min="1" + /> +
+
+
+
+ + setForm({ ...form(), min_order_amount: Number(e.currentTarget.value) })} + min="0" + placeholder="0" + /> +
+
+ + setForm({ ...form(), max_uses: e.currentTarget.value })} + min="1" + placeholder="Unlimited" + /> +
+
+
+

Applicable Roles

+
+ + {(role) => { + const active = () => form().role_keys.includes(role); + return ( + + ); + }} + +
+
+
+ + + + +
+
+
+
- - {/* Tabs */} -
- - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => ( - - - - - - - - - - )} - - - -
CodeTitleTypeValueMax UsesStatusActions
Loading...
Failed to load. Is the backend running?
No coupons found.
{item.code}{item.title || '—'}{item.type}{item.type === 'PERCENT' ? `${item.value}%` : `₹${item.value}`}{item.usage_limit != null ? item.usage_limit : '—'} - - {item.is_active ? 'Active' : 'Inactive'} - - -
- - -
-
-
-
-
- - -
-

{form().id ? 'Edit Coupon' : 'Create Coupon'}

- -
{formError()}
-
-
-
- - setForm({ ...form(), code: e.currentTarget.value.toUpperCase() })} - required - placeholder="e.g. SAVE10" - style="text-transform:uppercase" - /> -
-
- - setForm({ ...form(), title: e.currentTarget.value })} - required - placeholder="e.g. 10% off for companies" - /> -
-
-
- - -
-
- - setForm({ ...form(), value: Number(e.currentTarget.value) })} - required - min="1" - /> -
-
-
-
- - setForm({ ...form(), min_order_amount: Number(e.currentTarget.value) })} - min="0" - placeholder="0" - /> -
-
- - setForm({ ...form(), max_uses: e.currentTarget.value })} - min="1" - placeholder="Unlimited" - /> -
-
-
-

Applicable Roles

-
- - {(role) => { - const active = () => form().role_keys.includes(role); - return ( - - ); - }} - -
-
-
- - - - -
-
-
-
); } diff --git a/src/routes/admin/credit.tsx b/src/routes/admin/credit.tsx index aa3c234..59fb55f 100644 --- a/src/routes/admin/credit.tsx +++ b/src/routes/admin/credit.tsx @@ -136,270 +136,273 @@ export default function CreditPage() { return ( -
-
-

Credit Management

-

Audit TraceCoin balances and adjust credits

+
+
+

Credit Management

+

Audit TraceCoin balances and adjust credits

-
- {/* Tabs */} -
- - {(tab) => ( - - )} - -
- - {/* Balance & Ledger Tab */} - -
-
-

Search Account Balance

-
- setUserId(e.currentTarget.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - style="flex:1;padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" - /> + {/* Tabs */} +
+ + {(tab) => ( -
- -
{searchError()}
-
-
+ )} + +
- -
-
-

Current Balance

-

{balance()} TraceCoins

-

User: {searchedUserId()}

-
- -
-

TraceCoin Ledger

- -

No transactions found for this account.

+
+ {/* Balance & Ledger Tab */} + +
+
+

Search Account Balance

+
+ setUserId(e.currentTarget.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + class="rounded-lg border border-gray-200 px-3 py-2 text-sm" + style="flex:1" + /> + +
+ +
{searchError()}
- 0}> -
- - - - - - - - - - - - - {(entry) => ( + + + +
+
+

Current Balance

+

{balance()} TraceCoins

+

User: {searchedUserId()}

+
+ +
+

TraceCoin Ledger

+ +

No transactions found for this account.

+
+ 0}> +
+
TypeAmountRef IDExpires AtDate
+ - - - - - + + + + + - )} - - -
- - {entry.transactionType} - - - {entry.transactionType === 'ADD' ? '+' : '-'}{entry.amount} - - {entry.referenceId ? entry.referenceId.substring(0, 18) : '—'} - - {entry.expiresAt ? new Date(entry.expiresAt).toLocaleDateString() : '—'} - - {entry.createdAt ? new Date(entry.createdAt).toLocaleString() : '—'} - TypeAmountRef IDExpires AtDate
+ + + + {(entry) => ( + + + + {entry.transactionType} + + + + {entry.transactionType === 'ADD' ? '+' : '-'}{entry.amount} + + + {entry.referenceId ? entry.referenceId.substring(0, 18) : '—'} + + + {entry.expiresAt ? new Date(entry.expiresAt).toLocaleDateString() : '—'} + + + {entry.createdAt ? new Date(entry.createdAt).toLocaleString() : '—'} + + + )} + + + +
+
+
+
+
+
+
+ + {/* Reward / Deduct Tab */} + +
+

Reward or Adjust TraceCoins

+

+ Use this to reward TraceCoins for a valid support case, process a refund, or correct a balance manually. +

+ +
+ {adjSuccess()} +
+
+ +
{adjError()}
+
+
+
+ + setAdjUserId(e.currentTarget.value)} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+
+ + setAdjAmount(Number(e.currentTarget.value))} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+ + +
+
+
+ + setAdjReason(e.currentTarget.value)} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+ + setAdjRefId(e.currentTarget.value)} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+ +
+
+
+
+ + {/* Reconcile Tab */} + +
+
+

Ledger Reconciliation

+ +
{reconError()}
+
+
+
+
+ + setReconFrom(e.currentTarget.value)} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+ + setReconTo(e.currentTarget.value)} + style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" + /> +
+
+
+ +
+
+
+ + + +

No discrepancies found.

+
+ 0}> +
+
+ + + + + + + + + + + + {(row) => ( + + + + + + + )} + + +
User IDExpected BalanceActual BalanceDiscrepancy
{row.userId}{row.expectedBalance}{row.actualBalance} + {row.discrepancy} +
+
- +
- - - {/* Reward / Deduct Tab */} - -
-

Reward or Adjust TraceCoins

-

- Use this to reward TraceCoins for a valid support case, process a refund, or correct a balance manually. -

- -
- {adjSuccess()} -
-
- -
{adjError()}
-
-
-
- - setAdjUserId(e.currentTarget.value)} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
-
- - setAdjAmount(Number(e.currentTarget.value))} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
- - -
-
-
- - setAdjReason(e.currentTarget.value)} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
- - setAdjRefId(e.currentTarget.value)} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
- -
-
-
-
- - {/* Reconcile Tab */} - -
-
-

Ledger Reconciliation

- -
{reconError()}
-
-
-
-
- - setReconFrom(e.currentTarget.value)} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
- - setReconTo(e.currentTarget.value)} - style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box" - /> -
-
-
- -
-
-
- - - -

No discrepancies found.

-
- 0}> -
-
- - - - - - - - - - - - {(row) => ( - - - - - - - )} - - -
User IDExpected BalanceActual BalanceDiscrepancy
{row.userId}{row.expectedBalance}{row.actualBalance} - {row.discrepancy} -
-
-
-
-
-
-
+
); } diff --git a/src/routes/admin/discount.tsx b/src/routes/admin/discount.tsx index 0702084..93db228 100644 --- a/src/routes/admin/discount.tsx +++ b/src/routes/admin/discount.tsx @@ -146,194 +146,196 @@ export default function DiscountPage() { return ( -
-
-

Discount Management

-

Automatic discounts applied before coupons

+
+
+

Discount Management

+

Automatic discounts applied before coupons

+
+ + {/* Tabs */} +
+ + +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => ( + + + + + + + + + + )} + + + +
TitleScopeTargetTypeValueStatusActions
Loading...
Failed to load. Is the backend running?
No discounts found.
{item.title || '—'}{item.scope}{getTarget(item)}{item.type}{item.type === 'PERCENT' ? `${item.value}%` : `₹${item.value}`} + + {item.is_active ? 'Active' : 'Inactive'} + + +
+ +
+
+
+
+
+ + +
+

{form().id ? 'Edit Discount' : 'Create Discount'}

+ +
{formError()}
+
+
+
+ + setForm({ ...form(), title: e.currentTarget.value })} + required + placeholder="e.g. New user 10% off" + /> +
+
+ +
+ + +
+
+
+ + + + + + + +
+
+
+ + +
+
+ + setForm({ ...form(), value: Number(e.currentTarget.value) })} + required + min="1" + /> +
+
+
+ + + + +
+
+
+
- - {/* Tabs */} -
- - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => ( - - - - - - - - - - )} - - - -
TitleScopeTargetTypeValueStatusActions
Loading...
Failed to load. Is the backend running?
No discounts found.
{item.title || '—'}{item.scope}{getTarget(item)}{item.type}{item.type === 'PERCENT' ? `${item.value}%` : `₹${item.value}`} - - {item.is_active ? 'Active' : 'Inactive'} - - -
- -
-
-
-
-
- - -
-

{form().id ? 'Edit Discount' : 'Create Discount'}

- -
{formError()}
-
-
-
- - setForm({ ...form(), title: e.currentTarget.value })} - required - placeholder="e.g. New user 10% off" - /> -
-
- -
- - -
-
-
- - - - - - - -
-
-
- - -
-
- - setForm({ ...form(), value: Number(e.currentTarget.value) })} - required - min="1" - /> -
-
-
- - - - -
-
-
-
); } diff --git a/src/routes/admin/invoice.tsx b/src/routes/admin/invoice.tsx index 77769e2..7f37a18 100644 --- a/src/routes/admin/invoice.tsx +++ b/src/routes/admin/invoice.tsx @@ -32,87 +32,90 @@ export default function InvoicePage() { return ( -
-
-

Invoice Management

-

View and download all platform invoices.

+
+
+

Invoice Management

+

View and download all platform invoices.

-
-
- setSearch(e.currentTarget.value)} - style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;min-width:320px" - /> -
+
+
+ setSearch(e.currentTarget.value)} + class="rounded-lg border border-gray-200 px-3 py-2 text-sm" + style="min-width:320px" + /> +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - 0}> - {filteredInvoices().map((item) => ( +
+
+
Invoice #UserPackageTotal (₹)Tax (₹)StatusDateActions
Loading...
Failed to load. Is the backend running?
No records found.
+ - - - - - - - - + + + + + + + + - ))} - - -
{item.invoice_number || item.id}{item.user_id || '—'}{item.package_name || '—'}₹{item.total != null ? (item.total / 100).toFixed(2) : '—'}₹{item.tax != null ? (item.tax / 100).toFixed(2) : '—'} - - {item.status || '—'} - - {item.created_at ? new Date(item.created_at).toLocaleString() : '—'} -
- - - Download - - - - - -
-
Invoice #UserPackageTotal (₹)Tax (₹)StatusDateActions
+ + + + Loading... + + + Failed to load. Is the backend running? + + + No records found. + + 0}> + {filteredInvoices().map((item) => ( + + {item.invoice_number || item.id} + {item.user_id || '—'} + {item.package_name || '—'} + ₹{item.total != null ? (item.total / 100).toFixed(2) : '—'} + ₹{item.tax != null ? (item.tax / 100).toFixed(2) : '—'} + + + {item.status || '—'} + + + {item.created_at ? new Date(item.created_at).toLocaleString() : '—'} + +
+ + + Download + + + + + +
+ + + ))} +
+ + +
+
- +
); } diff --git a/src/routes/admin/jobs.tsx b/src/routes/admin/jobs.tsx index 3e1b385..ea248b8 100644 --- a/src/routes/admin/jobs.tsx +++ b/src/routes/admin/jobs.tsx @@ -63,95 +63,97 @@ export default function JobsPage() { return ( -
-
-

Jobs Management

-

Review live company job postings

+
+
+

Jobs Management

+

Review live company job postings

+
+ +
+
+ setSearch(e.currentTarget.value)} + style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;min-width:260px" + /> + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(job) => ( + + + + + + + + + + )} + + + +
TitleSkillsCompany / ClientRateLocationStatusActions
Loading...
Failed to load. Is the backend running?
No jobs found.
+
{job.title || '—'}
+ +
+ {job.description} +
+
+
+ {job.required_skills?.join(', ') || job.experience_level || '—'} + {job.client_name || job.company_name || '—'} + {job.hourly_rate_min != null + ? `₹${job.hourly_rate_min}–₹${job.hourly_rate_max ?? job.hourly_rate_min}/hr` + : '—'} + {job.location || '—'} + {job.status || '—'} + +
+ View + + Review + +
+
+
+
- -
- setSearch(e.currentTarget.value)} - style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;min-width:260px" - /> - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(job) => ( - - - - - - - - - - )} - - - -
TitleSkillsCompany / ClientRateLocationStatusActions
Loading...
Failed to load. Is the backend running?
No jobs found.
-
{job.title || '—'}
- -
- {job.description} -
-
-
- {job.required_skills?.join(', ') || job.experience_level || '—'} - {job.client_name || job.company_name || '—'} - {job.hourly_rate_min != null - ? `₹${job.hourly_rate_min}–₹${job.hourly_rate_max ?? job.hourly_rate_min}/hr` - : '—'} - {job.location || '—'} - {job.status || '—'} - -
- View - - Review - -
-
-
-
); } diff --git a/src/routes/admin/leads.tsx b/src/routes/admin/leads.tsx index 9f7225b..0149caa 100644 --- a/src/routes/admin/leads.tsx +++ b/src/routes/admin/leads.tsx @@ -49,107 +49,109 @@ export default function LeadsPage() { return ( -
-
-

Leads Management

-

View all requirements and lead requests from customers.

+
+
+

Leads Management

+

View all requirements and lead requests from customers.

+
+ +
+ {/* Filters */} +
+ setSearch(e.currentTarget.value)} + style="border:1px solid #cbd5e1;border-radius:8px;padding:8px 12px;font-size:14px;outline:none;min-width:220px;flex:1;max-width:320px" + /> + + + + {filtered().length} result{filtered().length !== 1 ? 's' : ''} + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => ( + + + + + + + + + )} + + + +
TitleRoleBudgetLocationStatusActions
Loading leads...
Failed to load. Is the backend running?
No leads found.
+
{item.title || '—'}
+ +
+ {String(item.description).slice(0, 60)}{String(item.description).length > 60 ? '…' : ''} +
+
+
{item.profession || item.role || '—'} + {item.budget_range || (item.budget_min != null ? `₹${item.budget_min}–₹${item.budget_max}` : '—')} + {item.location || '—'} + + {item.status || '—'} + + +
+ View +
+
+
+
- - {/* Filters */} -
- setSearch(e.currentTarget.value)} - style="border:1px solid #cbd5e1;border-radius:8px;padding:8px 12px;font-size:14px;outline:none;min-width:220px;flex:1;max-width:320px" - /> - - - - {filtered().length} result{filtered().length !== 1 ? 's' : ''} - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => ( - - - - - - - - - )} - - - -
TitleRoleBudgetLocationStatusActions
Loading leads...
Failed to load. Is the backend running?
No leads found.
-
{item.title || '—'}
- -
- {String(item.description).slice(0, 60)}{String(item.description).length > 60 ? '…' : ''} -
-
-
{item.profession || item.role || '—'} - {item.budget_range || (item.budget_min != null ? `₹${item.budget_min}–₹${item.budget_max}` : '—')} - {item.location || '—'} - - {item.status || '—'} - - -
- View -
-
-
-
); } diff --git a/src/routes/admin/ledger.tsx b/src/routes/admin/ledger.tsx index bc3ecb8..21becfe 100644 --- a/src/routes/admin/ledger.tsx +++ b/src/routes/admin/ledger.tsx @@ -56,63 +56,65 @@ export default function LedgerPage() { return ( -
-
-

Ledger Management

-

Platform financial ledger

+
+
+

Ledger Management

+

Platform financial ledger

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => { + const entryType = item.entry_type || item.type || '—'; + return ( + + + + + + + + + + ); + }} + + + +
TypeOrder IDInvoice IDUser IDAmountNoteDate
Loading...
Failed to load. Is the backend running?
No ledger entries found.
+ + {entryType} + + {item.order_id || '—'}{item.invoice_id || '—'}{item.user_id || '—'}{formatAmount(item)}{item.note || '—'}{item.created_at ? new Date(item.created_at).toLocaleString() : '—'}
+
+
- -
-
- - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => { - const entryType = item.entry_type || item.type || '—'; - return ( - - - - - - - - - - ); - }} - - - -
TypeOrder IDInvoice IDUser IDAmountNoteDate
Loading...
Failed to load. Is the backend running?
No ledger entries found.
- - {entryType} - - {item.order_id || '—'}{item.invoice_id || '—'}{item.user_id || '—'}{formatAmount(item)}{item.note || '—'}{item.created_at ? new Date(item.created_at).toLocaleString() : '—'}
-
-
); } diff --git a/src/routes/admin/notifications.tsx b/src/routes/admin/notifications.tsx index 67f91e6..d38141d 100644 --- a/src/routes/admin/notifications.tsx +++ b/src/routes/admin/notifications.tsx @@ -83,105 +83,113 @@ export default function NotificationsPage() { return ( -
-
-

Notifications

-

Approval outcomes and action-required updates

-
- -
- - {/* Tabs */} -
- - -
- -
-
- - - - - - - - - - - - - - - - - - - {(item) => ( - - - - - - - - )} - - -
TitleMessageEvent TypeCreated AtActions
Loading...
No notifications.
{item.title}{truncate(item.message, 80)} - - {item.event_type} - - - {item.created_at ? new Date(item.created_at).toLocaleString() : '—'} - -
- - - -
-
-
-
- - 0}> -

Loading...

-
- - -
+
+
+
+

Notifications

+

Approval outcomes and action-required updates

+
- + + {/* Tabs */} +
+ + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + {(item) => ( + + + + + + + + )} + + +
TitleMessageEvent TypeCreated AtActions
Loading...
No notifications.
{item.title}{truncate(item.message, 80)} + + {item.event_type} + + + {item.created_at ? new Date(item.created_at).toLocaleString() : '—'} + +
+ + + +
+
+
+
+ + 0}> +

Loading...

+
+ + +
+ +
+
+
+
); } diff --git a/src/routes/admin/order.tsx b/src/routes/admin/order.tsx index 7eccd25..89769fa 100644 --- a/src/routes/admin/order.tsx +++ b/src/routes/admin/order.tsx @@ -70,75 +70,78 @@ export default function OrderPage() { return ( -
-
-

Order Management

-

TraceCoin package purchase orders

+
+
+

Order Management

+

TraceCoin package purchase orders

+
+ +
+
+ setSearch(e.currentTarget.value)} + class="rounded-lg border border-gray-200 px-3 py-2 text-sm" + style="width:100%;max-width:420px" + /> +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => ( + + + + + + + + + + + )} + + + +
Order #UserPackageTraceCoinsCouponTotalStatusCreated At
Loading...
Failed to load. Is the backend running?
No orders found.
{item.order_number || item.id}{item.user_name || item.user_email || '—'}{item.package_name || '—'}{item.tracecoin_amount ?? '—'}{item.coupon_code || '—'}{formatAmount(item)} + + {item.status || '—'} + + {item.created_at ? new Date(item.created_at).toLocaleString() : '—'}
+
+
- -
- setSearch(e.currentTarget.value)} - style="width:100%;max-width:420px;padding:8px 12px;border:1px solid #e2e8f0;border-radius:8px;font-size:14px" - /> -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => ( - - - - - - - - - - - )} - - - -
Order #UserPackageTraceCoinsCouponTotalStatusCreated At
Loading...
Failed to load. Is the backend running?
No orders found.
{item.order_number || item.id}{item.user_name || item.user_email || '—'}{item.package_name || '—'}{item.tracecoin_amount ?? '—'}{item.coupon_code || '—'}{formatAmount(item)} - - {item.status || '—'} - - {item.created_at ? new Date(item.created_at).toLocaleString() : '—'}
-
-
); } diff --git a/src/routes/admin/pricing.tsx b/src/routes/admin/pricing.tsx index cca1f84..79fc920 100644 --- a/src/routes/admin/pricing.tsx +++ b/src/routes/admin/pricing.tsx @@ -150,212 +150,214 @@ export default function PricingPage() { return ( -
-
-

Pricing Management

-

Create and manage TraceCoin packages

+
+
+

Pricing Management

+

Create and manage TraceCoin packages

+
+ + {/* Tabs */} +
+ + +
+ +
+ {/* Packages list tab */} + +
+
+ + + + + + + + + + + + + + + + + + + + + + + 0}> + + {(pkg) => ( + <> + + + + + + + + + + + + + + + + )} + + + +
NameRoleTraceCoinsPrice (₹)Bonus (%)StatusActions
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" + /> +
+
+ +
+
+
+
- - {/* Tabs */} -
- - -
- - {/* Packages list tab */} - -
-
- - - - - - - - - - - - - - - - - - - - - - - 0}> - - {(pkg) => ( - <> - - - - - - - - - - - - - - - - )} - - - -
NameRoleTraceCoinsPrice (₹)Bonus (%)StatusActions
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" - /> -
-
- -
-
-
-
); } diff --git a/src/routes/admin/report.tsx b/src/routes/admin/report.tsx index 6e9496a..cc6c309 100644 --- a/src/routes/admin/report.tsx +++ b/src/routes/admin/report.tsx @@ -46,75 +46,77 @@ export default function ReportPage() { return ( -
-
-

Report Management

-

View platform analytics and generate reports.

+
+
+

Report Management

+

View platform analytics and generate reports.

+
+ +
+
+

Date Range

+
+
+ + setFrom(e.currentTarget.value)} + required + style="padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" + /> +
+
+ + setTo(e.currentTarget.value)} + required + style="padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" + /> +
+ +
+ +
{error()}
+
+
+ + +
+
+

Total Users

+

{userReport()?.total_users ?? '—'}

+
+
+

New Users

+

{userReport()?.new_users ?? '—'}

+
+
+

Active Users

+

{userReport()?.active_users ?? '—'}

+
+
+

Total Revenue

+

+ {revenueReport()?.total_revenue != null ? `₹${(revenueReport()!.total_revenue! / 100).toFixed(2)}` : '—'} +

+
+
+

Total Orders

+

{revenueReport()?.total_orders ?? '—'}

+
+
+

TraceCoins Sold

+

{revenueReport()?.total_tracecoins_sold ?? '—'}

+
+
+
- -
-

Date Range

-
-
- - setFrom(e.currentTarget.value)} - required - style="padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" - /> -
-
- - setTo(e.currentTarget.value)} - required - style="padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px" - /> -
- -
- -
{error()}
-
-
- - -
-
-

Total Users

-

{userReport()?.total_users ?? '—'}

-
-
-

New Users

-

{userReport()?.new_users ?? '—'}

-
-
-

Active Users

-

{userReport()?.active_users ?? '—'}

-
-
-

Total Revenue

-

- {revenueReport()?.total_revenue != null ? `₹${(revenueReport()!.total_revenue! / 100).toFixed(2)}` : '—'} -

-
-
-

Total Orders

-

{revenueReport()?.total_orders ?? '—'}

-
-
-

TraceCoins Sold

-

{revenueReport()?.total_tracecoins_sold ?? '—'}

-
-
-
); } diff --git a/src/routes/admin/review.tsx b/src/routes/admin/review.tsx index fdbff8b..81a5919 100644 --- a/src/routes/admin/review.tsx +++ b/src/routes/admin/review.tsx @@ -120,199 +120,205 @@ export default function ReviewPage() { return ( -
-
-

Review Management

-

Moderate platform reviews

+
+
+

Review Management

+

Moderate platform reviews

-
- {/* Tabs */} -
- - -
- - -
- setSearch(e.currentTarget.value)} - style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;min-width:320px" - /> + {/* Tabs */} +
+ +
-
-
- - - - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => { - const subjectType = item.subject_type || '—'; - const isPublished = item.status === 'PUBLISHED'; - return ( - - - - - - - - - ); - }} - - - -
ReviewerTypeRatingTitleStatusActions
Loading...
Failed to load. Is the backend running?
No reviews found.
{item.reviewer_name || item.reviewer_id || '—'} - - {subjectType} - - - {item.rating != null ? `⭐ ${item.rating}` : '—'} - {item.title || '—'} - - {isPublished ? 'Published' : 'Hidden'} - - -
- - - - - - -
-
-
-
- - -
-

Create Review

- -
{formError()}
+
+ +
+ setSearch(e.currentTarget.value)} + style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;min-width:320px" + /> +
+
+
+ + + + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => { + const subjectType = item.subject_type || '—'; + const isPublished = item.status === 'PUBLISHED'; + return ( + + + + + + + + + ); + }} + + + +
ReviewerTypeRatingTitleStatusActions
Loading...
Failed to load. Is the backend running?
No reviews found.
{item.reviewer_name || item.reviewer_id || '—'} + + {subjectType} + + + {item.rating != null ? `⭐ ${item.rating}` : '—'} + {item.title || '—'} + + {isPublished ? 'Published' : 'Hidden'} + + +
+ + + + + + +
+
+
+
-
-
- - -
-
- - setForm({ ...form(), subject_id: e.currentTarget.value })} - placeholder="e.g. general or package UUID" - /> -
-
- - setForm({ ...form(), reviewer_name: e.currentTarget.value })} - required - placeholder="Full name" - /> -
-
- - -
-
- - setForm({ ...form(), title: e.currentTarget.value })} - required - placeholder="Review title" - /> -
-
- -