import { useEffect, useRef, useState } from "react"; import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; import { differenceInCalendarDays } from "date-fns"; import { observer } from "mobx-react-lite"; // types import { TGroupedIssues, TIssue, TIssueMap } from "@plane/types"; // ui import { TOAST_TYPE, setToast } from "@plane/ui"; // components import { CalendarIssueBlocks, ICalendarDate } from "@/components/issues"; import { highlightIssueOnDrop } from "@/components/issues/issue-layouts/utils"; // helpers import { MONTHS_LIST } from "@/constants/calendar"; // helpers import { cn } from "@/helpers/common.helper"; import { renderFormattedPayloadDate } from "@/helpers/date-time.helper"; // types import { ICycleIssuesFilter } from "@/store/issue/cycle"; import { IModuleIssuesFilter } from "@/store/issue/module"; import { IProjectIssuesFilter } from "@/store/issue/project"; import { IProjectViewIssuesFilter } from "@/store/issue/project-views"; import { TRenderQuickActions } from "../list/list-view-types"; type Props = { issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter; date: ICalendarDate; issues: TIssueMap | undefined; groupedIssueIds: TGroupedIssues; quickActions: TRenderQuickActions; enableQuickIssueCreate?: boolean; disableIssueCreation?: boolean; handleDragAndDrop: ( issueId: string | undefined, sourceDate: string | undefined, destinationDate: string | undefined ) => Promise; quickAddCallback?: ( workspaceSlug: string, projectId: string, data: TIssue, viewId?: string ) => Promise; addIssuesToView?: (issueIds: string[]) => Promise; viewId?: string; readOnly?: boolean; selectedDate: Date; setSelectedDate: (date: Date) => void; }; export const CalendarDayTile: React.FC = observer((props) => { const { issuesFilterStore, date, issues, groupedIssueIds, quickActions, enableQuickIssueCreate, disableIssueCreation, quickAddCallback, addIssuesToView, viewId, readOnly = false, selectedDate, handleDragAndDrop, setSelectedDate, } = props; const [isDraggingOver, setIsDraggingOver] = useState(false); const [showAllIssues, setShowAllIssues] = useState(false); const calendarLayout = issuesFilterStore?.issueFilters?.displayFilters?.calendar?.layout ?? "month"; const formattedDatePayload = renderFormattedPayloadDate(date.date); const dayTileRef = useRef(null); useEffect(() => { const element = dayTileRef.current; if (!element) return; return combine( dropTargetForElements({ element, getData: () => ({ date: formattedDatePayload }), onDragEnter: () => { setIsDraggingOver(true); }, onDragLeave: () => { setIsDraggingOver(false); }, onDrop: ({ source, self }) => { setIsDraggingOver(false); const sourceData = source?.data as { id: string; date: string } | undefined; const destinationData = self?.data as { date: string } | undefined; if (!sourceData || !destinationData) return; const issueDetails = issues?.[sourceData?.id]; if (issueDetails?.start_date) { const issueStartDate = new Date(issueDetails.start_date); const targetDate = new Date(destinationData?.date); const diffInDays = differenceInCalendarDays(targetDate, issueStartDate); if (diffInDays < 0) { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "Due date cannot be before the start date of the issue.", }); return; } } handleDragAndDrop(sourceData?.id, sourceData?.date, destinationData?.date); setShowAllIssues(true); highlightIssueOnDrop(source?.element?.id, false); }, }) ); }, [dayTileRef?.current, formattedDatePayload]); if (!formattedDatePayload) return null; const issueIdList = groupedIssueIds ? groupedIssueIds[formattedDatePayload] : null; const totalIssues = issueIdList?.length ?? 0; const isToday = date.date.toDateString() === new Date().toDateString(); const isSelectedDate = date.date.toDateString() == selectedDate.toDateString(); const isWeekend = [0, 6].includes(date.date.getDay()); const isMonthLayout = calendarLayout === "month"; const normalBackground = isWeekend ? "bg-custom-background-90" : "bg-custom-background-100"; const draggingOverBackground = isWeekend ? "bg-custom-background-80" : "bg-custom-background-90"; return ( <>
{/* header */}
{date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "} {isToday ? ( {date.date.getDate()} ) : ( <>{date.date.getDate()} )}
{/* content */}
{/* Mobile view content */}
setSelectedDate(date.date)} className={cn( "text-sm py-2.5 h-full w-full font-medium mx-auto flex flex-col justify-start items-center md:hidden cursor-pointer opacity-80", { "bg-custom-background-100": !isWeekend, } )} >
{date.date.getDate()}
{totalIssues > 0 &&
}
); });