Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,656 changes: 79 additions & 1,577 deletions MtdrSpring/backend/src/main/frontend/src/App.js

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions MtdrSpring/backend/src/main/frontend/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState } from 'react';
import { API_USERS } from './API';

function Login({ onLogin, loginError }) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();
if (!username || !password) return;

setIsLoading(true);

try {
const response = await fetch(`${API_USERS}/username/${username}`);
if (!response.ok) throw new Error('Invalid credentials');

const userData = await response.json();
if (userData.password === password) {
localStorage.setItem(
'currentUser',
JSON.stringify({
id: userData.id,
username: userData.username,
name: userData.name,
role: userData.role,
})
);
onLogin(userData);
} else {
throw new Error('Invalid credentials');
}
} catch (error) {
onLogin(null, error.message);
} finally {
setIsLoading(false);
}
};

return (
<div className="login-overlay">
<div className="login-container">
<h2>TODO App Login</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Logging in...' : 'Login'}
</button>
{loginError && <div className="login-error">{loginError}</div>}
</form>
</div>
</div>
);
}

export default Login;
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ function ReportsDashboard() {
if (selectedSprint) {
setLoading(true);

// Cargar tareas completadas
// Load completed tasks
fetch(`${API_URL}/reports/sprint/${selectedSprint}/completed-tasks`)
.then(response => {
if (response.ok) {
Expand Down Expand Up @@ -187,7 +187,6 @@ function ReportsDashboard() {
});

// Fetch KPI data for all developers in the selected sprint
// Vamos a cargar los KPI para cada desarrollador individualmente
if (users && users.length > 0) {
Promise.all(
users.map(user =>
Expand All @@ -201,7 +200,7 @@ function ReportsDashboard() {
})
.then(data => {
if (data) {
// Añadir información del usuario al objeto KPI
// Add information of the user to KPI object
return {
...data,
userId: user.id,
Expand All @@ -216,7 +215,7 @@ function ReportsDashboard() {
})
)
).then(results => {
// Filtrar resultados nulos
// Filter null results
const validResults = results.filter(result => result !== null);
setAllUsersKpi(validResults);

Expand Down Expand Up @@ -742,8 +741,8 @@ function ReportsDashboard() {
<CompareArrowsIcon style={{ marginRight: '5px' }} />
Comparativas
</button>
<button
className={`tab-button ${tabValue === 4 ? 'active' : ''}`}
<button
className={`tab-button ${tabValue === 4 ? 'active' : ''}`}
onClick={(e) => handleTabChange(e, 4)}
>
<ChatIcon style={{ marginRight: '5px' }} />
Expand Down Expand Up @@ -802,9 +801,11 @@ function ReportsDashboard() {

if (actualHours > 0) {
const efficiencyValue = (estimatedHours / actualHours) * 100;
if (efficiencyValue < 80) {
const EFFICIENCY_LOW_THRESHOLD = 80;
const EFFICIENCY_HIGH_THRESHOLD = 120;
if (efficiencyValue < EFFICIENCY_LOW_THRESHOLD) {
efficiencyClass = 'efficiency-low';
} else if (efficiencyValue > 120) {
} else if (efficiencyValue > EFFICIENCY_HIGH_THRESHOLD) {
efficiencyClass = 'efficiency-high';
} else {
efficiencyClass = 'efficiency-medium';
Expand All @@ -818,7 +819,7 @@ function ReportsDashboard() {
<td className="align-right">{formatHours(task.estimatedHours)}</td>
<td className="align-right">{formatHours(task.actualHours)}</td>
<td className={`align-right ${efficiencyClass}`}>
{task.actualHours > 0
{task.actualHours > 0
? formatPercentage((task.estimatedHours / task.actualHours) * 100)
: 'N/A'}
</td>
Expand Down Expand Up @@ -1061,22 +1062,21 @@ function ReportsDashboard() {
<tbody>
{userKpi.tasks.map((task, index) => {
// Calcular clase de eficiencia
let efficiencyClass = '';
if (task.completed && task.actualHours > 0) {
const efficiencyValue = (task.estimatedHours / task.actualHours) * 100;
if (efficiencyValue < 80) {
efficiencyClass = 'efficiency-low';
} else if (efficiencyValue > 120) {
efficiencyClass = 'efficiency-high';
} else {
efficiencyClass = 'efficiency-medium';
let efficiencyClass = calculateEfficiencyClass(task);
function calculateEfficiencyClass(task) {
if (task.completed && task.actualHours > 0) {
const efficiencyValue = (task.estimatedHours / task.actualHours) * 100;
if (efficiencyValue < 80) return 'efficiency-low';
if (efficiencyValue > 120) return 'efficiency-high';
return 'efficiency-medium';
}
return '';
}

// Calcular clase de estado
let statusClass = '';
const status = task.status || 'Pending';
switch(status) {
const taskStatus = task.status || 'Pending';
switch(taskStatus) {
case 'Pending':
statusClass = 'status-pending';
break;
Expand All @@ -1098,7 +1098,7 @@ function ReportsDashboard() {
<td>{task.description}</td>
<td>
<span className={`status-badge ${statusClass}`}>
{status}
{taskStatus}
</span>
</td>
<td className="align-right">{formatHours(task.estimatedHours)}</td>
Expand Down
47 changes: 47 additions & 0 deletions MtdrSpring/backend/src/main/frontend/src/components/TaskManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useState, useEffect } from 'react';
import TaskTable from './TaskTable';
import { API_LIST, API_SPRINTS } from './API';

function TaskManager({ currentUser }) {
const [tasks, setTasks] = useState([]);
const [sprints, setSprints] = useState([]);
const [selectedSprint, setSelectedSprint] = useState(null);
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
loadTasks();
loadSprints();
}, []);

const loadTasks = async () => {
setIsLoading(true);
try {
const response = await fetch(API_LIST);
const data = await response.json();
setTasks(data);
} catch (error) {
console.error('Error loading tasks:', error);
} finally {
setIsLoading(false);
}
};

const loadSprints = async () => {
try {
const response = await fetch(API_SPRINTS);
const data = await response.json();
setSprints(data);
} catch (error) {
console.error('Error loading sprints:', error);
}
};

return (
<div>
<h2>Tasks</h2>
<TaskTable tasks={tasks} currentUser={currentUser} />
</div>
);
}

export default TaskManager;
26 changes: 26 additions & 0 deletions MtdrSpring/backend/src/main/frontend/src/components/TaskTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

function TaskTable({ tasks, currentUser }) {
return (
<table>
<thead>
<tr>
<th>Description</th>
<th>Status</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
{tasks.map((task) => (
<tr key={task.id}>
<td>{task.description}</td>
<td>{task.status}</td>
<td>{task.priority}</td>
</tr>
))}
</tbody>
</table>
);
}

export default TaskTable;