diff --git a/src/routes/admin/approval.tsx b/src/routes/admin/approval.tsx index bb6d5c9..8258bbd 100644 --- a/src/routes/admin/approval.tsx +++ b/src/routes/admin/approval.tsx @@ -676,396 +676,375 @@ export default function ApprovalPage() { return (
- - {/* ── Page header ── */} -
-

Approval Management

-

Review, approve, reject and configure approval workflows.

-
- - {/* ── Status tabs ── */} -
- - {(t) => { - const count = countFor(t.key); - return ( +
+ {/* Header */} +
+
+

Approval Management

+

Review, approve, reject and configure approval workflows.

+
+
- ); - }} - -
- -
- - -
{actionError()}
-
- -
{String((approvals.error as any)?.message || approvals.error)}
-
- - -
-
-
- Pending Jobs: {summary().jobs} - Pending Requirements: {summary().requirements} - Pending Profiles: {summary().profilePending} - Total Pending: {summary().totalPending}
- -
- -

- No pending approval requests are available right now. New submissions will appear here automatically. -

-
- -

- Current backend feed returns pending requests only for Approval Management. -

-
-
-
- - {/* ── Approval List / Detail ── */} - - - {/* Filter bar */} -
- { setSearch(e.currentTarget.value); setCurrentPage(1); }} - style="border:1px solid #cbd5e1;border-radius:6px;padding:7px 12px;font-size:14px;width:280px;outline:none" - /> - - - {filteredApprovals().length} record{filteredApprovals().length !== 1 ? 's' : ''}
-
-
- - - - - - - - - - - - - - - - - - - - 0}> - - {(item) => { - const status = statusValue(item); - const docRemark = latestDocumentRequest(item); - const isDocRequest = !!docRemark && status === 'CHANGES_REQUESTED'; - const dest = managementDestination(item._roleType || 'UNKNOWN'); - const isActing = acting().startsWith(item.id); - return ( - - - - - - - ); - }} - - - -
RequesterTypeRequest CategoryDocument RequestStatusSubmittedActions
Loading approvals...
{activeTab() === 'PENDING' ? 'No pending approvals right now.' : `No ${activeTab().toLowerCase().replace('_', ' ')} approvals available in this feed.`}
-
{requesterName(item)}
-
{requesterEmail(item) || item.requesterId?.slice(0, 12)}
-
- - -
{item._typeLabel || '—'}
- -
{item._parsedReason?.templateId}
-
-
- —}> -
- - Docs Requested - - {docRemark!.comment} - 0}> - Needed: {(docRemark!.fields || []).join(', ')} - + +
{actionError()}
+
+ +
{String((approvals.error as any)?.message || approvals.error)}
+
+ + {/* Metric Summary */} + +
+
+ Pending Jobs: {summary().jobs} + Pending Requirements: {summary().requirements} + Pending Profiles: {summary().profilePending} + Total Pending: {summary().totalPending} +
+
+ {summary().backendMode === 'RUST' && activeTab() !== 'PENDING' ? 'Backend returns pending only.' : ''} +
+
+
+ +
+
+ + {/* Tabs */} +
+ + {(t) => { + const count = countFor(t.key); + return ( + + ); + }} + +
+ + {/* Detail view vs List View */} + + + {/* Filters Row */} +
+
+
+
+ + + +
+ { setSearch(e.currentTarget.value); setCurrentPage(1); }} + class="h-11 w-full rounded-xl border border-[#d9dde6] bg-[#f9fafb] pl-11 pr-4 text-[14px] text-[#050026] outline-none transition-colors focus:border-[#050026] focus:bg-white" + /> +
+ + +
+
+ Showing {Math.min((currentPage() - 1) * perPage + 1, filteredApprovals().length)}–{Math.min(currentPage() * perPage, filteredApprovals().length)} of {filteredApprovals().length} +
+
+ + {/* Table */} +
+ + + + + + + + + + + + + + + + + + + + 0}> + + {(item) => { + const status = statusValue(item); + const docRemark = latestDocumentRequest(item); + const isDocRequest = !!docRemark && status === 'CHANGES_REQUESTED'; + const dest = managementDestination(item._roleType || 'UNKNOWN'); + const isActing = acting().startsWith(item.id); + return ( + + + + + + + + + + ); + }} + + + +
REQUESTERTYPECATEGORYDOCUMENT REQUESTSTATUSSUBMITTEDACTIONS
Loading approvals...
{activeTab() === 'PENDING' ? 'No pending approvals right now.' : `No ${activeTab().toLowerCase().replace('_', ' ')} approvals available.`}
+
{requesterName(item)}
+
{requesterEmail(item) || item.requesterId?.slice(0, 12)}
+
+ + +
{item._typeLabel || '—'}
+ +
{item._parsedReason?.templateId}
+
+
+ —}> +
+ Docs Requested + {docRemark!.comment} + 0}> + Needed: {(docRemark!.fields || []).join(', ')} + +
+
+
+ + + {(item.createdAt || item.created_at) ? new Date((item.createdAt || item.created_at)!).toLocaleDateString() : '—'} + +
+ + + + + + + + + + + + + + {dest.label.replace(' Management', '')} + + +
+
+
+ + {/* Pagination */} +
+ Page {currentPage()} of {totalPages()} +
+ + +
+
+
+ + {/* ── Inline Detail Panel ── */} + + setShowDetail(false)} + onApprove={handleApprove} + onReject={handleReject} + onRequestChanges={handleRequestChanges} + onRequestMoreDocuments={handleRequestMoreDocuments} + /> + +
+ + {/* ── Rules Tab ── */} + + +
{ruleError()}
+
+ +
+ +
+ + +
+

