feat: update current time indicator on page refocus (#27503)

Add updateCurrentTimeOnFocus prop to Calendar component that enables
the current time indicator to update when the page is refocused.
This helps users see the accurate current time after switching tabs.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Eunjae Lee
2026-02-02 14:40:20 +00:00
committed by GitHub
co-authored by Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Peer Richelsen
parent d743c92479
commit 4b7ea0c98f
4 changed files with 48 additions and 22 deletions
@@ -1,14 +1,12 @@
"use client";
import { useMemo, useEffect } from "react";
import dayjs from "@calcom/dayjs";
import { useTimePreferences } from "@calcom/features/bookings/lib";
import { Calendar } from "@calcom/web/modules/calendars/weeklyview/components/Calendar";
import type { CalendarEvent } from "@calcom/features/calendars/weeklyview/types/events";
import { useGetTheme } from "@calcom/lib/hooks/useTheme";
import { Calendar } from "@calcom/web/modules/calendars/weeklyview/components/Calendar";
import { useBanners } from "@calcom/web/modules/shell/banners/useBanners";
import { useEffect, useMemo } from "react";
import { useBookingDetailsSheetStore } from "../store/bookingDetailsSheetStore";
import type { BookingOutput } from "../types";
@@ -101,6 +99,7 @@ export function BookingCalendarView({
}}
showTimezone
hideHeader
updateCurrentTimeOnFocus
/>
</div>
</>
@@ -1,13 +1,16 @@
import React, { useEffect, useMemo, useRef } from "react";
import {
CalendarStoreContext,
createCalendarStore,
useCalendarStore,
} from "@calcom/features/calendars/weeklyview/state/store";
import classNames from "@calcom/ui/classNames";
import { CalendarStoreContext, createCalendarStore, useCalendarStore } from "@calcom/features/calendars/weeklyview/state/store";
import type React from "react";
import { useEffect, useMemo, useRef } from "react";
import "@calcom/features/calendars/weeklyview/styles/styles.css";
import type { CalendarComponentProps } from "@calcom/features/calendars/weeklyview/types/state";
import { getDaysBetweenDates, getHoursToDisplay } from "@calcom/features/calendars/weeklyview/utils";
import { DateValues } from "./DateValues";
import { CurrentTime } from "./currentTime";
import { DateValues } from "./DateValues";
import { AvailableCellsForDay, EmptyCell } from "./event/Empty";
import { EventList } from "./event/EventList";
import { SchedulerColumns } from "./grid";
@@ -35,6 +38,7 @@ function CalendarInner(props: CalendarComponentProps) {
const showBorder = useCalendarStore((state) => state.showBorder ?? true);
const borderColor = useCalendarStore((state) => state.borderColor ?? "default");
const scrollToCurrentTime = useCalendarStore((state) => state.scrollToCurrentTime ?? true);
const updateCurrentTimeOnFocus = useCalendarStore((state) => state.updateCurrentTimeOnFocus ?? false);
const days = useMemo(() => getDaysBetweenDates(startDate, endDate), [startDate, endDate]);
@@ -75,7 +79,11 @@ function CalendarInner(props: CalendarComponentProps) {
borderColor={borderColor}
/>
<div className="relative flex flex-auto">
<CurrentTime timezone={timezone} scrollToCurrentTime={scrollToCurrentTime} />
<CurrentTime
timezone={timezone}
scrollToCurrentTime={scrollToCurrentTime}
updateOnFocus={updateCurrentTimeOnFocus}
/>
<div
className={classNames(
"bg-default dark:bg-cal-muted ring-muted sticky left-0 z-10 w-16 flex-none ring-1",
@@ -1,9 +1,7 @@
import { useEffect, useState, useRef } from "react";
import dayjs from "@calcom/dayjs";
import { useTimePreferences } from "@calcom/features/bookings/lib";
import { useCalendarStore } from "@calcom/features/calendars/weeklyview/state/store";
import { useCallback, useEffect, useRef, useState } from "react";
function calculateMinutesFromStart(startHour: number, currentHour: number, currentMinute: number) {
const startMinute = startHour * 60;
@@ -14,9 +12,11 @@ function calculateMinutesFromStart(startHour: number, currentHour: number, curre
export function CurrentTime({
timezone,
scrollToCurrentTime = true,
updateOnFocus = false,
}: {
timezone: string;
scrollToCurrentTime?: boolean;
updateOnFocus?: boolean;
}) {
const { timeFormat } = useTimePreferences();
const currentTimeRef = useRef<HTMLDivElement>(null);
@@ -27,29 +27,44 @@ export function CurrentTime({
endHour: state.endHour || 23,
}));
useEffect(() => {
// Set the container scroll position based on the current time.
const currentDateTime = dayjs().tz(timezone); // Get current date and time in the specified timezone
const updateCurrentTimePosition = useCallback(() => {
const currentDateTime = dayjs().tz(timezone);
const currentHour = currentDateTime.hour();
const currentMinute = currentDateTime.minute();
if (currentHour > endHour || currentHour < startHour) {
setCurrentTimePos(null);
return;
}
const minutesFromStart = calculateMinutesFromStart(startHour, currentHour, currentMinute);
setCurrentTimePos(minutesFromStart);
}, [timezone, startHour, endHour]);
useEffect(() => {
updateCurrentTimePosition();
if (!scrollToCurrentTime || !currentTimeRef.current || scrolledIntoView) return;
// Within a small timeout so element has time to render.
setTimeout(() => {
// Doesn't seem to cause any issue. Put it under condition if needed
currentTimeRef?.current?.scrollIntoView({ block: "center" });
setScrolledIntoView(true);
}, 100);
}, [startHour, endHour, scrolledIntoView, timezone, scrollToCurrentTime]);
}, [updateCurrentTimePosition, scrolledIntoView, scrollToCurrentTime]);
useEffect(() => {
if (!updateOnFocus) return;
const handleVisibilityChange = () => {
if (document.visibilityState === "visible") {
updateCurrentTimePosition();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, [updateOnFocus, updateCurrentTimePosition]);
return (
<div
@@ -1,6 +1,5 @@
import type { IFromUser, IToUser } from "@calcom/features/availability/lib/getUserAvailability";
import type { TimeRange } from "@calcom/types/schedule";
import type { BorderColor } from "./common";
import type { CalendarEvent } from "./events";
@@ -158,6 +157,11 @@ export type CalendarState = {
* Selected booking UID to highlight the corresponding event
*/
selectedBookingUid?: string | null;
/**
* Update the current time indicator when the page is refocused
* @default false
*/
updateCurrentTimeOnFocus?: boolean;
};
export type CalendarComponentProps = CalendarPublicActions & CalendarState & { isPending?: boolean };