'use client' import { useState, useRef, useEffect, useCallback } from 'react' import { createPortal } from 'react-dom' import { Button } from '@/components/ui/button' import { deleteUser, updateUserRole, updateUserSubscription } from '@/app/actions/admin' import { toast } from 'sonner' import { Trash2, Shield, ShieldOff, Crown, ChevronDown } from 'lucide-react' import { format } from 'date-fns' import { useLanguage } from '@/lib/i18n' const TIERS = ['BASIC', 'PRO', 'BUSINESS', 'ENTERPRISE'] as const const tierColors: Record = { BASIC: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300', PRO: 'bg-brand-accent/10 text-brand-accent', BUSINESS: 'bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', ENTERPRISE: 'bg-purple-50 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400', } function TierDropdown({ userId, tier, isOpen, onToggle, onClose, onChange }: { userId: string tier: string isOpen: boolean onToggle: () => void onClose: () => void onChange: (tier: string) => void }) { const btnRef = useRef(null) const [pos, setPos] = useState({ top: 0, left: 0 }) const updatePos = useCallback(() => { if (btnRef.current) { const r = btnRef.current.getBoundingClientRect() setPos({ top: r.bottom + 4, left: r.left }) } }, []) useEffect(() => { if (isOpen) { updatePos() window.addEventListener('scroll', updatePos, true) window.addEventListener('resize', updatePos) } return () => { window.removeEventListener('scroll', updatePos, true) window.removeEventListener('resize', updatePos) } }, [isOpen, updatePos]) return ( {isOpen && typeof document !== 'undefined' && createPortal( <>
{TIERS.map((t) => ( ))}
, document.body )} ) } export function UserList({ initialUsers }: { initialUsers: any[] }) { const { t } = useLanguage() const [users, setUsers] = useState(initialUsers) const [openDropdown, setOpenDropdown] = useState(null) const handleDelete = async (id: string) => { if (!confirm(t('admin.users.confirmDelete'))) return try { await deleteUser(id) toast.success(t('admin.users.deleteSuccess')) setUsers(prev => prev.filter(u => u.id !== id)) } catch (e) { toast.error(t('admin.users.deleteFailed')) } } const handleRoleToggle = async (user: any) => { const newRole = user.role === 'ADMIN' ? 'USER' : 'ADMIN' try { await updateUserRole(user.id, newRole) toast.success(t('admin.users.roleUpdateSuccess', { role: newRole })) setUsers(prev => prev.map(u => u.id === user.id ? { ...u, role: newRole } : u)) } catch (e) { toast.error(t('admin.users.roleUpdateFailed')) } } const handleTierChange = async (userId: string, tier: string) => { setOpenDropdown(null) try { await updateUserSubscription(userId, tier) toast.success(t('admin.users.tierUpdateSuccess', { tier })) setUsers(prev => prev.map(u => u.id === userId ? { ...u, subscription: { tier, status: 'ACTIVE' } } : u)) } catch (e) { toast.error(t('admin.users.tierUpdateFailed')) } } const getUserTier = (user: any) => user.subscription?.tier || 'BASIC' return (
{users.map((user) => { const tier = getUserTier(user) return ( setOpenDropdown(openDropdown === user.id ? null : user.id)} onClose={() => setOpenDropdown(null)} onChange={(t) => handleTierChange(user.id, t)} /> ) })}
{t('admin.users.table.name')} {t('admin.users.table.email')} {t('admin.users.table.role')} {t('admin.users.table.subscription')} {t('admin.users.table.createdAt')} {t('admin.users.table.actions')}
{user.name || t('common.notAvailable')} {user.email} {user.role === 'ADMIN' ? t('admin.users.roles.admin') : t('admin.users.roles.user')} {format(new Date(user.createdAt), 'PP')}
) }