From 9701697af207be74fdd67efc17927483c44f377a Mon Sep 17 00:00:00 2001 From: Dakshesh Jain Date: Fri, 2 Dec 2022 17:17:13 +0530 Subject: [PATCH 1/6] feat: filter, sort issues, command as shortcut for mac device --- apps/app/components/command-palette/index.tsx | 14 +- .../project/issues/BoardView/SingleBoard.tsx | 113 +++---- .../project/issues/BoardView/index.tsx | 32 -- apps/app/constants/common.ts | 28 ++ apps/app/lib/hooks/useIssuesFilter.tsx | 92 ++++++ apps/app/lib/hooks/useIssuesProperties.tsx | 19 +- .../projects/[projectId]/issues/index.tsx | 292 +++++++++--------- apps/app/pages/workspace/index.tsx | 4 +- apps/app/types/state.d.ts | 1 + apps/app/ui/CustomMenu/index.tsx | 74 +++++ apps/app/ui/CustomMenu/types.d.ts | 11 + apps/app/ui/index.ts | 1 + yarn.lock | 186 ----------- 13 files changed, 437 insertions(+), 430 deletions(-) create mode 100644 apps/app/lib/hooks/useIssuesFilter.tsx create mode 100644 apps/app/ui/CustomMenu/index.tsx create mode 100644 apps/app/ui/CustomMenu/types.d.ts diff --git a/apps/app/components/command-palette/index.tsx b/apps/app/components/command-palette/index.tsx index b626eac7a..ceb27634e 100644 --- a/apps/app/components/command-palette/index.tsx +++ b/apps/app/components/command-palette/index.tsx @@ -85,25 +85,25 @@ const CommandPalette: React.FC = () => { const handleKeyDown = useCallback( (e: KeyboardEvent) => { - if (e.ctrlKey && e.key === "/") { + if ((e.ctrlKey || e.metaKey) && e.key === "/") { e.preventDefault(); setIsPaletteOpen(true); - } else if (e.ctrlKey && e.key === "i") { + } else if ((e.ctrlKey || e.metaKey) && e.key === "i") { e.preventDefault(); setIsIssueModalOpen(true); - } else if (e.ctrlKey && e.key === "p") { + } else if ((e.ctrlKey || e.metaKey) && e.key === "p") { e.preventDefault(); setIsProjectModalOpen(true); - } else if (e.ctrlKey && e.key === "b") { + } else if ((e.ctrlKey || e.metaKey) && e.key === "b") { e.preventDefault(); toggleCollapsed(); - } else if (e.ctrlKey && e.key === "h") { + } else if ((e.ctrlKey || e.metaKey) && e.key === "h") { e.preventDefault(); setIsShortcutsModalOpen(true); - } else if (e.ctrlKey && e.key === "q") { + } else if ((e.ctrlKey || e.metaKey) && e.key === "q") { e.preventDefault(); setIsCreateCycleModalOpen(true); - } else if (e.ctrlKey && e.altKey && e.key === "c") { + } else if ((e.ctrlKey || e.metaKey) && e.altKey && e.key === "c") { e.preventDefault(); if (!router.query.issueId) return; diff --git a/apps/app/components/project/issues/BoardView/SingleBoard.tsx b/apps/app/components/project/issues/BoardView/SingleBoard.tsx index 4f2c3b1d6..64e513f46 100644 --- a/apps/app/components/project/issues/BoardView/SingleBoard.tsx +++ b/apps/app/components/project/issues/BoardView/SingleBoard.tsx @@ -5,7 +5,11 @@ import Link from "next/link"; import { Draggable } from "react-beautiful-dnd"; import StrictModeDroppable from "components/dnd/StrictModeDroppable"; // common -import { addSpaceIfCamelCase, renderShortNumericDateFormat } from "constants/common"; +import { + addSpaceIfCamelCase, + findHowManyDaysLeft, + renderShortNumericDateFormat, +} from "constants/common"; // types import { IIssue, Properties, NestedKeyOf } from "types"; // icons @@ -23,7 +27,9 @@ import { divide } from "lodash"; type Props = { selectedGroup: NestedKeyOf | null; groupTitle: string; - groupedByIssues: any; + groupedByIssues: { + [key: string]: IIssue[]; + }; index: number; setIsIssueOpen: React.Dispatch>; properties: Properties; @@ -103,9 +109,6 @@ const SingleBoard: React.FC = ({ border: `2px solid ${bgColor}`, backgroundColor: `${bgColor}20`, }} - onClick={() => { - // setInput(true); - }} > = ({ className="h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none" onClick={() => setPreloadedData({ - // ...state, actionType: "edit", }) } > - {/* */} @@ -197,7 +187,7 @@ const SingleBoard: React.FC = ({ {...provided.droppableProps} ref={provided.innerRef} > - {groupedByIssues[groupTitle].map((childIssue: any, index: number) => ( + {groupedByIssues[groupTitle].map((childIssue, index: number) => ( {(provided, snapshot) => ( @@ -212,6 +202,9 @@ const SingleBoard: React.FC = ({ className="px-2 py-3 space-y-1.5 select-none" {...provided.dragHandleProps} > + + {childIssue.name} + {Object.keys(properties).map( (key) => properties[key as keyof Properties] && @@ -236,34 +229,65 @@ const SingleBoard: React.FC = ({ : key === "target_date" ? "text-xs bg-indigo-50 px-2 py-1 mt-2 flex items-center gap-x-1 rounded w-min whitespace-nowrap" : "text-sm text-gray-500" - } gap-1 + } gap-1 relative `} > - {key === "target_date" ? ( - <> - {" "} + {key === "start_date" && childIssue.start_date !== null && ( + + + {renderShortNumericDateFormat(childIssue.start_date)} - {childIssue.target_date ? renderShortNumericDateFormat(childIssue.target_date) - : "N/A"} - - ) : ( - "" + : "None"} + )} - {key === "name" && ( - - {childIssue.name} + {key === "target_date" && ( + <> + + + {childIssue.target_date + ? renderShortNumericDateFormat(childIssue.target_date) + : "N/A"} + {childIssue.target_date && ( + + {childIssue.target_date < new Date().toISOString() + ? `Target date has passed by ${findHowManyDaysLeft( + childIssue.target_date + )} days` + : findHowManyDaysLeft(childIssue.target_date) <= 3 + ? `Target date is in ${findHowManyDaysLeft( + childIssue.target_date + )} days` + : "Target date"} + + )} + + + )} + {key === "key" && ( + + {childIssue.project_detail?.identifier}- + {childIssue.sequence_id} )} {key === "state" && ( <>{addSpaceIfCamelCase(childIssue["state_detail"].name)} )} {key === "priority" && <>{childIssue.priority}} - {key === "description" && <>{childIssue.description}} {key === "assignee" ? (
{childIssue?.assignee_details?.length > 0 ? ( childIssue?.assignee_details?.map( - (assignee: any, index: number) => ( + (assignee, index: number) => (
= ({ ) ) ) : ( - None + No assignee. )}
) : null} @@ -299,29 +323,6 @@ const SingleBoard: React.FC = ({ ) )}
- - {/*
- -
- - -
-
*/} )} diff --git a/apps/app/components/project/issues/BoardView/index.tsx b/apps/app/components/project/issues/BoardView/index.tsx index 557ec406f..010b9cbdc 100644 --- a/apps/app/components/project/issues/BoardView/index.tsx +++ b/apps/app/components/project/issues/BoardView/index.tsx @@ -67,8 +67,6 @@ const BoardView: React.FC = ({ properties, selectedGroup, groupedByIssues setIssueDeletionData(removedItem); setIsIssueDeletionOpen(true); - - console.log(removedItem); } else { if (type === "state") { const newStates = Array.from(states ?? []); @@ -168,21 +166,6 @@ const BoardView: React.FC = ({ properties, selectedGroup, groupedByIssues return ( <> - {/* } - projectId={projectId as string} - /> */} - {/* } - /> */} setIsIssueDeletionOpen(false)} @@ -199,21 +182,6 @@ const BoardView: React.FC = ({ properties, selectedGroup, groupedByIssues {groupedByIssues ? (
- {/* - {(provided, snapshot) => ( - - )} - */}
{(provided) => ( diff --git a/apps/app/constants/common.ts b/apps/app/constants/common.ts index 7dd866885..1937d65e3 100644 --- a/apps/app/constants/common.ts +++ b/apps/app/constants/common.ts @@ -1,3 +1,5 @@ +import { NestedKeyOf } from "types"; + export const classNames = (...classes: string[]) => { return classes.filter(Boolean).join(" "); }; @@ -30,6 +32,32 @@ export const groupBy = (array: any[], key: string) => { }, {}); }; +export const orderArrayBy = ( + array: any[], + key: string, + ordering: "ascending" | "descending" = "ascending" +) => { + const innerKey = key.split("."); // split the key by dot + return array.sort((a, b) => { + const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key + const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key + if (keyA < keyB) { + return ordering === "ascending" ? -1 : 1; + } + if (keyA > keyB) { + return ordering === "ascending" ? 1 : -1; + } + return 0; + }); +}; + +export const findHowManyDaysLeft = (date: string | Date) => { + const today = new Date(); + const eventDate = new Date(date); + const timeDiff = Math.abs(eventDate.getTime() - today.getTime()); + return Math.ceil(timeDiff / (1000 * 3600 * 24)); +}; + export const timeAgo = (time: any) => { switch (typeof time) { case "number": diff --git a/apps/app/lib/hooks/useIssuesFilter.tsx b/apps/app/lib/hooks/useIssuesFilter.tsx new file mode 100644 index 000000000..797cc29dd --- /dev/null +++ b/apps/app/lib/hooks/useIssuesFilter.tsx @@ -0,0 +1,92 @@ +import { useState } from "react"; +// hooks +import useTheme from "./useTheme"; +import useUser from "./useUser"; +// commons +import { groupBy, orderArrayBy } from "constants/common"; + +// types +import type { IssueResponse, IIssue, NestedKeyOf } from "types"; + +const PRIORITIES = ["high", "medium", "low"]; + +const useIssuesFilter = (projectIssues?: IssueResponse) => { + const { issueView, setIssueView, groupByProperty, setGroupByProperty } = useTheme(); + + const [orderBy, setOrderBy] = useState | null>(null); + + const [filterIssue, setFilterIssue] = useState<"activeIssue" | "backlogIssue" | null>(null); + + const { states } = useUser(); + + let groupedByIssues: { + [key: string]: IIssue[]; + } = { + ...(groupByProperty === "state_detail.name" + ? Object.fromEntries( + states + ?.sort((a, b) => a.sequence - b.sequence) + ?.map((state) => [ + state.name, + projectIssues?.results.filter((issue) => issue.state === state.name) ?? [], + ]) ?? [] + ) + : groupByProperty === "priority" + ? Object.fromEntries( + PRIORITIES.map((priority) => [ + priority, + projectIssues?.results.filter((issue) => issue.priority === priority) ?? [], + ]) + ) + : {}), + ...groupBy(projectIssues?.results ?? [], groupByProperty ?? ""), + }; + + if (orderBy !== null) { + groupedByIssues = Object.fromEntries( + Object.entries(groupedByIssues).map(([key, value]) => [key, orderArrayBy(value, orderBy)]) + ); + } + + if (filterIssue !== null) { + if (filterIssue === "activeIssue") { + groupedByIssues = Object.keys(groupedByIssues).reduce((acc, key) => { + const value = groupedByIssues[key]; + const filteredValue = value.filter( + (issue) => + issue.state_detail.group === "started" || issue.state_detail.group === "unstarted" + ); + if (filteredValue.length > 0) { + acc[key] = filteredValue; + } + return acc; + }, {} as typeof groupedByIssues); + } else if (filterIssue === "backlogIssue") { + groupedByIssues = Object.keys(groupedByIssues).reduce((acc, key) => { + const value = groupedByIssues[key]; + const filteredValue = value.filter( + (issue) => + issue.state_detail.group === "backlog" || issue.state_detail.group === "cancelled" + ); + if (filteredValue.length > 0) { + acc[key] = filteredValue; + } + return acc; + }, {} as typeof groupedByIssues); + } + } + + return { + groupedByIssues, + issueView, + setIssueView, + groupByProperty, + setGroupByProperty, + orderBy, + setOrderBy, + filterIssue, + setFilterIssue, + } as const; +}; + +export default useIssuesFilter; diff --git a/apps/app/lib/hooks/useIssuesProperties.tsx b/apps/app/lib/hooks/useIssuesProperties.tsx index 8b7f3b286..14de06969 100644 --- a/apps/app/lib/hooks/useIssuesProperties.tsx +++ b/apps/app/lib/hooks/useIssuesProperties.tsx @@ -1,4 +1,4 @@ -import { useState, useContext, useEffect, useCallback } from "react"; +import { useState, useEffect, useCallback } from "react"; // swr import useSWR from "swr"; // api routes @@ -80,7 +80,22 @@ const useIssuesProperties = (workspaceSlug?: string, projectId?: string) => { [workspaceSlug, projectId, issueProperties, user] ); - return [properties, updateIssueProperties] as const; + const newProperties = Object.keys(properties).reduce((obj: any, key) => { + if ( + key !== "children" && + key !== "name" && + key !== "parent" && + key !== "project" && + key !== "description" && + key !== "attachments" && + key !== "sequence_id" + ) { + obj[key] = properties[key as keyof Properties]; + } + return obj; + }, {}); + + return [newProperties, updateIssueProperties] as const; }; export default useIssuesProperties; diff --git a/apps/app/pages/projects/[projectId]/issues/index.tsx b/apps/app/pages/projects/[projectId]/issues/index.tsx index ca612d4b9..9bef5dcca 100644 --- a/apps/app/pages/projects/[projectId]/issues/index.tsx +++ b/apps/app/pages/projects/[projectId]/issues/index.tsx @@ -1,4 +1,3 @@ -// react import React, { useEffect, useState } from "react"; // next import type { NextPage } from "next"; @@ -6,52 +5,75 @@ import { useRouter } from "next/router"; // swr import useSWR from "swr"; // headless ui -import { Menu, Popover, Transition } from "@headlessui/react"; -// services -import stateServices from "lib/services/state.services"; -import issuesServices from "lib/services/issues.services"; +import { Popover, Transition } from "@headlessui/react"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // hooks import useUser from "lib/hooks/useUser"; -import useTheme from "lib/hooks/useTheme"; import useIssuesProperties from "lib/hooks/useIssuesProperties"; -// fetching keys -import { PROJECT_ISSUES_LIST, STATE_LIST } from "constants/fetch-keys"; +// api routes +import { PROJECT_MEMBERS } from "constants/api-routes"; +// services +import projectService from "lib/services/project.service"; // commons -import { groupBy } from "constants/common"; +import { classNames, replaceUnderscoreIfSnakeCase } from "constants/common"; // layouts import AdminLayout from "layouts/AdminLayout"; +// hooks +import useIssuesFilter from "lib/hooks/useIssuesFilter"; // components import ListView from "components/project/issues/ListView"; import BoardView from "components/project/issues/BoardView"; import ConfirmIssueDeletion from "components/project/issues/ConfirmIssueDeletion"; import CreateUpdateIssuesModal from "components/project/issues/CreateUpdateIssueModal"; // ui -import { Spinner } from "ui"; +import { Spinner, CustomMenu, BreadcrumbItem, Breadcrumbs } from "ui"; import { EmptySpace, EmptySpaceItem } from "ui/EmptySpace"; import HeaderButton from "ui/HeaderButton"; -import { BreadcrumbItem, Breadcrumbs } from "ui"; // icons import { ChevronDownIcon, ListBulletIcon, RectangleStackIcon } from "@heroicons/react/24/outline"; -import { PlusIcon, EyeIcon, EyeSlashIcon, Squares2X2Icon } from "@heroicons/react/20/solid"; +import { PlusIcon, Squares2X2Icon } from "@heroicons/react/20/solid"; // types -import type { IIssue, IssueResponse, Properties, IState, NestedKeyOf, ProjectMember } from "types"; -import { PROJECT_MEMBERS } from "constants/api-routes"; -import projectService from "lib/services/project.service"; +import type { IIssue, Properties, NestedKeyOf, ProjectMember } from "types"; -const PRIORITIES = ["high", "medium", "low"]; +const groupByOptions: Array<{ name: string; key: NestedKeyOf }> = [ + { name: "State", key: "state_detail.name" }, + { name: "Priority", key: "priority" }, + { name: "Created By", key: "created_by" }, +]; + +const orderByOptions: Array<{ name: string; key: NestedKeyOf }> = [ + { name: "Created", key: "created_at" }, + { name: "Update", key: "updated_at" }, +]; + +const filterIssueOptions: Array<{ + name: string; + key: "activeIssue" | "backlogIssue" | null; +}> = [ + { + name: "All", + key: null, + }, + { + name: "Active Issues", + key: "activeIssue", + }, + { + name: "Backlog Issues", + key: "backlogIssue", + }, +]; const ProjectIssues: NextPage = () => { const [isOpen, setIsOpen] = useState(false); - const { issueView, setIssueView, groupByProperty, setGroupByProperty } = useTheme(); - const [selectedIssue, setSelectedIssue] = useState< (IIssue & { actionType: "edit" | "delete" }) | undefined >(undefined); - const [editIssue, setEditIssue] = useState(); const [deleteIssue, setDeleteIssue] = useState(undefined); - const { activeWorkspace, activeProject } = useUser(); + const { activeWorkspace, activeProject, issues: projectIssues } = useUser(); const router = useRouter(); @@ -62,22 +84,6 @@ const ProjectIssues: NextPage = () => { projectId as string ); - const { data: projectIssues } = useSWR( - projectId && activeWorkspace - ? PROJECT_ISSUES_LIST(activeWorkspace.slug, projectId as string) - : null, - activeWorkspace && projectId - ? () => issuesServices.getIssues(activeWorkspace.slug, projectId as string) - : null - ); - - const { data: states } = useSWR( - activeWorkspace && activeProject ? STATE_LIST(activeProject.id) : null, - activeWorkspace && activeProject - ? () => stateServices.getStates(activeWorkspace.slug, activeProject.id) - : null - ); - const { data: members } = useSWR( activeWorkspace && activeProject ? PROJECT_MEMBERS : null, activeWorkspace && activeProject @@ -85,6 +91,18 @@ const ProjectIssues: NextPage = () => { : null ); + const { + issueView, + setIssueView, + groupByProperty, + setGroupByProperty, + groupedByIssues, + setOrderBy, + setFilterIssue, + orderBy, + filterIssue, + } = useIssuesFilter(projectIssues); + useEffect(() => { if (!isOpen) { const timer = setTimeout(() => { @@ -94,35 +112,6 @@ const ProjectIssues: NextPage = () => { } }, [isOpen]); - const groupedByIssues: { - [key: string]: IIssue[]; - } = { - ...(groupByProperty === "state_detail.name" - ? Object.fromEntries( - states - ?.sort((a, b) => a.sequence - b.sequence) - ?.map((state) => [ - state.name, - projectIssues?.results.filter((issue) => issue.state === state.name) ?? [], - ]) ?? [] - ) - : groupByProperty === "priority" - ? Object.fromEntries( - PRIORITIES.map((priority) => [ - priority, - projectIssues?.results.filter((issue) => issue.priority === priority) ?? [], - ]) - ) - : {}), - ...groupBy(projectIssues?.results ?? [], groupByProperty ?? ""), - }; - - const groupByOptions: Array<{ name: string; key: NestedKeyOf }> = [ - { name: "State", key: "state_detail.name" }, - { name: "Priority", key: "priority" }, - { name: "Created By", key: "created_by" }, - ]; - return ( {

Project Issues

-
+
- -
- - - {groupByOptions.find((option) => option.key === groupByProperty)?.name ?? - "No Grouping"} - -
-
-
-
- - - -
- {groupByOptions.map((option) => ( - - {({ active }) => ( - - )} - - ))} - {issueView === "list" ? ( - - {({ active }) => ( - - )} - - ) : null} -
-
-
-
{({ open }) => ( <> - - Properties - + + View + { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - -
-
- {Object.keys(properties).map((key) => ( - - ))} + {groupByOptions.map((option) => ( + setGroupByProperty(option.key)} + > + {option.name} + + ))} + +
+
+

Order by

+ option.key === orderBy)?.name ?? + "Select" + } + > + {orderByOptions.map((option) => ( + setOrderBy(option.key)} + > + {option.name} + + ))} + +
+
+

Issue type

+ option.key === filterIssue) + ?.name ?? "Select" + } + > + {filterIssueOptions.map((option) => ( + setFilterIssue(option.key)} + > + {option.name} + + ))} + +
+
+
+

Properties

+
+ {Object.keys(properties).map((key) => ( + + ))} +
+
@@ -335,4 +335,4 @@ const ProjectIssues: NextPage = () => { ); }; -export default ProjectIssues; +export default withAuth(ProjectIssues); diff --git a/apps/app/pages/workspace/index.tsx b/apps/app/pages/workspace/index.tsx index db86a80ea..8138f3a3d 100644 --- a/apps/app/pages/workspace/index.tsx +++ b/apps/app/pages/workspace/index.tsx @@ -103,7 +103,9 @@ const Workspace: NextPage = () => { {issue.name} - {issue.sequence_id} + + {issue.project_detail?.identifier}-{issue.sequence_id} + { + return ( + +
+ + {label} + +
+ + + +
{children}
+
+
+
+ ); +}; + +const MenuItem: React.FC = ({ children, renderAs, href, onClick }) => { + return ( + + {({ active }) => + renderAs === "a" ? ( + + + {children} + + + ) : ( + + ) + } + + ); +}; + +CustomMenu.MenuItem = MenuItem; + +export default CustomMenu; diff --git a/apps/app/ui/CustomMenu/types.d.ts b/apps/app/ui/CustomMenu/types.d.ts new file mode 100644 index 000000000..e8ccfc517 --- /dev/null +++ b/apps/app/ui/CustomMenu/types.d.ts @@ -0,0 +1,11 @@ +export type Props = { + children: React.ReactNode; + label: string; +}; + +export type MenuItemProps = { + children: string; + renderAs?: "button" | "a"; + href?: string; + onClick?: () => void; +}; diff --git a/apps/app/ui/index.ts b/apps/app/ui/index.ts index c5096b403..96c097668 100644 --- a/apps/app/ui/index.ts +++ b/apps/app/ui/index.ts @@ -3,6 +3,7 @@ export { default as Input } from "./Input"; export { default as Select } from "./Select"; export { default as TextArea } from "./TextArea"; export { default as CustomListbox } from "./CustomListbox"; +export { default as CustomMenu } from "./CustomMenu"; export { default as Spinner } from "./Spinner"; export { default as Tooltip } from "./Tooltip"; export { default as SearchListbox } from "./SearchListbox"; diff --git a/yarn.lock b/yarn.lock index 25d004aa9..b818694b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -77,187 +77,6 @@ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== -"@lexical/clipboard@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/clipboard/-/clipboard-0.5.0.tgz#3d835289c0e1543a13a5fd032294aa2614e4373a" - integrity sha512-JFvdH4N/80GxC0jhaiO/fdUOeYcX8pMFrcrpBDeNIcBN/9eF8Rn/czvoPLLNB9Kcbz8d8XXqabKEGCz2hFL//w== - dependencies: - "@lexical/html" "0.5.0" - "@lexical/list" "0.5.0" - "@lexical/selection" "0.5.0" - "@lexical/utils" "0.5.0" - -"@lexical/code@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/code/-/code-0.5.0.tgz#05c92e3b077af3148a494b44f5663dea14f7631f" - integrity sha512-GmqRaQ8EBtlu13ObSZYiGDzIsrkwRyyqI2HRVBrPo2iszLBpby+7uIncAVQVkxt1JNYOKE2n4JfxK8TSYyMtYQ== - dependencies: - "@lexical/utils" "0.5.0" - prismjs "^1.27.0" - -"@lexical/dragon@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/dragon/-/dragon-0.5.0.tgz#54ec8812e3fb907af5913c5d0436b8d28fa4efe8" - integrity sha512-Gf0jN8hjlF8E71wAsvbRpR1u9oS6RUjUw3VWp/Qa+IrtjBFFVzdTUloUs3cjMX9E/MFRJgt3wPsaKx2IuLBWQw== - -"@lexical/hashtag@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/hashtag/-/hashtag-0.5.0.tgz#dfe39ea73d1c4658c724419ef1113e27fb75a7f3" - integrity sha512-3MT72y72BmK4q7Rtb9gP3n83UL4vWC078T9io4zyPxKEI1Mh3UAVuRwh6Ypn0FeH94XvmuZAGVdoOC/nTd1now== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/history@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/history/-/history-0.5.0.tgz#5a13077e012f27f783beadca1c3fe545a2968f20" - integrity sha512-DCQgh1aQ1KS5JVYPU6GYr52BN0MQqmoXfFtf5uYCX9CbSAC0hDSK8ZPqwFW7jINqe6GwXxy7bo32j7E0A5023A== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/html@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/html/-/html-0.5.0.tgz#5eb2ccb9ffb7c24fff097db369d81431d7a98833" - integrity sha512-uJAof6gXTLOH9JnmPJ+wxILFtu7I/eCebFyVMjV53sqaeLsQ3pDfBTUe4RO+NciC+XBQ1WVpZgCM8Yx5c5cMmQ== - dependencies: - "@lexical/selection" "0.5.0" - -"@lexical/link@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.5.0.tgz#fa5f3baa1122eb2a1be12ac7a30977eb4c557e1e" - integrity sha512-XB8e+UPI9jeqsi7+Wr0n9SToljiS+gZmJ5gXANtR6lSZPtpcSUPs1iJZU2A2dNKXdvsZwSPCFdPL6ogFaaRvvQ== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/link@^0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.6.3.tgz#e09b670e69be7ea4509654aacec87e74b834d84f" - integrity sha512-duP+8OYEsIJ5AZLO5Y/cND+oNajvlc0geggmzrJ/XRcFiQAWXJ9BsmEeg6KZFzl2+Whkz3Zdkfu/1h80qllktA== - dependencies: - "@lexical/utils" "0.6.3" - -"@lexical/list@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.5.0.tgz#6ab4e1789d037af43f3d01012d2533c7c94daf15" - integrity sha512-TYXe4FtNL7Lk3XDEhPyUbT0Pb1TU58qZywGCdrtuRjPnF4oDvRXgg9EhYWfHzYwdsyhNgaHId+Fq41CjrwTMYg== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/list@0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.6.3.tgz#6389d051549860b53b93f53d537e116150ba20c7" - integrity sha512-zrQwX9J9hmLRjh4VkDykiv4P7et86ez85wAcvcoZNSwRGdLRMDxJLOyzJI6njr3CrebEKzHWVCsEcpn5T8bZcw== - dependencies: - "@lexical/utils" "0.6.3" - -"@lexical/mark@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/mark/-/mark-0.5.0.tgz#59c2a2a9f0ecfa063d48ce6f4a50e6d8bc6fcae1" - integrity sha512-leeqegWD4hqUdfYNsxB5iwsWozX2oc6mnJzcJfR4UB3Ksr0zH2xHc/z3Zp+CTeGuK5Tzppq5yGS+4cQ5xNpVgQ== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/markdown@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.5.0.tgz#3424a98e8600bc719f99bb4ab2484f0cf0e3c0f7" - integrity sha512-02RLx7PdVzvYxvx65FTbXkW6KcjQZ1waAaMDNKdtBV9r9Mv2Y2XunCUjErYHQ1JN9JkGGv0+JuliRT7qZTsF+Q== - dependencies: - "@lexical/code" "0.5.0" - "@lexical/link" "0.5.0" - "@lexical/list" "0.5.0" - "@lexical/rich-text" "0.5.0" - "@lexical/text" "0.5.0" - "@lexical/utils" "0.5.0" - -"@lexical/offset@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/offset/-/offset-0.5.0.tgz#445aae1c74198dd4ed7d59669735925621139e0a" - integrity sha512-ie4AFbvtt0CFBqaMcb0/gUuhoTt+YwbFXPFo1hW+oDVpmo3rJsEJKVsHhftBvHIP+/G5QlgPIhVmnlcSvEteTw== - -"@lexical/overflow@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/overflow/-/overflow-0.5.0.tgz#70daabdb96a3de9bf2f052ab2e38917aaf6e3b18" - integrity sha512-N+BQvgODU9lS7VK4FlxIRhGeASwsxfdkECtZ5iomHfqqNEI0WPLHbCTCkwS10rjfH1NrkXC314Y0SG2F7Ncv9Q== - -"@lexical/plain-text@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/plain-text/-/plain-text-0.5.0.tgz#385ac7c67b34116578e45fe34cca41e9f62cbcad" - integrity sha512-t1rnVnSXbPs9jLN/36/xZLNAlF9jwv8rSh6GHsjRIYiWX/MovNmgPmhNq/nkc+gRFZ2FKTFjdz3UeAUF4xQZMw== - -"@lexical/react@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/react/-/react-0.5.0.tgz#f227dd71f95e49bf817d648b9ffd5a31850876bc" - integrity sha512-bba0KXslxjf6M8XXJhx1rsrq9UV/6eo73WCZel2K+tGz8NEn1HCRTebQoebmRikzEQatEa3SoB6R47drMlk7Yw== - dependencies: - "@lexical/clipboard" "0.5.0" - "@lexical/code" "0.5.0" - "@lexical/dragon" "0.5.0" - "@lexical/hashtag" "0.5.0" - "@lexical/history" "0.5.0" - "@lexical/link" "0.5.0" - "@lexical/list" "0.5.0" - "@lexical/mark" "0.5.0" - "@lexical/markdown" "0.5.0" - "@lexical/overflow" "0.5.0" - "@lexical/plain-text" "0.5.0" - "@lexical/rich-text" "0.5.0" - "@lexical/selection" "0.5.0" - "@lexical/table" "0.5.0" - "@lexical/text" "0.5.0" - "@lexical/utils" "0.5.0" - "@lexical/yjs" "0.5.0" - -"@lexical/rich-text@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/rich-text/-/rich-text-0.5.0.tgz#9b7ddacdd74a49761f15486ed2846c5117a55d14" - integrity sha512-JhgMn70K410j3T/2WefPpEswZ+hWF3aJMNu7zkrCf2wB+KdrrGYoeNSZUzg2r4e6BuJgS117KlD99+MDnokCuw== - -"@lexical/selection@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/selection/-/selection-0.5.0.tgz#fe94f06fb17d9f5848921a0bbce10774398d3486" - integrity sha512-6I5qlqkYDIbDZPGwSOuvpWQUrqMY6URaKwrWsijQZMnNNKscGpC7IKb7sSDKn6YkLm7tuqig3hf2p+6hshkyWg== - -"@lexical/table@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.5.0.tgz#cf33fac7c2e0b520ab4747f9322cce434d117cb6" - integrity sha512-VNHWSsTFDSHNzLdQOR9qgKx4tvTuiDz6w0GfwBnMP4Ro2iKKtNowmZO4wDEZtVlUHvLMuOGuYqipOtKEDKbD4w== - dependencies: - "@lexical/utils" "0.5.0" - -"@lexical/table@0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.6.3.tgz#10eb7f1edd0269da18352145854ba0fc41d709f1" - integrity sha512-7ces57Y9wBwr2UXccXguyFC87QF6epdp2EZybb8yVEoWvMM5z51CnWELEbADYv5lnevPS2LC8LtJV3v1iSPZbA== - dependencies: - "@lexical/utils" "0.6.3" - -"@lexical/text@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/text/-/text-0.5.0.tgz#803e34d9b1e2430e8062d2db50c7452d4e03c86e" - integrity sha512-RqhOBU2Ecg0WVW8p1d3OB2a8sQyvh3suADdr7We50+Dn/k1M+jhKVWiQnf07ve4/yqYTj6/9/8AAg7kuNS2P/A== - -"@lexical/utils@0.5.0", "@lexical/utils@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.5.0.tgz#4f03e8090e65cde5e81801ab08a2450e2e03733a" - integrity sha512-FhQ+thPFTOyBxyRGcd3yJuYh/rvD8ro43DaelWD1KpSlwQ/YuWpdxsSuMqJ32ERpl+bmPPFP2kjkBofxSw1Quw== - dependencies: - "@lexical/list" "0.5.0" - "@lexical/table" "0.5.0" - -"@lexical/utils@0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.6.3.tgz#85276f9ef095d23634cb3f2d059f5781cee656ec" - integrity sha512-LijfKzH9Fdl30eZ/fWDigLsRPs/rz8sZAnRg6UsJGKR1SS3PeWLoO4RRWhnNzpMypVX8UdvbKv1DxMjQn3d/kw== - dependencies: - "@lexical/list" "0.6.3" - "@lexical/table" "0.6.3" - -"@lexical/yjs@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@lexical/yjs/-/yjs-0.5.0.tgz#a6a6e12f5eceaa5a37ae7999b97ba8ce217987b6" - integrity sha512-2io4GqnRoSh6Nu9bzsDOlwPFJYjXZ9SdgU4ZioH2VvyW4wVstd+ZF2QVcUJlhuwgQr6DzuvM/pqN914IufLzpw== - dependencies: - "@lexical/offset" "0.5.0" - "@next/env@12.2.2": version "12.2.2" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.2.2.tgz#cc1a0a445bd254499e30f632968c03192455f4cc" @@ -2094,11 +1913,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prismjs@^1.27.0: - version "1.29.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" - integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== - prop-types@^15.5.10, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" From 945a75e18b489e6b5a1224beb3d0112eaa6eb346 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Sat, 3 Dec 2022 19:11:07 +0530 Subject: [PATCH 2/6] feat: lexical integrated --- .../command-palette/addAsSubIssue.tsx | 214 +++++++++--------- apps/app/components/lexical/viewer.tsx | 10 +- .../CreateUpdateIssueModal/SelectAssignee.tsx | 2 +- .../CreateUpdateIssueModal/SelectCycles.tsx | 2 +- .../CreateUpdateIssueModal/SelectLabels.tsx | 2 +- .../SelectParentIssue.tsx | 47 ++++ .../SelectParentIssues.tsx | 66 ------ .../CreateUpdateIssueModal/SelectPriority.tsx | 6 +- .../issues/CreateUpdateIssueModal/index.tsx | 65 +++++- .../project/issues/IssuesListModal.tsx | 134 +++++++++++ .../project/issues/ListView/index.tsx | 15 +- .../issues/issue-detail/activity/index.tsx | 22 +- .../projects/[projectId]/issues/[issueId].tsx | 46 ++-- .../pages/projects/[projectId]/members.tsx | 2 +- apps/app/pages/workspace/members.tsx | 4 +- apps/app/ui/CustomListbox/index.tsx | 2 +- apps/app/ui/CustomListbox/types.d.ts | 2 +- apps/app/ui/SearchListbox/index.tsx | 16 +- 18 files changed, 417 insertions(+), 240 deletions(-) create mode 100644 apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssue.tsx delete mode 100644 apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssues.tsx create mode 100644 apps/app/components/project/issues/IssuesListModal.tsx diff --git a/apps/app/components/command-palette/addAsSubIssue.tsx b/apps/app/components/command-palette/addAsSubIssue.tsx index 41c3e3d28..11cfcc907 100644 --- a/apps/app/components/command-palette/addAsSubIssue.tsx +++ b/apps/app/components/command-palette/addAsSubIssue.tsx @@ -1,3 +1,4 @@ +// react import React, { useState } from "react"; // swr import { mutate } from "swr"; @@ -5,18 +6,18 @@ import { mutate } from "swr"; import { useForm } from "react-hook-form"; // headless ui import { Combobox, Dialog, Transition } from "@headlessui/react"; +// services +import issuesServices from "lib/services/issues.services"; // hooks import useUser from "lib/hooks/useUser"; // icons -import { MagnifyingGlassIcon } from "@heroicons/react/20/solid"; -import { FolderIcon } from "@heroicons/react/24/outline"; +import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; // commons import { classNames } from "constants/common"; // types import { IIssue, IssueResponse } from "types"; -import { Button } from "ui"; -import { PROJECT_ISSUES_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; -import issuesServices from "lib/services/issues.services"; +// constants +import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; type Props = { isOpen: boolean; @@ -41,18 +42,13 @@ const AddAsSubIssue: React.FC = ({ isOpen, setIsOpen, parentId }) => { []; const { - register, formState: { errors, isSubmitting }, - handleSubmit, - control, reset, - setError, } = useForm(); const handleCommandPaletteClose = () => { setIsOpen(false); setQuery(""); - reset(); }; const addAsSubIssue = (issueId: string) => { @@ -78,118 +74,112 @@ const AddAsSubIssue: React.FC = ({ isOpen, setIsOpen, parentId }) => { }; return ( - <> - setQuery("")} appear> - + setQuery("")} appear> + + +
+ + +
-
- + + +
+
-
- - - { - // const { url, onClick } = item; - // if (url) router.push(url); - // else if (onClick) onClick(); - // handleCommandPaletteClose(); - // }} + -
- 0 && ( + <> +
  • + {query === "" && ( +

    + Issues +

    + )} +
      + {filteredIssues.map((issue) => { + if ( + (issue.parent === "" || issue.parent === null) && + issue.id !== parentId + ) + return ( + + classNames( + "flex items-center gap-2 cursor-pointer select-none rounded-md px-3 py-2", + active ? "bg-gray-900 bg-opacity-5 text-gray-900" : "" + ) + } + onClick={() => { + addAsSubIssue(issue.id); + setIsOpen(false); + }} + > + + {issue.name} + + ); + })} +
    +
  • + + )} + + + {query !== "" && filteredIssues.length === 0 && ( +
    +
    - - - {filteredIssues.length > 0 && ( - <> -
  • - {query === "" && ( -

    - Issues -

    - )} -
      - {filteredIssues.map((issue) => { - if (issue.parent === "" || issue.parent === null) - return ( - - classNames( - "flex items-center gap-2 cursor-pointer select-none rounded-md px-3 py-2", - active ? "bg-gray-900 bg-opacity-5 text-gray-900" : "" - ) - } - onClick={() => { - addAsSubIssue(issue.id); - setIsOpen(false); - }} - > - - {issue.name} - - ); - })} -
    -
  • - - )} -
    - - {query !== "" && filteredIssues.length === 0 && ( -
    -
    - )} - - - -
    -
    -
    - + )} + + + +
    + + ); }; diff --git a/apps/app/components/lexical/viewer.tsx b/apps/app/components/lexical/viewer.tsx index 83be573c0..9ea988126 100644 --- a/apps/app/components/lexical/viewer.tsx +++ b/apps/app/components/lexical/viewer.tsx @@ -1,4 +1,3 @@ -import { FC } from "react"; import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; @@ -17,14 +16,11 @@ import { getValidatedValue } from "./helpers/editor"; import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary"; export interface RichTextViewerProps { - id: string; value: string; + id: string; } -const RichTextViewer: FC = (props) => { - // props - const { value, id } = props; - +const RichTextViewer: React.FC = ({ value, id }) => { return ( = (props) => {
    + } ErrorBoundary={LexicalErrorBoundary} placeholder={ diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx index bee25039f..376ab65e6 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx @@ -44,7 +44,7 @@ const SelectAssignee: React.FC = ({ control }) => { multiple={true} value={value} onChange={onChange} - icon={} + icon={} /> )} /> diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectCycles.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectCycles.tsx index 7987bff8d..6553c205a 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectCycles.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectCycles.tsx @@ -33,7 +33,7 @@ const SelectSprint: React.FC = ({ control, setIsOpen }) => { <>
    - + {cycles?.find((i) => i.id.toString() === value?.toString())?.name ?? "Cycle"} diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx index ede265c98..a7ef75203 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx @@ -83,7 +83,7 @@ const SelectLabels: React.FC = ({ control }) => { <>
    - + {value && value.length > 0 ? value.map((id) => issueLabels?.find((i) => i.id === id)?.name).join(", ") diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssue.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssue.tsx new file mode 100644 index 000000000..8a4b7af64 --- /dev/null +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssue.tsx @@ -0,0 +1,47 @@ +import React, { useState } from "react"; +// react hook form +import { Controller, Control } from "react-hook-form"; +// hooks +import useUser from "lib/hooks/useUser"; +// types +import type { IIssue } from "types"; +// icons +import { UserIcon } from "@heroicons/react/24/outline"; +// components +import IssuesListModal from "components/project/issues/IssuesListModal"; + +type Props = { + control: Control; +}; + +const SelectParent: React.FC = ({ control }) => { + const [isIssueListModalOpen, setIsIssueListModalOpen] = useState(false); + + const { issues } = useUser(); + + return ( + ( + <> + setIsIssueListModalOpen(false)} + onChange={onChange} + issues={issues} + /> + + + )} + /> + ); +}; + +export default SelectParent; diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssues.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssues.tsx deleted file mode 100644 index 83db0b895..000000000 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectParentIssues.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from "react"; -// react hook form -import { Controller } from "react-hook-form"; -// hooks -import useUser from "lib/hooks/useUser"; -// types -import type { IIssue } from "types"; -import type { Control } from "react-hook-form"; -import { UserIcon } from "@heroicons/react/24/outline"; - -type Props = { - control: Control; -}; - -import { SearchListbox } from "ui"; - -const SelectParent: React.FC = ({ control }) => { - const { issues: projectIssues } = useUser(); - - const getSelectedIssueKey = (issueId: string | undefined) => { - const identifier = projectIssues?.results?.find((i) => i.id.toString() === issueId?.toString()) - ?.project_detail?.identifier; - - const sequenceId = projectIssues?.results?.find( - (i) => i.id.toString() === issueId?.toString() - )?.sequence_id; - - if (issueId) return `${identifier}-${sequenceId}`; - else return "Parent issue"; - }; - - return ( - ( - { - return { - value: issue.id, - display: issue.name, - element: ( -
    -
    - {`${getSelectedIssueKey(issue.id)}`} - {issue.name} -
    -
    - ), - }; - })} - value={value} - width="xs" - buttonClassName="max-h-30 overflow-y-scroll" - optionsClassName="max-h-30 overflow-y-scroll" - onChange={onChange} - icon={} - /> - )} - /> - ); -}; - -export default SelectParent; diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectPriority.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectPriority.tsx index 2452908cd..b53dfe777 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectPriority.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectPriority.tsx @@ -28,8 +28,10 @@ const SelectPriority: React.FC = ({ control }) => { <>
    - - {value ?? "Priority"} + + + {value && value !== "" ? value : "Priority"} + = { + project: "", name: "", description: "", + state: "", + sprints: "", + priority: "", + labels_list: [], }; const CreateUpdateIssuesModal: React.FC = ({ @@ -65,6 +71,16 @@ const CreateUpdateIssuesModal: React.FC = ({ const [mostSimilarIssue, setMostSimilarIssue] = useState(); + // const [issueDescriptionValue, setIssueDescriptionValue] = useState(""); + // const handleDescriptionChange: any = (value: any) => { + // console.log(value); + // setIssueDescriptionValue(value); + // }; + + const RichTextEditor = dynamic(() => import("components/lexical/editor"), { + ssr: false, + }); + const router = useRouter(); const handleClose = () => { @@ -93,6 +109,7 @@ const CreateUpdateIssuesModal: React.FC = ({ setError, control, watch, + setValue, } = useForm({ defaultValues, }); @@ -159,6 +176,7 @@ const CreateUpdateIssuesModal: React.FC = ({ if (!activeWorkspace || !activeProject) return; const payload: Partial = { ...formData, + description: JSON.stringify(formData.description), target_date: formData.target_date ? renderDateFormat(formData.target_date ?? "") : null, }; if (!data) { @@ -261,6 +279,8 @@ const CreateUpdateIssuesModal: React.FC = ({ return () => setMostSimilarIssue(undefined); }, []); + // console.log(watch("parent")); + return ( <> {activeProject && ( @@ -373,13 +393,20 @@ const CreateUpdateIssuesModal: React.FC = ({ )}
    -