From cb4cfa1dd5a66117f029c469c73a75f821c20108 Mon Sep 17 00:00:00 2001 From: rahulramesha <71900764+rahulramesha@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:44:08 +0530 Subject: [PATCH] [WEB-782] fix: Date timezone changes error (#3992) * fix date related exceptions * replace new Date from develop branch changes as well * changes from self review * wrap getDate logic with try catch to handle in case of error scenarios * fix formatted time --- .../src/ui/components/editor-header.tsx | 3 +- .../src/ui/components/info-popover.tsx | 8 +++-- .../document-editor/src/utils/date-utils.ts | 26 +++++++++++++++ packages/types/src/pages.d.ts | 4 +-- web/components/api-token/modal/form.tsx | 2 +- .../widgets/issue-panels/issue-list-item.tsx | 9 ++---- web/components/gantt-chart/blocks/block.tsx | 10 +++--- .../notifications/notification-card.tsx | 16 ++++++---- .../select-snooze-till-modal.tsx | 10 +++--- web/components/pages/pages-list/list-item.tsx | 17 +++++----- web/helpers/cycle.helper.ts | 9 +++--- web/helpers/date-time.helper.ts | 27 +++++++++------- web/helpers/module.helper.ts | 9 +++--- web/helpers/project.helper.ts | 4 ++- .../projects/[projectId]/pages/[pageId].tsx | 10 +++--- web/store/page.store.ts | 14 ++++---- web/store/project-page.store.ts | 32 +++++++++++-------- 17 files changed, 127 insertions(+), 83 deletions(-) create mode 100644 packages/editor/document-editor/src/utils/date-utils.ts diff --git a/packages/editor/document-editor/src/ui/components/editor-header.tsx b/packages/editor/document-editor/src/ui/components/editor-header.tsx index aaa4c7be3..33ac4a0dc 100644 --- a/packages/editor/document-editor/src/ui/components/editor-header.tsx +++ b/packages/editor/document-editor/src/ui/components/editor-header.tsx @@ -7,6 +7,7 @@ import { AlertLabel } from "src/ui/components/alert-label"; import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu"; import { SummaryPopover } from "src/ui/components/summary-popover"; import { InfoPopover } from "src/ui/components/info-popover"; +import { getDate } from "src/utils/date-utils"; interface IEditorHeader { editor: Editor; @@ -72,7 +73,7 @@ export const EditorHeader = (props: IEditorHeader) => { Icon={Archive} backgroundColor="bg-blue-500/20" textColor="text-blue-500" - label={`Archived at ${archivedAt.toLocaleString()}`} + label={`Archived at ${getDate(archivedAt)?.toLocaleString()}`} /> )} diff --git a/packages/editor/document-editor/src/ui/components/info-popover.tsx b/packages/editor/document-editor/src/ui/components/info-popover.tsx index 9a17a9376..16a3452a6 100644 --- a/packages/editor/document-editor/src/ui/components/info-popover.tsx +++ b/packages/editor/document-editor/src/ui/components/info-popover.tsx @@ -3,13 +3,15 @@ import { usePopper } from "react-popper"; import { Calendar, History, Info } from "lucide-react"; // types import { DocumentDetails } from "src/types/editor-types"; +//utils +import { getDate } from "src/utils/date-utils"; type Props = { documentDetails: DocumentDetails; }; // function to render a Date in the format- 25 May 2023 at 2:53PM -const renderDate = (date: Date): string => { +const renderDate = (date: Date | undefined): string => { const options: Intl.DateTimeFormatOptions = { day: "numeric", month: "long", @@ -52,14 +54,14 @@ export const InfoPopover: React.FC = (props) => {
Last updated on
- {renderDate(documentDetails.last_updated_at)} + {renderDate(getDate(documentDetails?.last_updated_at))}
Created on
- {renderDate(documentDetails.created_on)} + {renderDate(getDate(documentDetails?.created_on))}
diff --git a/packages/editor/document-editor/src/utils/date-utils.ts b/packages/editor/document-editor/src/utils/date-utils.ts new file mode 100644 index 000000000..63c20a974 --- /dev/null +++ b/packages/editor/document-editor/src/utils/date-utils.ts @@ -0,0 +1,26 @@ +function isNumber(value: any) { + return typeof value === "number"; +} + +/** + * This method returns a date from string of type yyyy-mm-dd + * This method is recommended to use instead of new Date() as this does not introduce any timezone offsets + * @param date + * @returns date or undefined + */ +export const getDate = (date: string | Date | undefined | null): Date | undefined => { + try { + if (!date || date === "") return; + + if (typeof date !== "string" && !(date instanceof String)) return date; + const [yearString, monthString, dayString] = date.substring(0, 10).split("-"); + const year = parseInt(yearString); + const month = parseInt(monthString); + const day = parseInt(dayString); + if (!isNumber(year) || !isNumber(month) || !isNumber(day)) return; + + return new Date(year, month - 1, day); + } catch (e) { + return undefined; + } +}; diff --git a/packages/types/src/pages.d.ts b/packages/types/src/pages.d.ts index c9b3fb623..6e1e78be5 100644 --- a/packages/types/src/pages.d.ts +++ b/packages/types/src/pages.d.ts @@ -11,7 +11,7 @@ export interface IPage { archived_at: string | null; blocks: IPageBlock[]; color: string; - created_at: Date; + created_at: string | null; created_by: string; description: string; description_html: string; @@ -25,7 +25,7 @@ export interface IPage { owned_by: string; project: string; project_detail: IProjectLite; - updated_at: Date; + updated_at: string | null; updated_by: string; workspace: string; workspace_detail: IWorkspaceLite; diff --git a/web/components/api-token/modal/form.tsx b/web/components/api-token/modal/form.tsx index 3849fea74..b2b3f64dc 100644 --- a/web/components/api-token/modal/form.tsx +++ b/web/components/api-token/modal/form.tsx @@ -90,7 +90,7 @@ export const CreateApiTokenForm: React.FC = (props) => { // if never expires is toggled on, set expired_at to null if (neverExpires) payload.expired_at = null; // if never expires is toggled off, and the user has selected a custom date, set expired_at to the custom date - else if (data.expired_at === "custom") payload.expired_at = renderFormattedPayloadDate(customDate ?? new Date()); + else if (data.expired_at === "custom") payload.expired_at = renderFormattedPayloadDate(customDate); // if never expires is toggled off, and the user has selected a predefined date, set expired_at to the predefined date else { const expiryDate = getExpiryDate(data.expired_at ?? ""); diff --git a/web/components/dashboard/widgets/issue-panels/issue-list-item.tsx b/web/components/dashboard/widgets/issue-panels/issue-list-item.tsx index 72181c9b7..db2c07585 100644 --- a/web/components/dashboard/widgets/issue-panels/issue-list-item.tsx +++ b/web/components/dashboard/widgets/issue-panels/issue-list-item.tsx @@ -155,6 +155,7 @@ export const CreatedUpcomingIssueListItem: React.FC = observ if (!issue) return null; const projectDetails = getProjectById(issue.project_id); + const targetDate = getDate(issue.target_date); return ( = observ
{issue.name}
- {issue.target_date - ? isToday(new Date(issue.target_date)) - ? "Today" - : renderFormattedDate(issue.target_date) - : "-"} + {targetDate ? (isToday(targetDate) ? "Today" : renderFormattedDate(targetDate)) : "-"}
{issue.assignee_ids && issue.assignee_ids?.length > 0 ? ( @@ -210,7 +207,7 @@ export const CreatedOverdueIssueListItem: React.FC = observe const projectDetails = getProjectById(issue.project_id); - const dueBy = findTotalDaysInRange(getDate(issue.target_date), new Date(), false) ?? 0; + const dueBy: number = findTotalDaysInRange(getDate(issue.target_date), new Date(), false) ?? 0; return ( = observer((props) => { totalBlockShifts: number, dragDirection: "left" | "right" | "move" ) => { - if (!block.start_date || !block.target_date) return; + const originalStartDate = getDate(block.start_date); + const originalTargetDate = getDate(block.target_date); + + if (!originalStartDate || !originalTargetDate) return; - const originalStartDate = new Date(block.start_date); const updatedStartDate = new Date(originalStartDate); - - const originalTargetDate = new Date(block.target_date); const updatedTargetDate = new Date(originalTargetDate); // update the start date on left resize diff --git a/web/components/notifications/notification-card.tsx b/web/components/notifications/notification-card.tsx index e3716edbb..c7af0824c 100644 --- a/web/components/notifications/notification-card.tsx +++ b/web/components/notifications/notification-card.tsx @@ -4,10 +4,10 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { ArchiveRestore, Clock, MessageSquare, MoreVertical, User2 } from "lucide-react"; import { Menu } from "@headlessui/react"; -// icons +// type import type { IUserNotification, NotificationType } from "@plane/types"; // ui -import { ArchiveIcon, CustomMenu, Tooltip, TOAST_TYPE, setToast } from "@plane/ui"; +import { ArchiveIcon, CustomMenu, Tooltip, TOAST_TYPE, setToast } from "@plane/ui"; // constants import { ISSUE_OPENED, @@ -16,13 +16,13 @@ import { NOTIFICATION_SNOOZED, } from "@/constants/event-tracker"; import { snoozeOptions } from "@/constants/notification"; -// helper -import { calculateTimeAgo, renderFormattedTime, renderFormattedDate } from "@/helpers/date-time.helper"; -import { replaceUnderscoreIfSnakeCase, truncateText, stripAndTruncateHTML } from "@/helpers/string.helper"; // hooks import { useEventTracker } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; -// type +// helper +import { calculateTimeAgo, renderFormattedTime, renderFormattedDate, getDate } from "helpers/date-time.helper"; +import { replaceUnderscoreIfSnakeCase, truncateText, stripAndTruncateHTML } from "helpers/string.helper"; + type NotificationCardProps = { selectedTab: NotificationType; @@ -122,7 +122,9 @@ export const NotificationCard: React.FC = (props) => { const notificationField = notification.data.issue_activity.field; const notificationTriggeredBy = notification.triggered_by_details; - if (isSnoozedTabOpen && notification.snoozed_till! < new Date()) return null; + const snoozedTillDate = getDate(notification?.snoozed_till); + + if (snoozedTillDate && isSnoozedTabOpen && snoozedTillDate < new Date()) return null; return ( = (props) => { if (!formDataDate) return timeStamps; - const isToday = today.toDateString() === formDataDate.toDateString(); + const isToday = today.toDateString() === getDate(formDataDate)?.toDateString(); if (!isToday) return timeStamps; @@ -89,9 +91,9 @@ export const SnoozeNotificationModal: FC = (props) => { ); const minutes = parseInt(time[1]); - const dateTime = formData.date; - dateTime.setHours(hours); - dateTime.setMinutes(minutes); + const dateTime: Date | undefined = getDate(formData?.date); + dateTime?.setHours(hours); + dateTime?.setMinutes(minutes); await handleSubmitSnooze(notification.id, dateTime).then(() => { handleClose(); diff --git a/web/components/pages/pages-list/list-item.tsx b/web/components/pages/pages-list/list-item.tsx index 74fa42d71..57b41738f 100644 --- a/web/components/pages/pages-list/list-item.tsx +++ b/web/components/pages/pages-list/list-item.tsx @@ -192,14 +192,15 @@ export const PagesListItem: FC = observer(({ pageId, projectId }

{renderFormattedTime(archived_at)}

) : ( - -

{renderFormattedTime(updated_at)}

-
+ updated_at && ( + +

{renderFormattedTime(updated_at)}

+
+ ) )} {isEditingAllowed && ( 0) fallsInFilters = fallsInFilters && filter.status.includes(cycle.status.toLowerCase()); if (filterKey === "start_date" && filter.start_date && filter.start_date.length > 0) { + const startDate = getDate(cycle.start_date); filter.start_date.forEach((dateFilter) => { - fallsInFilters = - fallsInFilters && !!cycle.start_date && satisfiesDateFilter(new Date(cycle.start_date), dateFilter); + fallsInFilters = fallsInFilters && !!startDate && satisfiesDateFilter(startDate, dateFilter); }); } if (filterKey === "end_date" && filter.end_date && filter.end_date.length > 0) { + const endDate = getDate(cycle.end_date); filter.end_date.forEach((dateFilter) => { - fallsInFilters = - fallsInFilters && !!cycle.end_date && satisfiesDateFilter(new Date(cycle.end_date), dateFilter); + fallsInFilters = fallsInFilters && !!endDate && satisfiesDateFilter(endDate, dateFilter); }); } }); diff --git a/web/helpers/date-time.helper.ts b/web/helpers/date-time.helper.ts index db9bfa3bf..7ca4d49fb 100644 --- a/web/helpers/date-time.helper.ts +++ b/web/helpers/date-time.helper.ts @@ -8,7 +8,7 @@ import isNumber from "lodash/isNumber"; * @param {Date | string} date * @example renderFormattedDate("2024-01-01") // Jan 01, 2024 */ -export const renderFormattedDate = (date: string | Date | undefined): string | null => { +export const renderFormattedDate = (date: string | Date | undefined | null): string | null => { // Parse the date to check if it is valid const parsedDate = getDate(date); // return if undefined @@ -44,7 +44,7 @@ export const renderFormattedDateWithoutYear = (date: string | Date): string => { * @param {Date | string} date * @example renderFormattedPayloadDate("Jan 01, 20224") // "2024-01-01" */ -export const renderFormattedPayloadDate = (date: Date | string): string | null => { +export const renderFormattedPayloadDate = (date: Date | string | undefined | null): string | null => { // Parse the date to check if it is valid const parsedDate = getDate(date); // return if undefined @@ -67,7 +67,7 @@ export const renderFormattedPayloadDate = (date: Date | string): string | null = */ export const renderFormattedTime = (date: string | Date, timeFormat: "12-hour" | "24-hour" = "24-hour"): string => { // Parse the date to check if it is valid - const parsedDate = getDate(date); + const parsedDate = new Date(date); // return if undefined if (!parsedDate) return ""; // Check if the parsed date is valid @@ -208,14 +208,19 @@ export const checkIfDatesAreEqual = ( * @returns date or undefined */ export const getDate = (date: string | Date | undefined | null): Date | undefined => { - if (!date || date === "") return; + try { + if (!date || date === "") return; - if (typeof date !== "string" && !(date instanceof String)) return date; - const [yearString, monthString, dayString] = date.substring(0, 10).split("-"); - const year = parseInt(yearString); - const month = parseInt(monthString); - const day = parseInt(dayString); - if (!isNumber(year) || !isNumber(month) || !isNumber(day)) return; + if (typeof date !== "string" && !(date instanceof String)) return date; - return new Date(year, month - 1, day); + const [yearString, monthString, dayString] = date.substring(0, 10).split("-"); + const year = parseInt(yearString); + const month = parseInt(monthString); + const day = parseInt(dayString); + if (!isNumber(year) || !isNumber(month) || !isNumber(day)) return; + + return new Date(year, month - 1, day); + } catch (e) { + return undefined; + } }; diff --git a/web/helpers/module.helper.ts b/web/helpers/module.helper.ts index e9ce2a6ba..1a01915f2 100644 --- a/web/helpers/module.helper.ts +++ b/web/helpers/module.helper.ts @@ -1,6 +1,7 @@ import sortBy from "lodash/sortBy"; // helpers import { satisfiesDateFilter } from "@/helpers/filter.helper"; +import { getDate } from "@/helpers/date-time.helper"; // types import { IModule, TModuleDisplayFilters, TModuleFilters, TModuleOrderByOptions } from "@plane/types"; @@ -62,15 +63,15 @@ export const shouldFilterModule = ( fallsInFilters = fallsInFilters && filters.members.some((memberId) => memberIds.includes(memberId)); } if (filterKey === "start_date" && filters.start_date && filters.start_date.length > 0) { + const startDate = getDate(module.start_date); filters.start_date.forEach((dateFilter) => { - fallsInFilters = - fallsInFilters && !!module.start_date && satisfiesDateFilter(new Date(module.start_date), dateFilter); + fallsInFilters = fallsInFilters && !!startDate && satisfiesDateFilter(startDate, dateFilter); }); } if (filterKey === "target_date" && filters.target_date && filters.target_date.length > 0) { + const endDate = getDate(module.target_date); filters.target_date.forEach((dateFilter) => { - fallsInFilters = - fallsInFilters && !!module.target_date && satisfiesDateFilter(new Date(module.target_date), dateFilter); + fallsInFilters = fallsInFilters && !!endDate && satisfiesDateFilter(endDate, dateFilter); }); } }); diff --git a/web/helpers/project.helper.ts b/web/helpers/project.helper.ts index 024e77865..b4c461bb4 100644 --- a/web/helpers/project.helper.ts +++ b/web/helpers/project.helper.ts @@ -1,6 +1,7 @@ import sortBy from "lodash/sortBy"; // helpers import { satisfiesDateFilter } from "@/helpers/filter.helper"; +import { getDate } from "@/helpers/date-time.helper"; // types import { IProject, TProjectDisplayFilters, TProjectFilters, TProjectOrderByOptions } from "@plane/types"; // constants @@ -85,8 +86,9 @@ export const shouldFilterProject = ( fallsInFilters = fallsInFilters && filters.members.some((memberId) => memberIds.includes(memberId)); } if (filterKey === "created_at" && filters.created_at && filters.created_at.length > 0) { + const createdDate = getDate(project.created_at); filters.created_at.forEach((dateFilter) => { - fallsInFilters = fallsInFilters && satisfiesDateFilter(new Date(project.created_at), dateFilter); + fallsInFilters = fallsInFilters && !!createdDate && satisfiesDateFilter(createdDate, dateFilter); }); } }); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index 56b3ac32d..02fb238fe 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -266,8 +266,8 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { documentDetails={{ title: pageTitle, created_by: created_by, - created_on: created_at, - last_updated_at: updated_at, + created_on: getDate(created_at) ?? new Date(created_at ?? ""), + last_updated_at: getDate(updated_at) ?? new Date(created_at ?? ""), last_updated_by: updated_by, }} pageLockConfig={userCanLock && !archived_at ? { action: unlockPage, is_locked: is_locked } : undefined} @@ -277,7 +277,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { ? { action: archived_at ? unArchivePage : archivePage, is_archived: archived_at ? true : false, - archived_at: archived_at ? getDate(archived_at) : undefined, + archived_at: getDate(archived_at), } : undefined } @@ -293,8 +293,8 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { documentDetails={{ title: pageTitle, created_by: created_by, - created_on: created_at, - last_updated_at: updated_at, + created_on: getDate(created_at) ?? new Date(created_at ?? ""), + last_updated_at: getDate(updated_at) ?? new Date(created_at ?? ""), last_updated_by: updated_by, }} uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} diff --git a/web/store/page.store.ts b/web/store/page.store.ts index 7428b20e8..60b8e3c69 100644 --- a/web/store/page.store.ts +++ b/web/store/page.store.ts @@ -10,7 +10,7 @@ export interface IPageStore { access: number; archived_at: string | null; color: string; - created_at: Date; + created_at: string | null; created_by: string; description: string; description_html: string; @@ -23,7 +23,7 @@ export interface IPageStore { name: string; owned_by: string; project: string; - updated_at: Date; + updated_at: string | null; updated_by: string; workspace: string; @@ -52,7 +52,7 @@ export class PageStore implements IPageStore { isSubmitting: "submitting" | "submitted" | "saved" = "saved"; archived_at: string | null; color: string; - created_at: Date; + created_at: string | null; created_by: string; description: string; description_html = ""; @@ -64,7 +64,7 @@ export class PageStore implements IPageStore { name = ""; owned_by: string; project: string; - updated_at: Date; + updated_at: string | null; updated_by: string; workspace: string; oldName = ""; @@ -94,9 +94,9 @@ export class PageStore implements IPageStore { cleanup: action, }); this.created_by = page?.created_by || ""; - this.created_at = page?.created_at || new Date(); + this.created_at = page?.created_at ?? ""; this.color = page?.color || ""; - this.archived_at = page?.archived_at || null; + this.archived_at = page?.archived_at ?? null; this.name = page?.name || ""; this.description = page?.description || ""; this.description_stripped = page?.description_stripped || ""; @@ -104,7 +104,7 @@ export class PageStore implements IPageStore { this.access = page?.access || 0; this.workspace = page?.workspace || ""; this.updated_by = page?.updated_by || ""; - this.updated_at = page?.updated_at || new Date(); + this.updated_at = page?.updated_at ?? ""; this.project = page?.project || ""; this.owned_by = page?.owned_by || ""; this.labels = page?.labels || []; diff --git a/web/store/project-page.store.ts b/web/store/project-page.store.ts index 39415daf1..0e451602d 100644 --- a/web/store/project-page.store.ts +++ b/web/store/project-page.store.ts @@ -8,6 +8,8 @@ import { PageStore, IPageStore } from "@/store/page.store"; // types import { IPage, IRecentPages } from "@plane/types"; import { RootStore } from "./root.store"; +//helpers +import { getDate } from "helpers/date-time.helper"; export interface IProjectPageStore { loader: boolean; @@ -73,8 +75,8 @@ export class ProjectPageStore implements IProjectPageStore { const allProjectIds = Object.keys(this.projectPageMap[projectId]); return allProjectIds.sort((a, b) => { - const dateA = this.projectPageMap[projectId][a].created_at.getTime(); - const dateB = this.projectPageMap[projectId][b].created_at.getTime(); + const dateA = getDate(this.projectPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0; + const dateB = getDate(this.projectPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0; return dateB - dateA; }); } @@ -84,8 +86,8 @@ export class ProjectPageStore implements IProjectPageStore { if (!projectId || !this.projectArchivedPageMap[projectId]) return []; const archivedPages = Object.keys(this.projectArchivedPageMap[projectId]); return archivedPages.sort((a, b) => { - const dateA = this.projectArchivedPageMap[projectId][a].created_at.getTime(); - const dateB = this.projectArchivedPageMap[projectId][b].created_at.getTime(); + const dateA = getDate(this.projectArchivedPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0; + const dateB = getDate(this.projectArchivedPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0; return dateB - dateA; }); } @@ -126,22 +128,24 @@ export class ProjectPageStore implements IProjectPageStore { const projectId = this.rootStore.app.router.projectId; if (!this.projectPageIds || !projectId) return; - const today: string[] = this.projectPageIds.filter((page) => - isToday(this.projectPageMap[projectId][page].updated_at) - ); + const today: string[] = this.projectPageIds.filter((page) => { + const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at); + return updatedAt && isToday(updatedAt); + }); - const yesterday: string[] = this.projectPageIds.filter((page) => - isYesterday(this.projectPageMap[projectId][page].updated_at) - ); + const yesterday: string[] = this.projectPageIds.filter((page) => { + const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at); + return updatedAt && isYesterday(updatedAt); + }); const this_week: string[] = this.projectPageIds.filter((page) => { - const pageUpdatedAt = this.projectPageMap[projectId][page].updated_at; - return isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt); + const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at); + return pageUpdatedAt && isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt); }); const older: string[] = this.projectPageIds.filter((page) => { - const pageUpdatedAt = this.projectPageMap[projectId][page].updated_at; - return !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt); + const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at); + return pageUpdatedAt && !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt); }); return { today, yesterday, this_week, older };