Skip to content

Commit 4bfa490

Browse files
committed
fixed an issue where the scrollToCurrentTime and scrollToCurrentDay functions were not working properly likely due to a race condition when setting the scrollTop and scrollLeft properties
1 parent bc47f58 commit 4bfa490

5 files changed

Lines changed: 50 additions & 49 deletions

File tree

client/src/components/time_indicator.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ function TimeIndicator() {
6161
<>
6262
<div
6363
id="time-indicator-label"
64-
className="absolute z-[150] h-fit w-fit rounded-full bg-slate-400 p-1 pl-2 pr-2"
64+
className="absolute z-[75] h-fit w-fit rounded-full bg-slate-400 p-1 pl-2 pr-2"
6565
>
6666
<p className="text-slate-100">Now</p>
6767
</div>
6868
<div
6969
id="time-indicator"
70-
className="absolute z-[150] min-h-[2px] bg-slate-200 opacity-75"
70+
className="absolute z-[75] min-h-[2px] bg-slate-200 opacity-75"
7171
></div>
7272
</>
7373
);

client/src/components/timetable.tsx

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import TimetableTask, {
1212
TimetableTaskProps,
1313
} from "@/components/timetable_task";
1414

15+
/*
16+
NOTES:
17+
- Should rename timetable-barrier to timetable-content to be more descriptive.
18+
- Should use element.parentElement for position adjusting for more clarity.
19+
*/
20+
1521
/*
1622
Returns a rect {left, right, top, bottom, width, height} of the visible area of
1723
the timetable where timetable tasks are to be rendered.
@@ -96,6 +102,11 @@ export function getDayLeftPosition(day: string) {
96102
return day_label.getBoundingClientRect().left;
97103
}
98104

105+
/*
106+
Sync the timetable-foreground element's position and size with the
107+
timetable-barrier element. Ensures foreground elements inhabit the same area
108+
as the background elements.
109+
*/
99110
function resizeAndPositionTimetableForeground() {
100111
const foreground = document.getElementById("timetable-foreground");
101112
if (foreground == null) return;
@@ -110,6 +121,10 @@ function resizeAndPositionTimetableForeground() {
110121
foreground.style.height = barrier.clientHeight + "px";
111122
}
112123

124+
/*
125+
Sync the left position of the TimetableHeaders in the foreground with their
126+
respective columns, set the top position to 0px.
127+
*/
113128
function resizeAndPositionTimetableHeaders() {
114129
const timetable_headers = document.getElementById("timetable-headers");
115130
if (timetable_headers == null) return;
@@ -140,6 +155,10 @@ function resizeAndPositionTimetableHeaders() {
140155
time_header.style.zIndex = "1000";
141156
}
142157

158+
/*
159+
Sync the TimeLabels column top position with the underlying Time column and set
160+
the left position to 0px.
161+
*/
143162
function resizeAndPositionTimetableTimeLabels() {
144163
const time_labels = document.getElementById("Time-Labels");
145164
if (time_labels == null) return;
@@ -187,6 +206,11 @@ function resizeAndPositionTimetableSeparator() {
187206
separator.style.height = col_rect.height + "px";
188207
}
189208

209+
/*
210+
Sync the timetable-tasks element's size and position with the visible area of
211+
the timetable (area returned by getVisibleTimetableRect() ). Allows overflowing
212+
TimetableTasks to be hidden.
213+
*/
190214
function resizeAndPositionTimetableTaskArea() {
191215
const task_container = document.getElementById("timetable-tasks");
192216
if (task_container == null) return;
@@ -206,9 +230,10 @@ function resizeAndPositionTimetableTaskArea() {
206230
}
207231

208232
/*
209-
Calls all of the resizeAndPosition functions.
233+
Calls all of the resizeAndPosition functions. Syncs the foreground elements of
234+
the timetable with the background elements.
210235
*/
211-
export function resizeTimetableElements() {
236+
export function resizeAndPositionTimetableElements() {
212237
resizeAndPositionTimetableForeground();
213238
resizeAndPositionTimetableHeaders();
214239
resizeAndPositionTimetableTimeLabels();
@@ -230,37 +255,25 @@ specified "top" or "bottom".
230255
export function scrollToCurrentTime(align?: string) {
231256
const timetable_barrier = document.getElementById("timetable-barrier");
232257
if (timetable_barrier == null) return;
258+
const barrier_rect = timetable_barrier.getBoundingClientRect();
233259

234260
const visible = getVisibleTimetableRect();
235261
if (visible == undefined) return;
236262

237-
const timetable = document.getElementById("timetable");
263+
const timetable = document.getElementById("timetable-background");
238264
if (timetable == null) return;
239265

240-
const time_header = document.getElementById("time-header");
241-
if (time_header == null) return;
242-
const time_header_height = time_header.getBoundingClientRect().height;
243-
if (time_header_height == undefined) return;
244-
245-
const scroll_height = timetable.scrollHeight - time_header_height;
246-
const scroll_max = scroll_height - visible.height; // Top row is sticky
247-
248-
timetable_barrier.scrollTop = 0; // Ensures consistent position
249-
250266
const now = new Date(Date.now());
251267
const now_top = getTimeTopPosition(now.getHours(), now.getMinutes());
252268
if (now_top == undefined) return;
253269

254270
let target_top;
255271
if (align === "top") target_top = visible.top;
256272
else if (align === "bottom") target_top = visible.bottom;
257-
else target_top = visible.top + visible.height / 2;
258-
259-
let scroll_amount = now_top - target_top;
260-
if (scroll_amount < 0) scroll_amount = 0;
261-
if (scroll_amount > scroll_max) scroll_amount = scroll_max;
273+
else target_top = barrier_rect.top + barrier_rect.height / 2;
262274

263-
timetable_barrier.scrollTop = scroll_amount;
275+
const scroll_amount = now_top - target_top;
276+
timetable_barrier.scrollTop += scroll_amount;
264277
}
265278

266279
/*
@@ -280,20 +293,14 @@ export function scrollToCurrentDay(align?: string) {
280293
const visible = getVisibleTimetableRect();
281294
if (visible == undefined) return;
282295

283-
const timetable = document.getElementById("timetable");
296+
const timetable = document.getElementById("timetable-background");
284297
if (timetable == null) return;
285298

286-
const time_header = document.getElementById("time-header");
287-
if (time_header == undefined) return;
299+
const time_header = document.getElementById("Time-Header");
300+
if (time_header == null) return;
288301
const time_header_width = time_header.getBoundingClientRect().width;
289-
if (time_header_width == undefined) return;
290302
const row_width = time_header_width; // easier to read later
291303

292-
const scroll_width = timetable.scrollWidth - time_header_width; // sticky
293-
const scroll_max = scroll_width - visible.width;
294-
295-
timetable_barrier.scrollLeft = 0;
296-
297304
enum DateDay {
298305
Monday = 1,
299306
Tuesday,
@@ -314,11 +321,8 @@ export function scrollToCurrentDay(align?: string) {
314321
else if (align == "right") target_left = visible.right - row_width;
315322
else target_left = visible.left + visible.width / 2 - row_width / 2;
316323

317-
let scroll_amount = today_left - target_left;
318-
if (scroll_amount < 0) scroll_amount = 0;
319-
if (scroll_amount > scroll_max) scroll_amount = scroll_max;
320-
321-
timetable_barrier.scrollLeft = scroll_amount;
324+
const scroll_amount = today_left - target_left;
325+
timetable_barrier.scrollLeft += scroll_amount;
322326
}
323327

324328
/*
@@ -355,7 +359,7 @@ There can only be one timetable per page as the logic uses ids.
355359
*/
356360
function Timetable({ timetable_tasks_props }: TimetableProps) {
357361
useEffect(() => {
358-
resizeTimetableElements();
362+
resizeAndPositionTimetableElements();
359363
scrollToCurrentTimeAndDay();
360364
});
361365

@@ -367,11 +371,11 @@ function Timetable({ timetable_tasks_props }: TimetableProps) {
367371
<div
368372
id="timetable-barrier"
369373
className="h-full w-full overflow-auto overscroll-none"
370-
onScroll={resizeTimetableElements}
374+
onScroll={resizeAndPositionTimetableElements}
371375
>
372376
<div
373-
id="timetable"
374-
className="timetable flex h-full w-full flex-row gap-[4px]"
377+
id="timetable-background"
378+
className="timetable-background flex h-full w-full flex-row gap-[4px]"
375379
>
376380
<TimetableColumn day="Time" />
377381
<TimetableColumn day="Monday" />

client/src/components/timetable_slot.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ sets positioning to sticky + top-0, darkens background colour, and
66
sets id to the label + the suffix "-header".
77
88
@prop time_label: Optional boolean determining if slot is a time label or not,
9-
if true sets positioing to sticky + left-0, also sets id to the time prop value.
9+
sets id to the time prop value.
1010
1111
@prop time: The time the slot represents, currently unused but intended to be
1212
used by drag and drop functionality.
@@ -23,10 +23,8 @@ interface TimetableSlotProps {
2323
}
2424

2525
/*
26-
A single slot of the timetable. Must have a time in HH:MM:DD format,
27-
all other props are optional.
28-
29-
Used to represent at 1 hour segment of a singular day.
26+
A single slot of the timetable (representing 1 hour of 1 day). Must have a time
27+
in HH:MM:DD format, all other props are optional.
3028
*/
3129
function TimetableSlot({
3230
label,

client/src/components/timetable_task.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ export function resizeAndPositionTimetableTask(task: HTMLElement) {
7070
const duration_height = one_hour_height * duration_hours;
7171

7272
const hours = Number(hour.substring(0, 2));
73-
console.log(hours);
7473

7574
const time_top = getTimeTopPosition(hours, start_offset_hours * 60);
7675
if (time_top == undefined) return;
@@ -320,7 +319,7 @@ function TimetableTask({
320319
</div>
321320
<div
322321
id={id + "-tooltip"}
323-
className="timetable-task-tooltip pointer-events-auto absolute z-[75] max-w-64 rounded-lg bg-slate-800 p-3"
322+
className="timetable-task-tooltip pointer-events-auto absolute z-[100] max-w-64 rounded-lg bg-slate-800 p-3"
324323
style={{ display: "none" }}
325324
onMouseOver={mouseOverHandler}
326325
onMouseOut={mouseOutHandler}

client/src/pages/[id]/schedule.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
22

33
import Timetable, {
44
getDurationMinutes,
5-
resizeTimetableElements,
5+
resizeAndPositionTimetableElements,
66
} from "@/components/timetable";
77
import { TimetableTaskProps } from "@/components/timetable_task";
88

@@ -70,11 +70,11 @@ function Schedule() {
7070
*/
7171
useEffect(() => {
7272
function addEventListeners() {
73-
window.addEventListener("resize", resizeTimetableElements);
73+
window.addEventListener("resize", resizeAndPositionTimetableElements);
7474
}
7575

7676
function removeEventListeners() {
77-
window.removeEventListener("resize", resizeTimetableElements);
77+
window.removeEventListener("resize", resizeAndPositionTimetableElements);
7878
}
7979

8080
/*

0 commit comments

Comments
 (0)