Skip to content
Open
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
45 changes: 28 additions & 17 deletions src/components/timesheet/TimeEntryModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,6 @@ export function TimeEntryModal({ isOpen, onClose, date, entry }: TimeEntryModalP
const [taskId, setTaskId] = useState('');
const [hours, setHours] = useState('');
const [minutes, setMinutes] = useState('');

// When hours is 24, minutes must be 0
const handleHoursChange = (value: string) => {
setHours(value);
if (parseInt(value) >= 24) {
setMinutes('0');
}
};
const [notes, setNotes] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [extensionInstalled, setExtensionInstalled] = useState<boolean | null>(null);
Expand Down Expand Up @@ -126,10 +118,11 @@ export function TimeEntryModal({ isOpen, onClose, date, entry }: TimeEntryModalP
// Find task by code and use its id
const task = project?.tasks.find((t) => t.code === entry.taskId);
setTaskId(task?.id || '');
const h = Math.floor(entry.hours);
const m = Math.round((entry.hours - h) * 60);
setHours(h.toString());
setMinutes(m.toString());
const totalMinutes = Math.round(entry.hours * 60);
const h = Math.floor(totalMinutes / 60);
const m = totalMinutes % 60;
setHours(h > 0 ? h.toString() : '');
setMinutes(m > 0 ? m.toString() : '');
setNotes(entry.notes || '');
} else {
// New entry - use matching customer option value
Expand Down Expand Up @@ -183,7 +176,9 @@ export function TimeEntryModal({ isOpen, onClose, date, entry }: TimeEntryModalP
e.preventDefault();
if (!date || !projectId || !taskId || isSubmitting) return;

const totalHours = (parseInt(hours) || 0) + (parseInt(minutes) || 0) / 60;
const h = Math.max(0, Math.min(24, parseInt(hours) || 0));
const m = h >= 24 ? 0 : Math.max(0, Math.min(59, parseInt(minutes) || 0));
const totalHours = h + m / 60;
if (totalHours <= 0) return;

const project = projects.find((p) => p.id === projectId);
Expand Down Expand Up @@ -341,17 +336,33 @@ export function TimeEntryModal({ isOpen, onClose, date, entry }: TimeEntryModalP
min="0"
max="24"
value={hours}
onChange={(e) => handleHoursChange(e.target.value)}
onChange={(e) => {
const v = e.target.value;
if (v === '') {
setHours('');
return;
}
const n = Math.max(0, Math.min(24, parseInt(v) || 0));
setHours(n.toString());
if (n >= 24) setMinutes('0');
}}
placeholder="0"
/>
<Input
label="Minutes"
type="number"
min="0"
max="45"
step="15"
max="59"
value={minutes}
onChange={(e) => setMinutes(e.target.value)}
onChange={(e) => {
const v = e.target.value;
if (v === '') {
setMinutes('');
return;
}
const n = Math.max(0, Math.min(59, parseInt(v) || 0));
setMinutes(n.toString());
}}
placeholder="0"
Comment on lines 352 to 366
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8c039d8. Both onChange handlers now clamp values to valid ranges (hours 0-24, minutes 0-59). The submit handler also clamps before computing totalHours as a safety net.

disabled={parseInt(hours) >= 24}
/>
Expand Down
Loading