mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix date time misalignment
This commit is contained in:
parent
6bc133e3b1
commit
80a4a5dd62
@ -72,7 +72,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 ${new Date(archivedAt).toLocaleString()}`}
|
label={`Archived at ${archivedAt.toLocaleString()}`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -52,14 +52,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(new Date(documentDetails.last_updated_at))}
|
{renderDate(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(new Date(documentDetails.created_on))}
|
{renderDate(documentDetails.created_on)}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@ import { X } from "lucide-react";
|
|||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate, renderFormattedDate } from "helpers/date-time.helper";
|
import { renderFormattedPayloadDate, renderFormattedDate, getDate } from "helpers/date-time.helper";
|
||||||
import { DateFilterSelect } from "./date-filter-select";
|
import { DateFilterSelect } from "./date-filter-select";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -44,10 +44,10 @@ export const DateFilterModal: React.FC<Props> = ({ title, handleClose, isOpen, o
|
|||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const date1 = watch("date1");
|
const date1 = getDate(watch("date1"));
|
||||||
const date2 = watch("date2");
|
const date2 = getDate(watch("date1"));
|
||||||
|
|
||||||
const isInvalid = watch("filterType") === "range" ? new Date(date1) > new Date(date2) : false;
|
const isInvalid = watch("filterType") === "range" && date1 && date2 ? date1 > date2 : false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={Fragment}>
|
<Transition.Root show={isOpen} as={Fragment}>
|
||||||
@ -90,37 +90,45 @@ export const DateFilterModal: React.FC<Props> = ({ title, handleClose, isOpen, o
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="date1"
|
name="date1"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => {
|
||||||
<DayPicker
|
const dateValue = getDate(value);
|
||||||
selected={value ? new Date(value) : undefined}
|
const date2Value = getDate(watch("date2"));
|
||||||
defaultMonth={value ? new Date(value) : undefined}
|
return (
|
||||||
onSelect={(date) => {
|
|
||||||
if (!date) return;
|
|
||||||
onChange(date);
|
|
||||||
}}
|
|
||||||
mode="single"
|
|
||||||
disabled={[{ after: new Date(watch("date2")) }]}
|
|
||||||
className="border border-custom-border-200 p-3 rounded-md"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{watch("filterType") === "range" && (
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="date2"
|
|
||||||
render={({ field: { value, onChange } }) => (
|
|
||||||
<DayPicker
|
<DayPicker
|
||||||
selected={value ? new Date(value) : undefined}
|
selected={value ? dateValue : undefined}
|
||||||
defaultMonth={value ? new Date(value) : undefined}
|
defaultMonth={value ? dateValue : undefined}
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
if (!date) return;
|
if (!date) return;
|
||||||
onChange(date);
|
onChange(date);
|
||||||
}}
|
}}
|
||||||
mode="single"
|
mode="single"
|
||||||
disabled={[{ before: new Date(watch("date1")) }]}
|
disabled={date2Value ? [{ after: date2Value }] : undefined}
|
||||||
className="border border-custom-border-200 p-3 rounded-md"
|
className="border border-custom-border-200 p-3 rounded-md"
|
||||||
/>
|
/>
|
||||||
)}
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{watch("filterType") === "range" && (
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="date2"
|
||||||
|
render={({ field: { value, onChange } }) => {
|
||||||
|
const dateValue = getDate(value);
|
||||||
|
const date1Value = getDate(watch("date1"));
|
||||||
|
return (
|
||||||
|
<DayPicker
|
||||||
|
selected={value ? dateValue : undefined}
|
||||||
|
defaultMonth={value ? dateValue : undefined}
|
||||||
|
onSelect={(date) => {
|
||||||
|
if (!date) return;
|
||||||
|
onChange(date);
|
||||||
|
}}
|
||||||
|
mode="single"
|
||||||
|
disabled={date1Value ? [{ before: date1Value }] : undefined}
|
||||||
|
className="border border-custom-border-200 p-3 rounded-md"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@ import { eachDayOfInterval, isValid } from "date-fns";
|
|||||||
// ui
|
// ui
|
||||||
import { LineGraph } from "components/ui";
|
import { LineGraph } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedDateWithoutYear } from "helpers/date-time.helper";
|
import { getDate, renderFormattedDateWithoutYear } from "helpers/date-time.helper";
|
||||||
//types
|
//types
|
||||||
import { TCompletionChartDistribution } from "@plane/types";
|
import { TCompletionChartDistribution } from "@plane/types";
|
||||||
|
|
||||||
@ -47,11 +47,11 @@ const ProgressChart: React.FC<Props> = ({ distribution, startDate, endDate, tota
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const generateXAxisTickValues = () => {
|
const generateXAxisTickValues = () => {
|
||||||
const start = new Date(startDate);
|
const start = getDate(startDate);
|
||||||
const end = new Date(endDate);
|
const end = getDate(endDate);
|
||||||
|
|
||||||
let dates: Date[] = [];
|
let dates: Date[] = [];
|
||||||
if (isValid(start) && isValid(end)) {
|
if (start && end && isValid(start) && isValid(end)) {
|
||||||
dates = eachDayOfInterval({ start, end });
|
dates = eachDayOfInterval({ start, end });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,12 @@ import { EmptyState } from "components/empty-state";
|
|||||||
// icons
|
// icons
|
||||||
import { ArrowRight, CalendarCheck, CalendarDays, Star, Target } from "lucide-react";
|
import { ArrowRight, CalendarCheck, CalendarDays, Star, Target } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedDate, findHowManyDaysLeft, renderFormattedDateWithoutYear } from "helpers/date-time.helper";
|
import {
|
||||||
|
renderFormattedDate,
|
||||||
|
findHowManyDaysLeft,
|
||||||
|
renderFormattedDateWithoutYear,
|
||||||
|
getDate,
|
||||||
|
} from "helpers/date-time.helper";
|
||||||
import { truncateText } from "helpers/string.helper";
|
import { truncateText } from "helpers/string.helper";
|
||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
// types
|
// types
|
||||||
@ -124,8 +129,8 @@ export const ActiveCycleRoot: React.FC<IActiveCycleDetails> = observer((props) =
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const endDate = new Date(activeCycle.end_date ?? "");
|
const endDate = getDate(activeCycle.end_date);
|
||||||
const startDate = new Date(activeCycle.start_date ?? "");
|
const startDate = getDate(activeCycle.start_date);
|
||||||
const daysLeft = findHowManyDaysLeft(activeCycle.end_date) ?? 0;
|
const daysLeft = findHowManyDaysLeft(activeCycle.end_date) ?? 0;
|
||||||
const cycleStatus = activeCycle.status.toLowerCase() as TCycleGroups;
|
const cycleStatus = activeCycle.status.toLowerCase() as TCycleGroups;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import { CycleQuickActions } from "components/cycles";
|
|||||||
import { CYCLE_STATUS } from "constants/cycle";
|
import { CYCLE_STATUS } from "constants/cycle";
|
||||||
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "constants/event-tracker";
|
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "constants/event-tracker";
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
import { findHowManyDaysLeft, renderFormattedDate } from "helpers/date-time.helper";
|
import { findHowManyDaysLeft, getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
// constants
|
// constants
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
//.types
|
//.types
|
||||||
@ -45,8 +45,8 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = observer((props) => {
|
|||||||
if (!cycleDetails) return null;
|
if (!cycleDetails) return null;
|
||||||
|
|
||||||
const cycleStatus = cycleDetails.status.toLocaleLowerCase();
|
const cycleStatus = cycleDetails.status.toLocaleLowerCase();
|
||||||
const endDate = new Date(cycleDetails.end_date ?? "");
|
const endDate = getDate(cycleDetails.end_date);
|
||||||
const startDate = new Date(cycleDetails.start_date ?? "");
|
const startDate = getDate(cycleDetails.start_date);
|
||||||
const isDateValid = cycleDetails.start_date || cycleDetails.end_date;
|
const isDateValid = cycleDetails.start_date || cycleDetails.end_date;
|
||||||
|
|
||||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
@ -5,7 +5,7 @@ import { Button, Input, TextArea } from "@plane/ui";
|
|||||||
import { DateRangeDropdown, ProjectDropdown } from "components/dropdowns";
|
import { DateRangeDropdown, ProjectDropdown } from "components/dropdowns";
|
||||||
// ui
|
// ui
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { ICycle } from "@plane/types";
|
import { ICycle } from "@plane/types";
|
||||||
|
|
||||||
@ -135,8 +135,8 @@ export const CycleForm: React.FC<Props> = (props) => {
|
|||||||
className="h-7"
|
className="h-7"
|
||||||
minDate={new Date()}
|
minDate={new Date()}
|
||||||
value={{
|
value={{
|
||||||
from: startDateValue ? new Date(startDateValue) : undefined,
|
from: startDateValue ? getDate(startDateValue) : undefined,
|
||||||
to: endDateValue ? new Date(endDateValue) : undefined,
|
to: endDateValue ? getDate(endDateValue) : undefined,
|
||||||
}}
|
}}
|
||||||
onSelect={(val) => {
|
onSelect={(val) => {
|
||||||
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
||||||
|
@ -8,6 +8,7 @@ import { useCycle } from "hooks/store";
|
|||||||
// components
|
// components
|
||||||
// types
|
// types
|
||||||
import { ICycle } from "@plane/types";
|
import { ICycle } from "@plane/types";
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
// constants
|
// constants
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -41,8 +42,8 @@ export const CyclesListGanttChartView: FC<Props> = observer((props) => {
|
|||||||
data: block,
|
data: block,
|
||||||
id: block?.id ?? "",
|
id: block?.id ?? "",
|
||||||
sort_order: block?.sort_order ?? 0,
|
sort_order: block?.sort_order ?? 0,
|
||||||
start_date: new Date(block?.start_date ?? ""),
|
start_date: getDate(block?.start_date),
|
||||||
target_date: new Date(block?.end_date ?? ""),
|
target_date: getDate(block?.end_date),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return structuredBlocks;
|
return structuredBlocks;
|
||||||
|
@ -9,7 +9,7 @@ import { Tooltip, CircularProgressIndicator, CycleGroupIcon, AvatarGroup, Avatar
|
|||||||
import { CycleQuickActions } from "components/cycles";
|
import { CycleQuickActions } from "components/cycles";
|
||||||
import { CYCLE_STATUS } from "constants/cycle";
|
import { CYCLE_STATUS } from "constants/cycle";
|
||||||
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "constants/event-tracker";
|
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "constants/event-tracker";
|
||||||
import { findHowManyDaysLeft, renderFormattedDate } from "helpers/date-time.helper";
|
import { findHowManyDaysLeft, getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
// ui
|
// ui
|
||||||
@ -119,8 +119,8 @@ export const CyclesListItem: FC<TCyclesListItem> = observer((props) => {
|
|||||||
// TODO: change this logic once backend fix the response
|
// TODO: change this logic once backend fix the response
|
||||||
const cycleStatus = cycleDetails.status ? (cycleDetails.status.toLocaleLowerCase() as TCycleGroups) : "draft";
|
const cycleStatus = cycleDetails.status ? (cycleDetails.status.toLocaleLowerCase() as TCycleGroups) : "draft";
|
||||||
const isCompleted = cycleStatus === "completed";
|
const isCompleted = cycleStatus === "completed";
|
||||||
const endDate = new Date(cycleDetails.end_date ?? "");
|
const endDate = getDate(cycleDetails.end_date);
|
||||||
const startDate = new Date(cycleDetails.start_date ?? "");
|
const startDate = getDate(cycleDetails.start_date);
|
||||||
|
|
||||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import { CYCLE_STATUS } from "constants/cycle";
|
|||||||
import { CYCLE_UPDATED } from "constants/event-tracker";
|
import { CYCLE_UPDATED } from "constants/event-tracker";
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
// helpers
|
// helpers
|
||||||
import { findHowManyDaysLeft, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { findHowManyDaysLeft, getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
@ -182,8 +182,11 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const cycleStatus = cycleDetails?.status.toLocaleLowerCase();
|
const cycleStatus = cycleDetails?.status.toLocaleLowerCase();
|
||||||
const isCompleted = cycleStatus === "completed";
|
const isCompleted = cycleStatus === "completed";
|
||||||
|
|
||||||
const isStartValid = new Date(`${cycleDetails?.start_date}`) <= new Date();
|
const startDate = getDate(cycleDetails?.start_date);
|
||||||
const isEndValid = new Date(`${cycleDetails?.end_date}`) >= new Date(`${cycleDetails?.start_date}`);
|
const endDate = getDate(cycleDetails?.end_date);
|
||||||
|
|
||||||
|
const isStartValid = startDate && startDate <= new Date();
|
||||||
|
const isEndValid = endDate && startDate && endDate >= startDate;
|
||||||
|
|
||||||
const progressPercentage = cycleDetails
|
const progressPercentage = cycleDetails
|
||||||
? isCompleted && cycleDetails?.progress_snapshot
|
? isCompleted && cycleDetails?.progress_snapshot
|
||||||
@ -313,8 +316,8 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
buttonVariant="background-with-text"
|
buttonVariant="background-with-text"
|
||||||
minDate={new Date()}
|
minDate={new Date()}
|
||||||
value={{
|
value={{
|
||||||
from: startDateValue ? new Date(startDateValue) : undefined,
|
from: startDateValue ? getDate(startDateValue) : undefined,
|
||||||
to: endDateValue ? new Date(endDateValue) : undefined,
|
to: endDateValue ? getDate(endDateValue) : undefined,
|
||||||
}}
|
}}
|
||||||
onSelect={(val) => {
|
onSelect={(val) => {
|
||||||
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
||||||
|
@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
|
|||||||
// ui
|
// ui
|
||||||
import { Avatar, AvatarGroup, ControlLink, PriorityIcon } from "@plane/ui";
|
import { Avatar, AvatarGroup, ControlLink, PriorityIcon } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { findTotalDaysInRange, renderFormattedDate } from "helpers/date-time.helper";
|
import { findTotalDaysInRange, getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { useIssueDetail, useMember, useProject } from "hooks/store";
|
import { useIssueDetail, useMember, useProject } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import { TIssue, TWidgetIssue } from "@plane/types";
|
import { TIssue, TWidgetIssue } from "@plane/types";
|
||||||
@ -34,6 +34,8 @@ export const AssignedUpcomingIssueListItem: React.FC<IssueListItemProps> = obser
|
|||||||
const blockedByIssueProjectDetails =
|
const blockedByIssueProjectDetails =
|
||||||
blockedByIssues.length === 1 ? getProjectById(blockedByIssues[0]?.project_id ?? "") : null;
|
blockedByIssues.length === 1 ? getProjectById(blockedByIssues[0]?.project_id ?? "") : null;
|
||||||
|
|
||||||
|
const targetDate = getDate(issueDetails.target_date);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlLink
|
<ControlLink
|
||||||
href={`/${workspaceSlug}/projects/${issueDetails.project_id}/issues/${issueDetails.id}`}
|
href={`/${workspaceSlug}/projects/${issueDetails.project_id}/issues/${issueDetails.id}`}
|
||||||
@ -48,11 +50,7 @@ export const AssignedUpcomingIssueListItem: React.FC<IssueListItemProps> = obser
|
|||||||
<h6 className="text-sm flex-grow truncate">{issueDetails.name}</h6>
|
<h6 className="text-sm flex-grow truncate">{issueDetails.name}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-center">
|
<div className="text-xs text-center">
|
||||||
{issueDetails.target_date
|
{targetDate ? (isToday(targetDate) ? "Today" : renderFormattedDate(targetDate)) : "-"}
|
||||||
? isToday(new Date(issueDetails.target_date))
|
|
||||||
? "Today"
|
|
||||||
: renderFormattedDate(issueDetails.target_date)
|
|
||||||
: "-"}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-center">
|
<div className="text-xs text-center">
|
||||||
{blockedByIssues.length > 0
|
{blockedByIssues.length > 0
|
||||||
@ -83,7 +81,7 @@ export const AssignedOverdueIssueListItem: React.FC<IssueListItemProps> = observ
|
|||||||
const blockedByIssueProjectDetails =
|
const blockedByIssueProjectDetails =
|
||||||
blockedByIssues.length === 1 ? getProjectById(blockedByIssues[0]?.project_id ?? "") : null;
|
blockedByIssues.length === 1 ? getProjectById(blockedByIssues[0]?.project_id ?? "") : null;
|
||||||
|
|
||||||
const dueBy = findTotalDaysInRange(new Date(issueDetails.target_date ?? ""), new Date(), false) ?? 0;
|
const dueBy = findTotalDaysInRange(getDate(issueDetails.target_date), new Date(), false) ?? 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlLink
|
<ControlLink
|
||||||
@ -212,7 +210,7 @@ export const CreatedOverdueIssueListItem: React.FC<IssueListItemProps> = observe
|
|||||||
|
|
||||||
const projectDetails = getProjectById(issue.project_id);
|
const projectDetails = getProjectById(issue.project_id);
|
||||||
|
|
||||||
const dueBy = findTotalDaysInRange(new Date(issue.target_date ?? ""), new Date(), false) ?? 0;
|
const dueBy = findTotalDaysInRange(getDate(issue.target_date), new Date(), false) ?? 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlLink
|
<ControlLink
|
||||||
|
@ -5,7 +5,7 @@ import { Combobox } from "@headlessui/react";
|
|||||||
import { CalendarDays, X } from "lucide-react";
|
import { CalendarDays, X } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// components
|
// components
|
||||||
@ -168,8 +168,8 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||||||
{...attributes.popper}
|
{...attributes.popper}
|
||||||
>
|
>
|
||||||
<DayPicker
|
<DayPicker
|
||||||
selected={value ? new Date(value) : undefined}
|
selected={value ? getDate(value) : undefined}
|
||||||
defaultMonth={value ? new Date(value) : undefined}
|
defaultMonth={value ? getDate(value) : undefined}
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
dropdownOnChange(date ?? null);
|
dropdownOnChange(date ?? null);
|
||||||
}}
|
}}
|
||||||
|
@ -2,7 +2,7 @@ import { useState, FC } from "react";
|
|||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IExportData } from "@plane/types";
|
import { IExportData } from "@plane/types";
|
||||||
|
|
||||||
@ -18,7 +18,8 @@ export const SingleExport: FC<Props> = ({ service, refreshing }) => {
|
|||||||
|
|
||||||
const checkExpiry = (inputDateString: string) => {
|
const checkExpiry = (inputDateString: string) => {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const expiryDate = new Date(inputDateString);
|
const expiryDate = getDate(inputDateString);
|
||||||
|
if (!expiryDate) return false;
|
||||||
expiryDate.setDate(expiryDate.getDate() + 7);
|
expiryDate.setDate(expiryDate.getDate() + 7);
|
||||||
return expiryDate > currentDate;
|
return expiryDate > currentDate;
|
||||||
};
|
};
|
||||||
@ -38,12 +39,12 @@ export const SingleExport: FC<Props> = ({ service, refreshing }) => {
|
|||||||
service.status === "completed"
|
service.status === "completed"
|
||||||
? "bg-green-500/20 text-green-500"
|
? "bg-green-500/20 text-green-500"
|
||||||
: service.status === "processing"
|
: service.status === "processing"
|
||||||
? "bg-yellow-500/20 text-yellow-500"
|
? "bg-yellow-500/20 text-yellow-500"
|
||||||
: service.status === "failed"
|
: service.status === "failed"
|
||||||
? "bg-red-500/20 text-red-500"
|
? "bg-red-500/20 text-red-500"
|
||||||
: service.status === "expired"
|
: service.status === "expired"
|
||||||
? "bg-orange-500/20 text-orange-500"
|
? "bg-orange-500/20 text-orange-500"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{refreshing ? "Refreshing..." : service.status}
|
{refreshing ? "Refreshing..." : service.status}
|
||||||
|
@ -6,8 +6,8 @@ export interface IGanttBlock {
|
|||||||
width: number;
|
width: number;
|
||||||
};
|
};
|
||||||
sort_order: number;
|
sort_order: number;
|
||||||
start_date: Date | null;
|
start_date: Date | undefined;
|
||||||
target_date: Date | null;
|
target_date: Date | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBlockUpdateData {
|
export interface IBlockUpdateData {
|
||||||
|
@ -20,6 +20,8 @@ import { EUserProjectRoles } from "constants/project";
|
|||||||
import { useUser, useInboxIssues, useIssueDetail, useWorkspace, useEventTracker } from "hooks/store";
|
import { useUser, useInboxIssues, useIssueDetail, useWorkspace, useEventTracker } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import type { TInboxDetailedStatus } from "@plane/types";
|
import type { TInboxDetailedStatus } from "@plane/types";
|
||||||
|
//helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
|
|
||||||
type TInboxIssueActionsHeader = {
|
type TInboxIssueActionsHeader = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -168,11 +170,11 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const tomorrow = new Date(today);
|
const tomorrow = getDate(today);
|
||||||
tomorrow.setDate(today.getDate() + 1);
|
tomorrow?.setDate(today.getDate() + 1);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!issueStatus || !issueStatus.snoozed_till) return;
|
if (!issueStatus || !issueStatus.snoozed_till) return;
|
||||||
setDate(new Date(issueStatus.snoozed_till));
|
setDate(issueStatus.snoozed_till);
|
||||||
}, [issueStatus]);
|
}, [issueStatus]);
|
||||||
|
|
||||||
if (!issueStatus || !issue || !inboxIssues) return <></>;
|
if (!issueStatus || !issue || !inboxIssues) return <></>;
|
||||||
@ -266,19 +268,23 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
{({ close }) => (
|
{({ close }) => (
|
||||||
<div className="flex h-full w-full flex-col gap-y-1">
|
<div className="flex h-full w-full flex-col gap-y-1">
|
||||||
<DayPicker
|
<DayPicker
|
||||||
selected={date ? new Date(date) : undefined}
|
selected={date ? getDate(date) : undefined}
|
||||||
defaultMonth={date ? new Date(date) : undefined}
|
defaultMonth={date ? getDate(date) : undefined}
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
if (!date) return;
|
if (!date) return;
|
||||||
setDate(date);
|
setDate(date);
|
||||||
}}
|
}}
|
||||||
mode="single"
|
mode="single"
|
||||||
className="rounded-md border border-custom-border-200 p-3"
|
className="rounded-md border border-custom-border-200 p-3"
|
||||||
disabled={[
|
disabled={
|
||||||
{
|
tomorrow
|
||||||
before: tomorrow,
|
? [
|
||||||
},
|
{
|
||||||
]}
|
before: tomorrow,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@ -286,7 +292,7 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
close();
|
close();
|
||||||
inboxIssueOperations.updateInboxIssueStatus({
|
inboxIssueOperations.updateInboxIssueStatus({
|
||||||
status: 0,
|
status: 0,
|
||||||
snoozed_till: new Date(date),
|
snoozed_till: date,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -8,7 +8,7 @@ import { DateDropdown, PriorityDropdown, MemberDropdown, StateDropdown } from "c
|
|||||||
import { IssueLabel, TIssueOperations } from "components/issues";
|
import { IssueLabel, TIssueOperations } from "components/issues";
|
||||||
// icons
|
// icons
|
||||||
// helper
|
// helper
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { useIssueDetail, useProject, useProjectState } from "hooks/store";
|
import { useIssueDetail, useProject, useProjectState } from "hooks/store";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -33,7 +33,7 @@ export const InboxIssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const projectDetails = issue ? getProjectById(issue.project_id) : null;
|
const projectDetails = issue ? getProjectById(issue.project_id) : null;
|
||||||
|
|
||||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
const minDate = issue.start_date ? getDate(issue.start_date) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
|
|
||||||
const currentIssueState = projectStates?.find((s) => s.id === issue.state_id);
|
const currentIssueState = projectStates?.find((s) => s.id === issue.state_id);
|
||||||
|
@ -44,7 +44,7 @@ import {
|
|||||||
import { STATE_GROUPS } from "constants/state";
|
import { STATE_GROUPS } from "constants/state";
|
||||||
// types
|
// types
|
||||||
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 { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
||||||
@ -112,10 +112,10 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const isInArchivableGroup =
|
const isInArchivableGroup =
|
||||||
!!stateDetails && [STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateDetails?.group);
|
!!stateDetails && [STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateDetails?.group);
|
||||||
|
|
||||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
const minDate = issue.start_date ? getDate(issue.start_date) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
|
|
||||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
const maxDate = issue.target_date ? getDate(issue.target_date) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -12,6 +12,8 @@ import { ICycleIssuesFilter } from "store/issue/cycle";
|
|||||||
import { IModuleIssuesFilter } from "store/issue/module";
|
import { IModuleIssuesFilter } from "store/issue/module";
|
||||||
import { IProjectIssuesFilter } from "store/issue/project";
|
import { IProjectIssuesFilter } from "store/issue/project";
|
||||||
import { IProjectViewIssuesFilter } from "store/issue/project-views";
|
import { IProjectViewIssuesFilter } from "store/issue/project-views";
|
||||||
|
// helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
|
issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
|
||||||
@ -47,8 +49,10 @@ export const CalendarMonthsDropdown: React.FC<Props> = observer((props: Props) =
|
|||||||
|
|
||||||
const daysList = Object.keys(allDaysOfActiveWeek);
|
const daysList = Object.keys(allDaysOfActiveWeek);
|
||||||
|
|
||||||
const firstDay = new Date(daysList[0]);
|
const firstDay = getDate(daysList[0]);
|
||||||
const lastDay = new Date(daysList[daysList.length - 1]);
|
const lastDay = getDate(daysList[daysList.length - 1]);
|
||||||
|
|
||||||
|
if (!firstDay || !lastDay) return "Week";
|
||||||
|
|
||||||
if (firstDay.getMonth() === lastDay.getMonth() && firstDay.getFullYear() === lastDay.getFullYear())
|
if (firstDay.getMonth() === lastDay.getMonth() && firstDay.getFullYear() === lastDay.getFullYear())
|
||||||
return `${MONTHS_LIST[firstDay.getMonth() + 1].title} ${firstDay.getFullYear()}`;
|
return `${MONTHS_LIST[firstDay.getMonth() + 1].title} ${firstDay.getFullYear()}`;
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
import { ISSUE_UPDATED } from "constants/event-tracker";
|
import { ISSUE_UPDATED } from "constants/event-tracker";
|
||||||
import { EIssuesStoreType } from "constants/issue";
|
import { EIssuesStoreType } from "constants/issue";
|
||||||
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 { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||||
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState } from "hooks/store";
|
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState } from "hooks/store";
|
||||||
import { usePlatformOS } from "hooks/use-platform-os";
|
import { usePlatformOS } from "hooks/use-platform-os";
|
||||||
@ -242,10 +242,10 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
|
|
||||||
const defaultLabelOptions = issue?.label_ids?.map((id) => labelMap[id]) || [];
|
const defaultLabelOptions = issue?.label_ids?.map((id) => labelMap[id]) || [];
|
||||||
|
|
||||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
const minDate = issue.start_date ? getDate(issue.start_date) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
|
|
||||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
const maxDate = issue.target_date ? getDate(issue.target_date) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -6,7 +6,7 @@ import { CalendarCheck2 } from "lucide-react";
|
|||||||
import { DateDropdown } from "components/dropdowns";
|
import { DateDropdown } from "components/dropdowns";
|
||||||
// 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 { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||||
import { useProjectState } from "hooks/store";
|
import { useProjectState } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
@ -30,7 +30,7 @@ export const SpreadsheetDueDateColumn: React.FC<Props> = observer((props: Props)
|
|||||||
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
value={issue.target_date}
|
value={issue.target_date}
|
||||||
minDate={issue.start_date ? new Date(issue.start_date) : undefined}
|
minDate={issue.start_date ? getDate(issue.start_date) : undefined}
|
||||||
onChange={(data) => {
|
onChange={(data) => {
|
||||||
const targetDate = data ? renderFormattedPayloadDate(data) : null;
|
const targetDate = data ? renderFormattedPayloadDate(data) : null;
|
||||||
onChange(
|
onChange(
|
||||||
|
@ -4,7 +4,7 @@ import { CalendarClock } from "lucide-react";
|
|||||||
// components
|
// components
|
||||||
import { DateDropdown } from "components/dropdowns";
|
import { DateDropdown } from "components/dropdowns";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export const SpreadsheetStartDateColumn: React.FC<Props> = observer((props: Prop
|
|||||||
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
value={issue.start_date}
|
value={issue.start_date}
|
||||||
maxDate={issue.target_date ? new Date(issue.target_date) : undefined}
|
maxDate={issue.target_date ? getDate(issue.target_date) : undefined}
|
||||||
onChange={(data) => {
|
onChange={(data) => {
|
||||||
const startDate = data ? renderFormattedPayloadDate(data) : null;
|
const startDate = data ? renderFormattedPayloadDate(data) : null;
|
||||||
onChange(
|
onChange(
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
import { ParentIssuesListModal } from "components/issues";
|
import { ParentIssuesListModal } from "components/issues";
|
||||||
import { IssueLabelSelect } from "components/issues/select";
|
import { IssueLabelSelect } from "components/issues/select";
|
||||||
import { CreateLabelModal } from "components/labels";
|
import { CreateLabelModal } from "components/labels";
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "hooks/store";
|
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
@ -241,10 +241,10 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
const startDate = watch("start_date");
|
const startDate = watch("start_date");
|
||||||
const targetDate = watch("target_date");
|
const targetDate = watch("target_date");
|
||||||
|
|
||||||
const minDate = startDate ? new Date(startDate) : null;
|
const minDate = startDate ? getDate(startDate) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
|
|
||||||
const maxDate = targetDate ? new Date(targetDate) : null;
|
const maxDate = targetDate ? getDate(targetDate) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
const projectDetails = getProjectById(projectId);
|
const projectDetails = getProjectById(projectId);
|
||||||
|
@ -26,7 +26,7 @@ import {
|
|||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
// components
|
// components
|
||||||
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";
|
||||||
// helpers
|
// helpers
|
||||||
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||||
import { useIssueDetail, useProject, useProjectState } from "hooks/store";
|
import { useIssueDetail, useProject, useProjectState } from "hooks/store";
|
||||||
@ -54,10 +54,10 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
const isEstimateEnabled = projectDetails?.estimate;
|
const isEstimateEnabled = projectDetails?.estimate;
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
|
|
||||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
const minDate = issue.start_date ? getDate(issue.start_date) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
|
|
||||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
const maxDate = issue.target_date ? getDate(issue.target_date) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -6,7 +6,7 @@ import { DateRangeDropdown, ProjectDropdown, MemberDropdown } from "components/d
|
|||||||
import { ModuleStatusSelect } from "components/modules";
|
import { ModuleStatusSelect } from "components/modules";
|
||||||
// ui
|
// ui
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IModule } from "@plane/types";
|
import { IModule } from "@plane/types";
|
||||||
|
|
||||||
@ -147,8 +147,8 @@ export const ModuleForm: React.FC<Props> = (props) => {
|
|||||||
className="h-7"
|
className="h-7"
|
||||||
minDate={new Date()}
|
minDate={new Date()}
|
||||||
value={{
|
value={{
|
||||||
from: startDateValue ? new Date(startDateValue) : undefined,
|
from: startDateValue ? getDate(startDateValue) : undefined,
|
||||||
to: endDateValue ? new Date(endDateValue) : undefined,
|
to: endDateValue ? getDate(endDateValue) : undefined,
|
||||||
}}
|
}}
|
||||||
onSelect={(val) => {
|
onSelect={(val) => {
|
||||||
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
||||||
|
@ -7,6 +7,7 @@ import { ModuleGanttBlock } from "components/modules";
|
|||||||
import { useModule, useProject } from "hooks/store";
|
import { useModule, useProject } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import { IModule } from "@plane/types";
|
import { IModule } from "@plane/types";
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
|
|
||||||
export const ModulesListGanttChartView: React.FC = observer(() => {
|
export const ModulesListGanttChartView: React.FC = observer(() => {
|
||||||
// router
|
// router
|
||||||
@ -34,8 +35,8 @@ export const ModulesListGanttChartView: React.FC = observer(() => {
|
|||||||
data: block,
|
data: block,
|
||||||
id: block.id,
|
id: block.id,
|
||||||
sort_order: block.sort_order,
|
sort_order: block.sort_order,
|
||||||
start_date: block.start_date ? new Date(block.start_date) : null,
|
start_date: getDate(block.start_date),
|
||||||
target_date: block.target_date ? new Date(block.target_date) : null,
|
target_date: getDate(block.target_date),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules";
|
|||||||
import { MODULE_FAVORITED, MODULE_UNFAVORITED } from "constants/event-tracker";
|
import { MODULE_FAVORITED, MODULE_UNFAVORITED } from "constants/event-tracker";
|
||||||
import { MODULE_STATUS } from "constants/module";
|
import { MODULE_STATUS } from "constants/module";
|
||||||
import { EUserProjectRoles } from "constants/project";
|
import { EUserProjectRoles } from "constants/project";
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
import { useEventTracker, useMember, useModule, useUser } from "hooks/store";
|
import { useEventTracker, useMember, useModule, useUser } from "hooks/store";
|
||||||
import { usePlatformOS } from "hooks/use-platform-os";
|
import { usePlatformOS } from "hooks/use-platform-os";
|
||||||
@ -147,8 +147,8 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const completionPercentage = (moduleDetails.completed_issues / moduleTotalIssues) * 100;
|
const completionPercentage = (moduleDetails.completed_issues / moduleTotalIssues) * 100;
|
||||||
|
|
||||||
const endDate = new Date(moduleDetails.target_date ?? "");
|
const endDate = getDate(moduleDetails.target_date);
|
||||||
const startDate = new Date(moduleDetails.start_date ?? "");
|
const startDate = getDate(moduleDetails.start_date);
|
||||||
|
|
||||||
const isDateValid = moduleDetails.target_date || moduleDetails.start_date;
|
const isDateValid = moduleDetails.target_date || moduleDetails.start_date;
|
||||||
|
|
||||||
@ -160,8 +160,8 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
|
|||||||
? !moduleTotalIssues || moduleTotalIssues === 0
|
? !moduleTotalIssues || moduleTotalIssues === 0
|
||||||
? "0 Issue"
|
? "0 Issue"
|
||||||
: moduleTotalIssues === moduleDetails.completed_issues
|
: moduleTotalIssues === moduleDetails.completed_issues
|
||||||
? `${moduleTotalIssues} Issue${moduleTotalIssues > 1 ? "s" : ""}`
|
? `${moduleTotalIssues} Issue${moduleTotalIssues > 1 ? "s" : ""}`
|
||||||
: `${moduleDetails.completed_issues}/${moduleTotalIssues} Issues`
|
: `${moduleDetails.completed_issues}/${moduleTotalIssues} Issues`
|
||||||
: "0 Issue";
|
: "0 Issue";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -18,7 +18,7 @@ import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules";
|
|||||||
import { MODULE_FAVORITED, MODULE_UNFAVORITED } from "constants/event-tracker";
|
import { MODULE_FAVORITED, MODULE_UNFAVORITED } from "constants/event-tracker";
|
||||||
import { MODULE_STATUS } from "constants/module";
|
import { MODULE_STATUS } from "constants/module";
|
||||||
import { EUserProjectRoles } from "constants/project";
|
import { EUserProjectRoles } from "constants/project";
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
import { useModule, useUser, useEventTracker, useMember } from "hooks/store";
|
import { useModule, useUser, useEventTracker, useMember } from "hooks/store";
|
||||||
import { usePlatformOS } from "hooks/use-platform-os";
|
import { usePlatformOS } from "hooks/use-platform-os";
|
||||||
@ -150,8 +150,8 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
|
|||||||
const completionPercentage =
|
const completionPercentage =
|
||||||
((moduleDetails.completed_issues + moduleDetails.cancelled_issues) / moduleDetails.total_issues) * 100;
|
((moduleDetails.completed_issues + moduleDetails.cancelled_issues) / moduleDetails.total_issues) * 100;
|
||||||
|
|
||||||
const endDate = new Date(moduleDetails.target_date ?? "");
|
const endDate = getDate(moduleDetails.target_date);
|
||||||
const startDate = new Date(moduleDetails.start_date ?? "");
|
const startDate = getDate(moduleDetails.start_date);
|
||||||
|
|
||||||
const renderDate = moduleDetails.start_date || moduleDetails.target_date;
|
const renderDate = moduleDetails.start_date || moduleDetails.target_date;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import { MODULE_LINK_CREATED, MODULE_LINK_DELETED, MODULE_LINK_UPDATED, MODULE_U
|
|||||||
import { MODULE_STATUS } from "constants/module";
|
import { MODULE_STATUS } from "constants/module";
|
||||||
import { EUserProjectRoles } from "constants/project";
|
import { EUserProjectRoles } from "constants/project";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useModule, useUser, useEventTracker } from "hooks/store";
|
import { useModule, useUser, useEventTracker } from "hooks/store";
|
||||||
@ -207,8 +207,10 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
});
|
});
|
||||||
}, [moduleDetails, reset]);
|
}, [moduleDetails, reset]);
|
||||||
|
|
||||||
const isStartValid = new Date(`${moduleDetails?.start_date}`) <= new Date();
|
const startDate = getDate(moduleDetails?.start_date);
|
||||||
const isEndValid = new Date(`${moduleDetails?.target_date}`) >= new Date(`${moduleDetails?.start_date}`);
|
const endDate = getDate(moduleDetails?.target_date);
|
||||||
|
const isStartValid = startDate && startDate <= new Date();
|
||||||
|
const isEndValid = startDate && endDate && endDate >= startDate;
|
||||||
|
|
||||||
const progressPercentage = moduleDetails
|
const progressPercentage = moduleDetails
|
||||||
? Math.round((moduleDetails.completed_issues / moduleDetails.total_issues) * 100)
|
? Math.round((moduleDetails.completed_issues / moduleDetails.total_issues) * 100)
|
||||||
@ -348,26 +350,30 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="target_date"
|
name="target_date"
|
||||||
render={({ field: { value: endDateValue, onChange: onChangeEndDate } }) => (
|
render={({ field: { value: endDateValue, onChange: onChangeEndDate } }) => {
|
||||||
<DateRangeDropdown
|
const startDate = getDate(startDateValue);
|
||||||
buttonContainerClassName="w-full"
|
const endDate = getDate(endDateValue);
|
||||||
buttonVariant="background-with-text"
|
return (
|
||||||
minDate={new Date()}
|
<DateRangeDropdown
|
||||||
value={{
|
buttonContainerClassName="w-full"
|
||||||
from: startDateValue ? new Date(startDateValue) : undefined,
|
buttonVariant="background-with-text"
|
||||||
to: endDateValue ? new Date(endDateValue) : undefined,
|
minDate={new Date()}
|
||||||
}}
|
value={{
|
||||||
onSelect={(val) => {
|
from: startDate,
|
||||||
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
to: endDate,
|
||||||
onChangeEndDate(val?.to ? renderFormattedPayloadDate(val.to) : null);
|
}}
|
||||||
handleDateChange(val?.from, val?.to);
|
onSelect={(val) => {
|
||||||
}}
|
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
|
||||||
placeholder={{
|
onChangeEndDate(val?.to ? renderFormattedPayloadDate(val.to) : null);
|
||||||
from: "Start date",
|
handleDateChange(val?.from, val?.to);
|
||||||
to: "Target date",
|
}}
|
||||||
}}
|
placeholder={{
|
||||||
/>
|
from: "Start date",
|
||||||
)}
|
to: "Target date",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -117,7 +117,7 @@ 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 && new Date(notification.snoozed_till!) < new Date()) return null;
|
if (isSnoozedTabOpen && notification.snoozed_till! < new Date()) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
@ -56,7 +56,7 @@ export const SnoozeNotificationModal: FC<SnoozeModalProps> = (props) => {
|
|||||||
|
|
||||||
if (!formDataDate) return timeStamps;
|
if (!formDataDate) return timeStamps;
|
||||||
|
|
||||||
const isToday = today.toDateString() === new Date(formDataDate).toDateString();
|
const isToday = today.toDateString() === formDataDate.toDateString();
|
||||||
|
|
||||||
if (!isToday) return timeStamps;
|
if (!isToday) return timeStamps;
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ export const SnoozeNotificationModal: FC<SnoozeModalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
const minutes = parseInt(time[1]);
|
const minutes = parseInt(time[1]);
|
||||||
|
|
||||||
const dateTime = new Date(formData.date);
|
const dateTime = formData.date;
|
||||||
dateTime.setHours(hours);
|
dateTime.setHours(hours);
|
||||||
dateTime.setMinutes(minutes);
|
dateTime.setMinutes(minutes);
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ const UserNotificationContextProvider: React.FC<{
|
|||||||
|
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
const { selectedTab, snoozed, archived, readNotification, selectedNotificationForSnooze } = state;
|
const { selectedTab, snoozed, archived, readNotification } = state;
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
type: snoozed || archived || readNotification ? undefined : selectedTab,
|
type: snoozed || archived || readNotification ? undefined : selectedTab,
|
||||||
@ -207,7 +207,7 @@ const UserNotificationContextProvider: React.FC<{
|
|||||||
(previousNotifications: any) =>
|
(previousNotifications: any) =>
|
||||||
previousNotifications?.map((notification: any) =>
|
previousNotifications?.map((notification: any) =>
|
||||||
notification.id === notificationId
|
notification.id === notificationId
|
||||||
? { ...notification, snoozed_till: isSnoozed ? null : new Date(dateTime!) }
|
? { ...notification, snoozed_till: isSnoozed ? null : dateTime }
|
||||||
: notification
|
: notification
|
||||||
) || [],
|
) || [],
|
||||||
false
|
false
|
||||||
|
@ -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 "./date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { ICycle, TCycleFilters } from "@plane/types";
|
import { ICycle, TCycleFilters } from "@plane/types";
|
||||||
|
|
||||||
@ -39,18 +40,18 @@ export const shouldFilterCycle = (cycle: ICycle, filter: TCycleFilters): boolean
|
|||||||
let fallsInFilters = true;
|
let fallsInFilters = true;
|
||||||
Object.keys(filter).forEach((key) => {
|
Object.keys(filter).forEach((key) => {
|
||||||
const filterKey = key as keyof TCycleFilters;
|
const filterKey = key as keyof TCycleFilters;
|
||||||
|
const startDate = getDate(cycle.start_date);
|
||||||
|
const endDate = getDate(cycle.end_date);
|
||||||
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) {
|
||||||
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) {
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { differenceInDays, format, formatDistanceToNow, isAfter, isEqual, isValid, parseISO } from "date-fns";
|
import { differenceInDays, format, formatDistanceToNow, isAfter, isEqual, isValid, parseISO } from "date-fns";
|
||||||
import { isNil } from "lodash";
|
import isNumber from "lodash/isNumber";
|
||||||
|
|
||||||
// Format Date Helpers
|
// Format Date Helpers
|
||||||
/**
|
/**
|
||||||
@ -8,10 +8,11 @@ import { isNil } from "lodash";
|
|||||||
* @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): string | null => {
|
export const renderFormattedDate = (date: string | Date | undefined): string | null => {
|
||||||
if (!date) return null;
|
|
||||||
// Parse the date to check if it is valid
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = new Date(date);
|
const parsedDate = getDate(date);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedDate) return null;
|
||||||
// Check if the parsed date is valid before formatting
|
// Check if the parsed date is valid before formatting
|
||||||
if (!isValid(parsedDate)) return null; // Return null for invalid dates
|
if (!isValid(parsedDate)) return null; // Return null for invalid dates
|
||||||
// Format the date in format (MMM dd, yyyy)
|
// Format the date in format (MMM dd, yyyy)
|
||||||
@ -26,9 +27,10 @@ export const renderFormattedDate = (date: string | Date): string | null => {
|
|||||||
* @example renderShortDateFormat("2024-01-01") // Jan 01
|
* @example renderShortDateFormat("2024-01-01") // Jan 01
|
||||||
*/
|
*/
|
||||||
export const renderFormattedDateWithoutYear = (date: string | Date): string => {
|
export const renderFormattedDateWithoutYear = (date: string | Date): string => {
|
||||||
if (!date) return "";
|
|
||||||
// Parse the date to check if it is valid
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = new Date(date);
|
const parsedDate = getDate(date);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedDate) return "";
|
||||||
// Check if the parsed date is valid before formatting
|
// Check if the parsed date is valid before formatting
|
||||||
if (!isValid(parsedDate)) return ""; // Return empty string for invalid dates
|
if (!isValid(parsedDate)) return ""; // Return empty string for invalid dates
|
||||||
// Format the date in short format (MMM dd)
|
// Format the date in short format (MMM dd)
|
||||||
@ -43,9 +45,10 @@ export const renderFormattedDateWithoutYear = (date: string | Date): string => {
|
|||||||
* @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): string | null => {
|
||||||
if (!date) return null;
|
|
||||||
// Parse the date to check if it is valid
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = new Date(date);
|
const parsedDate = getDate(date);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedDate) return null;
|
||||||
// Check if the parsed date is valid before formatting
|
// Check if the parsed date is valid before formatting
|
||||||
if (!isValid(parsedDate)) return null; // Return null for invalid dates
|
if (!isValid(parsedDate)) return null; // Return null for invalid dates
|
||||||
// Format the date in payload format (yyyy-mm-dd)
|
// Format the date in payload format (yyyy-mm-dd)
|
||||||
@ -63,9 +66,10 @@ export const renderFormattedPayloadDate = (date: Date | string): string | null =
|
|||||||
* @example renderFormattedTime("2024-01-01 13:00:00", "12-hour") // 01:00 PM
|
* @example renderFormattedTime("2024-01-01 13:00:00", "12-hour") // 01:00 PM
|
||||||
*/
|
*/
|
||||||
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 => {
|
||||||
if (!date || date === "") return "";
|
|
||||||
// Parse the date to check if it is valid
|
// Parse the date to check if it is valid
|
||||||
const parsedDate = new Date(date);
|
const parsedDate = getDate(date);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedDate) return "";
|
||||||
// Check if the parsed date is valid
|
// Check if the parsed date is valid
|
||||||
if (!isValid(parsedDate)) return ""; // Return empty string for invalid dates
|
if (!isValid(parsedDate)) return ""; // Return empty string for invalid dates
|
||||||
// Format the date in 12 hour format if in12HourFormat is true
|
// Format the date in 12 hour format if in12HourFormat is true
|
||||||
@ -92,10 +96,11 @@ export const findTotalDaysInRange = (
|
|||||||
endDate: Date | string | undefined | null,
|
endDate: Date | string | undefined | null,
|
||||||
inclusive: boolean = true
|
inclusive: boolean = true
|
||||||
): number | undefined => {
|
): number | undefined => {
|
||||||
if (!startDate || !endDate) return undefined;
|
|
||||||
// Parse the dates to check if they are valid
|
// Parse the dates to check if they are valid
|
||||||
const parsedStartDate = new Date(startDate);
|
const parsedStartDate = getDate(startDate);
|
||||||
const parsedEndDate = new Date(endDate);
|
const parsedEndDate = getDate(endDate);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedStartDate || !parsedEndDate) return;
|
||||||
// Check if the parsed dates are valid before calculating the difference
|
// Check if the parsed dates are valid before calculating the difference
|
||||||
if (!isValid(parsedStartDate) || !isValid(parsedEndDate)) return 0; // Return 0 for invalid dates
|
if (!isValid(parsedStartDate) || !isValid(parsedEndDate)) return 0; // Return 0 for invalid dates
|
||||||
// Calculate the difference in days
|
// Calculate the difference in days
|
||||||
@ -131,6 +136,7 @@ export const calculateTimeAgo = (time: string | number | Date | null): string =>
|
|||||||
if (!time) return "";
|
if (!time) return "";
|
||||||
// Parse the time to check if it is valid
|
// Parse the time to check if it is valid
|
||||||
const parsedTime = typeof time === "string" || typeof time === "number" ? parseISO(String(time)) : time;
|
const parsedTime = typeof time === "string" || typeof time === "number" ? parseISO(String(time)) : time;
|
||||||
|
// return if undefined
|
||||||
if (!parsedTime) return ""; // Return empty string for invalid dates
|
if (!parsedTime) return ""; // Return empty string for invalid dates
|
||||||
// Format the time in the form of amount of time passed since the event happened
|
// Format the time in the form of amount of time passed since the event happened
|
||||||
const distance = formatDistanceToNow(parsedTime, { addSuffix: true });
|
const distance = formatDistanceToNow(parsedTime, { addSuffix: true });
|
||||||
@ -164,7 +170,7 @@ export const isDateGreaterThanToday = (dateStr: string): boolean => {
|
|||||||
* @example getWeekNumber(new Date("2023-09-01")) // 35
|
* @example getWeekNumber(new Date("2023-09-01")) // 35
|
||||||
*/
|
*/
|
||||||
export const getWeekNumberOfDate = (date: Date): number => {
|
export const getWeekNumberOfDate = (date: Date): number => {
|
||||||
const currentDate = new Date(date);
|
const currentDate = date;
|
||||||
// Adjust the starting day to Sunday (0) instead of Monday (1)
|
// Adjust the starting day to Sunday (0) instead of Monday (1)
|
||||||
const startDate = new Date(currentDate.getFullYear(), 0, 1);
|
const startDate = new Date(currentDate.getFullYear(), 0, 1);
|
||||||
// Calculate the number of days between currentDate and startDate
|
// Calculate the number of days between currentDate and startDate
|
||||||
@ -186,10 +192,24 @@ export const checkIfDatesAreEqual = (
|
|||||||
date1: Date | string | null | undefined,
|
date1: Date | string | null | undefined,
|
||||||
date2: Date | string | null | undefined
|
date2: Date | string | null | undefined
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (isNil(date1) && isNil(date2)) return true;
|
const parsedDate1 = getDate(date1);
|
||||||
if (isNil(date1) || isNil(date2)) return false;
|
const parsedDate2 = getDate(date2);
|
||||||
|
// return if undefined
|
||||||
|
if (!parsedDate1 && !parsedDate2) return true;
|
||||||
|
if (!parsedDate1 || !parsedDate2) return false;
|
||||||
|
|
||||||
const parsedDate1 = new Date(date1);
|
|
||||||
const parsedDate2 = new Date(date2);
|
|
||||||
return isEqual(parsedDate1, parsedDate2);
|
return isEqual(parsedDate1, parsedDate2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDate = (date: string | Date | undefined | null): Date | undefined => {
|
||||||
|
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);
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
||||||
|
import { getDate } from "./date-time.helper";
|
||||||
|
|
||||||
type TFilters = {
|
type TFilters = {
|
||||||
[key: string]: string[] | null;
|
[key: string]: string[] | null;
|
||||||
@ -31,9 +32,10 @@ export const calculateTotalFilters = (filters: TFilters): number =>
|
|||||||
export const satisfiesDateFilter = (date: Date, filter: string): boolean => {
|
export const satisfiesDateFilter = (date: Date, filter: string): boolean => {
|
||||||
const [value, operator, from] = filter.split(";");
|
const [value, operator, from] = filter.split(";");
|
||||||
|
|
||||||
if (!from) {
|
const dateValue = getDate(value);
|
||||||
if (operator === "after") return date >= new Date(value);
|
if (!from && dateValue) {
|
||||||
if (operator === "before") return date <= new Date(value);
|
if (operator === "after") return date >= dateValue;
|
||||||
|
if (operator === "before") return date <= dateValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from === "fromnow") {
|
if (from === "fromnow") {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
// helpers
|
// helpers
|
||||||
|
import { getDate } from "./date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IGanttBlock } from "components/gantt-chart";
|
import { IGanttBlock } from "components/gantt-chart";
|
||||||
// constants
|
// constants
|
||||||
@ -157,7 +158,9 @@ export const shouldHighlightIssueDueDate = (
|
|||||||
// if the issue is completed or cancelled, don't highlight the due date
|
// if the issue is completed or cancelled, don't highlight the due date
|
||||||
if ([STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateGroup)) return false;
|
if ([STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateGroup)) return false;
|
||||||
|
|
||||||
const parsedDate = new Date(date);
|
const parsedDate = getDate(date);
|
||||||
|
if (!parsedDate) return false;
|
||||||
|
|
||||||
const targetDateDistance = differenceInCalendarDays(parsedDate, new Date());
|
const targetDateDistance = differenceInCalendarDays(parsedDate, new Date());
|
||||||
|
|
||||||
// if the issue is overdue, highlight the due date
|
// if the issue is overdue, highlight the due date
|
||||||
@ -168,8 +171,8 @@ export const renderIssueBlocksStructure = (blocks: TIssue[]): IGanttBlock[] =>
|
|||||||
data: block,
|
data: block,
|
||||||
id: block.id,
|
id: block.id,
|
||||||
sort_order: block.sort_order,
|
sort_order: block.sort_order,
|
||||||
start_date: block.start_date ? new Date(block.start_date) : null,
|
start_date: getDate(block.start_date),
|
||||||
target_date: block.target_date ? new Date(block.target_date) : null,
|
target_date: getDate(block.target_date),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function getChangedIssuefields(formData: Partial<TIssue>, dirtyFields: { [key: string]: boolean | undefined }) {
|
export function getChangedIssuefields(formData: Partial<TIssue>, dirtyFields: { [key: string]: boolean | 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 "./date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IModule, TModuleDisplayFilters, TModuleFilters, TModuleOrderByOptions } from "@plane/types";
|
import { IModule, TModuleDisplayFilters, TModuleFilters, TModuleOrderByOptions } from "@plane/types";
|
||||||
|
|
||||||
@ -53,6 +54,9 @@ export const shouldFilterModule = (
|
|||||||
let fallsInFilters = true;
|
let fallsInFilters = true;
|
||||||
Object.keys(filters).forEach((key) => {
|
Object.keys(filters).forEach((key) => {
|
||||||
const filterKey = key as keyof TModuleFilters;
|
const filterKey = key as keyof TModuleFilters;
|
||||||
|
const startDate = getDate(module.start_date);
|
||||||
|
const endDate = getDate(module.target_date);
|
||||||
|
|
||||||
if (filterKey === "status" && filters.status && filters.status.length > 0)
|
if (filterKey === "status" && filters.status && filters.status.length > 0)
|
||||||
fallsInFilters = fallsInFilters && filters.status.includes(module.status.toLowerCase());
|
fallsInFilters = fallsInFilters && filters.status.includes(module.status.toLowerCase());
|
||||||
if (filterKey === "lead" && filters.lead && filters.lead.length > 0)
|
if (filterKey === "lead" && filters.lead && filters.lead.length > 0)
|
||||||
@ -63,14 +67,12 @@ export const shouldFilterModule = (
|
|||||||
}
|
}
|
||||||
if (filterKey === "start_date" && filters.start_date && filters.start_date.length > 0) {
|
if (filterKey === "start_date" && filters.start_date && filters.start_date.length > 0) {
|
||||||
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) {
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -24,6 +24,7 @@ import { FileService } from "services/file.service";
|
|||||||
// ui
|
// ui
|
||||||
// assets
|
// assets
|
||||||
// helpers
|
// helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IPage } from "@plane/types";
|
import { IPage } from "@plane/types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
@ -276,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 ? new Date(archived_at) : undefined,
|
archived_at: archived_at ? getDate(archived_at) : undefined,
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import sortBy from "lodash/sortBy";
|
|||||||
import { action, computed, observable, makeObservable, runInAction } from "mobx";
|
import { action, computed, observable, makeObservable, runInAction } from "mobx";
|
||||||
import { computedFn } from "mobx-utils";
|
import { computedFn } from "mobx-utils";
|
||||||
// types
|
// types
|
||||||
|
// helpers
|
||||||
|
import { getDate } from "helpers/date-time.helper";
|
||||||
// mobx
|
// mobx
|
||||||
// services
|
// services
|
||||||
import { CycleService } from "services/cycle.service";
|
import { CycleService } from "services/cycle.service";
|
||||||
@ -121,8 +123,9 @@ export class CycleStore implements ICycleStore {
|
|||||||
const projectId = this.rootStore.app.router.projectId;
|
const projectId = this.rootStore.app.router.projectId;
|
||||||
if (!projectId || !this.fetchedMap[projectId]) return null;
|
if (!projectId || !this.fetchedMap[projectId]) return null;
|
||||||
let completedCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
let completedCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
||||||
const hasEndDatePassed = isPast(new Date(c.end_date ?? ""));
|
const endDate = getDate(c.end_date);
|
||||||
const isEndDateToday = isToday(new Date(c.end_date ?? ""));
|
const hasEndDatePassed = endDate && isPast(endDate);
|
||||||
|
const isEndDateToday = endDate && isToday(endDate);
|
||||||
return c.project_id === projectId && hasEndDatePassed && !isEndDateToday;
|
return c.project_id === projectId && hasEndDatePassed && !isEndDateToday;
|
||||||
});
|
});
|
||||||
completedCycles = sortBy(completedCycles, [(c) => c.sort_order]);
|
completedCycles = sortBy(completedCycles, [(c) => c.sort_order]);
|
||||||
@ -137,7 +140,8 @@ export class CycleStore implements ICycleStore {
|
|||||||
const projectId = this.rootStore.app.router.projectId;
|
const projectId = this.rootStore.app.router.projectId;
|
||||||
if (!projectId || !this.fetchedMap[projectId]) return null;
|
if (!projectId || !this.fetchedMap[projectId]) return null;
|
||||||
let upcomingCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
let upcomingCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
||||||
const isStartDateUpcoming = isFuture(new Date(c.start_date ?? ""));
|
const startDate = getDate(c.start_date);
|
||||||
|
const isStartDateUpcoming = startDate && isFuture(startDate);
|
||||||
return c.project_id === projectId && isStartDateUpcoming;
|
return c.project_id === projectId && isStartDateUpcoming;
|
||||||
});
|
});
|
||||||
upcomingCycles = sortBy(upcomingCycles, [(c) => c.sort_order]);
|
upcomingCycles = sortBy(upcomingCycles, [(c) => c.sort_order]);
|
||||||
@ -152,7 +156,8 @@ export class CycleStore implements ICycleStore {
|
|||||||
const projectId = this.rootStore.app.router.projectId;
|
const projectId = this.rootStore.app.router.projectId;
|
||||||
if (!projectId || !this.fetchedMap[projectId]) return null;
|
if (!projectId || !this.fetchedMap[projectId]) return null;
|
||||||
let incompleteCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
let incompleteCycles = Object.values(this.cycleMap ?? {}).filter((c) => {
|
||||||
const hasEndDatePassed = isPast(new Date(c.end_date ?? ""));
|
const endDate = getDate(c.end_date);
|
||||||
|
const hasEndDatePassed = endDate && isPast(endDate);
|
||||||
return c.project_id === projectId && !hasEndDatePassed;
|
return c.project_id === projectId && !hasEndDatePassed;
|
||||||
});
|
});
|
||||||
incompleteCycles = sortBy(incompleteCycles, [(c) => c.sort_order]);
|
incompleteCycles = sortBy(incompleteCycles, [(c) => c.sort_order]);
|
||||||
|
@ -73,8 +73,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 = new Date(this.projectPageMap[projectId][a].created_at).getTime();
|
const dateA = this.projectPageMap[projectId][a].created_at.getTime();
|
||||||
const dateB = new Date(this.projectPageMap[projectId][b].created_at).getTime();
|
const dateB = this.projectPageMap[projectId][b].created_at.getTime();
|
||||||
return dateB - dateA;
|
return dateB - dateA;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -84,8 +84,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 = new Date(this.projectArchivedPageMap[projectId][a].created_at).getTime();
|
const dateA = this.projectArchivedPageMap[projectId][a].created_at.getTime();
|
||||||
const dateB = new Date(this.projectArchivedPageMap[projectId][b].created_at).getTime();
|
const dateB = this.projectArchivedPageMap[projectId][b].created_at.getTime();
|
||||||
return dateB - dateA;
|
return dateB - dateA;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -127,25 +127,21 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||||||
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(new Date(this.projectPageMap[projectId][page].updated_at))
|
isToday(this.projectPageMap[projectId][page].updated_at)
|
||||||
);
|
);
|
||||||
|
|
||||||
const yesterday: string[] = this.projectPageIds.filter((page) =>
|
const yesterday: string[] = this.projectPageIds.filter((page) =>
|
||||||
isYesterday(new Date(this.projectPageMap[projectId][page].updated_at))
|
isYesterday(this.projectPageMap[projectId][page].updated_at)
|
||||||
);
|
);
|
||||||
|
|
||||||
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 = this.projectPageMap[projectId][page].updated_at;
|
||||||
return (
|
return isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
||||||
isThisWeek(new Date(pageUpdatedAt)) &&
|
|
||||||
!isToday(new Date(pageUpdatedAt)) &&
|
|
||||||
!isYesterday(new Date(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 = this.projectPageMap[projectId][page].updated_at;
|
||||||
return !isThisWeek(new Date(pageUpdatedAt)) && !isYesterday(new Date(pageUpdatedAt));
|
return !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { today, yesterday, this_week, older };
|
return { today, yesterday, this_week, older };
|
||||||
|
Loading…
Reference in New Issue
Block a user