diff --git a/apps/web/core/components/issues/issue-layouts/calendar/issue-block.tsx b/apps/web/core/components/issues/issue-layouts/calendar/issue-block.tsx index e5ea1c0cf6a..d92cc31cece 100644 --- a/apps/web/core/components/issues/issue-layouts/calendar/issue-block.tsx +++ b/apps/web/core/components/issues/issue-layouts/calendar/issue-block.tsx @@ -8,15 +8,18 @@ import { MoreHorizontal } from "lucide-react"; // plane helpers import { useOutsideClickDetector } from "@plane/hooks"; // types +import { PriorityIcon, priorityBlockClasses } from "@plane/propel/icons"; import { Tooltip } from "@plane/propel/tooltip"; import { TIssue } from "@plane/types"; // ui -import { ControlLink } from "@plane/ui"; +import { ControlLink, Avatar } from "@plane/ui"; import { cn, generateWorkItemLink } from "@plane/utils"; // helpers // hooks import { useIssueDetail } from "@/hooks/store/use-issue-detail"; import { useIssues } from "@/hooks/store/use-issues"; +import { useLabel } from "@/hooks/store/use-label"; +import { useMember } from "@/hooks/store/use-member"; import { useProject } from "@/hooks/store/use-project"; import { useProjectState } from "@/hooks/store/use-project-state"; import { useIssueStoreType } from "@/hooks/use-issue-layout-store"; @@ -49,24 +52,30 @@ export const CalendarIssueBlock = observer( const { getIsIssuePeeked } = useIssueDetail(); const { handleRedirection } = useIssuePeekOverviewRedirection(isEpic); const { isMobile } = usePlatformOS(); + const { labelMap } = useLabel(); + const { getUserDetails } = useMember(); const storeType = useIssueStoreType() as CalendarStoreType; const { issuesFilter } = useIssues(storeType); const { getProjectIdentifierById } = useProject(); - const stateColor = getProjectStates(issue?.project_id)?.find((state) => state?.id == issue?.state_id)?.color || ""; + const stateColor = + getProjectStates(issue?.project_id)?.find((state) => state?.id == issue?.state_id)?.color || ""; const projectIdentifier = getProjectIdentifierById(issue?.project_id); + const priority = issue?.priority || "none"; + const assignees = issue?.assignee_ids?.map((id) => getUserDetails(id)).filter(Boolean) || []; + const labels = issue?.label_ids?.map((id) => labelMap[id]).filter(Boolean) || []; // handlers - const handleIssuePeekOverview = (issue: TIssue) => handleRedirection(workspaceSlug.toString(), issue, isMobile); + const handleIssuePeekOverview = (issue: TIssue) => + handleRedirection(workspaceSlug.toString(), issue, isMobile); useOutsideClickDetector(menuActionRef, () => setIsMenuActive(false)); const customActionButton = (
setIsMenuActive(!isMenuActive)} > @@ -74,7 +83,8 @@ export const CalendarIssueBlock = observer( ); const isMenuActionRefAboveScreenBottom = - menuActionRef?.current && menuActionRef?.current?.getBoundingClientRect().bottom < window.innerHeight - 220; + menuActionRef?.current && + menuActionRef?.current?.getBoundingClientRect().bottom < window.innerHeight - 220; const placement = isMenuActionRefAboveScreenBottom ? "bottom-end" : "top-end"; @@ -103,51 +113,102 @@ export const CalendarIssueBlock = observer( )}
-
- - {issue.project_id && ( - +
+ + - )} + {issue.project_id && ( + + )} +
+ +
{ + e.preventDefault(); + e.stopPropagation(); + }} + > + {quickActions({ + issue, + parentRef: blockRef, + customActionButton, + placement, + })} +
+
+ +
-
{issue.name}
+
+ {issue.name} +
-
{ - e.preventDefault(); - e.stopPropagation(); - }} - > - {quickActions({ - issue, - parentRef: blockRef, - customActionButton, - placement, - })} + +
+
+ {labels.slice(0, 2).map((label) => ( + + {label.name} + + ))} + {labels.length > 2 && ( + + +{labels.length - 2} + + )} +
+ +
+ {assignees.slice(0, 3).map((assignee) => ( + + + + ))} + {assignees.length > 3 && ( +
+ +{assignees.length - 3} +
+ )} +
diff --git a/packages/propel/src/icons/priority-icon.tsx b/packages/propel/src/icons/priority-icon.tsx index e7da9debba4..bd8d6f5f020 100644 --- a/packages/propel/src/icons/priority-icon.tsx +++ b/packages/propel/src/icons/priority-icon.tsx @@ -12,27 +12,34 @@ interface IPriorityIcon { withContainer?: boolean; } +const priorityClasses = { + urgent: "bg-red-600/20 text-red-600 border-red-600", + high: "bg-orange-500/20 text-orange-500 border-orange-500", + medium: "bg-yellow-500/20 text-yellow-500 border-yellow-500", + low: "bg-custom-primary-100/20 text-custom-primary-100 border-custom-primary-100", + none: "bg-custom-background-80 text-custom-text-200 border-custom-border-300", +}; + +export const priorityBlockClasses: Record = { + urgent: "bg-red-500/10 border border-red-500/30", + high: "bg-orange-500/10 border border-orange-500/30", + medium: "bg-yellow-500/10 border border-yellow-500/30", + low: "bg-blue-500/10 border border-blue-500/30", + none: "bg-gray-500/10 border border-gray-500/30", +}; + +const icons = { + urgent: AlertCircle, + high: SignalHigh, + medium: SignalMedium, + low: SignalLow, + none: Ban, +}; + export const PriorityIcon: React.FC = (props) => { const { priority, className = "", containerClassName = "", size = 14, withContainer = false } = props; - const priorityClasses = { - urgent: "bg-red-600/20 text-red-600 border-red-600", - high: "bg-orange-500/20 text-orange-500 border-orange-500", - medium: "bg-yellow-500/20 text-yellow-500 border-yellow-500", - low: "bg-custom-primary-100/20 text-custom-primary-100 border-custom-primary-100", - none: "bg-custom-background-80 text-custom-text-200 border-custom-border-300", - }; - - // get priority icon - const icons = { - urgent: AlertCircle, - high: SignalHigh, - medium: SignalMedium, - low: SignalLow, - none: Ban, - }; const Icon = icons[priority ?? "none"]; - if (!Icon) return null; return (