fix: key drag targets by date, not weekday, in views wider than a week
Some checks are pending
Playwright Tests / test (push) Waiting to run
Some checks are pending
Playwright Tests / test (push) Waiting to run
The drop preview and the empty-slot input were keyed by date.getDay(), which is only unique inside a 7-day window. At 21 days every column sharing the hovered column's weekday lit up — the mirrored drop targets, one per Tuesday. The invisible half was worse: handleDrop resolved its target with visibleDays.find(d => d.getDay() === dayOfWeek), so dropping on the second or third Tuesday scheduled the task on the first one. Both now use the column's own date; handleDragOver/handleDrop take a Date instead of a weekday number. Task rendering was already date-based, so only drag state was affected. v1.115.3 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6f4fe219dc
commit
d4ec6b0ef3
15
CHANGELOG.md
15
CHANGELOG.md
@ -2,6 +2,21 @@
|
||||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## [1.115.3] - 2026-09-03
|
||||
|
||||
### Fixed
|
||||
- Drag & drop in views wider than 7 days: the drop target was keyed by weekday
|
||||
(`date.getDay()`), which is only unique inside a 7-day window. In a 21-day view every
|
||||
column sharing the weekday of the hovered one lit up as a drop target — three mirrored
|
||||
highlights, one per Tuesday. Now keyed by the local date.
|
||||
- Same bug, worse half: `handleDrop` resolved the target date with
|
||||
`visibleDays.find(d => d.getDay() === dayOfWeek)`, so dropping a task on the second or
|
||||
third Tuesday of a wide view silently scheduled it on the *first* Tuesday. The drop now
|
||||
uses the column's own date. Tasks dragged in a >7-day view before this fix may sit on the
|
||||
wrong date.
|
||||
- The inline "click an empty slot to add a task" input had the same weekday key, so clicking
|
||||
one slot opened an input in every column with that weekday.
|
||||
|
||||
## [1.115.2] - 2026-09-03
|
||||
|
||||
### Changed
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.115.2",
|
||||
"version": "1.115.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.115.2",
|
||||
"version": "1.115.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.11.1",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.115.2",
|
||||
"version": "1.115.3",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -1071,8 +1071,10 @@ export default function WeeklyView() {
|
||||
const [slideDirection, setSlideDirection] = useState<"next" | "prev" | null>(
|
||||
null,
|
||||
);
|
||||
// Keyed by local date ("YYYY-MM-DD"), not by weekday: with more than 7 visible day
|
||||
// columns a weekday matches several columns at once, which lit up every Tuesday.
|
||||
const [activeSlot, setActiveSlot] = useState<{
|
||||
day: number;
|
||||
dateKey: string;
|
||||
slot: string;
|
||||
} | null>(null);
|
||||
const [newSlotTask, setNewSlotTask] = useState("");
|
||||
@ -1081,7 +1083,7 @@ export default function WeeklyView() {
|
||||
);
|
||||
const [currentTime, setCurrentTime] = useState(new Date());
|
||||
const [dropPreview, setDropPreview] = useState<{
|
||||
day?: number;
|
||||
dateKey?: string;
|
||||
slot?: string;
|
||||
listId?: string;
|
||||
slotIdx?: number;
|
||||
@ -5023,7 +5025,7 @@ export default function WeeklyView() {
|
||||
|
||||
const handleDragOver = (
|
||||
e: DragEvent | React.DragEvent,
|
||||
dayOfWeek?: number,
|
||||
date?: Date,
|
||||
slot?: string,
|
||||
) => {
|
||||
// Reject someday list drags on day slots
|
||||
@ -5039,17 +5041,16 @@ export default function WeeklyView() {
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
// Update drop preview if we have day and slot info
|
||||
if (dayOfWeek !== undefined && slot) {
|
||||
setDropPreview({ day: dayOfWeek, slot });
|
||||
if (date && slot) {
|
||||
setDropPreview({ dateKey: formatDateToISO(date), slot });
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = async (e: DragEvent, dayOfWeek: number, slot?: string) => {
|
||||
const handleDrop = async (e: DragEvent, date: Date, slot?: string) => {
|
||||
e.preventDefault();
|
||||
if (draggedTask) {
|
||||
const visibleDays = getVisibleDays();
|
||||
const targetDateObj =
|
||||
visibleDays.find((d) => d.getDay() === dayOfWeek) || new Date();
|
||||
const targetDateObj = date;
|
||||
const dayOfWeek = targetDateObj.getDay();
|
||||
|
||||
let targetSlot = slot;
|
||||
|
||||
@ -7652,7 +7653,7 @@ export default function WeeklyView() {
|
||||
const isHourStart = minutes === "00";
|
||||
const slotEvents = getEventsForSlot(date, slot);
|
||||
const isActive =
|
||||
activeSlot?.day === date.getDay() &&
|
||||
activeSlot?.dateKey === formatDateToISO(date) &&
|
||||
activeSlot?.slot === slot;
|
||||
const isProtected = isSlotProtected(date, slot);
|
||||
const isOccupiedByTask = isSlotOccupiedByTask(date, slot, draggedTask?.id);
|
||||
@ -7674,7 +7675,7 @@ export default function WeeklyView() {
|
||||
}
|
||||
|
||||
if (!isActive) {
|
||||
setActiveSlot({ day: date.getDay(), slot });
|
||||
setActiveSlot({ dateKey: formatDateToISO(date), slot });
|
||||
setNewSlotTask("");
|
||||
}
|
||||
};
|
||||
@ -7694,11 +7695,11 @@ export default function WeeklyView() {
|
||||
const handleSlotDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
if (isProtected || isOccupiedByTask) return; // Don't allow dropping on protected or occupied slots
|
||||
handleDrop(e, date.getDay(), slot);
|
||||
handleDrop(e, date, slot);
|
||||
};
|
||||
|
||||
const isDropTarget =
|
||||
dropPreview?.day === date.getDay() &&
|
||||
dropPreview?.dateKey === formatDateToISO(date) &&
|
||||
dropPreview?.slot === slot;
|
||||
|
||||
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||
@ -7736,7 +7737,7 @@ export default function WeeklyView() {
|
||||
}}
|
||||
onDragOver={(e) =>
|
||||
!isProtected && !isOccupiedByTask &&
|
||||
handleDragOver(e, date.getDay(), slot)
|
||||
handleDragOver(e, date, slot)
|
||||
}
|
||||
onDrop={handleSlotDrop}
|
||||
>
|
||||
@ -7947,8 +7948,8 @@ export default function WeeklyView() {
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
onDragOver={(e) => handleDragOver(e, date.getDay())}
|
||||
onDrop={(e) => handleDrop(e, date.getDay())}
|
||||
onDragOver={(e) => handleDragOver(e, date)}
|
||||
onDrop={(e) => handleDrop(e, date)}
|
||||
onDragLeave={handleDragLeave}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user