feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
import { createResource, createSignal, createMemo, Show, For } from 'solid-js';
|
|
|
|
|
import { A } from '@solidjs/router';
|
|
|
|
|
|
|
|
|
|
const API = '/api/gateway';
|
|
|
|
|
|
|
|
|
|
type SupportCase = {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
type: 'platform_issue' | 'customer_query' | 'professional_query' | 'billing_issue' | 'lead_dispute';
|
|
|
|
|
priority: 'low' | 'medium' | 'high' | 'critical';
|
|
|
|
|
status: 'new' | 'in_progress' | 'waiting_for_user' | 'resolved' | 'closed';
|
|
|
|
|
requesterName?: string;
|
|
|
|
|
requesterEmail?: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const STATUS_OPTIONS: SupportCase['status'][] = ['new', 'in_progress', 'waiting_for_user', 'resolved', 'closed'];
|
|
|
|
|
const TYPE_OPTIONS: SupportCase['type'][] = ['platform_issue', 'customer_query', 'professional_query', 'billing_issue', 'lead_dispute'];
|
|
|
|
|
const PRIORITY_OPTIONS: SupportCase['priority'][] = ['low', 'medium', 'high', 'critical'];
|
|
|
|
|
|
|
|
|
|
function formatValue(input: string): string {
|
|
|
|
|
return input.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function typeBadgeStyle(type: string): string {
|
|
|
|
|
const map: Record<string, string> = {
|
|
|
|
|
platform_issue: 'background:#dbeafe;color:#1d4ed8',
|
|
|
|
|
customer_query: 'background:#dcfce7;color:#15803d',
|
|
|
|
|
billing_issue: 'background:#ffedd5;color:#c2410c',
|
|
|
|
|
lead_dispute: 'background:#fee2e2;color:#b91c1c',
|
|
|
|
|
professional_query: 'background:#f3e8ff;color:#7e22ce',
|
|
|
|
|
};
|
|
|
|
|
return map[type] || 'background:#f1f5f9;color:#475569';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function priorityBadgeStyle(priority: string): string {
|
|
|
|
|
const map: Record<string, string> = {
|
|
|
|
|
low: 'background:#f1f5f9;color:#475569',
|
|
|
|
|
medium: 'background:#dbeafe;color:#1d4ed8',
|
|
|
|
|
high: 'background:#ffedd5;color:#c2410c',
|
|
|
|
|
critical: 'background:#fee2e2;color:#b91c1c',
|
|
|
|
|
};
|
|
|
|
|
return map[priority] || 'background:#f1f5f9;color:#475569';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function statusBadgeStyle(status: string): string {
|
|
|
|
|
const map: Record<string, string> = {
|
|
|
|
|
new: 'background:#dbeafe;color:#1d4ed8',
|
|
|
|
|
in_progress: 'background:#ffedd5;color:#c2410c',
|
|
|
|
|
waiting_for_user: 'background:#fef9c3;color:#a16207',
|
|
|
|
|
resolved: 'background:#dcfce7;color:#15803d',
|
|
|
|
|
closed: 'background:#f1f5f9;color:#475569',
|
|
|
|
|
};
|
|
|
|
|
return map[status] || 'background:#f1f5f9;color:#475569';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const BADGE_STYLE = 'display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600';
|
|
|
|
|
|
|
|
|
|
async function loadAllCases(): Promise<SupportCase[]> {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${API}/api/admin/support-cases`);
|
|
|
|
|
if (!res.ok) throw new Error('Failed');
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
return Array.isArray(data.cases) ? data.cases : Array.isArray(data) ? data : [];
|
|
|
|
|
} catch {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function SupportPage() {
|
|
|
|
|
const [activeTab, setActiveTab] = createSignal<'queue' | 'create'>('queue');
|
|
|
|
|
const [statusFilter, setStatusFilter] = createSignal<'all' | SupportCase['status']>('all');
|
|
|
|
|
const [refetchKey, setRefetchKey] = createSignal(0);
|
|
|
|
|
|
|
|
|
|
const [cases] = createResource(refetchKey, loadAllCases);
|
|
|
|
|
|
|
|
|
|
const refetch = () => setRefetchKey((k) => k + 1);
|
|
|
|
|
|
|
|
|
|
const filteredCases = createMemo(() => {
|
|
|
|
|
const all = cases() ?? [];
|
|
|
|
|
const sf = statusFilter();
|
|
|
|
|
if (sf === 'all') return all;
|
|
|
|
|
return all.filter((c) => c.status === sf);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const stats = createMemo(() => {
|
|
|
|
|
const all = cases() ?? [];
|
|
|
|
|
return {
|
|
|
|
|
newCount: all.filter((c) => c.status === 'new').length,
|
|
|
|
|
inProgressCount: all.filter((c) => c.status === 'in_progress').length,
|
|
|
|
|
waitingCount: all.filter((c) => c.status === 'waiting_for_user').length,
|
|
|
|
|
total: all.length,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Create Case form state
|
|
|
|
|
const [fTitle, setFTitle] = createSignal('');
|
|
|
|
|
const [fDesc, setFDesc] = createSignal('');
|
|
|
|
|
const [fType, setFType] = createSignal<SupportCase['type']>('customer_query');
|
|
|
|
|
const [fPriority, setFPriority] = createSignal<SupportCase['priority']>('medium');
|
|
|
|
|
const [fRequesterName, setFRequesterName] = createSignal('');
|
|
|
|
|
const [fRequesterEmail, setFRequesterEmail] = createSignal('');
|
|
|
|
|
const [createLoading, setCreateLoading] = createSignal(false);
|
|
|
|
|
const [createSuccess, setCreateSuccess] = createSignal('');
|
|
|
|
|
const [createError, setCreateError] = createSignal('');
|
|
|
|
|
|
|
|
|
|
const resetForm = () => {
|
|
|
|
|
setFTitle('');
|
|
|
|
|
setFDesc('');
|
|
|
|
|
setFType('customer_query');
|
|
|
|
|
setFPriority('medium');
|
|
|
|
|
setFRequesterName('');
|
|
|
|
|
setFRequesterEmail('');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCreate = async (e: Event) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setCreateLoading(true);
|
|
|
|
|
setCreateSuccess('');
|
|
|
|
|
setCreateError('');
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${API}/api/admin/support-cases`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
title: fTitle(),
|
|
|
|
|
description: fDesc(),
|
|
|
|
|
type: fType(),
|
|
|
|
|
priority: fPriority(),
|
|
|
|
|
requesterName: fRequesterName(),
|
|
|
|
|
requesterEmail: fRequesterEmail(),
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
const d = await res.json().catch(() => ({}));
|
|
|
|
|
throw new Error((d as any).message || 'Failed to create case');
|
|
|
|
|
}
|
|
|
|
|
setCreateSuccess('Case created!');
|
|
|
|
|
resetForm();
|
|
|
|
|
refetch();
|
|
|
|
|
setActiveTab('queue');
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
setCreateError(err.message || 'Failed to create case');
|
|
|
|
|
} finally {
|
|
|
|
|
setCreateLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const statCards = [
|
|
|
|
|
{ label: 'New', getValue: () => stats().newCount },
|
|
|
|
|
{ label: 'In Progress', getValue: () => stats().inProgressCount },
|
|
|
|
|
{ label: 'Waiting', getValue: () => stats().waitingCount },
|
|
|
|
|
{ label: 'Total', getValue: () => stats().total },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
<div class="flex flex-col -mx-6 -mt-6 min-h-full">
|
|
|
|
|
<div class="bg-white border-b border-gray-200 px-6 py-4">
|
|
|
|
|
<h1 class="text-xl font-semibold text-gray-900">Support Management</h1>
|
|
|
|
|
<p class="text-sm text-gray-500 mt-0.5">Handle platform issues and customer queries</p>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
</div>
|
|
|
|
|
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
{/* Tabs */}
|
|
|
|
|
<div class="bg-white border-b border-gray-200 px-6 flex items-center gap-8 sticky top-0 z-10">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
class={activeTab() === 'queue'
|
|
|
|
|
? 'py-3 border-b-2 border-orange-500 text-orange-600 text-sm font-medium'
|
|
|
|
|
: 'py-3 border-b-2 border-transparent text-gray-500 hover:text-gray-700 text-sm font-medium transition-colors'}
|
|
|
|
|
onClick={() => setActiveTab('queue')}
|
|
|
|
|
>
|
|
|
|
|
Support Queue
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
class={activeTab() === 'create'
|
|
|
|
|
? 'py-3 border-b-2 border-orange-500 text-orange-600 text-sm font-medium'
|
|
|
|
|
: 'py-3 border-b-2 border-transparent text-gray-500 hover:text-gray-700 text-sm font-medium transition-colors'}
|
|
|
|
|
onClick={() => setActiveTab('create')}
|
|
|
|
|
>
|
|
|
|
|
Create Case
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
<div class="flex-1 p-6">
|
|
|
|
|
{/* Stats bar */}
|
|
|
|
|
<div style="display:flex;gap:12px;margin-bottom:16px">
|
|
|
|
|
<For each={statCards}>
|
|
|
|
|
{(card) => (
|
|
|
|
|
<div style="background:#f8f9fa;border:1px solid #e5e7eb;border-radius:8px;padding:12px 20px;text-align:center">
|
|
|
|
|
<div style="font-size:24px;font-weight:700">{card.getValue()}</div>
|
|
|
|
|
<div style="font-size:12px;color:#6b7280">{card.label}</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
</div>
|
|
|
|
|
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
{/* Support Queue Tab */}
|
|
|
|
|
<Show when={activeTab() === 'queue'}>
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:16px">
|
|
|
|
|
<div style="display:flex;align-items:center;justify-content:flex-end">
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
<select
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
value={statusFilter()}
|
|
|
|
|
onChange={(e) => setStatusFilter(e.currentTarget.value as typeof statusFilter extends () => infer R ? R : never)}
|
|
|
|
|
style="padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px"
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
>
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
<option value="all">All statuses</option>
|
|
|
|
|
<For each={STATUS_OPTIONS}>
|
|
|
|
|
{(s) => <option value={s}>{formatValue(s)}</option>}
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
</For>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
|
|
|
|
|
<div class="table-card">
|
|
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
<table class="data-table w-full text-sm">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Issue</th>
|
|
|
|
|
<th>Type</th>
|
|
|
|
|
<th>Priority</th>
|
|
|
|
|
<th>Status</th>
|
|
|
|
|
<th>Requester</th>
|
|
|
|
|
<th>Updated At</th>
|
|
|
|
|
<th class="text-right">Actions</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<Show when={cases.loading}>
|
|
|
|
|
<tr><td colspan="7" style="text-align:center;padding:32px;color:#64748b">Loading...</td></tr>
|
|
|
|
|
</Show>
|
|
|
|
|
<Show when={!cases.loading && cases.error}>
|
|
|
|
|
<tr><td colspan="7" style="text-align:center;padding:32px;color:#b91c1c">Failed to load cases.</td></tr>
|
|
|
|
|
</Show>
|
|
|
|
|
<Show when={!cases.loading && !cases.error && filteredCases().length === 0}>
|
|
|
|
|
<tr><td colspan="7" style="text-align:center;padding:32px;color:#94a3b8">No support cases found.</td></tr>
|
|
|
|
|
</Show>
|
|
|
|
|
<Show when={!cases.loading && !cases.error && filteredCases().length > 0}>
|
|
|
|
|
<For each={filteredCases()}>
|
|
|
|
|
{(item) => (
|
|
|
|
|
<tr class="hover:bg-slate-50" style="cursor:pointer" onClick={() => {}}>
|
|
|
|
|
<td>
|
|
|
|
|
<div class="font-semibold text-slate-900">{item.title}</div>
|
|
|
|
|
<div style="font-size:12px;color:#64748b;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{item.description}</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<span style={`${BADGE_STYLE};${typeBadgeStyle(item.type)}`}>{formatValue(item.type)}</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<span style={`${BADGE_STYLE};${priorityBadgeStyle(item.priority)}`}>{formatValue(item.priority)}</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<span style={`${BADGE_STYLE};${statusBadgeStyle(item.status)}`}>{formatValue(item.status)}</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<div style="font-size:13px">{item.requesterName || '—'}</div>
|
|
|
|
|
<div style="font-size:11px;color:#64748b">{item.requesterEmail || ''}</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="text-slate-500" style="font-size:12px">
|
|
|
|
|
{item.updatedAt ? new Date(item.updatedAt).toLocaleString() : '—'}
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<div class="flex items-center justify-end gap-1">
|
|
|
|
|
<A class="inline-flex items-center rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors" href={`/admin/support/${item.id}`}>View</A>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</Show>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
{/* Create Case Tab */}
|
|
|
|
|
<Show when={activeTab() === 'create'}>
|
|
|
|
|
<section class="rounded-xl border border-gray-200 bg-white shadow-sm" style="max-width:600px">
|
|
|
|
|
<h2 style="margin:0 0 6px;font-size:16px;font-weight:700;color:#1e293b">Create Support Case</h2>
|
|
|
|
|
<p style="margin:0 0 20px;font-size:13px;color:#64748b">
|
|
|
|
|
Create an internal support record for platform issues, customer concerns, or compensation-related reviews.
|
|
|
|
|
</p>
|
|
|
|
|
<Show when={createSuccess()}>
|
|
|
|
|
<div style="background:#dcfce7;border:1px solid #86efac;border-radius:6px;padding:10px 14px;margin-bottom:14px;font-size:14px;color:#15803d;font-weight:600">
|
|
|
|
|
{createSuccess()}
|
|
|
|
|
</div>
|
|
|
|
|
</Show>
|
|
|
|
|
<Show when={createError()}>
|
|
|
|
|
<div class="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700" style="margin-bottom:14px">{createError()}</div>
|
|
|
|
|
</Show>
|
|
|
|
|
<form onSubmit={handleCreate} style="display:flex;flex-direction:column;gap:14px">
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Title</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
required
|
|
|
|
|
value={fTitle()}
|
|
|
|
|
onInput={(e) => setFTitle(e.currentTarget.value)}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Description</label>
|
|
|
|
|
<textarea
|
|
|
|
|
required
|
|
|
|
|
rows="4"
|
|
|
|
|
value={fDesc()}
|
|
|
|
|
onInput={(e) => setFDesc(e.currentTarget.value)}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;resize:vertical;box-sizing:border-box"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Type</label>
|
|
|
|
|
<select
|
|
|
|
|
value={fType()}
|
|
|
|
|
onChange={(e) => setFType(e.currentTarget.value as SupportCase['type'])}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box"
|
|
|
|
|
>
|
|
|
|
|
<For each={TYPE_OPTIONS}>
|
|
|
|
|
{(t) => <option value={t}>{formatValue(t)}</option>}
|
|
|
|
|
</For>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Priority</label>
|
|
|
|
|
<select
|
|
|
|
|
value={fPriority()}
|
|
|
|
|
onChange={(e) => setFPriority(e.currentTarget.value as SupportCase['priority'])}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box"
|
|
|
|
|
>
|
|
|
|
|
<For each={PRIORITY_OPTIONS}>
|
|
|
|
|
{(p) => <option value={p}>{formatValue(p)}</option>}
|
|
|
|
|
</For>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Requester Name</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={fRequesterName()}
|
|
|
|
|
onInput={(e) => setFRequesterName(e.currentTarget.value)}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label style="display:block;font-size:13px;font-weight:600;margin-bottom:4px">Requester Email</label>
|
|
|
|
|
<input
|
|
|
|
|
type="email"
|
|
|
|
|
value={fRequesterEmail()}
|
|
|
|
|
onInput={(e) => setFRequesterEmail(e.currentTarget.value)}
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;box-sizing:border-box"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2026-03-24 08:10:29 +01:00
|
|
|
<button class="btn-primary" type="submit" disabled={createLoading()}>
|
ui(step-3): apply reference layout to 14 more management pages
- pricing, credit, coupon, discount, tax, order, invoice: white header,
data-table/table-card, navy buttons, inline styles removed
- review, leads, jobs, notifications, support, report, ledger: same
pattern + orange tab underlines where applicable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 05:20:55 +01:00
|
|
|
{createLoading() ? 'Creating...' : 'Create Support Case'}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</section>
|
|
|
|
|
</Show>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
);
|
|
|
|
|
}
|