New Approval Rule

+
+
+ + setNewRuleName(e.currentTarget.value)} + placeholder="e.g. Profile Approval by Admin" + /> +
+
+ + +
+
+ + +
+
+ + setNewPriority(parseInt(e.currentTarget.value, 10) || 1)} + /> +
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + 0}> + + {(rule) => ( + + + + + + - - - + + )} + + + +
Rule NameEntity TypeApprover TypePriorityActions
Loading...
No approval rules configured yet.
{rule.name || '—'}{rule.entityType || rule.entity_type || '—'}{rule.approverType || rule.approver_type || '—'}{rule.priority ?? '—'} +
+
- -
- - - {(item.createdAt || item.created_at) ? new Date((item.createdAt || item.created_at)!).toLocaleDateString() : '—'} - -
- {/* View detail */} - - - - Full Request - - - - - Profile Review - - +
+
+
- - {/* Request More Documents */} - - {/* Request Changes */} - - {/* Approve */} - - {/* Reject */} - - - - - - - {/* Approved → link to management page */} - - - Open {dest.label.replace(' Management', '')} - - -
-
-
-
- - Page {currentPage()} of {totalPages()} -
-
- - {/* ── Inline Detail Panel ── */} - - setShowDetail(false)} - onApprove={handleApprove} - onReject={handleReject} - onRequestChanges={handleRequestChanges} - onRequestMoreDocuments={handleRequestMoreDocuments} - /> - -
- - {/* ── Rules Tab ── */} - - -
{ruleError()}
-
- -
-
-
- - -
-

New Approval Rule

