124 lines
4.7 KiB
TypeScript
124 lines
4.7 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import axios from 'axios';
|
|
|
|
const API_ENDPOINT = 'https://api.portfolio.techarvest.co.zw';
|
|
|
|
interface User {
|
|
email: string;
|
|
is_active: boolean;
|
|
is_admin: boolean;
|
|
login_count: number;
|
|
login_limit: number;
|
|
}
|
|
|
|
const Admin: React.FC = () => {
|
|
const [users, setUsers] = useState<User[]>([]);
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [limit, setLimit] = useState(3);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const fetchUsers = async () => {
|
|
try {
|
|
const response = await axios.get(`${API_ENDPOINT}/admin/users`, {
|
|
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
|
|
});
|
|
setUsers(response.data);
|
|
} catch (err) {
|
|
console.error('Failed to fetch users:', err);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchUsers();
|
|
}, []);
|
|
|
|
const handleCreateUser = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setLoading(true);
|
|
setError('');
|
|
try {
|
|
await axios.post(`${API_ENDPOINT}/admin/users`, {
|
|
email,
|
|
password,
|
|
login_limit: limit
|
|
}, {
|
|
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
|
|
});
|
|
setEmail('');
|
|
setPassword('');
|
|
fetchUsers();
|
|
alert('User created successfully');
|
|
} catch (err: any) {
|
|
setError(err.response?.data?.detail || 'Failed to create user');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div style={{ maxWidth: '900px', margin: '40px auto', padding: '20px', fontFamily: 'system-ui, sans-serif' }}>
|
|
<h1 style={{ color: '#333' }}>Admin Dashboard - User Management</h1>
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 2fr', gap: '30px' }}>
|
|
{/* Create User Form */}
|
|
<section style={{ background: 'white', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
|
|
<h2 style={{ fontSize: '18px', marginBottom: '15px' }}>Create New Access</h2>
|
|
<form onSubmit={handleCreateUser} style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
|
{error && <div style={{ color: 'red', fontSize: '12px' }}>{error}</div>}
|
|
<input
|
|
type="email" placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} required
|
|
style={{ padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
|
|
/>
|
|
<input
|
|
type="password" placeholder="Password" value={password} onChange={e => setPassword(e.target.value)} required
|
|
style={{ padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
|
|
/>
|
|
<div>
|
|
<label style={{ fontSize: '12px', display: 'block', marginBottom: '4px' }}>Login Limit</label>
|
|
<input
|
|
type="number" value={limit} onChange={e => setLimit(parseInt(e.target.value))}
|
|
style={{ padding: '8px', border: '1px solid #ddd', borderRadius: '4px', width: '100%' }}
|
|
/>
|
|
</div>
|
|
<button
|
|
type="submit" disabled={loading}
|
|
style={{ padding: '10px', background: '#1a73e8', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontWeight: 'bold' }}
|
|
>
|
|
{loading ? 'Creating...' : 'Create Account'}
|
|
</button>
|
|
</form>
|
|
</section>
|
|
|
|
{/* User List */}
|
|
<section style={{ background: 'white', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
|
|
<h2 style={{ fontSize: '18px', marginBottom: '15px' }}>Active Access Keys</h2>
|
|
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '14px' }}>
|
|
<thead>
|
|
<tr style={{ borderBottom: '2px solid #eee', textAlign: 'left' }}>
|
|
<th style={{ padding: '10px' }}>Email</th>
|
|
<th style={{ padding: '10px' }}>Logins</th>
|
|
<th style={{ padding: '10px' }}>Limit</th>
|
|
<th style={{ padding: '10px' }}>Role</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{users.map(u => (
|
|
<tr key={u.email} style={{ borderBottom: '1px solid #f0f0f0' }}>
|
|
<td style={{ padding: '10px' }}>{u.email}</td>
|
|
<td style={{ padding: '10px' }}>{u.login_count}</td>
|
|
<td style={{ padding: '10px' }}>{u.login_limit}</td>
|
|
<td style={{ padding: '10px' }}>{u.is_admin ? 'Admin' : 'Guest'}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Admin;
|