From 51188cb073082873d5959781a614bc4caa6e01ce Mon Sep 17 00:00:00 2001 From: Louis Mazin Date: Tue, 15 Sep 2026 20:21:53 +0200 Subject: [PATCH] test --- backend/time_tracking/views.py | 16 ++++- frontend/src/pages/TimeClockPage.jsx | 74 ++++++++++-------------- frontend/src/pages/WeeklySummaryPage.jsx | 40 ++----------- 3 files changed, 51 insertions(+), 79 deletions(-) diff --git a/backend/time_tracking/views.py b/backend/time_tracking/views.py index ea1e5a9..684b146 100644 --- a/backend/time_tracking/views.py +++ b/backend/time_tracking/views.py @@ -121,8 +121,22 @@ class TimeEntryScanView(APIView): end_time__isnull=True, ).exclude(date=now.date()).order_by('-date', '-start_time').first() if previous_open_entry: + last_date = previous_open_entry.date + previous_open_entry.end_time = datetime_time(23, 59, 59) + previous_open_entry.save(update_fields=['end_time', 'updated_at']) + + current_date = last_date + timedelta(days=1) + while current_date < now.date(): + TimeEntry.objects.create( + user=request.user, + date=current_date, + start_time=datetime_time.min, + end_time=datetime_time(23, 59, 59), + ) + current_date += timedelta(days=1) + entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time) - message = 'Sortie enregistrée. L’entrée est restée sur la journée précédente.' + message = 'Sortie enregistrée sur plusieurs jours.' else: entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time) message = 'Sortie enregistrée sans entrée correspondante.' diff --git a/frontend/src/pages/TimeClockPage.jsx b/frontend/src/pages/TimeClockPage.jsx index 0490b10..d252f27 100644 --- a/frontend/src/pages/TimeClockPage.jsx +++ b/frontend/src/pages/TimeClockPage.jsx @@ -4,12 +4,6 @@ import './TimeClockPage.css'; import { timeApi } from '../api/time'; import { useAuth } from '../context/AuthContext'; -const getNextDateKey = (dateKey) => { - const nextDate = new Date(`${dateKey}T12:00:00`); - nextDate.setDate(nextDate.getDate() + 1); - return nextDate.toISOString().slice(0, 10); -}; - const TimeClockPage = () => { const videoRef = useRef(null); const streamRef = useRef(null); @@ -80,10 +74,24 @@ const TimeClockPage = () => { end_time: newEntry.end_time, }); } else { - await Promise.all([ - timeApi.createTimeEntry({ date: newEntry.date, start_time: newEntry.start_time }), - timeApi.createTimeEntry({ date: newEntry.end_date, end_time: newEntry.end_time }), - ]); + const dates = []; + const cursor = new Date(`${newEntry.date}T12:00:00`); + const lastDate = new Date(`${newEntry.end_date}T12:00:00`); + + while (cursor <= lastDate) { + dates.push(cursor.toISOString().slice(0, 10)); + cursor.setDate(cursor.getDate() + 1); + } + + await Promise.all(dates.map((date, index) => { + if (index === 0) { + return timeApi.createTimeEntry({ date, start_time: newEntry.start_time }); + } + if (index === dates.length - 1) { + return timeApi.createTimeEntry({ date, end_time: newEntry.end_time }); + } + return timeApi.createTimeEntry({ date, start_time: '00:00', end_time: '23:59' }); + })); } setNewEntry({ date: new Date().toISOString().split('T')[0], @@ -280,46 +288,28 @@ const TimeClockPage = () => { }; const getDisplayTimeEntries = () => { - const pairedEndIds = new Set(); - const expanded = []; const toMinutes = (time) => { const [hours, minutes] = time.split(':').map(Number); return hours * 60 + minutes; }; - timeEntries.forEach((entry) => { - if (!entry.start_time && entry.end_time) return; - + return timeEntries.map((entry) => { if (entry.start_time && !entry.end_time) { - const dateKey = String(entry.date).slice(0, 10); - const matchingEnd = timeEntries.find((candidate) => ( - candidate.id !== entry.id && - !candidate.start_time && - candidate.end_time && - String(candidate.date).slice(0, 10) === getNextDateKey(dateKey) && - (candidate.user === entry.user || candidate.username === entry.username) - )); - - if (matchingEnd) { - pairedEndIds.add(matchingEnd.id); - expanded.push({ - ...entry, - end_time: '24:00:00', - duration: (1440 - toMinutes(entry.start_time)) / 60, - }); - expanded.push({ - ...matchingEnd, - start_time: '00:00:00', - duration: toMinutes(matchingEnd.end_time) / 60, - }); - return; - } + return { + ...entry, + end_time: '24:00:00', + duration: (1440 - toMinutes(entry.start_time)) / 60, + }; } - - expanded.push(entry); + if (!entry.start_time && entry.end_time) { + return { + ...entry, + start_time: '00:00:00', + duration: toMinutes(entry.end_time) / 60, + }; + } + return entry; }); - - return expanded.filter((entry) => !pairedEndIds.has(entry.id)); }; const formatDate = (dateString) => { diff --git a/frontend/src/pages/WeeklySummaryPage.jsx b/frontend/src/pages/WeeklySummaryPage.jsx index 341914b..eb1ffd3 100644 --- a/frontend/src/pages/WeeklySummaryPage.jsx +++ b/frontend/src/pages/WeeklySummaryPage.jsx @@ -8,44 +8,12 @@ const DEFAULT_END_HOUR = 18; const HOUR_HEIGHT = 64; const USER_COLORS = ['#c56a3d', '#3d7c8c', '#8a5a9e', '#5d8b55', '#c08a32', '#b04f66', '#4772a8']; -const getNextDateKey = (dateKey) => { - const nextDate = new Date(`${dateKey}T12:00:00`); - nextDate.setDate(nextDate.getDate() + 1); - return nextDate.toISOString().slice(0, 10); -}; - const expandOvernightAttendances = (entries) => { - const pairedEndIds = new Set(); - const expanded = []; - - entries.forEach((entry) => { - if (!entry.start_time && entry.end_time) { - return; - } - - if (entry.start_time && !entry.end_time) { - const dateKey = String(entry.date).slice(0, 10); - const nextDateKey = getNextDateKey(dateKey); - const matchingEnd = entries.find((candidate) => ( - candidate.id !== entry.id && - !candidate.start_time && - candidate.end_time && - String(candidate.date).slice(0, 10) === nextDateKey && - (candidate.user === entry.user || candidate.username === entry.username) - )); - - if (matchingEnd) { - pairedEndIds.add(matchingEnd.id); - expanded.push({ ...entry, end_time: '24:00:00' }); - expanded.push({ ...matchingEnd, start_time: '00:00:00' }); - return; - } - } - - expanded.push(entry); + return entries.map((entry) => { + if (entry.start_time && !entry.end_time) return { ...entry, end_time: '24:00:00' }; + if (!entry.start_time && entry.end_time) return { ...entry, start_time: '00:00:00' }; + return entry; }); - - return expanded.filter((entry) => !pairedEndIds.has(entry.id)); }; const WeeklySummaryPage = ({ userId }) => {