| import React, { useState, useEffect, useCallback } from 'react'; |
| import { motion, AnimatePresence } from 'framer-motion'; |
| import { |
| Users, Search, RefreshCw, Plus, Eye, Edit, Trash2, ChevronLeft, ChevronRight, X, User |
| } from 'lucide-react'; |
| import styles from './UserManagement.module.css'; |
|
|
| const UserManagement = ({ |
| users, |
| usersLoading, |
| userPagination, |
| setUserPagination, |
| userFilter, |
| setUserFilter, |
| searchQuery, |
| setSearchQuery, |
| lastUpdate, |
| formatLastUpdate, |
| formatDate, |
| handleManualRefresh, |
| setShowAddUserModal, |
| setSelectedUser, |
| setShowUserModal, |
| setEditingUser, |
| deleteUser, |
| setIsFormActive |
| }) => { |
| return ( |
| <div className={styles['management-content']}> |
| <div className={`${styles['content-header']} ${styles['user-management-header']}`}> |
| {} |
| <div className={styles['order-header-column-1']}> |
| <div className={styles['order-header-title-section']}> |
| <h2 className={styles['order-header-title']}>User Management</h2> |
| <span className={styles['order-header-badge']}> |
| Last updated: {formatLastUpdate(lastUpdate)} |
| </span> |
| </div> |
| <div className={styles['user-header-search-section']}> |
| <div className={styles['search-bar']} style={{position:'relative'}}> |
| <Search size={20} /> |
| <input |
| type="text" |
| placeholder="Search users..." |
| value={searchQuery} |
| onChange={(e) => setSearchQuery(e.target.value)} |
| /> |
| {searchQuery && ( |
| <button |
| type="button" |
| style={{position:'absolute',right:8,top:'50%',transform:'translateY(-50%)',background:'none',border:'none',padding:0,cursor:'pointer'}} |
| onClick={() => { setSearchQuery(''); handleManualRefresh(); }} |
| aria-label="Clear search" |
| > |
| <X size={16} /> |
| </button> |
| )} |
| </div> |
| <button |
| className={`${styles['add-btn']} ${styles['adv-btn']} ${styles['order-refresh-btn']}`} |
| onClick={() => { |
| handleManualRefresh(); |
| }} |
| disabled={usersLoading} |
| > |
| <RefreshCw size={20} className={usersLoading ? styles['animate-spin'] : ''} /> |
| {usersLoading ? 'Loading...' : 'Refresh'} |
| </button> |
| </div> |
| </div> |
| |
| {} |
| <div className={styles['user-header-column-2']}> |
| <select |
| value={userFilter} |
| onChange={(e) => setUserFilter(e.target.value)} |
| className={`${styles['filter-select']} ${styles['glass']} ${styles['user-filter-select']}`} |
| > |
| <option value="all">All Users</option> |
| <option value="active">Active</option> |
| <option value="inactive">Inactive</option> |
| </select> |
| <button |
| className={`${styles['add-btn']} ${styles['adv-btn']} ${styles['user-add-btn']}`} |
| onClick={() => { |
| setShowAddUserModal(true); |
| setIsFormActive(true); |
| }} |
| > |
| <Plus size={20} /> |
| Add User |
| </button> |
| </div> |
| </div> |
| |
| <div className={`${styles['data-table']} ${styles['glass']} ${styles['user-data-table']}`} style={{boxShadow:'0 8px 32px var(--color-shadow)',marginTop:24}}> |
| <div className={`${styles['table-header']} ${styles['user-table-header']}`} style={{position:'sticky',top:0,zIndex:2}}> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>Name</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>Email</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>City</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>Phone</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}>Status</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}>Joined</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}>Actions</div> |
| </div> |
| {} |
| {usersLoading ? ( |
| Array.from({length: userPagination.limit}).map((_,i) => ( |
| <div key={i} className={`${styles['table-row']} ${styles['user-table-row']}`} style={{opacity:0.7}}> |
| {[...Array(8)].map((_,j) => ( |
| <div key={j} className={`${styles['table-cell']} ${styles['user-table-cell']}`}> |
| <div className={styles['skeleton-shimmer']} style={{height:18,borderRadius:6,background:'linear-gradient(90deg,rgba(200,200,220,0.08) 25%,rgba(180,180,200,0.18) 50%,rgba(200,200,220,0.08) 75%)',animation:'shimmer 1.2s infinite linear'}}></div> |
| </div> |
| ))} |
| </div> |
| )) |
| ) : users.length > 0 ? ( |
| users.map((user, index) => ( |
| <motion.div |
| key={user._id} |
| className={`${styles['table-row']} ${styles['user-table-row']} ${styles['user-table-row-hover']} ${index % 2 === 0 ? styles['user-table-row-alternate'] : ''}`} |
| whileHover={{scale:1.01,boxShadow:'0 4px 24px var(--color-shadow)'}} |
| style={{transition:'box-shadow 0.2s,background 0.3s'}} |
| > |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}> |
| <div className={styles['user-info']}> |
| <div className={`${styles['user-avatar']} ${styles['glass']}`}> |
| <User size={20} /> |
| </div> |
| <span>{user.name}</span> |
| </div> |
| </div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>{user.email}</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>{user.recentCity}</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-left']}`}>{user.recentPhone}</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}> |
| <span className={`${styles['status-badge']} ${user.isActive ? styles['active'] : styles['inactive']}`}>{user.isActive ? 'Active' : 'Inactive'}</span> |
| </div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}>{formatDate(user?.createdAt)}</div> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['table-cell-center']}`}> |
| <div className={styles['action-buttons-container']}> |
| <motion.button |
| className={`${styles['action-button']} ${styles['view']}`} |
| whileTap={{scale:0.95}} |
| onClick={() => { setSelectedUser(user); setShowUserModal(true); }} |
| > |
| <Plus size={20} /> |
| </motion.button> |
| <motion.button |
| className={`${styles['action-button']} ${styles['edit']}`} |
| whileTap={{scale:0.95}} |
| onClick={() => { setEditingUser(user); setShowUserModal(true); }} |
| > |
| <Edit size={20} /> |
| </motion.button> |
| <motion.button |
| className={`${styles['action-button']} ${styles['delete']}`} |
| whileTap={{scale:0.95}} |
| onClick={() => deleteUser(user._id)} |
| > |
| <Trash2 size={20} /> |
| </motion.button> |
| </div> |
| </div> |
| </motion.div> |
| )) |
| ) : ( |
| <div className={`${styles['table-row']} ${styles['user-table-row']}`}> |
| <div className={`${styles['table-cell']} ${styles['user-table-cell']} ${styles['empty-state-container']}`} colSpan="5" style={{textAlign: 'center', padding: '40px 20px'}}> |
| <div className={styles['empty-state-content']}> |
| <Users size={48} className={styles['empty-state-icon']} /> |
| <div className={styles['empty-state-text']}> |
| <p className={styles['empty-state-title']}> |
| {searchQuery ? 'No users found matching your search' : 'No users found'} |
| </p> |
| <p className={styles['empty-state-subtitle']}> |
| {searchQuery ? 'Try adjusting your search terms' : 'Users will appear here once they register'} |
| </p> |
| </div> |
| {searchQuery ? ( |
| <button |
| className={`${styles['adv-btn']} ${styles['empty-state-button']} ${styles['clear']}`} |
| onClick={() => setSearchQuery('')} |
| > |
| Clear Search |
| </button> |
| ) : ( |
| <button |
| className={`${styles['adv-btn']} ${styles['empty-state-button']} ${styles['add']}`} |
| onClick={() => { |
| setShowAddUserModal(true); |
| setIsFormActive(true); |
| }} |
| > |
| <Plus size={16} className={styles['empty-state-button-icon']} /> |
| Add First User |
| </button> |
| )} |
| </div> |
| </div> |
| </div> |
| )} |
| </div> |
| |
| <div className={`${styles['pagination']} ${styles['user-pagination']}`} style={{marginTop:24,display:'flex',justifyContent:'center',gap:16}}> |
| <button |
| className={`${styles['pagination-btn']} ${styles['adv-btn']}`} |
| disabled={userPagination.page === 1} |
| onClick={() => setUserPagination(prev => ({ ...prev, page: prev.page - 1 }))} |
| > |
| <ChevronLeft size={20} /> |
| </button> |
| <span className={`${styles['pagination-info']} ${styles['user-pagination-info']}`} style={{fontWeight:600}}> |
| Page {userPagination.page} of {userPagination.pages} |
| </span> |
| <button |
| className={`${styles['pagination-btn']} ${styles['adv-btn']}`} |
| disabled={userPagination.page === userPagination.pages} |
| onClick={() => setUserPagination(prev => ({ ...prev, page: prev.page + 1 }))} |
| > |
| <ChevronRight size={20} /> |
| </button> |
| </div> |
| |
| </div> |
| ); |
| }; |
|
|
| export default UserManagement; |