185 lines
7.7 KiB
HTML
185 lines
7.7 KiB
HTML
{% extends "layout.html" %}
|
|
|
|
{% block content %}
|
|
<div class="timetrack-container">
|
|
<h2>Team Hours</h2>
|
|
|
|
<div class="date-filter">
|
|
<form id="date-range-form" method="GET" action="{{ url_for('team_hours') }}">
|
|
<div class="form-group">
|
|
<label for="start-date">Start Date:</label>
|
|
<input type="date" id="start-date" name="start_date" value="{{ start_date.strftime('%Y-%m-%d') }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="end-date">End Date:</label>
|
|
<input type="date" id="end-date" name="end_date" value="{{ end_date.strftime('%Y-%m-%d') }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="include-self">
|
|
<input type="checkbox" id="include-self" name="include_self" {% if request.args.get('include_self') %}checked{% endif %}> Include my hours
|
|
</label>
|
|
</div>
|
|
<button type="submit" class="btn">Apply Filter</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="team-hours-container">
|
|
<div id="loading">Loading team data...</div>
|
|
<div id="team-info" style="display: none;">
|
|
<h3>Team: <span id="team-name"></span></h3>
|
|
<p id="team-description"></p>
|
|
</div>
|
|
|
|
<div id="team-hours-table" style="display: none;">
|
|
<table class="time-history">
|
|
<thead id="table-header">
|
|
<tr>
|
|
<th>Team Member</th>
|
|
{% for date in date_range %}
|
|
<th>{{ date.strftime('%a, %b %d') }}</th>
|
|
{% endfor %}
|
|
<th>Total Hours</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="table-body">
|
|
<!-- Team member data will be added dynamically -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div id="no-data" style="display: none;">
|
|
<p>No time entries found for the selected date range.</p>
|
|
</div>
|
|
|
|
<div id="error-message" style="display: none;" class="error-message">
|
|
<!-- Error messages will be displayed here -->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="team-hours-details" id="member-details" style="display: none;">
|
|
<h3>Detailed Entries for <span id="selected-member"></span></h3>
|
|
<table class="time-history">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Arrival</th>
|
|
<th>Departure</th>
|
|
<th>Work Duration</th>
|
|
<th>Break Duration</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="details-body">
|
|
<!-- Entry details will be added dynamically -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Load team hours data when the page loads
|
|
loadTeamHoursData();
|
|
|
|
// Handle date filter form submission
|
|
document.getElementById('date-range-form').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
loadTeamHoursData();
|
|
});
|
|
|
|
function loadTeamHoursData() {
|
|
// Show loading indicator
|
|
document.getElementById('loading').style.display = 'block';
|
|
document.getElementById('team-hours-table').style.display = 'none';
|
|
document.getElementById('team-info').style.display = 'none';
|
|
document.getElementById('no-data').style.display = 'none';
|
|
document.getElementById('error-message').style.display = 'none';
|
|
document.getElementById('member-details').style.display = 'none';
|
|
|
|
// Get filter values
|
|
const startDate = document.getElementById('start-date').value;
|
|
const endDate = document.getElementById('end-date').value;
|
|
const includeSelf = document.getElementById('include-self').checked;
|
|
|
|
// Build API URL with query parameters
|
|
const apiUrl = `/api/team/hours_data?start_date=${startDate}&end_date=${endDate}&include_self=${includeSelf}`;
|
|
|
|
// Fetch data from API
|
|
fetch(apiUrl)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
return response.json().then(data => {
|
|
throw new Error(data.message || 'Failed to load team hours data');
|
|
});
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.success) {
|
|
displayTeamData(data);
|
|
} else {
|
|
showError(data.message || 'Failed to load team hours data.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching team hours data:', error);
|
|
showError(error.message || 'An error occurred while loading the team hours data.');
|
|
});
|
|
}
|
|
|
|
function displayTeamData(data) {
|
|
// Populate team info
|
|
document.getElementById('team-name').textContent = data.team.name;
|
|
document.getElementById('team-description').textContent = data.team.description || '';
|
|
document.getElementById('team-info').style.display = 'block';
|
|
|
|
// Populate team hours table
|
|
const tableHeader = document.getElementById('table-header').querySelector('tr');
|
|
tableHeader.innerHTML = '<th>Team Member</th>';
|
|
data.date_range.forEach(dateStr => {
|
|
const th = document.createElement('th');
|
|
th.textContent = new Date(dateStr).toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' });
|
|
tableHeader.appendChild(th);
|
|
});
|
|
const totalHoursTh = document.createElement('th');
|
|
totalHoursTh.textContent = 'Total Hours';
|
|
tableHeader.appendChild(totalHoursTh);
|
|
|
|
const tableBody = document.getElementById('table-body');
|
|
tableBody.innerHTML = '';
|
|
data.team_data.forEach(memberData => {
|
|
const row = document.createElement('tr');
|
|
|
|
// Add username cell
|
|
const usernameCell = document.createElement('td');
|
|
usernameCell.textContent = memberData.user.username;
|
|
row.appendChild(usernameCell);
|
|
|
|
// Add daily hours cells
|
|
data.date_range.forEach(dateStr => {
|
|
const cell = document.createElement('td');
|
|
cell.textContent = `${memberData.daily_hours[dateStr] || 0}h`;
|
|
row.appendChild(cell);
|
|
});
|
|
|
|
// Add total hours cell
|
|
const totalCell = document.createElement('td');
|
|
totalCell.innerHTML = `<strong>${memberData.total_hours}h</strong>`;
|
|
row.appendChild(totalCell);
|
|
|
|
tableBody.appendChild(row);
|
|
});
|
|
|
|
// Populate detailed entries
|
|
document.getElementById('team-hours-table').style.display = 'block';
|
|
document.getElementById('loading').style.display = 'none';
|
|
}
|
|
|
|
function showError(message) {
|
|
document.getElementById('error-message').textContent = message;
|
|
document.getElementById('error-message').style.display = 'block';
|
|
document.getElementById('loading').style.display = 'none';
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|