import React, { useState } from 'react'; import { useNavigate, useLocation, Link } from 'react-router-dom'; import { useAuth } from '../../context/AuthContext'; import api from '../../utils/api'; import { Card } from '../../components/ui/card'; import { Button } from '../../components/ui/button'; import { Input } from '../../components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu'; import { toast } from 'sonner'; import { Users, Search, User, CreditCard, Eye, CheckCircle, Calendar, AlertCircle, Clock, Mail, UserPlus, Upload, Download, FileDown, ChevronDown, CircleMinus } from 'lucide-react'; import PaymentActivationDialog from '../../components/PaymentActivationDialog'; import ConfirmationDialog from '../../components/ConfirmationDialog'; import CreateMemberDialog from '../../components/CreateMemberDialog'; import InviteMemberDialog from '../../components/InviteMemberDialog'; import WordPressImportWizard from '../../components/WordPressImportWizard'; import StatusBadge from '../../components/StatusBadge'; import { StatCard } from '@/components/StatCard'; import { useMembers } from '../../hooks/use-users'; const AdminMembers = () => { const navigate = useNavigate(); const location = useLocation(); const { hasPermission } = useAuth(); const { users, filteredUsers, loading, searchQuery, setSearchQuery, filterValue: statusFilter, setFilterValue: setStatusFilter, refetch, } = useMembers(); const [paymentDialogOpen, setPaymentDialogOpen] = useState(false); const [selectedUserForPayment, setSelectedUserForPayment] = useState(null); const [statusChanging, setStatusChanging] = useState(null); const [confirmDialogOpen, setConfirmDialogOpen] = useState(false); const [pendingStatusChange, setPendingStatusChange] = useState(null); const [createDialogOpen, setCreateDialogOpen] = useState(false); const [inviteDialogOpen, setInviteDialogOpen] = useState(false); const [importDialogOpen, setImportDialogOpen] = useState(false); const [exporting, setExporting] = useState(false); const handleActivatePayment = (user) => { setSelectedUserForPayment(user); setPaymentDialogOpen(true); }; const handlePaymentSuccess = () => { refetch(); // Refresh list }; const handleStatusChangeRequest = (userId, currentStatus, newStatus, user) => { // Skip confirmation if status didn't actually change if (currentStatus === newStatus) return; setPendingStatusChange({ userId, newStatus, user }); setConfirmDialogOpen(true); }; const confirmStatusChange = async () => { if (!pendingStatusChange) return; const { userId, newStatus } = pendingStatusChange; setStatusChanging(userId); setConfirmDialogOpen(false); try { await api.put(`/admin/users/${userId}/status`, { status: newStatus }); toast.success('Member status updated successfully'); refetch(); // Refresh list } catch (error) { toast.error(error.response?.data?.detail || 'Failed to update status'); } finally { setStatusChanging(null); setPendingStatusChange(null); } }; const handleExport = async (filterType) => { setExporting(true); try { let params = {}; if (filterType === 'current') { if (statusFilter && statusFilter !== 'all') { params.status = statusFilter; } if (searchQuery) { params.search = searchQuery; } } // filterType === 'all' will export all members without filters const response = await api.get('/admin/users/export', { params, responseType: 'blob' }); // Create download link const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `members_export_${new Date().toISOString().split('T')[0]}.csv`); document.body.appendChild(link); link.click(); link.remove(); toast.success('Members exported successfully'); } catch (error) { toast.error('Failed to export members'); } finally { setExporting(false); } }; const getStatusChangeMessage = () => { if (!pendingStatusChange) return {}; const { newStatus, user } = pendingStatusChange; const userName = `${user.first_name} ${user.last_name}`; const messages = { payment_pending: { title: 'Revert to Payment Pending?', description: `This will change ${userName}'s status back to Payment Pending. They will need to complete payment again to become active.`, variant: 'warning', confirmText: 'Yes, Revert Status', }, active: { title: 'Activate Member?', description: `This will activate ${userName}'s membership. They will gain full access to member features and resources.`, variant: 'success', confirmText: 'Yes, Activate', }, inactive: { title: 'Deactivate Member?', description: `This will deactivate ${userName}'s membership. They will lose access to member-only features but their data will be preserved.`, variant: 'warning', confirmText: 'Yes, Deactivate', }, canceled: { title: 'Cancel Membership?', description: `This will mark ${userName}'s membership as canceled. This indicates they voluntarily ended their membership. Their subscription will not auto-renew.`, variant: 'danger', confirmText: 'Yes, Cancel Membership', }, expired: { title: 'Mark Membership as Expired?', description: `This will mark ${userName}'s membership as expired. This indicates their subscription period has ended without renewal.`, variant: 'warning', confirmText: 'Yes, Mark as Expired', }, }; return messages[newStatus] || { title: 'Confirm Status Change', description: `Are you sure you want to change ${userName}'s status to ${newStatus}?`, variant: 'warning', confirmText: 'Confirm', }; }; const getReminderInfo = (user) => { const emailReminders = user.email_verification_reminders_sent || 0; const eventReminders = user.event_attendance_reminders_sent || 0; const paymentReminders = user.payment_reminders_sent || 0; const renewalReminders = user.renewal_reminders_sent || 0; const totalReminders = emailReminders + eventReminders + paymentReminders + renewalReminders; return { emailReminders, eventReminders, paymentReminders, renewalReminders, totalReminders, lastReminderAt: user.last_email_verification_reminder_at || user.last_event_attendance_reminder_at || user.last_payment_reminder_at || user.last_renewal_reminder_at }; }; return ( <>
Manage paying members and their subscriptions.
Loading members...
Email: {user.email}
Phone: {user.phone}
Registered: {joinedDate ? new Date(joinedDate).toLocaleDateString() : 'N/A'}
Member Since: {memberDate ? new Date(joinedDate).toLocaleDateString() : 'N/A'}
{user.referred_by_member_name && (Referred by: {user.referred_by_member_name}
)}
Last reminder: {new Date(reminderInfo.lastReminderAt).toLocaleDateString()} at {new Date(reminderInfo.lastReminderAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
)}{searchQuery || statusFilter !== 'all' ? 'Try adjusting your filters' : 'No members yet'}