-
-
- - setNewRuleName(e.currentTarget.value)} - placeholder="e.g. Profile Approval by Admin" - /> -
-
- - -
-
- - -
-
- - setNewPriority(parseInt(e.currentTarget.value, 10) || 1)} /> -
-
-
- - -
-
-
- -
-
- - - - - - - - - - - - - - - - - - 0}> - - {(rule) => ( - - - - - - - - )} - - - -
Rule NameEntity TypeApprover TypePriorityActions
Loading...
No approval rules configured yet.
{rule.name || '—'}{rule.entityType || rule.entity_type || '—'}{rule.approverType || rule.approver_type || '—'}{rule.priority ?? '—'} -
- -
-
-
-
- -
); @@ -1092,62 +1071,67 @@ function ApprovalDetailPanel(props: { return (

Select an approval from the list.

+

Select an approval from the list.

}> -
+
-

Approval Detail

-

{a()!._typeLabel || 'Request'}

+

Approval Detail

+

{a()!._typeLabel || 'Request'}

- +
-
+
{/* Request info */} -
-

Request Summary

- +
+

Request Summary

+
- - - - - - + + + + + +
ID{a()!.id}
Category{a()!._typeLabel || '—'}
Status
Priority{a()!.priority ?? '—'}
Template{a()!._parsedReason?.templateId || '—'}
Submitted{(a()!.createdAt || a()!.created_at) ? new Date((a()!.createdAt || a()!.created_at)!).toLocaleString() : '—'}
ID{a()!.id}
Category{a()!._typeLabel || '—'}
Status
Priority{a()!.priority ?? '—'}
Template{a()!._parsedReason?.templateId || '—'}
Submitted{(a()!.createdAt || a()!.created_at) ? new Date((a()!.createdAt || a()!.created_at)!).toLocaleString() : '—'}
{/* Requester info */} -
-

Requester

- +
+

Requester

+
- - - - + + + +
Name{requesterName(a()!)}
Email{requesterEmail(a()!) || '—'}
Role
Profession{a()!._parsedReason?.profession || '—'}
Name{requesterName(a()!)}
Email{requesterEmail(a()!) || '—'}
Role
Profession{a()!._parsedReason?.profession || '—'}
{/* Actions */} -
+
- - - - + + + + - + Open {dest().label} - Open Full Request + Open Full Request - Open Profile Review + Open Profile Review
@@ -1155,13 +1139,13 @@ function ApprovalDetailPanel(props: { {/* Submitted fields */} 0}> -
-

Submitted Data

-
+
+

Submitted Data

+
{Object.entries(a()!._parsedReason!.values!).map(([k, v]) => ( -
-
{k.replace(/_/g, ' ').toUpperCase()}
-
{String(v) || '—'}
+
+
{k.replace(/_/g, ' ').toUpperCase()}
+
{String(v) || '—'}
))}
@@ -1170,11 +1154,11 @@ function ApprovalDetailPanel(props: { {/* Document request spotlight (USP) */} -
-

Requested Documents

-

{docRemark()!.comment}

+
+

Requested Documents

+

{docRemark()!.comment}

0}> -

+

Required: {(docRemark()!.fields || []).join(', ')}

@@ -1183,26 +1167,26 @@ function ApprovalDetailPanel(props: { {/* Admin remarks history */} 0}> -
-

Admin Remarks History

-
+
+

Admin Remarks History

+
{(remark, i) => { const typeColor: Record = { - INFO: '#e0f2fe', - CHANGES_REQUESTED: '#fff7ed', - MORE_DOCUMENTS_REQUESTED: '#eff6ff', - REJECTED: '#fef2f2', + INFO: 'bg-[#e0f2fe] border-[#bae6fd]', + CHANGES_REQUESTED: 'bg-[#fff7ed] border-[#fed7aa]', + MORE_DOCUMENTS_REQUESTED: 'bg-[#eff6ff] border-[#bfdbfe]', + REJECTED: 'bg-[#fef2f2] border-[#fecaca]', }; return ( -
-
- {remark.type.replace(/_/g, ' ')} - Remark #{i() + 1} +
+
+ {remark.type.replace(/_/g, ' ')} + Remark #{i() + 1}
-

{remark.comment}

+

{remark.comment}

0}> -

Fields: {remark.fields!.join(', ')}

+

Fields: {remark.fields!.join(', ')}

); diff --git a/src/routes/admin/onboarding-schemas/index.tsx b/src/routes/admin/onboarding-schemas/index.tsx index 974a5ca..60e65d5 100644 --- a/src/routes/admin/onboarding-schemas/index.tsx +++ b/src/routes/admin/onboarding-schemas/index.tsx @@ -30,7 +30,7 @@ async function loadSchemas(): Promise { })); const hydrated = await Promise.all( - baseRows.map(async (row) => { + baseRows.map(async (row: { id: string; roleId: string; roleKey: string; version: number; status: string }) => { if (!row.roleId) { return { ...row, @@ -94,77 +94,102 @@ export default function OnboardingSchemasPage() { return (
- - {/* ── Page header ── */} -
-
-

Onboarding Management

-

Manage onboarding flows, role assignments, and previewable step groups for external users.

-
- Create Onboarding Flow -
- - - - {/* ── Content ── */} -
- -
{deleteError()}
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - 0}> - {schemas()!.map((schema) => ( - - - - - - - - - ))} - - -
FlowRoleStepsVersionStatusActions
Loading onboarding flows…
Failed to load onboarding schemas. Is the backend running?
No onboarding flows created yet.
{schema.title}{schema.roleKey || '—'}{schema.stepCount}v{schema.version} - {schema.status} - -
- 👁 - -
-
+
+ {/* Header */} +
+
+

Onboarding Management

+

Manage onboarding flows, role assignments, and previewable step groups for external users.

+
+
+ + + + {/* Content */} +
+
+ +
{deleteError()}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + 0}> + {schemas()!.map((schema) => ( + + + + + + + + + ))} + + +
FLOWROLESTEPSVERSIONSTATUSACTIONS
Loading onboarding flows…
Failed to load onboarding schemas. Is the backend running?
No onboarding flows created yet.
{schema.title}{schema.roleKey || '—'} + + {schema.stepCount} Steps + + v{schema.version} + {schema.status} + +
+ + + + + + + +
+
+
+
+
diff --git a/src/routes/admin/verification-status.tsx b/src/routes/admin/verification-status.tsx index 9a3ea70..7a32e8c 100644 --- a/src/routes/admin/verification-status.tsx +++ b/src/routes/admin/verification-status.tsx @@ -50,83 +50,91 @@ export default function VerificationStatusPage() { return (
- - {/* ── Page header ── */} -
-
-

Verification Status

-

Track request status states and open a specific record for follow-up.

-
- - Open Approval Center - -
- - {/* ── Content ── */} -
-
-
- - - - - - - - - - - - - - - - - - - - {(item) => ( - - - - - - - - - )} - - -
IDTypeRequesterStatusSubmittedActions
Loading verification statuses…
No verification status records found.
{item.id.slice(0, 8)}…{item.type} -

{item.requesterName}

-

{item.requesterEmail}

-
- - {item.status} - - {item.createdAt ? new Date(item.createdAt).toLocaleString() : '—'} - -
+
+ {/* Header */} +
+
+

Verification Status

+

Track request status states and open a specific record for follow-up.

+
+
+ + {/* Content */} +
+
+
+ + + + + + + + + + + + + + + + + + + + {(item) => ( + + + + + + + + + )} + + +
IDTYPEREQUESTERSTATUSSUBMITTEDACTIONS
Loading verification statuses…
No verification status records found.
{item.id.slice(0, 8)}…{item.type} +

{item.requesterName}

+

{item.requesterEmail}

+
+ + {item.status} + + {item.createdAt ? new Date(item.createdAt).toLocaleString() : '—'} + +
+
+
+