mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: due date highlight logic (#3763)
This commit is contained in:
parent
ba6479674c
commit
33c99ded77
@ -1,7 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { differenceInCalendarDays } from "date-fns";
|
||||
import {
|
||||
LinkIcon,
|
||||
Signal,
|
||||
@ -15,7 +14,7 @@ import {
|
||||
CalendarDays,
|
||||
} from "lucide-react";
|
||||
// hooks
|
||||
import { useEstimate, useIssueDetail, useProject, useUser } from "hooks/store";
|
||||
import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import {
|
||||
@ -41,6 +40,7 @@ import { ContrastIcon, DiceIcon, DoubleCircleIcon, RelatedIcon, UserGroupIcon }
|
||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
import { cn } from "helpers/common.helper";
|
||||
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||
// types
|
||||
import type { TIssueOperations } from "./root";
|
||||
|
||||
@ -65,6 +65,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
const {
|
||||
issue: { getIssueById },
|
||||
} = useIssueDetail();
|
||||
const { getStateById } = useProjectState();
|
||||
// states
|
||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||
|
||||
@ -83,6 +84,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
};
|
||||
|
||||
const projectDetails = issue ? getProjectById(issue.project_id) : null;
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
|
||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
||||
minDate?.setDate(minDate.getDate());
|
||||
@ -90,8 +92,6 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
||||
maxDate?.setDate(maxDate.getDate());
|
||||
|
||||
const targetDateDistance = issue.target_date ? differenceInCalendarDays(new Date(issue.target_date), new Date()) : 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
{workspaceSlug && projectId && issue && (
|
||||
@ -242,7 +242,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
buttonContainerClassName="w-full text-left"
|
||||
buttonClassName={cn("text-sm", {
|
||||
"text-custom-text-400": !issue.target_date,
|
||||
"text-red-500": targetDateDistance <= 0,
|
||||
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
|
||||
})}
|
||||
hideIcon
|
||||
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useRouter } from "next/router";
|
||||
import { differenceInCalendarDays } from "date-fns";
|
||||
import { Layers, Link, Paperclip } from "lucide-react";
|
||||
import xor from "lodash/xor";
|
||||
// hooks
|
||||
import { useEventTracker, useEstimate, useLabel, useIssues } from "hooks/store";
|
||||
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState } from "hooks/store";
|
||||
// components
|
||||
import { IssuePropertyLabels } from "../properties/labels";
|
||||
import { Tooltip } from "@plane/ui";
|
||||
@ -21,6 +20,7 @@ import {
|
||||
} from "components/dropdowns";
|
||||
// helpers
|
||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
import { TIssue, IIssueDisplayProperties, TIssuePriorities } from "@plane/types";
|
||||
@ -48,11 +48,14 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
const {
|
||||
issues: { addIssueToCycle, removeIssueFromCycle },
|
||||
} = useIssues(EIssuesStoreType.CYCLE);
|
||||
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
||||
const { getStateById } = useProjectState();
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, cycleId, moduleId } = router.query;
|
||||
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
||||
const currentLayout = `${activeLayout} layout`;
|
||||
// derived values
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
|
||||
const issueOperations = useMemo(
|
||||
() => ({
|
||||
@ -232,8 +235,6 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
||||
maxDate?.setDate(maxDate.getDate());
|
||||
|
||||
const targetDateDistance = issue.target_date ? differenceInCalendarDays(new Date(issue.target_date), new Date()) : 1;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{/* basic properties */}
|
||||
@ -301,7 +302,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
minDate={minDate ?? undefined}
|
||||
placeholder="Due date"
|
||||
buttonVariant={issue.target_date ? "border-with-text" : "border-without-text"}
|
||||
buttonClassName={targetDateDistance <= 0 ? "text-red-500" : ""}
|
||||
buttonClassName={shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group) ? "text-red-500" : ""}
|
||||
clearIconClassName="!text-custom-text-100"
|
||||
disabled={isReadOnly}
|
||||
showTooltip
|
||||
|
@ -1,13 +1,15 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
||||
// hooks
|
||||
import { useProjectState } from "hooks/store";
|
||||
// components
|
||||
import { DateDropdown } from "components/dropdowns";
|
||||
// helpers
|
||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
import { TIssue } from "@plane/types";
|
||||
import { cn } from "helpers/common.helper";
|
||||
|
||||
type Props = {
|
||||
issue: TIssue;
|
||||
@ -18,8 +20,10 @@ type Props = {
|
||||
|
||||
export const SpreadsheetDueDateColumn: React.FC<Props> = observer((props: Props) => {
|
||||
const { issue, onChange, disabled, onClose } = props;
|
||||
|
||||
const targetDateDistance = issue.target_date ? differenceInCalendarDays(new Date(issue.target_date), new Date()) : 1;
|
||||
// store hooks
|
||||
const { getStateById } = useProjectState();
|
||||
// derived values
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
|
||||
return (
|
||||
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
||||
@ -42,7 +46,7 @@ export const SpreadsheetDueDateColumn: React.FC<Props> = observer((props: Props)
|
||||
buttonVariant="transparent-with-text"
|
||||
buttonContainerClassName="w-full"
|
||||
buttonClassName={cn("rounded-none text-left", {
|
||||
"text-red-500": targetDateDistance <= 0,
|
||||
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
|
||||
})}
|
||||
clearIconClassName="!text-custom-text-100"
|
||||
onClose={onClose}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { differenceInCalendarDays } from "date-fns";
|
||||
import { Signal, Tag, Triangle, LayoutPanelTop, CircleDot, CopyPlus, XCircle, CalendarDays } from "lucide-react";
|
||||
// hooks
|
||||
import { useIssueDetail, useProject } from "hooks/store";
|
||||
import { useIssueDetail, useProject, useProjectState } from "hooks/store";
|
||||
// ui icons
|
||||
import { DiceIcon, DoubleCircleIcon, UserGroupIcon, ContrastIcon, RelatedIcon } from "@plane/ui";
|
||||
import {
|
||||
@ -26,6 +25,7 @@ import {
|
||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
import { shouldHighlightIssueDueDate } from "helpers/issue.helper";
|
||||
|
||||
interface IPeekOverviewProperties {
|
||||
workspaceSlug: string;
|
||||
@ -42,11 +42,13 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
||||
const {
|
||||
issue: { getIssueById },
|
||||
} = useIssueDetail();
|
||||
const { getStateById } = useProjectState();
|
||||
// derived values
|
||||
const issue = getIssueById(issueId);
|
||||
if (!issue) return <></>;
|
||||
const projectDetails = getProjectById(issue.project_id);
|
||||
const isEstimateEnabled = projectDetails?.estimate;
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
|
||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
||||
minDate?.setDate(minDate.getDate());
|
||||
@ -54,8 +56,6 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
||||
maxDate?.setDate(maxDate.getDate());
|
||||
|
||||
const targetDateDistance = issue.target_date ? differenceInCalendarDays(new Date(issue.target_date), new Date()) : 1;
|
||||
|
||||
return (
|
||||
<div className="mt-1">
|
||||
<h6 className="text-sm font-medium">Properties</h6>
|
||||
@ -169,7 +169,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
||||
buttonContainerClassName="w-full text-left"
|
||||
buttonClassName={cn("text-sm", {
|
||||
"text-custom-text-400": !issue.target_date,
|
||||
"text-red-500": targetDateDistance <= 0,
|
||||
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
|
||||
})}
|
||||
hideIcon
|
||||
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
|
||||
|
@ -1,11 +1,20 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
|
||||
// helpers
|
||||
import { orderArrayBy } from "helpers/array.helper";
|
||||
// types
|
||||
import { TIssue, TIssueGroupByOptions, TIssueLayouts, TIssueOrderByOptions, TIssueParams } from "@plane/types";
|
||||
import {
|
||||
TIssue,
|
||||
TIssueGroupByOptions,
|
||||
TIssueLayouts,
|
||||
TIssueOrderByOptions,
|
||||
TIssueParams,
|
||||
TStateGroups,
|
||||
} from "@plane/types";
|
||||
import { IGanttBlock } from "components/gantt-chart";
|
||||
// constants
|
||||
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
||||
import { STATE_GROUPS } from "constants/state";
|
||||
|
||||
type THandleIssuesMutation = (
|
||||
formData: Partial<TIssue>,
|
||||
@ -134,6 +143,26 @@ export const createIssuePayload: (projectId: string, formData: Partial<TIssue>)
|
||||
return payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description check if the issue due date should be highlighted
|
||||
* @param date
|
||||
* @param stateGroup
|
||||
* @returns boolean
|
||||
*/
|
||||
export const shouldHighlightIssueDueDate = (
|
||||
date: string | Date | null,
|
||||
stateGroup: TStateGroups | undefined
|
||||
): boolean => {
|
||||
if (!date || !stateGroup) return false;
|
||||
// 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;
|
||||
|
||||
const parsedDate = new Date(date);
|
||||
const targetDateDistance = differenceInCalendarDays(parsedDate, new Date());
|
||||
|
||||
// if the issue is overdue, highlight the due date
|
||||
return targetDateDistance <= 0;
|
||||
};
|
||||
export const renderIssueBlocksStructure = (blocks: TIssue[]): IGanttBlock[] =>
|
||||
blocks?.map((block) => ({
|
||||
data: block,
|
||||
|
Loading…
Reference in New Issue
Block a user