316 lines
10 KiB
JavaScript
316 lines
10 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import teamService from '../services/teamService';
|
|
import './Admin.css';
|
|
|
|
const Admin = () => {
|
|
const { user, userTeams, loadUserTeams } = useAuth();
|
|
|
|
// User Management State
|
|
const [users, setUsers] = useState([]);
|
|
const [userLoading, setUserLoading] = useState(false);
|
|
const [userError, setUserError] = useState('');
|
|
|
|
// Permission Management State
|
|
const [selectedUser, setSelectedUser] = useState(null);
|
|
const [selectedTeam, setSelectedTeam] = useState(null);
|
|
const [permissionLoading, setPermissionLoading] = useState(false);
|
|
const [permissionError, setPermissionError] = useState('');
|
|
|
|
// Time Reports State
|
|
const [reports, setReports] = useState([]);
|
|
const [reportLoading, setReportLoading] = useState(false);
|
|
const [reportError, setReportError] = useState('');
|
|
const [reportStartDate, setReportStartDate] = useState(getDateString(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)));
|
|
const [reportEndDate, setReportEndDate] = useState(getDateString(new Date()));
|
|
|
|
// Load all users on mount
|
|
useEffect(() => {
|
|
fetchUsers();
|
|
}, []);
|
|
|
|
// Load initial reports
|
|
useEffect(() => {
|
|
loadTeamReports();
|
|
}, []);
|
|
|
|
// Helper function to format dates
|
|
function getDateString(date) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
// ============ USER MANAGEMENT ============
|
|
const fetchUsers = async () => {
|
|
setUserLoading(true);
|
|
setUserError('');
|
|
try {
|
|
const allUsers = await teamService.getAllUsers();
|
|
setUsers(allUsers);
|
|
} catch (error) {
|
|
console.error('Error fetching users:', error);
|
|
setUserError('Failed to load users');
|
|
} finally {
|
|
setUserLoading(false);
|
|
}
|
|
};
|
|
|
|
// ============ PERMISSION MANAGEMENT ============
|
|
const loadTeamMembers = async (teamId) => {
|
|
try {
|
|
const members = await teamService.getTeamMembers(teamId);
|
|
console.log('Team members:', members);
|
|
} catch (error) {
|
|
console.error('Error loading team members:', error);
|
|
}
|
|
};
|
|
|
|
const updateMemberRole = async (teamId, userId, newRole) => {
|
|
if (!selectedTeam || !selectedUser) {
|
|
setPermissionError('Please select a team and user first');
|
|
return;
|
|
}
|
|
|
|
setPermissionLoading(true);
|
|
setPermissionError('');
|
|
try {
|
|
await teamService.updateMemberRole(teamId, userId, newRole);
|
|
setPermissionError('');
|
|
// Reload teams to reflect changes
|
|
await loadUserTeams(user.id);
|
|
alert('Permission updated successfully');
|
|
setSelectedUser(null);
|
|
setSelectedTeam(null);
|
|
} catch (error) {
|
|
console.error('Error updating member role:', error);
|
|
setPermissionError('Failed to update permissions');
|
|
} finally {
|
|
setPermissionLoading(false);
|
|
}
|
|
};
|
|
|
|
// ============ TIME REPORTS ============
|
|
const loadTeamReports = async () => {
|
|
setReportLoading(true);
|
|
setReportError('');
|
|
try {
|
|
const startDate = new Date(reportStartDate);
|
|
const endDate = new Date(reportEndDate);
|
|
endDate.setHours(23, 59, 59, 999);
|
|
|
|
const reportsData = await teamService.getAllTeamReports(startDate, endDate);
|
|
setReports(reportsData);
|
|
} catch (error) {
|
|
console.error('Error loading reports:', error);
|
|
setReportError('Failed to load time reports');
|
|
} finally {
|
|
setReportLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleReportDateChange = () => {
|
|
loadTeamReports();
|
|
};
|
|
|
|
// ============ RENDER ============
|
|
return (
|
|
<div className="admin-page">
|
|
<header className="admin-header">
|
|
<h1>Admin Panel</h1>
|
|
<p>Manage users, permissions, and view team reports</p>
|
|
</header>
|
|
|
|
<div className="admin-sections">
|
|
{/* USER MANAGEMENT SECTION */}
|
|
<section className="admin-section">
|
|
<div className="section-header">
|
|
<h2>User Management</h2>
|
|
<button className="btn-refresh" onClick={fetchUsers} disabled={userLoading}>
|
|
{userLoading ? 'Loading...' : 'Refresh'}
|
|
</button>
|
|
</div>
|
|
|
|
{userError && <div className="error-message">{userError}</div>}
|
|
|
|
<div className="user-list">
|
|
{users.length === 0 ? (
|
|
<p>No users found</p>
|
|
) : (
|
|
<table className="users-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Email</th>
|
|
<th>Full Name</th>
|
|
<th>Company</th>
|
|
<th>Global Role</th>
|
|
<th>Created At</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{users.map((usr) => (
|
|
<tr key={usr.id}>
|
|
<td>{usr.email || 'N/A'}</td>
|
|
<td>{usr.fullName || 'N/A'}</td>
|
|
<td>{usr.company || 'N/A'}</td>
|
|
<td>
|
|
<span className={`role-badge role-${usr.globalRole}`}>
|
|
{usr.globalRole}
|
|
</span>
|
|
</td>
|
|
<td>{new Date(usr.createdAt).toLocaleDateString()}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
{/* PERMISSION MANAGEMENT SECTION */}
|
|
<section className="admin-section">
|
|
<h2>Permission Management</h2>
|
|
|
|
{permissionError && <div className="error-message">{permissionError}</div>}
|
|
|
|
<div className="permission-controls">
|
|
<div className="control-group">
|
|
<label>Select User:</label>
|
|
<select
|
|
value={selectedUser || ''}
|
|
onChange={(e) => setSelectedUser(e.target.value)}
|
|
>
|
|
<option value="">Choose a user...</option>
|
|
{users.map((usr) => (
|
|
<option key={usr.id} value={usr.id}>
|
|
{usr.email}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div className="control-group">
|
|
<label>Select Team:</label>
|
|
<select
|
|
value={selectedTeam || ''}
|
|
onChange={(e) => setSelectedTeam(e.target.value)}
|
|
>
|
|
<option value="">Choose a team...</option>
|
|
{userTeams.map((team) => (
|
|
<option key={team.id} value={team.id}>
|
|
{team.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div className="role-buttons">
|
|
<button
|
|
className="btn-role"
|
|
onClick={() => updateMemberRole(selectedTeam, selectedUser, 'admin')}
|
|
disabled={!selectedTeam || !selectedUser || permissionLoading}
|
|
>
|
|
Set as Admin
|
|
</button>
|
|
<button
|
|
className="btn-role"
|
|
onClick={() => updateMemberRole(selectedTeam, selectedUser, 'manager')}
|
|
disabled={!selectedTeam || !selectedUser || permissionLoading}
|
|
>
|
|
Set as Manager
|
|
</button>
|
|
<button
|
|
className="btn-role"
|
|
onClick={() => updateMemberRole(selectedTeam, selectedUser, 'user')}
|
|
disabled={!selectedTeam || !selectedUser || permissionLoading}
|
|
>
|
|
Set as User
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* TIME REPORTS SECTION */}
|
|
<section className="admin-section">
|
|
<div className="section-header">
|
|
<h2>Team Time Reports</h2>
|
|
<div className="report-filters">
|
|
<input
|
|
type="date"
|
|
value={reportStartDate}
|
|
onChange={(e) => setReportStartDate(e.target.value)}
|
|
/>
|
|
<span>to</span>
|
|
<input
|
|
type="date"
|
|
value={reportEndDate}
|
|
onChange={(e) => setReportEndDate(e.target.value)}
|
|
/>
|
|
<button
|
|
className="btn-refresh"
|
|
onClick={handleReportDateChange}
|
|
disabled={reportLoading}
|
|
>
|
|
{reportLoading ? 'Loading...' : 'Load Reports'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{reportError && <div className="error-message">{reportError}</div>}
|
|
|
|
<div className="reports-container">
|
|
{reports.length === 0 ? (
|
|
<p>No time reports available for the selected date range</p>
|
|
) : (
|
|
reports.map((teamReport) => (
|
|
<div key={teamReport.teamId} className="team-report-card">
|
|
<h3>{teamReport.teamName}</h3>
|
|
<table className="report-table">
|
|
<thead>
|
|
<tr>
|
|
<th>User Email</th>
|
|
<th>Role</th>
|
|
<th>Total Sessions</th>
|
|
<th>Total Time</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{teamReport.userReports.map((userReport, idx) => (
|
|
<tr key={idx}>
|
|
<td>{userReport.userEmail}</td>
|
|
<td>
|
|
<span className={`role-badge role-${userReport.memberRole}`}>
|
|
{userReport.memberRole}
|
|
</span>
|
|
</td>
|
|
<td>{userReport.totalSessions}</td>
|
|
<td>{formatDuration(userReport.totalDurationMs)}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
<div className="team-summary">
|
|
<strong>Team Total Time:</strong> {formatDuration(teamReport.totalDurationMs)}
|
|
</div>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Helper function to format duration in milliseconds
|
|
function formatDuration(ms) {
|
|
if (!ms || ms === 0) return '0h 0m';
|
|
const hours = Math.floor(ms / (1000 * 60 * 60));
|
|
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
|
|
if (hours === 0) return `${minutes}m`;
|
|
return `${hours}h ${minutes}m`;
|
|
}
|
|
|
|
export default Admin;
|