nxtgauge-admin-solid/src/routes/admin/company.tsx

141 lines
5.2 KiB
TypeScript
Raw Normal View History

import { For, Show, createMemo, createSignal, onMount } from 'solid-js';
import AdminShell from '~/components/AdminShell';
type AdminContact = {
name: string;
email: string;
phone: string;
};
type CompanyRecord = {
id: string;
companyCode: string;
name: string;
registrationNumber: string;
industry: string;
location: string;
joinedOn: string;
adminContact: AdminContact;
accountStatus: string;
verificationStatus: string;
subscriptionType: string;
jobPostingsCount: number;
totalHires: number;
updatedAt: string;
};
export default function CompanyManagementPage() {
const [rows, setRows] = createSignal<CompanyRecord[]>([]);
const [search, setSearch] = createSignal('');
const [statusFilter, setStatusFilter] = createSignal('all');
const [sortBy, setSortBy] = createSignal('name_asc');
const load = async () => {
try {
const r = await fetch('/api/admin/companies');
if (!r.ok) throw new Error('Failed to fetch companies');
const data = await r.json();
const mapped: CompanyRecord[] = data.map((c: any) => ({
id: c.id,
companyCode: c.id.slice(0, 8).toUpperCase(),
name: c.company_name,
registrationNumber: c.registration_number || 'Pending Registration',
industry: c.industry || 'Not Specified',
location: 'Not Specified',
joinedOn: new Date(c.created_at).toLocaleDateString(),
adminContact: { name: 'Company Admin', email: '...', phone: '...' },
accountStatus: c.status.toUpperCase(),
verificationStatus: c.status === 'APPROVED' ? 'VERIFIED' : 'PENDING',
subscriptionType: 'STANDARD',
jobPostingsCount: 0,
totalHires: 0,
updatedAt: c.updated_at,
}));
setRows(mapped);
} catch (e) {
console.error(e);
setRows([]);
}
};
onMount(() => void load());
const filteredRows = createMemo(() => {
let r = rows();
if (statusFilter() !== 'all') r = r.filter((d) => d.accountStatus === statusFilter().toUpperCase());
const q = search().toLowerCase();
if (q) {
r = r.filter(it => it.name.toLowerCase().includes(q) || it.companyCode.toLowerCase().includes(q));
}
const sorted = [...r];
sorted.sort((a, b) => {
if (sortBy() === 'name_desc') return b.name.localeCompare(a.name);
return a.name.localeCompare(b.name);
});
return sorted;
});
return (
<AdminShell>
<div class="w-full space-y-6 pb-8">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-[#111827]">Companies Management</h1>
<p class="text-sm text-[#6B7280]">Manage all registered companies and their verification status.</p>
</div>
</div>
<div class="flex items-center gap-4 bg-white p-4 rounded-xl border border-[#E5E7EB]">
<input
type="text"
placeholder="Search company..."
class="flex-1 h-10 px-4 rounded-lg border border-[#E5E7EB] outline-none focus:border-[#FF5E13]"
value={search()}
onInput={(e) => setSearch(e.currentTarget.value)}
/>
<select
class="h-10 px-4 rounded-lg border border-[#E5E7EB] outline-none"
value={statusFilter()}
onChange={(e) => setStatusFilter(e.currentTarget.value)}
>
<option value="all">All Status</option>
<option value="pending">Pending</option>
<option value="active">Active</option>
<option value="suspended">Suspended</option>
</select>
</div>
<div class="bg-white rounded-xl border border-[#E5E7EB] overflow-hidden">
<table class="min-w-full divide-y divide-[#E5E7EB]">
<thead class="bg-[#F9FAFB]">
<tr>
<th class="px-6 py-3 text-left text-xs font-semibold text-[#4B5563] uppercase tracking-wider">Company</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-[#4B5563] uppercase tracking-wider">Industry</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-[#4B5563] uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-[#4B5563] uppercase tracking-wider">Joined</th>
</tr>
</thead>
<tbody class="divide-y divide-[#E5E7EB]">
<For each={filteredRows()}>{(c) => (
<tr>
<td class="px-6 py-4">
<div class="font-semibold text-[#111827]">{c.name}</div>
<div class="text-xs text-[#6B7280]">{c.companyCode}</div>
</td>
<td class="px-6 py-4 text-sm text-[#4B5563]">{c.industry}</td>
<td class="px-6 py-4">
<span class={`px-2 py-1 text-xs font-bold rounded-full ${c.accountStatus === 'ACTIVE' ? 'bg-green-100 text-green-700' : 'bg-yellow-100 text-yellow-700'}`}>
{c.accountStatus}
</span>
</td>
<td class="px-6 py-4 text-sm text-[#4B5563]">{c.joinedOn}</td>
</tr>
)}</For>
</tbody>
</table>
</div>
</div>
</AdminShell>
);
}