feat: refactor AdminMembers and AdminStaff to utilize useMembers hook for improved member management
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate, useLocation, Link } from 'react-router-dom';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import api from '../../utils/api';
|
||||
@@ -21,16 +21,22 @@ import InviteStaffDialog from '../../components/InviteStaffDialog';
|
||||
import WordPressImportWizard from '../../components/WordPressImportWizard';
|
||||
import StatusBadge from '../../components/StatusBadge';
|
||||
import { StatCard } from '@/components/StatCard';
|
||||
import useMembers from '../../hooks/use-members';
|
||||
|
||||
const AdminMembers = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { hasPermission } = useAuth();
|
||||
const [users, setUsers] = useState([]);
|
||||
const [filteredUsers, setFilteredUsers] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [statusFilter, setStatusFilter] = useState('active');
|
||||
const {
|
||||
users,
|
||||
filteredUsers,
|
||||
loading,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
filterValue: statusFilter,
|
||||
setFilterValue: setStatusFilter,
|
||||
fetchMembers,
|
||||
} = useMembers();
|
||||
const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);
|
||||
const [selectedUserForPayment, setSelectedUserForPayment] = useState(null);
|
||||
const [statusChanging, setStatusChanging] = useState(null);
|
||||
@@ -41,46 +47,6 @@ const AdminMembers = () => {
|
||||
const [importDialogOpen, setImportDialogOpen] = useState(false);
|
||||
const [exporting, setExporting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchMembers();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
filterUsers();
|
||||
}, [users, searchQuery, statusFilter]);
|
||||
|
||||
const fetchMembers = async () => {
|
||||
try {
|
||||
const response = await api.get('/admin/users');
|
||||
// Filter to only members
|
||||
const members = response.data.filter(user => user.role === 'member');
|
||||
setUsers(members);
|
||||
} catch (error) {
|
||||
toast.error('Failed to fetch members');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const filterUsers = () => {
|
||||
let filtered = users;
|
||||
|
||||
if (statusFilter && statusFilter !== 'all') {
|
||||
filtered = filtered.filter(user => user.status === statusFilter);
|
||||
}
|
||||
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
filtered = filtered.filter(user =>
|
||||
user.first_name.toLowerCase().includes(query) ||
|
||||
user.last_name.toLowerCase().includes(query) ||
|
||||
user.email.toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
|
||||
setFilteredUsers(filtered);
|
||||
};
|
||||
|
||||
const handleActivatePayment = (user) => {
|
||||
setSelectedUserForPayment(user);
|
||||
setPaymentDialogOpen(true);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } 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 { Badge } from '../../components/ui/badge';
|
||||
import { Input } from '../../components/ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../components/ui/tabs';
|
||||
@@ -16,71 +15,40 @@ import { UserCog, Search, Shield, UserPlus, Mail, Edit, Eye, Trash2, UserCheck,
|
||||
import StatusBadge from '../../components/StatusBadge';
|
||||
import { StatCard } from '@/components/StatCard';
|
||||
import { CircleMinus, CreditCard, Users } from 'lucide-react';
|
||||
import useMembers from '../../hooks/use-members';
|
||||
|
||||
// Staff roles (non-guest, non-member) - includes all admin-type roles
|
||||
const STAFF_ROLES = ['admin', 'superadmin', 'finance'];
|
||||
|
||||
const AdminStaff = () => {
|
||||
const navigate = useNavigate();
|
||||
const { hasPermission, user } = useAuth();
|
||||
const [users, setUsers] = useState([]);
|
||||
const [filteredUsers, setFilteredUsers] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [roleFilter, setRoleFilter] = useState('all');
|
||||
const {
|
||||
users,
|
||||
filteredUsers,
|
||||
loading,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
filterValue: roleFilter,
|
||||
setFilterValue: setRoleFilter,
|
||||
fetchMembers,
|
||||
} = useMembers({
|
||||
initialFilter: 'all',
|
||||
filterKey: 'role',
|
||||
allowedRoles: STAFF_ROLES,
|
||||
fetchErrorMessage: 'Failed to fetch staff',
|
||||
});
|
||||
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
||||
const [inviteDialogOpen, setInviteDialogOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState('staff-list');
|
||||
|
||||
// Staff roles (non-guest, non-member) - includes all admin-type roles
|
||||
const STAFF_ROLES = ['admin', 'superadmin', 'finance'];
|
||||
|
||||
useEffect(() => {
|
||||
fetchStaff();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
filterUsers();
|
||||
}, [users, searchQuery, roleFilter]);
|
||||
|
||||
const fetchStaff = async () => {
|
||||
try {
|
||||
const response = await api.get('/admin/users');
|
||||
// Filter to only staff roles
|
||||
const staffUsers = response.data.filter(user =>
|
||||
STAFF_ROLES.includes(user.role)
|
||||
);
|
||||
setUsers(staffUsers);
|
||||
} catch (error) {
|
||||
toast.error('Failed to fetch staff');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const filterUsers = () => {
|
||||
let filtered = users;
|
||||
|
||||
if (roleFilter && roleFilter !== 'all') {
|
||||
filtered = filtered.filter(user => user.role === roleFilter);
|
||||
}
|
||||
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
filtered = filtered.filter(user =>
|
||||
user.first_name.toLowerCase().includes(query) ||
|
||||
user.last_name.toLowerCase().includes(query) ||
|
||||
user.email.toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
|
||||
setFilteredUsers(filtered);
|
||||
};
|
||||
|
||||
const handleToggleStatus = async (userId, currentStatus) => {
|
||||
const newStatus = currentStatus === 'active' ? 'inactive' : 'active';
|
||||
|
||||
try {
|
||||
await api.put(`/admin/users/${userId}/status`, { status: newStatus });
|
||||
toast.success(`User ${newStatus === 'active' ? 'activated' : 'deactivated'} successfully`);
|
||||
fetchStaff(); // Refresh list
|
||||
fetchMembers(); // Refresh list
|
||||
} catch (error) {
|
||||
toast.error(error.response?.data?.detail || 'Failed to update user status');
|
||||
}
|
||||
@@ -94,7 +62,7 @@ const AdminStaff = () => {
|
||||
try {
|
||||
await api.delete(`/admin/users/${userId}`);
|
||||
toast.success('User deleted successfully');
|
||||
fetchStaff(); // Refresh list
|
||||
fetchMembers(); // Refresh list
|
||||
} catch (error) {
|
||||
toast.error(error.response?.data?.detail || 'Failed to delete user');
|
||||
}
|
||||
@@ -336,7 +304,7 @@ const AdminStaff = () => {
|
||||
<CreateStaffDialog
|
||||
open={createDialogOpen}
|
||||
onOpenChange={setCreateDialogOpen}
|
||||
onSuccess={fetchStaff}
|
||||
onSuccess={fetchMembers}
|
||||
/>
|
||||
|
||||
<InviteStaffDialog
|
||||
|
||||
Reference in New Issue
Block a user