Files
fichajes/src/pages/Admin.js
Antoni Nuñez Romeu 114fda056d
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 3m51s
Hotfixes and CI/CD
2026-04-17 15:33:19 +02:00

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;