'use client' import React, { useMemo, useState } from 'react' import { UsersIcon } from '@heroicons/react/24/outline' import { useTranslation } from '../../i18n/useTranslation' type UserType = 'personal' | 'company' type UserStatus = 'active' | 'inactive' | 'pending' | 'blocked' export interface RegisteredUser { id: string | number name: string email: string userType: UserType registeredAt: string | Date refCode?: string status: UserStatus } interface Props { users?: RegisteredUser[] loading?: boolean } function statusBadgeClass(s: UserStatus) { switch (s) { case 'active': return 'bg-green-100 text-green-800' case 'inactive': return 'bg-gray-100 text-gray-800' case 'pending': return 'bg-amber-100 text-amber-800' case 'blocked': return 'bg-rose-100 text-rose-800' default: return 'bg-slate-100 text-slate-800' } } function typeBadgeClass(t: UserType) { return t === 'company' ? 'bg-indigo-100 text-indigo-800' : 'bg-blue-100 text-blue-800' } // CSV export helper function exportCsv(rows: RegisteredUser[]) { const header = ['Name', 'Email', 'Type', 'Registered', 'Status'] const csv = [ header.join(','), ...rows.map(r => [ `"${r.name.replace(/"/g, '""')}"`, `"${r.email}"`, r.userType, `"${new Date(r.registeredAt).toLocaleString()}"`, r.status ].join(',')) ].join('\n') const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `registered-users-${Date.now()}.csv` a.click() URL.revokeObjectURL(url) } export default function RegisteredUserList({ users, loading }: Props) { const { t } = useTranslation() // Normalize backend shape to local RegisteredUser shape const normalizedUsers = useMemo(() => { if (!users || users.length === 0) return [] return users.map((u: any) => ({ id: u.id ?? u._id ?? u.userId ?? '', name: u.name ?? u.fullName ?? u.companyName ?? u.email ?? '', email: u.email ?? '', userType: (u.userType ?? u.type ?? 'personal') as UserType, registeredAt: u.registeredAt ?? u.createdAt ?? new Date().toISOString(), status: (u.status ?? 'inactive') as UserStatus, })) }, [users]) // Latest 5 rows only from backend const sorted = useMemo(() => { const data = normalizedUsers.slice() return data.sort((a, b) => new Date(b.registeredAt).getTime() - new Date(a.registeredAt).getTime()) }, [normalizedUsers]) const rows = sorted.slice(0, 5) // Total badge: from backend list length const totalRegistered = normalizedUsers.length // Modal state const [open, setOpen] = useState(false) const [query, setQuery] = useState('') const [typeFilter, setTypeFilter] = useState<'all' | UserType>('all') const [statusFilter, setStatusFilter] = useState<'all' | UserStatus>('all') const [page, setPage] = useState(1) const pageSize = 10 // Full dataset for modal (backend only) const allRows = useMemo(() => { return normalizedUsers.slice().sort((a, b) => new Date(b.registeredAt).getTime() - new Date(a.registeredAt).getTime()) }, [normalizedUsers]) const filtered = useMemo(() => { return allRows.filter(r => { if (typeFilter !== 'all' && r.userType !== typeFilter) return false if (statusFilter !== 'all' && r.status !== statusFilter) return false if (!query.trim()) return true const q = query.toLowerCase() return r.name.toLowerCase().includes(q) || r.email.toLowerCase().includes(q) }) }, [allRows, query, typeFilter, statusFilter]) const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize)) const pageRows = filtered.slice((page - 1) * pageSize, page * pageSize) const resetAndOpen = () => { setQuery('') setTypeFilter('all') setStatusFilter('all') setPage(1) setOpen(true) } // Lock scroll when modal open React.useEffect(() => { if (!open) return const prev = document.body.style.overflow document.body.style.overflow = 'hidden' return () => { document.body.style.overflow = prev } }, [open]) return ( <>

{t('referralManagement.registeredUsersTitle')}

{t('referralManagement.totalRefBadge')} {totalRegistered}

{t('referralManagement.registeredUsersSubtitle')}

{t('referralManagement.showingLatest5')}

{loading ? ( <> ) : rows.length === 0 ? ( ) : ( rows.map(u => { const date = new Date(u.registeredAt).toLocaleString() return ( ) }) )}
{t('referralManagement.colUser')} {t('referralManagement.colEmail')} {t('referralManagement.colType')} {t('referralManagement.colRegistered')} {t('referralManagement.colStatus')}
{t('referralManagement.noRegisteredUsers')}
{u.name} {u.email} {u.userType === 'company' ? t('referralManagement.typeCompany') : t('referralManagement.typePersonal')} {date} {u.status.charAt(0).toUpperCase() + u.status.slice(1)}
{/* Modal with full list */} {open && (
setOpen(false)} aria-hidden />

{t('referralManagement.allRegisteredUsersTitle')}

{t('referralManagement.allRegisteredUsersSubtitle')}

{ setQuery(e.target.value); setPage(1) }} placeholder={t('referralManagement.searchPlaceholder')} className="md:col-span-2 w-full rounded-2xl border border-slate-200 px-3 py-2 text-sm text-slate-900 shadow-sm transition focus:outline-none focus:ring-2 focus:ring-slate-900/20 focus:border-slate-300 placeholder:text-slate-500" />
{pageRows.length === 0 ? ( ) : ( pageRows.map(u => { const date = new Date(u.registeredAt).toLocaleString() return ( ) }) )}
{t('referralManagement.colUser')} {t('referralManagement.colEmail')} {t('referralManagement.colType')} {t('referralManagement.colRegistered')} {t('referralManagement.colStatus')}
{t('referralManagement.noUsersMatchFilters')}
{u.name} {u.email} {u.userType === 'company' ? t('referralManagement.typeCompany') : t('referralManagement.typePersonal')} {date} {u.status.charAt(0).toUpperCase() + u.status.slice(1)}
{t('referralManagement.showing')} {pageRows.length} {t('referralManagement.of')} {filtered.length} {t('referralManagement.colUser').toLowerCase()}s
{t('referralManagement.pageOf').replace('{page}', String(page)).replace('{total}', String(totalPages))}
)} ) }