[WEB-3374]feat: added merge date display (#7141)
* feat: added merge date display * chore: moved formatter ti utils * chore: removed unwanted props
This commit is contained in:
parent
edeeee1227
commit
1608e4f122
9 changed files with 248 additions and 103 deletions
|
|
@ -333,3 +333,59 @@ export const generateDateArray = (startDate: string | Date, endDate: string | Da
|
|||
}
|
||||
return dateArray;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats merged date range display with smart formatting
|
||||
* - Single date: "Jan 24, 2025"
|
||||
* - Same year, same month: "Jan 24 - 28, 2025"
|
||||
* - Same year, different month: "Jan 24 - Feb 6, 2025"
|
||||
* - Different year: "Dec 28, 2024 - Jan 4, 2025"
|
||||
*/
|
||||
export const formatDateRange = (
|
||||
parsedStartDate: Date | null | undefined,
|
||||
parsedEndDate: Date | null | undefined
|
||||
): string => {
|
||||
// If no dates are provided
|
||||
if (!parsedStartDate && !parsedEndDate) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// If only start date is provided
|
||||
if (parsedStartDate && !parsedEndDate) {
|
||||
return format(parsedStartDate, "MMM dd, yyyy");
|
||||
}
|
||||
|
||||
// If only end date is provided
|
||||
if (!parsedStartDate && parsedEndDate) {
|
||||
return format(parsedEndDate, "MMM dd, yyyy");
|
||||
}
|
||||
|
||||
// If both dates are provided
|
||||
if (parsedStartDate && parsedEndDate) {
|
||||
const startYear = parsedStartDate.getFullYear();
|
||||
const startMonth = parsedStartDate.getMonth();
|
||||
const endYear = parsedEndDate.getFullYear();
|
||||
const endMonth = parsedEndDate.getMonth();
|
||||
|
||||
// Same year, same month
|
||||
if (startYear === endYear && startMonth === endMonth) {
|
||||
const startDay = format(parsedStartDate, "dd");
|
||||
const endDay = format(parsedEndDate, "dd");
|
||||
return `${format(parsedStartDate, "MMM")} ${startDay} - ${endDay}, ${startYear}`;
|
||||
}
|
||||
|
||||
// Same year, different month
|
||||
if (startYear === endYear) {
|
||||
const startFormatted = format(parsedStartDate, "MMM dd");
|
||||
const endFormatted = format(parsedEndDate, "MMM dd");
|
||||
return `${startFormatted} - ${endFormatted}, ${startYear}`;
|
||||
}
|
||||
|
||||
// Different year
|
||||
const startFormatted = format(parsedStartDate, "MMM dd, yyyy");
|
||||
const endFormatted = format(parsedEndDate, "MMM dd, yyyy");
|
||||
return `${startFormatted} - ${endFormatted}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
|
@ -3,21 +3,12 @@
|
|||
import React, { FC, useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
ArchiveRestoreIcon,
|
||||
ArrowRight,
|
||||
ChevronRight,
|
||||
EllipsisIcon,
|
||||
LinkIcon,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { ArrowRight, ChevronRight } from "lucide-react";
|
||||
// Plane Imports
|
||||
import { CYCLE_STATUS, CYCLE_UPDATED, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { ICycle } from "@plane/types";
|
||||
import { CustomMenu, setToast, TOAST_TYPE } from "@plane/ui";
|
||||
import { copyUrlToClipboard } from "@plane/utils";
|
||||
import { setToast, TOAST_TYPE } from "@plane/ui";
|
||||
// components
|
||||
import { DateRangeDropdown } from "@/components/dropdowns";
|
||||
// helpers
|
||||
|
|
@ -239,6 +230,7 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
|
|||
{renderFormattedDateInUserTimezone(cycleDetails.end_date ?? "")}
|
||||
</span>
|
||||
}
|
||||
mergeDates
|
||||
showTooltip={!!cycleDetails.start_date && !!cycleDetails.end_date} // show tooltip only if both start and end date are present
|
||||
required={cycleDetails.status !== "draft"}
|
||||
disabled={!isEditingAllowed || isArchived || isCompleted}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import React, { FC, MouseEvent, useEffect, useMemo, useState } from "react";
|
||||
import { format, parseISO } from "date-fns";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
|
@ -23,6 +22,7 @@ import { Avatar, AvatarGroup, FavoriteStar, LayersIcon, Tooltip, TransferIcon, s
|
|||
import { CycleQuickActions, TransferIssuesModal } from "@/components/cycles";
|
||||
import { DateRangeDropdown } from "@/components/dropdowns";
|
||||
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
|
||||
import { MergedDateDisplay } from "@/components/dropdowns/merged-date";
|
||||
import { getDate } from "@/helpers/date-time.helper";
|
||||
import { getFileURL } from "@/helpers/file.helper";
|
||||
// hooks
|
||||
|
|
@ -230,9 +230,7 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
|
|||
>
|
||||
<div className="flex gap-1 text-xs text-custom-text-300 font-medium items-center">
|
||||
<CalendarDays className="h-3 w-3 flex-shrink-0 my-auto" />
|
||||
{cycleDetails.start_date && <span>{format(parseISO(cycleDetails.start_date), "MMM dd, yyyy")}</span>}
|
||||
<ArrowRight className="h-3 w-3 flex-shrink-0 my-auto" />
|
||||
{cycleDetails.end_date && <span>{format(parseISO(cycleDetails.end_date), "MMM dd, yyyy")}</span>}
|
||||
<MergedDateDisplay startDate={cycleDetails.start_date} endDate={cycleDetails.end_date} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
{projectUTCOffset && (
|
||||
|
|
@ -269,6 +267,7 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
|
|||
{renderFormattedDateInUserTimezone(cycleDetails.end_date ?? "")}
|
||||
</span>
|
||||
}
|
||||
mergeDates
|
||||
required={cycleDetails.status !== "draft"}
|
||||
disabled
|
||||
hideIcon={{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|||
import { Placement } from "@popperjs/core";
|
||||
import { DateRange, Matcher } from "react-day-picker";
|
||||
import { usePopper } from "react-popper";
|
||||
import { ArrowRight, CalendarCheck2, CalendarDays } from "lucide-react";
|
||||
import { ArrowRight, CalendarCheck2, CalendarDays, X } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
|
|
@ -17,6 +17,7 @@ import { renderFormattedDate } from "@/helpers/date-time.helper";
|
|||
import { useDropdown } from "@/hooks/use-dropdown";
|
||||
// components
|
||||
import { DropdownButton } from "./buttons";
|
||||
import { MergedDateDisplay } from "./merged-date";
|
||||
// types
|
||||
import { TButtonVariants } from "./types";
|
||||
|
||||
|
|
@ -30,11 +31,14 @@ type Props = {
|
|||
buttonVariant: TButtonVariants;
|
||||
cancelButtonText?: string;
|
||||
className?: string;
|
||||
clearIconClassName?: string;
|
||||
disabled?: boolean;
|
||||
hideIcon?: {
|
||||
from?: boolean;
|
||||
to?: boolean;
|
||||
};
|
||||
isClearable?: boolean;
|
||||
mergeDates?: boolean;
|
||||
minDate?: Date;
|
||||
maxDate?: Date;
|
||||
onSelect?: (range: DateRange | undefined) => void;
|
||||
|
|
@ -65,11 +69,14 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
|||
buttonToDateClassName,
|
||||
buttonVariant,
|
||||
className,
|
||||
clearIconClassName = "",
|
||||
disabled = false,
|
||||
hideIcon = {
|
||||
from: true,
|
||||
to: true,
|
||||
},
|
||||
isClearable = false,
|
||||
mergeDates,
|
||||
minDate,
|
||||
maxDate,
|
||||
onSelect,
|
||||
|
|
@ -118,20 +125,18 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
|||
setIsOpen,
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
setDateRange({
|
||||
from: value.from,
|
||||
to: value.to,
|
||||
});
|
||||
if (referenceElement) referenceElement.blur();
|
||||
};
|
||||
|
||||
const disabledDays: Matcher[] = [];
|
||||
if (minDate) disabledDays.push({ before: minDate });
|
||||
if (maxDate) disabledDays.push({ after: maxDate });
|
||||
|
||||
const clearDates = () => {
|
||||
const clearedRange = { from: undefined, to: undefined };
|
||||
setDateRange(clearedRange);
|
||||
onSelect?.(clearedRange);
|
||||
};
|
||||
|
||||
const hasDisplayedDates = dateRange.from || dateRange.to;
|
||||
|
||||
useEffect(() => {
|
||||
setDateRange(value);
|
||||
}, [value]);
|
||||
|
|
@ -158,9 +163,9 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
|||
tooltipContent={
|
||||
customTooltipContent ?? (
|
||||
<>
|
||||
{dateRange.from ? renderFormattedDate(dateRange.from) : "N/A"}
|
||||
{" - "}
|
||||
{dateRange.to ? renderFormattedDate(dateRange.to) : "N/A"}
|
||||
{dateRange.from ? renderFormattedDate(dateRange.from) : ""}
|
||||
{dateRange.from && dateRange.to ? " - " : ""}
|
||||
{dateRange.to ? renderFormattedDate(dateRange.to) : ""}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -168,19 +173,70 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
|||
variant={buttonVariant}
|
||||
renderToolTipByDefault={renderByDefault}
|
||||
>
|
||||
<span
|
||||
className={cn("h-full flex items-center justify-center gap-1 rounded-sm flex-grow", buttonFromDateClassName)}
|
||||
>
|
||||
{!hideIcon.from && <CalendarDays className="h-3 w-3 flex-shrink-0" />}
|
||||
{dateRange.from ? renderFormattedDate(dateRange.from) : renderPlaceholder ? placeholder.from : ""}
|
||||
</span>
|
||||
<ArrowRight className="h-3 w-3 flex-shrink-0" />
|
||||
<span
|
||||
className={cn("h-full flex items-center justify-center gap-1 rounded-sm flex-grow", buttonToDateClassName)}
|
||||
>
|
||||
{!hideIcon.to && <CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
|
||||
{dateRange.to ? renderFormattedDate(dateRange.to) : renderPlaceholder ? placeholder.to : ""}
|
||||
</span>
|
||||
{mergeDates ? (
|
||||
// Merged date display
|
||||
<div className="flex items-center gap-1.5 w-full">
|
||||
{!hideIcon.from && <CalendarDays className="h-3 w-3 flex-shrink-0" />}
|
||||
{dateRange.from || dateRange.to ? (
|
||||
<MergedDateDisplay
|
||||
startDate={dateRange.from}
|
||||
endDate={dateRange.to}
|
||||
className="flex-grow truncate text-xs"
|
||||
/>
|
||||
) : (
|
||||
renderPlaceholder && (
|
||||
<>
|
||||
<span className="text-custom-text-400">{placeholder.from}</span>
|
||||
<ArrowRight className="h-3 w-3 flex-shrink-0 text-custom-text-400" />
|
||||
<span className="text-custom-text-400">{placeholder.to}</span>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
{isClearable && !disabled && hasDisplayedDates && (
|
||||
<X
|
||||
className={cn("h-2.5 w-2.5 flex-shrink-0 cursor-pointer", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
clearDates();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
// Original separate date display
|
||||
<>
|
||||
<span
|
||||
className={cn(
|
||||
"h-full flex items-center justify-center gap-1 rounded-sm flex-grow",
|
||||
buttonFromDateClassName
|
||||
)}
|
||||
>
|
||||
{!hideIcon.from && <CalendarDays className="h-3 w-3 flex-shrink-0" />}
|
||||
{dateRange.from ? renderFormattedDate(dateRange.from) : renderPlaceholder ? placeholder.from : ""}
|
||||
</span>
|
||||
<ArrowRight className="h-3 w-3 flex-shrink-0" />
|
||||
<span
|
||||
className={cn(
|
||||
"h-full flex items-center justify-center gap-1 rounded-sm flex-grow",
|
||||
buttonToDateClassName
|
||||
)}
|
||||
>
|
||||
{!hideIcon.to && <CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
|
||||
{dateRange.to ? renderFormattedDate(dateRange.to) : renderPlaceholder ? placeholder.to : ""}
|
||||
</span>
|
||||
{isClearable && !disabled && hasDisplayedDates && (
|
||||
<X
|
||||
className={cn("h-2.5 w-2.5 flex-shrink-0 cursor-pointer ml-1", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
clearDates();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DropdownButton>
|
||||
</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ export * from "./cycle";
|
|||
export * from "./date-range";
|
||||
export * from "./date";
|
||||
export * from "./estimate";
|
||||
export * from "./merged-date";
|
||||
export * from "./module";
|
||||
export * from "./priority";
|
||||
export * from "./project";
|
||||
|
|
|
|||
34
web/core/components/dropdowns/merged-date.tsx
Normal file
34
web/core/components/dropdowns/merged-date.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// helpers
|
||||
import { formatDateRange } from "@plane/utils";
|
||||
import { getDate } from "@/helpers/date-time.helper";
|
||||
|
||||
type Props = {
|
||||
startDate: Date | string | null | undefined;
|
||||
endDate: Date | string | null | undefined;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats merged date range display with smart formatting
|
||||
* - Single date: "Jan 24, 2025"
|
||||
* - Same year, same month: "Jan 24 - 28, 2025"
|
||||
* - Same year, different month: "Jan 24 - Feb 6, 2025"
|
||||
* - Different year: "Dec 28, 2024 - Jan 4, 2025"
|
||||
*/
|
||||
export const MergedDateDisplay: React.FC<Props> = observer((props) => {
|
||||
const { startDate, endDate, className = "" } = props;
|
||||
|
||||
// Parse dates
|
||||
const parsedStartDate = getDate(startDate);
|
||||
const parsedEndDate = getDate(endDate);
|
||||
|
||||
const displayText = formatDateRange(parsedStartDate, parsedEndDate);
|
||||
|
||||
if (!displayText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <span className={className}>{displayText}</span>;
|
||||
});
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
// plane imports
|
||||
import { SyntheticEvent } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { CalendarClock } from "lucide-react";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { IIssueDisplayProperties, TIssue } from "@plane/types";
|
||||
// components
|
||||
import { PriorityDropdown, MemberDropdown, StateDropdown, DateDropdown } from "@/components/dropdowns";
|
||||
import { PriorityDropdown, MemberDropdown, StateDropdown, DateRangeDropdown } from "@/components/dropdowns";
|
||||
// hooks
|
||||
import { WithDisplayPropertiesHOC } from "@/components/issues/issue-layouts/properties/with-display-properties-HOC";
|
||||
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||
|
|
@ -37,6 +36,22 @@ export const SubIssuesListItemProperties: React.FC<Props> = observer((props) =>
|
|||
e.preventDefault();
|
||||
};
|
||||
|
||||
const handleStartDate = (date: Date | null) => {
|
||||
if (issue.project_id) {
|
||||
updateSubIssue(workspaceSlug, issue.project_id, parentIssueId, issueId, {
|
||||
start_date: date ? renderFormattedPayloadDate(date) : null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleTargetDate = (date: Date | null) => {
|
||||
if (issue.project_id) {
|
||||
updateSubIssue(workspaceSlug, issue.project_id, parentIssueId, issueId, {
|
||||
target_date: date ? renderFormattedPayloadDate(date) : null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!displayProperties) return <></>;
|
||||
|
||||
const maxDate = getDate(issue.target_date);
|
||||
|
|
@ -88,29 +103,32 @@ export const SubIssuesListItemProperties: React.FC<Props> = observer((props) =>
|
|||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
|
||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="due_date">
|
||||
<div className="h-5 flex-shrink-0" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
|
||||
<DateDropdown
|
||||
value={issue.target_date ?? null}
|
||||
onChange={(val) =>
|
||||
issue.project_id &&
|
||||
updateSubIssue(
|
||||
workspaceSlug,
|
||||
issue.project_id,
|
||||
parentIssueId,
|
||||
issueId,
|
||||
{
|
||||
target_date: val ? renderFormattedPayloadDate(val) : null,
|
||||
},
|
||||
{ ...issue }
|
||||
)
|
||||
}
|
||||
maxDate={maxDate}
|
||||
placeholder={t("common.order_by.due_date")}
|
||||
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
|
||||
buttonVariant={issue.target_date ? "border-with-text" : "border-without-text"}
|
||||
optionsClassName="z-30"
|
||||
{/* merged dates */}
|
||||
<WithDisplayPropertiesHOC
|
||||
displayProperties={displayProperties}
|
||||
displayPropertyKey={["start_date", "due_date"]}
|
||||
shouldRenderProperty={(properties) => !!(properties.start_date || properties.due_date)}
|
||||
>
|
||||
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
|
||||
<DateRangeDropdown
|
||||
value={{
|
||||
from: getDate(issue.start_date) || undefined,
|
||||
to: getDate(issue.target_date) || undefined,
|
||||
}}
|
||||
onSelect={(range) => {
|
||||
handleStartDate(range?.from ?? null);
|
||||
handleTargetDate(range?.to ?? null);
|
||||
}}
|
||||
hideIcon={{
|
||||
from: false,
|
||||
}}
|
||||
isClearable
|
||||
mergeDates
|
||||
buttonVariant={issue.start_date || issue.target_date ? "border-with-text" : "border-without-text"}
|
||||
disabled={!disabled}
|
||||
showTooltip
|
||||
customTooltipHeading="Date Range"
|
||||
renderPlaceholder={false}
|
||||
/>
|
||||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import xor from "lodash/xor";
|
|||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
// icons
|
||||
import { CalendarCheck2, CalendarClock, Layers, Link, Paperclip } from "lucide-react";
|
||||
import { Layers, Link, Paperclip } from "lucide-react";
|
||||
// types
|
||||
import { ISSUE_UPDATED } from "@plane/constants";
|
||||
// i18n
|
||||
|
|
@ -15,13 +15,13 @@ import { TIssue, IIssueDisplayProperties, TIssuePriorities } from "@plane/types"
|
|||
import { Tooltip } from "@plane/ui";
|
||||
// components
|
||||
import {
|
||||
DateDropdown,
|
||||
EstimateDropdown,
|
||||
PriorityDropdown,
|
||||
MemberDropdown,
|
||||
ModuleDropdown,
|
||||
CycleDropdown,
|
||||
StateDropdown,
|
||||
DateRangeDropdown,
|
||||
} from "@/components/dropdowns";
|
||||
// constants
|
||||
// helpers
|
||||
|
|
@ -265,12 +265,6 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||
|
||||
const defaultLabelOptions = issue?.label_ids?.map((id) => labelMap[id]) || [];
|
||||
|
||||
const minDate = getDate(issue.start_date);
|
||||
minDate?.setDate(minDate.getDate());
|
||||
|
||||
const maxDate = getDate(issue.target_date);
|
||||
maxDate?.setDate(maxDate.getDate());
|
||||
|
||||
const handleEventPropagation = (e: SyntheticEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
|
@ -310,40 +304,34 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
|
||||
{/* start date */}
|
||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="start_date">
|
||||
{/* merged dates */}
|
||||
<WithDisplayPropertiesHOC
|
||||
displayProperties={displayProperties}
|
||||
displayPropertyKey={["start_date", "due_date"]}
|
||||
shouldRenderProperty={(properties) => !!(properties.start_date || properties.due_date)}
|
||||
>
|
||||
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
|
||||
<DateDropdown
|
||||
value={issue.start_date ?? null}
|
||||
onChange={handleStartDate}
|
||||
maxDate={maxDate}
|
||||
placeholder={t("common.order_by.start_date")}
|
||||
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
|
||||
buttonVariant={issue.start_date ? "border-with-text" : "border-without-text"}
|
||||
optionsClassName="z-10"
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
|
||||
{/* target/due date */}
|
||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="due_date">
|
||||
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
|
||||
<DateDropdown
|
||||
value={issue?.target_date ?? null}
|
||||
onChange={handleTargetDate}
|
||||
minDate={minDate}
|
||||
placeholder={t("common.order_by.due_date")}
|
||||
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
|
||||
buttonVariant={issue.target_date ? "border-with-text" : "border-without-text"}
|
||||
<DateRangeDropdown
|
||||
value={{
|
||||
from: getDate(issue.start_date) || undefined,
|
||||
to: getDate(issue.target_date) || undefined,
|
||||
}}
|
||||
onSelect={(range) => {
|
||||
handleStartDate(range?.from ?? null);
|
||||
handleTargetDate(range?.to ?? null);
|
||||
}}
|
||||
hideIcon={{
|
||||
from: false,
|
||||
}}
|
||||
isClearable
|
||||
mergeDates
|
||||
buttonVariant={issue.start_date || issue.target_date ? "border-with-text" : "border-without-text"}
|
||||
buttonClassName={shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group) ? "text-red-500" : ""}
|
||||
clearIconClassName="!text-custom-text-100"
|
||||
optionsClassName="z-10"
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
renderPlaceholder={false}
|
||||
customTooltipHeading="Date Range"
|
||||
/>
|
||||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
|
|||
target_date: val?.to ? renderFormattedPayloadDate(val.to) : null,
|
||||
});
|
||||
}}
|
||||
mergeDates
|
||||
placeholder={{
|
||||
from: t("start_date"),
|
||||
to: t("end_date"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue