From 986f81e3ae1dbec2a855830088bcecf2558aa266 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:38:05 +0530 Subject: [PATCH] [WEB-905] chore: issue peek overview and kanban layout improvement (#4135) * chore: peek overview and kanban card improvement * chore: peek overview improvement --- .../issue-layouts/calendar/issue-block.tsx | 2 ++ .../issues/issue-layouts/gantt/blocks.tsx | 3 ++ .../issues/issue-layouts/kanban/block.tsx | 10 ++++--- .../issues/issue-layouts/list/block.tsx | 2 ++ .../issue-layouts/spreadsheet/issue-row.tsx | 12 +++++--- web/components/issues/peek-overview/view.tsx | 16 ++++++---- .../issues/sub-issues/issue-list-item.tsx | 3 ++ web/hooks/use-peek-overview-outside-click.tsx | 29 +++++++++++++++++++ 8 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 web/hooks/use-peek-overview-outside-click.tsx diff --git a/web/components/issues/issue-layouts/calendar/issue-block.tsx b/web/components/issues/issue-layouts/calendar/issue-block.tsx index 713049ac3..44ca0c9df 100644 --- a/web/components/issues/issue-layouts/calendar/issue-block.tsx +++ b/web/components/issues/issue-layouts/calendar/issue-block.tsx @@ -41,6 +41,7 @@ export const CalendarIssueBlock: React.FC = observer((props) => { issue && issue.project_id && issue.id && + peekIssue?.issueId !== issue.id && setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); useOutsideClickDetector(menuActionRef, () => setIsMenuActive(false)); @@ -64,6 +65,7 @@ export const CalendarIssueBlock: React.FC = observer((props) => { return ( handleIssuePeekOverview(issue)} diff --git a/web/components/issues/issue-layouts/gantt/blocks.tsx b/web/components/issues/issue-layouts/gantt/blocks.tsx index aff992b66..02ed66e5a 100644 --- a/web/components/issues/issue-layouts/gantt/blocks.tsx +++ b/web/components/issues/issue-layouts/gantt/blocks.tsx @@ -20,6 +20,7 @@ export const IssueGanttBlock: React.FC = observer((props) => { const { getProjectStates } = useProjectState(); const { issue: { getIssueById }, + peekIssue, setPeekIssue, } = useIssueDetail(); // derived values @@ -31,11 +32,13 @@ export const IssueGanttBlock: React.FC = observer((props) => { workspaceSlug && issueDetails && !issueDetails.tempId && + peekIssue?.issueId !== issueDetails.id && setPeekIssue({ workspaceSlug, projectId: issueDetails.project_id, issueId: issueDetails.id }); const { isMobile } = usePlatformOS(); return (
= observer((prop const { router: { workspaceSlug }, } = useApplication(); - const { setPeekIssue } = useIssueDetail(); + const { peekIssue, setPeekIssue } = useIssueDetail(); const handleIssuePeekOverview = (issue: TIssue) => workspaceSlug && issue && issue.project_id && issue.id && + peekIssue?.issueId !== issue.id && setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); return ( @@ -69,16 +70,17 @@ const KanbanIssueDetailsBlock: React.FC = observer((prop {issue?.is_draft ? ( - {issue.name} + {issue.name} ) : ( handleIssuePeekOverview(issue)} - className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100" + className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100 pb-1.5" disabled={!!issue?.tempId} > @@ -138,7 +140,7 @@ export const KanbanIssueBlock: React.FC = memo((props) => { >
= observer((props: IssueBlock issue && issue.project_id && issue.id && + peekIssue?.issueId !== issue.id && setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); const issue = issuesMap[issueId]; @@ -71,6 +72,7 @@ export const IssueBlock: React.FC = observer((props: IssueBlock ) : ( { const [isMenuActive, setIsMenuActive] = useState(false); const menuActionRef = useRef(null); - const handleIssuePeekOverview = (issue: TIssue) => { - if (workspaceSlug && issue && issue.project_id && issue.id) - setPeekIssue({ workspaceSlug: workspaceSlug.toString(), projectId: issue.project_id, issueId: issue.id }); - }; + const handleIssuePeekOverview = (issue: TIssue) => + workspaceSlug && + issue && + issue.project_id && + issue.id && + peekIssue?.issueId !== issue.id && + setPeekIssue({ workspaceSlug: workspaceSlug.toString(), projectId: issue.project_id, issueId: issue.id }); const { subIssues: subIssuesStore, issue } = useIssueDetail(); @@ -240,6 +243,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
handleIssuePeekOverview(issueDetail)} diff --git a/web/components/issues/peek-overview/view.tsx b/web/components/issues/peek-overview/view.tsx index 0366fbb61..d5b723f66 100644 --- a/web/components/issues/peek-overview/view.tsx +++ b/web/components/issues/peek-overview/view.tsx @@ -16,7 +16,7 @@ import { // hooks import { useIssueDetail, useUser } from "@/hooks/store"; import useKeypress from "@/hooks/use-keypress"; -import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; +import usePeekOverviewOutsideClickDetector from "@/hooks/use-peek-overview-outside-click"; // store hooks import { IssueActivity } from "../issue-detail/issue-activity"; import { SubIssuesRoot } from "../sub-issues"; @@ -55,11 +55,15 @@ export const IssueView: FC = observer((props) => { setPeekIssue(undefined); }; - useOutsideClickDetector(issuePeekOverviewRef, () => { - if (!isAnyModalOpen) { - removeRoutePeekId(); - } - }); + usePeekOverviewOutsideClickDetector( + issuePeekOverviewRef, + () => { + if (!isAnyModalOpen) { + removeRoutePeekId(); + } + }, + issueId + ); const handleKeyDown = () => { const slashCommandDropdownElement = document.querySelector("#slash-command"); const dropdownElement = document.activeElement?.tagName === "INPUT"; diff --git a/web/components/issues/sub-issues/issue-list-item.tsx b/web/components/issues/sub-issues/issue-list-item.tsx index 27d6ca209..a2eaad398 100644 --- a/web/components/issues/sub-issues/issue-list-item.tsx +++ b/web/components/issues/sub-issues/issue-list-item.tsx @@ -42,6 +42,7 @@ export const IssueListItem: React.FC = observer((props) => { } = props; const { + peekIssue, setPeekIssue, issue: { getIssueById }, subIssues: { subIssueHelpersByIssueId, setSubIssueHelpers }, @@ -64,6 +65,7 @@ export const IssueListItem: React.FC = observer((props) => { issue && issue.project_id && issue.id && + peekIssue?.issueId !== issue.id && setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); if (!issue) return <>; @@ -117,6 +119,7 @@ export const IssueListItem: React.FC = observer((props) => {
handleIssuePeekOverview(issue)} diff --git a/web/hooks/use-peek-overview-outside-click.tsx b/web/hooks/use-peek-overview-outside-click.tsx new file mode 100644 index 000000000..22b9badff --- /dev/null +++ b/web/hooks/use-peek-overview-outside-click.tsx @@ -0,0 +1,29 @@ +import React, { useEffect } from "react"; + +const usePeekOverviewOutsideClickDetector = ( + ref: React.RefObject, + callback: () => void, + issueId: string +) => { + const handleClick = (event: MouseEvent) => { + if (ref.current && !ref.current.contains(event.target as Node)) { + let targetElement = event.target as HTMLElement | null; + while (targetElement) { + if (targetElement.id === `issue-${issueId}`) { + return; + } + targetElement = targetElement.parentElement; + } + callback(); + } + }; + + useEffect(() => { + document.addEventListener("mousedown", handleClick); + + return () => { + document.removeEventListener("mousedown", handleClick); + }; + }); +}; +export default usePeekOverviewOutsideClickDetector;