[WEB-5158] chore: calendar start of week alignment fix and code refactoring #7978

This commit is contained in:
Anmol Singh Bhatia 2025-10-23 13:59:29 +05:30 committed by GitHub
parent f94da68597
commit 38cdf756a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 9 deletions

View file

@ -1,10 +1,13 @@
import { observable, action, makeObservable, runInAction, computed } from "mobx";
import { observable, action, makeObservable, runInAction, computed, reaction } from "mobx";
// helpers
import { computedFn } from "mobx-utils";
import type { ICalendarPayload, ICalendarWeek } from "@plane/types";
import { EStartOfTheWeek } from "@plane/types";
import { generateCalendarData, getWeekNumberOfDate } from "@plane/utils";
// types
import type { IIssueRootStore } from "./root.store";
export interface ICalendarStore {
calendarFilters: {
activeMonthDate: Date;
@ -15,6 +18,7 @@ export interface ICalendarStore {
// action
updateCalendarFilters: (filters: Partial<{ activeMonthDate: Date; activeWeekDate: Date }>) => void;
updateCalendarPayload: (date: Date) => void;
regenerateCalendar: () => void;
// computed
allWeeksOfActiveMonth:
@ -38,8 +42,10 @@ export class CalendarStore implements ICalendarStore {
activeWeekDate: new Date(),
};
calendarPayload: ICalendarPayload | null = null;
// root store
rootStore;
constructor() {
constructor(_rootStore: IIssueRootStore) {
makeObservable(this, {
loader: observable.ref,
error: observable.ref,
@ -51,6 +57,7 @@ export class CalendarStore implements ICalendarStore {
// actions
updateCalendarFilters: action,
updateCalendarPayload: action,
regenerateCalendar: action,
//computed
allWeeksOfActiveMonth: computed,
@ -58,7 +65,17 @@ export class CalendarStore implements ICalendarStore {
allDaysOfActiveWeek: computed,
});
this.rootStore = _rootStore;
this.initCalendar();
// Watch for changes in startOfWeek preference and regenerate calendar
reaction(
() => this.rootStore.rootStore.user.userProfile.data?.start_of_the_week,
() => {
// Regenerate calendar when startOfWeek preference changes
this.regenerateCalendar();
}
);
}
get allWeeksOfActiveMonth() {
@ -138,14 +155,32 @@ export class CalendarStore implements ICalendarStore {
if (!this.calendarPayload) return null;
const nextDate = new Date(date);
const startOfWeek = this.rootStore.rootStore.user.userProfile.data?.start_of_the_week ?? EStartOfTheWeek.SUNDAY;
runInAction(() => {
this.calendarPayload = generateCalendarData(this.calendarPayload, nextDate);
this.calendarPayload = generateCalendarData(this.calendarPayload, nextDate, startOfWeek);
});
};
initCalendar = () => {
const newCalendarPayload = generateCalendarData(null, new Date());
const startOfWeek = this.rootStore.rootStore.user.userProfile.data?.start_of_the_week ?? EStartOfTheWeek.SUNDAY;
const newCalendarPayload = generateCalendarData(null, new Date(), startOfWeek);
runInAction(() => {
this.calendarPayload = newCalendarPayload;
});
};
/**
* Force complete regeneration of calendar data
* This should be called when startOfWeek preference changes
*/
regenerateCalendar = () => {
const startOfWeek = this.rootStore.rootStore.user.userProfile.data?.start_of_the_week ?? EStartOfTheWeek.SUNDAY;
const { activeMonthDate } = this.calendarFilters;
// Force complete regeneration by passing null to clear all cached data
const newCalendarPayload = generateCalendarData(null, activeMonthDate, startOfWeek);
runInAction(() => {
this.calendarPayload = newCalendarPayload;

View file

@ -266,7 +266,7 @@ export class IssueRootStore implements IIssueRootStore {
this.archivedIssues = new ArchivedIssues(this, this.archivedIssuesFilter);
this.issueKanBanView = new IssueKanBanViewStore(this);
this.issueCalendarView = new CalendarStore();
this.issueCalendarView = new CalendarStore(this);
this.projectEpicsFilter = new ProjectEpicsFilter(this);
this.projectEpics = new ProjectEpics(this, this.projectEpicsFilter);

View file

@ -7,9 +7,14 @@ import { getWeekNumberOfDate, renderFormattedPayloadDate } from "./datetime";
* @returns {ICalendarPayload} calendar payload to render the calendar
* @param {ICalendarPayload | null} currentStructure current calendar payload
* @param {Date} startDate date of the month to render
* @param {EStartOfTheWeek} startOfWeek the day to start the week on
* @description Returns calendar payload to render the calendar, if currentStructure is null, it will generate the payload for the month of startDate, else it will construct the payload for the month of startDate and append it to the currentStructure
*/
export const generateCalendarData = (currentStructure: ICalendarPayload | null, startDate: Date): ICalendarPayload => {
export const generateCalendarData = (
currentStructure: ICalendarPayload | null,
startDate: Date,
startOfWeek: EStartOfTheWeek = EStartOfTheWeek.SUNDAY
): ICalendarPayload => {
const calendarData: ICalendarPayload = currentStructure ?? {};
const startMonth = startDate.getMonth();
@ -19,10 +24,15 @@ export const generateCalendarData = (currentStructure: ICalendarPayload | null,
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const totalDaysInMonth = new Date(year, month + 1, 0).getDate();
const firstDayOfMonth = new Date(year, month, 1).getDay(); // Sunday is 0, Monday is 1, ..., Saturday is 6
const firstDayOfMonthRaw = new Date(year, month, 1).getDay(); // Sunday is 0, Monday is 1, ..., Saturday is 6
// Adjust firstDayOfMonth based on startOfWeek preference
// This calculates how many empty cells we need at the start of the calendar
const firstDayOfMonth = (firstDayOfMonthRaw - startOfWeek + 7) % 7;
calendarData[`y-${year}`] ||= {};
calendarData[`y-${year}`][`m-${month}`] ||= {};
// Always reset the month data to ensure clean regeneration with correct startOfWeek
calendarData[`y-${year}`][`m-${month}`] = {};
const numWeeks = Math.ceil((totalDaysInMonth + firstDayOfMonth) / 7);
@ -50,7 +60,9 @@ export const generateCalendarData = (currentStructure: ICalendarPayload | null,
};
}
calendarData[`y-${year}`][`m-${month}`][`w-${weekNumber}`] = currentWeekObject;
// Use sequential week index instead of calculated week number for the key
// This ensures weeks are grouped correctly regardless of startOfWeek preference
calendarData[`y-${year}`][`m-${month}`][`w-${week}`] = currentWeekObject;
}
return calendarData;