forked from github/plane
[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
This commit is contained in:
parent
7d3a96b3d0
commit
cb4cfa1dd5
@ -7,6 +7,7 @@ import { AlertLabel } from "src/ui/components/alert-label";
|
|||||||
import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu";
|
import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu";
|
||||||
import { SummaryPopover } from "src/ui/components/summary-popover";
|
import { SummaryPopover } from "src/ui/components/summary-popover";
|
||||||
import { InfoPopover } from "src/ui/components/info-popover";
|
import { InfoPopover } from "src/ui/components/info-popover";
|
||||||
|
import { getDate } from "src/utils/date-utils";
|
||||||
|
|
||||||
interface IEditorHeader {
|
interface IEditorHeader {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
@ -72,7 +73,7 @@ export const EditorHeader = (props: IEditorHeader) => {
|
|||||||
Icon={Archive}
|
Icon={Archive}
|
||||||
backgroundColor="bg-blue-500/20"
|
backgroundColor="bg-blue-500/20"
|
||||||
textColor="text-blue-500"
|
textColor="text-blue-500"
|
||||||
label={`Archived at ${archivedAt.toLocaleString()}`}
|
label={`Archived at ${getDate(archivedAt)?.toLocaleString()}`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -3,13 +3,15 @@ import { usePopper } from "react-popper";
|
|||||||
import { Calendar, History, Info } from "lucide-react";
|
import { Calendar, History, Info } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import { DocumentDetails } from "src/types/editor-types";
|
import { DocumentDetails } from "src/types/editor-types";
|
||||||
|
//utils
|
||||||
|
import { getDate } from "src/utils/date-utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
documentDetails: DocumentDetails;
|
documentDetails: DocumentDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
// function to render a Date in the format- 25 May 2023 at 2:53PM
|
// 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 = {
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
@ -52,14 +54,14 @@ export const InfoPopover: React.FC<Props> = (props) => {
|
|||||||
<h6 className="text-xs text-custom-text-400">Last updated on</h6>
|
<h6 className="text-xs text-custom-text-400">Last updated on</h6>
|
||||||
<h5 className="flex items-center gap-1 text-sm">
|
<h5 className="flex items-center gap-1 text-sm">
|
||||||
<History className="h-3 w-3" />
|
<History className="h-3 w-3" />
|
||||||
{renderDate(documentDetails.last_updated_at)}
|
{renderDate(getDate(documentDetails?.last_updated_at))}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<h6 className="text-xs text-custom-text-400">Created on</h6>
|
<h6 className="text-xs text-custom-text-400">Created on</h6>
|
||||||
<h5 className="flex items-center gap-1 text-sm">
|
<h5 className="flex items-center gap-1 text-sm">
|
||||||
<Calendar className="h-3 w-3" />
|
<Calendar className="h-3 w-3" />
|
||||||
{renderDate(documentDetails.created_on)}
|
{renderDate(getDate(documentDetails?.created_on))}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
26
packages/editor/document-editor/src/utils/date-utils.ts
Normal file
26
packages/editor/document-editor/src/utils/date-utils.ts
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
};
|
4
packages/types/src/pages.d.ts
vendored
4
packages/types/src/pages.d.ts
vendored
@ -11,7 +11,7 @@ export interface IPage {
|
|||||||
archived_at: string | null;
|
archived_at: string | null;
|
||||||
blocks: IPageBlock[];
|
blocks: IPageBlock[];
|
||||||
color: string;
|
color: string;
|
||||||
created_at: Date;
|
created_at: string | null;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
description: string;
|
description: string;
|
||||||
description_html: string;
|
description_html: string;
|
||||||
@ -25,7 +25,7 @@ export interface IPage {
|
|||||||
owned_by: string;
|
owned_by: string;
|
||||||
project: string;
|
project: string;
|
||||||
project_detail: IProjectLite;
|
project_detail: IProjectLite;
|
||||||
updated_at: Date;
|
updated_at: string | null;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
workspace: string;
|
workspace: string;
|
||||||
workspace_detail: IWorkspaceLite;
|
workspace_detail: IWorkspaceLite;
|
||||||
|
@ -90,7 +90,7 @@ export const CreateApiTokenForm: React.FC<Props> = (props) => {
|
|||||||
// if never expires is toggled on, set expired_at to null
|
// if never expires is toggled on, set expired_at to null
|
||||||
if (neverExpires) payload.expired_at = 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
|
// 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
|
// if never expires is toggled off, and the user has selected a predefined date, set expired_at to the predefined date
|
||||||
else {
|
else {
|
||||||
const expiryDate = getExpiryDate(data.expired_at ?? "");
|
const expiryDate = getExpiryDate(data.expired_at ?? "");
|
||||||
|
@ -155,6 +155,7 @@ export const CreatedUpcomingIssueListItem: React.FC<IssueListItemProps> = observ
|
|||||||
if (!issue) return null;
|
if (!issue) return null;
|
||||||
|
|
||||||
const projectDetails = getProjectById(issue.project_id);
|
const projectDetails = getProjectById(issue.project_id);
|
||||||
|
const targetDate = getDate(issue.target_date);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlLink
|
<ControlLink
|
||||||
@ -170,11 +171,7 @@ export const CreatedUpcomingIssueListItem: React.FC<IssueListItemProps> = observ
|
|||||||
<h6 className="text-sm flex-grow truncate">{issue.name}</h6>
|
<h6 className="text-sm flex-grow truncate">{issue.name}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-center">
|
<div className="text-xs text-center">
|
||||||
{issue.target_date
|
{targetDate ? (isToday(targetDate) ? "Today" : renderFormattedDate(targetDate)) : "-"}
|
||||||
? isToday(new Date(issue.target_date))
|
|
||||||
? "Today"
|
|
||||||
: renderFormattedDate(issue.target_date)
|
|
||||||
: "-"}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs flex justify-center">
|
<div className="text-xs flex justify-center">
|
||||||
{issue.assignee_ids && issue.assignee_ids?.length > 0 ? (
|
{issue.assignee_ids && issue.assignee_ids?.length > 0 ? (
|
||||||
@ -210,7 +207,7 @@ export const CreatedOverdueIssueListItem: React.FC<IssueListItemProps> = observe
|
|||||||
|
|
||||||
const projectDetails = getProjectById(issue.project_id);
|
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 (
|
return (
|
||||||
<ControlLink
|
<ControlLink
|
||||||
|
@ -3,7 +3,7 @@ import { observer } from "mobx-react";
|
|||||||
// components
|
// components
|
||||||
// helpers
|
// helpers
|
||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||||
import { useIssueDetail } from "@/hooks/store";
|
import { useIssueDetail } from "@/hooks/store";
|
||||||
// types
|
// types
|
||||||
// constants
|
// constants
|
||||||
@ -45,12 +45,12 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
|
|||||||
totalBlockShifts: number,
|
totalBlockShifts: number,
|
||||||
dragDirection: "left" | "right" | "move"
|
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 updatedStartDate = new Date(originalStartDate);
|
||||||
|
|
||||||
const originalTargetDate = new Date(block.target_date);
|
|
||||||
const updatedTargetDate = new Date(originalTargetDate);
|
const updatedTargetDate = new Date(originalTargetDate);
|
||||||
|
|
||||||
// update the start date on left resize
|
// update the start date on left resize
|
||||||
|
@ -4,10 +4,10 @@ import Link from "next/link";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { ArchiveRestore, Clock, MessageSquare, MoreVertical, User2 } from "lucide-react";
|
import { ArchiveRestore, Clock, MessageSquare, MoreVertical, User2 } from "lucide-react";
|
||||||
import { Menu } from "@headlessui/react";
|
import { Menu } from "@headlessui/react";
|
||||||
// icons
|
// type
|
||||||
import type { IUserNotification, NotificationType } from "@plane/types";
|
import type { IUserNotification, NotificationType } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { ArchiveIcon, CustomMenu, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
import { ArchiveIcon, CustomMenu, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
import {
|
import {
|
||||||
ISSUE_OPENED,
|
ISSUE_OPENED,
|
||||||
@ -16,13 +16,13 @@ import {
|
|||||||
NOTIFICATION_SNOOZED,
|
NOTIFICATION_SNOOZED,
|
||||||
} from "@/constants/event-tracker";
|
} from "@/constants/event-tracker";
|
||||||
import { snoozeOptions } from "@/constants/notification";
|
import { snoozeOptions } from "@/constants/notification";
|
||||||
// helper
|
|
||||||
import { calculateTimeAgo, renderFormattedTime, renderFormattedDate } from "@/helpers/date-time.helper";
|
|
||||||
import { replaceUnderscoreIfSnakeCase, truncateText, stripAndTruncateHTML } from "@/helpers/string.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker } from "@/hooks/store";
|
import { useEventTracker } from "@/hooks/store";
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
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 = {
|
type NotificationCardProps = {
|
||||||
selectedTab: NotificationType;
|
selectedTab: NotificationType;
|
||||||
@ -122,7 +122,9 @@ export const NotificationCard: React.FC<NotificationCardProps> = (props) => {
|
|||||||
const notificationField = notification.data.issue_activity.field;
|
const notificationField = notification.data.issue_activity.field;
|
||||||
const notificationTriggeredBy = notification.triggered_by_details;
|
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 (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
@ -10,6 +10,8 @@ import { DateDropdown } from "@/components/dropdowns";
|
|||||||
import { allTimeIn30MinutesInterval12HoursFormat } from "@/constants/notification";
|
import { allTimeIn30MinutesInterval12HoursFormat } from "@/constants/notification";
|
||||||
// ui
|
// ui
|
||||||
// types
|
// types
|
||||||
|
// helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
|
|
||||||
type SnoozeModalProps = {
|
type SnoozeModalProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -56,7 +58,7 @@ export const SnoozeNotificationModal: FC<SnoozeModalProps> = (props) => {
|
|||||||
|
|
||||||
if (!formDataDate) return timeStamps;
|
if (!formDataDate) return timeStamps;
|
||||||
|
|
||||||
const isToday = today.toDateString() === formDataDate.toDateString();
|
const isToday = today.toDateString() === getDate(formDataDate)?.toDateString();
|
||||||
|
|
||||||
if (!isToday) return timeStamps;
|
if (!isToday) return timeStamps;
|
||||||
|
|
||||||
@ -89,9 +91,9 @@ export const SnoozeNotificationModal: FC<SnoozeModalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
const minutes = parseInt(time[1]);
|
const minutes = parseInt(time[1]);
|
||||||
|
|
||||||
const dateTime = formData.date;
|
const dateTime: Date | undefined = getDate(formData?.date);
|
||||||
dateTime.setHours(hours);
|
dateTime?.setHours(hours);
|
||||||
dateTime.setMinutes(minutes);
|
dateTime?.setMinutes(minutes);
|
||||||
|
|
||||||
await handleSubmitSnooze(notification.id, dateTime).then(() => {
|
await handleSubmitSnooze(notification.id, dateTime).then(() => {
|
||||||
handleClose();
|
handleClose();
|
||||||
|
@ -192,14 +192,15 @@ export const PagesListItem: FC<IPagesListItem> = observer(({ pageId, projectId }
|
|||||||
<p className="text-sm text-custom-text-200">{renderFormattedTime(archived_at)}</p>
|
<p className="text-sm text-custom-text-200">{renderFormattedTime(archived_at)}</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Tooltip
|
updated_at && (
|
||||||
isMobile={isMobile}
|
<Tooltip
|
||||||
tooltipContent={`Last updated at ${renderFormattedTime(updated_at)} on ${renderFormattedDate(
|
tooltipContent={`Last updated at ${renderFormattedTime(updated_at)} on ${renderFormattedDate(
|
||||||
updated_at
|
updated_at
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
<p className="text-sm text-custom-text-200">{renderFormattedTime(updated_at)}</p>
|
<p className="text-sm text-custom-text-200">{renderFormattedTime(updated_at)}</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
{isEditingAllowed && (
|
{isEditingAllowed && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import sortBy from "lodash/sortBy";
|
import sortBy from "lodash/sortBy";
|
||||||
// helpers
|
// helpers
|
||||||
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
||||||
|
import { getDate } from "@/helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { ICycle, TCycleFilters } from "@plane/types";
|
import { ICycle, TCycleFilters } from "@plane/types";
|
||||||
|
|
||||||
@ -42,15 +43,15 @@ export const shouldFilterCycle = (cycle: ICycle, filter: TCycleFilters): boolean
|
|||||||
if (filterKey === "status" && filter.status && filter.status.length > 0)
|
if (filterKey === "status" && filter.status && filter.status.length > 0)
|
||||||
fallsInFilters = fallsInFilters && filter.status.includes(cycle.status.toLowerCase());
|
fallsInFilters = fallsInFilters && filter.status.includes(cycle.status.toLowerCase());
|
||||||
if (filterKey === "start_date" && filter.start_date && filter.start_date.length > 0) {
|
if (filterKey === "start_date" && filter.start_date && filter.start_date.length > 0) {
|
||||||
|
const startDate = getDate(cycle.start_date);
|
||||||
filter.start_date.forEach((dateFilter) => {
|
filter.start_date.forEach((dateFilter) => {
|
||||||
fallsInFilters =
|
fallsInFilters = fallsInFilters && !!startDate && satisfiesDateFilter(startDate, dateFilter);
|
||||||
fallsInFilters && !!cycle.start_date && satisfiesDateFilter(new Date(cycle.start_date), dateFilter);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (filterKey === "end_date" && filter.end_date && filter.end_date.length > 0) {
|
if (filterKey === "end_date" && filter.end_date && filter.end_date.length > 0) {
|
||||||
|
const endDate = getDate(cycle.end_date);
|
||||||
filter.end_date.forEach((dateFilter) => {
|
filter.end_date.forEach((dateFilter) => {
|
||||||
fallsInFilters =
|
fallsInFilters = fallsInFilters && !!endDate && satisfiesDateFilter(endDate, dateFilter);
|
||||||
fallsInFilters && !!cycle.end_date && satisfiesDateFilter(new Date(cycle.end_date), dateFilter);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@ import isNumber from "lodash/isNumber";
|
|||||||
* @param {Date | string} date
|
* @param {Date | string} date
|
||||||
* @example renderFormattedDate("2024-01-01") // Jan 01, 2024
|
* @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
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = getDate(date);
|
const parsedDate = getDate(date);
|
||||||
// return if undefined
|
// return if undefined
|
||||||
@ -44,7 +44,7 @@ export const renderFormattedDateWithoutYear = (date: string | Date): string => {
|
|||||||
* @param {Date | string} date
|
* @param {Date | string} date
|
||||||
* @example renderFormattedPayloadDate("Jan 01, 20224") // "2024-01-01"
|
* @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
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = getDate(date);
|
const parsedDate = getDate(date);
|
||||||
// return if undefined
|
// 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 => {
|
export const renderFormattedTime = (date: string | Date, timeFormat: "12-hour" | "24-hour" = "24-hour"): string => {
|
||||||
// Parse the date to check if it is valid
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = getDate(date);
|
const parsedDate = new Date(date);
|
||||||
// return if undefined
|
// return if undefined
|
||||||
if (!parsedDate) return "";
|
if (!parsedDate) return "";
|
||||||
// Check if the parsed date is valid
|
// Check if the parsed date is valid
|
||||||
@ -208,14 +208,19 @@ export const checkIfDatesAreEqual = (
|
|||||||
* @returns date or undefined
|
* @returns date or undefined
|
||||||
*/
|
*/
|
||||||
export const getDate = (date: string | Date | undefined | null): Date | 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;
|
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);
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import sortBy from "lodash/sortBy";
|
import sortBy from "lodash/sortBy";
|
||||||
// helpers
|
// helpers
|
||||||
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
||||||
|
import { getDate } from "@/helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IModule, TModuleDisplayFilters, TModuleFilters, TModuleOrderByOptions } from "@plane/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));
|
fallsInFilters = fallsInFilters && filters.members.some((memberId) => memberIds.includes(memberId));
|
||||||
}
|
}
|
||||||
if (filterKey === "start_date" && filters.start_date && filters.start_date.length > 0) {
|
if (filterKey === "start_date" && filters.start_date && filters.start_date.length > 0) {
|
||||||
|
const startDate = getDate(module.start_date);
|
||||||
filters.start_date.forEach((dateFilter) => {
|
filters.start_date.forEach((dateFilter) => {
|
||||||
fallsInFilters =
|
fallsInFilters = fallsInFilters && !!startDate && satisfiesDateFilter(startDate, dateFilter);
|
||||||
fallsInFilters && !!module.start_date && satisfiesDateFilter(new Date(module.start_date), dateFilter);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (filterKey === "target_date" && filters.target_date && filters.target_date.length > 0) {
|
if (filterKey === "target_date" && filters.target_date && filters.target_date.length > 0) {
|
||||||
|
const endDate = getDate(module.target_date);
|
||||||
filters.target_date.forEach((dateFilter) => {
|
filters.target_date.forEach((dateFilter) => {
|
||||||
fallsInFilters =
|
fallsInFilters = fallsInFilters && !!endDate && satisfiesDateFilter(endDate, dateFilter);
|
||||||
fallsInFilters && !!module.target_date && satisfiesDateFilter(new Date(module.target_date), dateFilter);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import sortBy from "lodash/sortBy";
|
import sortBy from "lodash/sortBy";
|
||||||
// helpers
|
// helpers
|
||||||
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
import { satisfiesDateFilter } from "@/helpers/filter.helper";
|
||||||
|
import { getDate } from "@/helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IProject, TProjectDisplayFilters, TProjectFilters, TProjectOrderByOptions } from "@plane/types";
|
import { IProject, TProjectDisplayFilters, TProjectFilters, TProjectOrderByOptions } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -85,8 +86,9 @@ export const shouldFilterProject = (
|
|||||||
fallsInFilters = fallsInFilters && filters.members.some((memberId) => memberIds.includes(memberId));
|
fallsInFilters = fallsInFilters && filters.members.some((memberId) => memberIds.includes(memberId));
|
||||||
}
|
}
|
||||||
if (filterKey === "created_at" && filters.created_at && filters.created_at.length > 0) {
|
if (filterKey === "created_at" && filters.created_at && filters.created_at.length > 0) {
|
||||||
|
const createdDate = getDate(project.created_at);
|
||||||
filters.created_at.forEach((dateFilter) => {
|
filters.created_at.forEach((dateFilter) => {
|
||||||
fallsInFilters = fallsInFilters && satisfiesDateFilter(new Date(project.created_at), dateFilter);
|
fallsInFilters = fallsInFilters && !!createdDate && satisfiesDateFilter(createdDate, dateFilter);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -266,8 +266,8 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
documentDetails={{
|
documentDetails={{
|
||||||
title: pageTitle,
|
title: pageTitle,
|
||||||
created_by: created_by,
|
created_by: created_by,
|
||||||
created_on: created_at,
|
created_on: getDate(created_at) ?? new Date(created_at ?? ""),
|
||||||
last_updated_at: updated_at,
|
last_updated_at: getDate(updated_at) ?? new Date(created_at ?? ""),
|
||||||
last_updated_by: updated_by,
|
last_updated_by: updated_by,
|
||||||
}}
|
}}
|
||||||
pageLockConfig={userCanLock && !archived_at ? { action: unlockPage, is_locked: is_locked } : undefined}
|
pageLockConfig={userCanLock && !archived_at ? { action: unlockPage, is_locked: is_locked } : undefined}
|
||||||
@ -277,7 +277,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
? {
|
? {
|
||||||
action: archived_at ? unArchivePage : archivePage,
|
action: archived_at ? unArchivePage : archivePage,
|
||||||
is_archived: archived_at ? true : false,
|
is_archived: archived_at ? true : false,
|
||||||
archived_at: archived_at ? getDate(archived_at) : undefined,
|
archived_at: getDate(archived_at),
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
@ -293,8 +293,8 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
documentDetails={{
|
documentDetails={{
|
||||||
title: pageTitle,
|
title: pageTitle,
|
||||||
created_by: created_by,
|
created_by: created_by,
|
||||||
created_on: created_at,
|
created_on: getDate(created_at) ?? new Date(created_at ?? ""),
|
||||||
last_updated_at: updated_at,
|
last_updated_at: getDate(updated_at) ?? new Date(created_at ?? ""),
|
||||||
last_updated_by: updated_by,
|
last_updated_by: updated_by,
|
||||||
}}
|
}}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
|
@ -10,7 +10,7 @@ export interface IPageStore {
|
|||||||
access: number;
|
access: number;
|
||||||
archived_at: string | null;
|
archived_at: string | null;
|
||||||
color: string;
|
color: string;
|
||||||
created_at: Date;
|
created_at: string | null;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
description: string;
|
description: string;
|
||||||
description_html: string;
|
description_html: string;
|
||||||
@ -23,7 +23,7 @@ export interface IPageStore {
|
|||||||
name: string;
|
name: string;
|
||||||
owned_by: string;
|
owned_by: string;
|
||||||
project: string;
|
project: string;
|
||||||
updated_at: Date;
|
updated_at: string | null;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
workspace: string;
|
workspace: string;
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ export class PageStore implements IPageStore {
|
|||||||
isSubmitting: "submitting" | "submitted" | "saved" = "saved";
|
isSubmitting: "submitting" | "submitted" | "saved" = "saved";
|
||||||
archived_at: string | null;
|
archived_at: string | null;
|
||||||
color: string;
|
color: string;
|
||||||
created_at: Date;
|
created_at: string | null;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
description: string;
|
description: string;
|
||||||
description_html = "";
|
description_html = "";
|
||||||
@ -64,7 +64,7 @@ export class PageStore implements IPageStore {
|
|||||||
name = "";
|
name = "";
|
||||||
owned_by: string;
|
owned_by: string;
|
||||||
project: string;
|
project: string;
|
||||||
updated_at: Date;
|
updated_at: string | null;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
workspace: string;
|
workspace: string;
|
||||||
oldName = "";
|
oldName = "";
|
||||||
@ -94,9 +94,9 @@ export class PageStore implements IPageStore {
|
|||||||
cleanup: action,
|
cleanup: action,
|
||||||
});
|
});
|
||||||
this.created_by = page?.created_by || "";
|
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.color = page?.color || "";
|
||||||
this.archived_at = page?.archived_at || null;
|
this.archived_at = page?.archived_at ?? null;
|
||||||
this.name = page?.name || "";
|
this.name = page?.name || "";
|
||||||
this.description = page?.description || "";
|
this.description = page?.description || "";
|
||||||
this.description_stripped = page?.description_stripped || "";
|
this.description_stripped = page?.description_stripped || "";
|
||||||
@ -104,7 +104,7 @@ export class PageStore implements IPageStore {
|
|||||||
this.access = page?.access || 0;
|
this.access = page?.access || 0;
|
||||||
this.workspace = page?.workspace || "";
|
this.workspace = page?.workspace || "";
|
||||||
this.updated_by = page?.updated_by || "";
|
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.project = page?.project || "";
|
||||||
this.owned_by = page?.owned_by || "";
|
this.owned_by = page?.owned_by || "";
|
||||||
this.labels = page?.labels || [];
|
this.labels = page?.labels || [];
|
||||||
|
@ -8,6 +8,8 @@ import { PageStore, IPageStore } from "@/store/page.store";
|
|||||||
// types
|
// types
|
||||||
import { IPage, IRecentPages } from "@plane/types";
|
import { IPage, IRecentPages } from "@plane/types";
|
||||||
import { RootStore } from "./root.store";
|
import { RootStore } from "./root.store";
|
||||||
|
//helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
|
|
||||||
export interface IProjectPageStore {
|
export interface IProjectPageStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
@ -73,8 +75,8 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||||||
|
|
||||||
const allProjectIds = Object.keys(this.projectPageMap[projectId]);
|
const allProjectIds = Object.keys(this.projectPageMap[projectId]);
|
||||||
return allProjectIds.sort((a, b) => {
|
return allProjectIds.sort((a, b) => {
|
||||||
const dateA = this.projectPageMap[projectId][a].created_at.getTime();
|
const dateA = getDate(this.projectPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0;
|
||||||
const dateB = this.projectPageMap[projectId][b].created_at.getTime();
|
const dateB = getDate(this.projectPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0;
|
||||||
return dateB - dateA;
|
return dateB - dateA;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -84,8 +86,8 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||||||
if (!projectId || !this.projectArchivedPageMap[projectId]) return [];
|
if (!projectId || !this.projectArchivedPageMap[projectId]) return [];
|
||||||
const archivedPages = Object.keys(this.projectArchivedPageMap[projectId]);
|
const archivedPages = Object.keys(this.projectArchivedPageMap[projectId]);
|
||||||
return archivedPages.sort((a, b) => {
|
return archivedPages.sort((a, b) => {
|
||||||
const dateA = this.projectArchivedPageMap[projectId][a].created_at.getTime();
|
const dateA = getDate(this.projectArchivedPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0;
|
||||||
const dateB = this.projectArchivedPageMap[projectId][b].created_at.getTime();
|
const dateB = getDate(this.projectArchivedPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0;
|
||||||
return dateB - dateA;
|
return dateB - dateA;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -126,22 +128,24 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||||||
const projectId = this.rootStore.app.router.projectId;
|
const projectId = this.rootStore.app.router.projectId;
|
||||||
if (!this.projectPageIds || !projectId) return;
|
if (!this.projectPageIds || !projectId) return;
|
||||||
|
|
||||||
const today: string[] = this.projectPageIds.filter((page) =>
|
const today: string[] = this.projectPageIds.filter((page) => {
|
||||||
isToday(this.projectPageMap[projectId][page].updated_at)
|
const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
||||||
);
|
return updatedAt && isToday(updatedAt);
|
||||||
|
});
|
||||||
|
|
||||||
const yesterday: string[] = this.projectPageIds.filter((page) =>
|
const yesterday: string[] = this.projectPageIds.filter((page) => {
|
||||||
isYesterday(this.projectPageMap[projectId][page].updated_at)
|
const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
||||||
);
|
return updatedAt && isYesterday(updatedAt);
|
||||||
|
});
|
||||||
|
|
||||||
const this_week: string[] = this.projectPageIds.filter((page) => {
|
const this_week: string[] = this.projectPageIds.filter((page) => {
|
||||||
const pageUpdatedAt = this.projectPageMap[projectId][page].updated_at;
|
const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
||||||
return isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
return pageUpdatedAt && isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
||||||
});
|
});
|
||||||
|
|
||||||
const older: string[] = this.projectPageIds.filter((page) => {
|
const older: string[] = this.projectPageIds.filter((page) => {
|
||||||
const pageUpdatedAt = this.projectPageMap[projectId][page].updated_at;
|
const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
||||||
return !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
return pageUpdatedAt && !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { today, yesterday, this_week, older };
|
return { today, yesterday, this_week, older };
|
||||||
|
Loading…
Reference in New Issue
Block a user