diff --git a/apps/app/components/account/email-code-form.tsx b/apps/app/components/account/email-code-form.tsx index 98ab10cb7..003d515f4 100644 --- a/apps/app/components/account/email-code-form.tsx +++ b/apps/app/components/account/email-code-form.tsx @@ -114,15 +114,15 @@ export const EmailCodeForm = ({ onSuccess }: any) => { error={errors.token} placeholder="Enter code" /> - {/* { - console.log("Triggered"); handleSubmit(onSubmit); }} > Resend code - */} + */} )}
diff --git a/apps/app/components/core/board-view/all-boards.tsx b/apps/app/components/core/board-view/all-boards.tsx index d4e995403..f5b03267c 100644 --- a/apps/app/components/core/board-view/all-boards.tsx +++ b/apps/app/components/core/board-view/all-boards.tsx @@ -11,9 +11,11 @@ type Props = { states: IState[] | undefined; members: IProjectMember[] | undefined; addIssueToState: (groupTitle: string, stateId: string | null) => void; + handleEditIssue: (issue: IIssue) => void; openIssuesListModal?: (() => void) | null; handleDeleteIssue: (issue: IIssue) => void; handleTrashBox: (isDragging: boolean) => void; + removeIssue: ((bridgeId: string) => void) | null; userAuth: UserAuth; }; @@ -23,9 +25,11 @@ export const AllBoards: React.FC = ({ states, members, addIssueToState, + handleEditIssue, openIssuesListModal, handleDeleteIssue, handleTrashBox, + removeIssue, userAuth, }) => { const { groupedByIssues, groupByProperty: selectedGroup, orderBy } = useIssueView(issues); @@ -57,11 +61,13 @@ export const AllBoards: React.FC = ({ groupedByIssues={groupedByIssues} selectedGroup={selectedGroup} members={members} + handleEditIssue={handleEditIssue} addIssueToState={() => addIssueToState(singleGroup, stateId)} handleDeleteIssue={handleDeleteIssue} openIssuesListModal={openIssuesListModal ?? null} orderBy={orderBy} handleTrashBox={handleTrashBox} + removeIssue={removeIssue} userAuth={userAuth} /> ); diff --git a/apps/app/components/core/board-view/single-board.tsx b/apps/app/components/core/board-view/single-board.tsx index e0e790da5..b9600a47c 100644 --- a/apps/app/components/core/board-view/single-board.tsx +++ b/apps/app/components/core/board-view/single-board.tsx @@ -25,11 +25,13 @@ type Props = { }; selectedGroup: NestedKeyOf | null; members: IProjectMember[] | undefined; + handleEditIssue: (issue: IIssue) => void; addIssueToState: () => void; handleDeleteIssue: (issue: IIssue) => void; openIssuesListModal?: (() => void) | null; orderBy: NestedKeyOf | "manual" | null; handleTrashBox: (isDragging: boolean) => void; + removeIssue: ((bridgeId: string) => void) | null; userAuth: UserAuth; }; @@ -40,11 +42,13 @@ export const SingleBoard: React.FC = ({ groupedByIssues, selectedGroup, members, + handleEditIssue, addIssueToState, handleDeleteIssue, openIssuesListModal, orderBy, handleTrashBox, + removeIssue, userAuth, }) => { // collapse/expand @@ -104,10 +108,15 @@ export const SingleBoard: React.FC = ({ snapshot={snapshot} type={type} issue={issue} + selectedGroup={selectedGroup} properties={properties} + editIssue={() => handleEditIssue(issue)} handleDeleteIssue={handleDeleteIssue} orderBy={orderBy} handleTrashBox={handleTrashBox} + removeIssue={() => { + removeIssue && removeIssue(issue.bridge); + }} userAuth={userAuth} /> )} diff --git a/apps/app/components/core/board-view/single-issue.tsx b/apps/app/components/core/board-view/single-issue.tsx index 945592788..a19c683e2 100644 --- a/apps/app/components/core/board-view/single-issue.tsx +++ b/apps/app/components/core/board-view/single-issue.tsx @@ -23,6 +23,8 @@ import { ViewPrioritySelect, ViewStateSelect, } from "components/issues/view-select"; +// ui +import { CustomMenu } from "components/ui"; // types import { CycleIssueResponse, @@ -41,7 +43,10 @@ type Props = { provided: DraggableProvided; snapshot: DraggableStateSnapshot; issue: IIssue; + selectedGroup: NestedKeyOf | null; properties: Properties; + editIssue: () => void; + removeIssue?: (() => void) | null; handleDeleteIssue: (issue: IIssue) => void; orderBy: NestedKeyOf | "manual" | null; handleTrashBox: (isDragging: boolean) => void; @@ -53,7 +58,10 @@ export const SingleBoardIssue: React.FC = ({ provided, snapshot, issue, + selectedGroup, properties, + editIssue, + removeIssue, handleDeleteIssue, orderBy, handleTrashBox, @@ -170,13 +178,26 @@ export const SingleBoardIssue: React.FC = ({
{!isNotAllowed && (
- + */} + {type && !isNotAllowed && ( + + Edit + {type !== "issue" && removeIssue && ( + + <>Remove from {type} + + )} + handleDeleteIssue(issue)}> + Delete permanently + + + )}
)} @@ -195,7 +216,7 @@ export const SingleBoardIssue: React.FC = ({
- {properties.priority && ( + {properties.priority && selectedGroup !== "priority" && ( = ({ position="left" /> )} - {properties.state && ( + {properties.state && selectedGroup !== "state_detail.name" && ( = ({ issues }) => {

Display Properties

- {Object.keys(properties).map((key) => ( - - ))} + {Object.keys(properties).map((key) => { + if ( + issueView === "kanban" && + ((groupByProperty === "state_detail.name" && key === "state") || + (groupByProperty === "priority" && key === "priority")) + ) + return; + + return ( + + ); + })}
diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index 2edb7f804..b3278ec3e 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -452,9 +452,17 @@ export const IssuesView: React.FC = ({ states={states} members={members} addIssueToState={addIssueToState} + handleEditIssue={handleEditIssue} openIssuesListModal={type !== "issue" ? openIssuesListModal : null} handleDeleteIssue={handleDeleteIssue} handleTrashBox={handleTrashBox} + removeIssue={ + type === "cycle" + ? removeIssueFromCycle + : type === "module" + ? removeIssueFromModule + : null + } userAuth={userAuth} /> )} diff --git a/apps/app/components/core/sidebar/sidebar-progress-stats.tsx b/apps/app/components/core/sidebar/sidebar-progress-stats.tsx index ea8e1e401..8fb073f54 100644 --- a/apps/app/components/core/sidebar/sidebar-progress-stats.tsx +++ b/apps/app/components/core/sidebar/sidebar-progress-stats.tsx @@ -10,6 +10,8 @@ import { Tab } from "@headlessui/react"; // services import issuesServices from "services/issues.service"; import projectService from "services/project.service"; +// hooks +import useLocalStorage from "hooks/use-local-storage"; // components import { SingleProgressStats } from "components/core"; // ui @@ -20,7 +22,6 @@ import User from "public/user.png"; import { IIssue, IIssueLabels } from "types"; // fetch-keys import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys"; -import useLocalStorage from "hooks/use-local-storage"; // types type Props = { groupedIssues: any; @@ -39,8 +40,10 @@ const stateGroupColours: { export const SidebarProgressStats: React.FC = ({ groupedIssues, issues }) => { const router = useRouter(); - const [tab, setTab] = useLocalStorage("tab", "Assignees"); const { workspaceSlug, projectId } = router.query; + + const [tab, setTab] = useLocalStorage("tab", "Assignees"); + const { data: issueLabels } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, workspaceSlug && projectId diff --git a/apps/app/components/issues/form.tsx b/apps/app/components/issues/form.tsx index 5e034822a..3194481b6 100644 --- a/apps/app/components/issues/form.tsx +++ b/apps/app/components/issues/form.tsx @@ -16,8 +16,9 @@ import { IssueStateSelect, } from "components/issues/select"; import { CycleSelect as IssueCycleSelect } from "components/cycles/select"; -import { CreateUpdateStateModal } from "components/states"; +import { CreateStateModal } from "components/states"; import CreateUpdateCycleModal from "components/project/cycles/create-update-cycle-modal"; +import { CreateLabelModal } from "components/labels"; // ui import { Button, CustomDatePicker, CustomMenu, Input, Loader } from "components/ui"; // icons @@ -74,6 +75,7 @@ export const IssueForm: FC = ({ const [mostSimilarIssue, setMostSimilarIssue] = useState(); const [cycleModal, setCycleModal] = useState(false); const [stateModal, setStateModal] = useState(false); + const [labelModal, setLabelModal] = useState(false); const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false); const router = useRouter(); @@ -121,7 +123,7 @@ export const IssueForm: FC = ({ <> {projectId && ( <> - setStateModal(false)} projectId={projectId} @@ -131,6 +133,11 @@ export const IssueForm: FC = ({ setIsOpen={setCycleModal} projectId={projectId} /> + setLabelModal(false)} + projectId={projectId} + /> )}
@@ -281,7 +288,12 @@ export const IssueForm: FC = ({ control={control} name="labels_list" render={({ field: { value, onChange } }) => ( - + )} />
diff --git a/apps/app/components/issues/select/label.tsx b/apps/app/components/issues/select/label.tsx index 2d4e5a179..f0a1d2d64 100644 --- a/apps/app/components/issues/select/label.tsx +++ b/apps/app/components/issues/select/label.tsx @@ -1,15 +1,13 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; -// react-hook-form -import { useForm } from "react-hook-form"; // headless ui import { Combobox, Transition } from "@headlessui/react"; // icons -import { RectangleGroupIcon, TagIcon } from "@heroicons/react/24/outline"; +import { PlusIcon, RectangleGroupIcon, TagIcon } from "@heroicons/react/24/outline"; // services import issuesServices from "services/issues.service"; // types @@ -18,55 +16,26 @@ import type { IIssueLabels } from "types"; import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; type Props = { + setIsOpen: React.Dispatch>; value: string[]; onChange: (value: string[]) => void; projectId: string; }; -const defaultValues: Partial = { - name: "", -}; - -export const IssueLabelSelect: React.FC = ({ value, onChange, projectId }) => { +export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, projectId }) => { // states const [query, setQuery] = useState(""); const router = useRouter(); const { workspaceSlug } = router.query; - const [isOpen, setIsOpen] = useState(false); - - const { data: issueLabels, mutate: issueLabelsMutate } = useSWR( + const { data: issueLabels } = useSWR( projectId ? PROJECT_ISSUE_LABELS(projectId) : null, workspaceSlug && projectId ? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId) : null ); - const onSubmit = async (data: IIssueLabels) => { - if (!projectId || !workspaceSlug || isSubmitting) return; - await issuesServices - .createIssueLabel(workspaceSlug as string, projectId as string, data) - .then((response) => { - issueLabelsMutate((prevData) => [...(prevData ?? []), response], false); - setIsOpen(false); - reset(defaultValues); - }) - .catch((error) => { - console.log(error); - }); - }; - - const { - formState: { isSubmitting }, - setFocus, - reset, - } = useForm({ defaultValues }); - - useEffect(() => { - isOpen && setFocus("name"); - }, [isOpen, setFocus]); - const filteredOptions = query === "" ? issueLabels @@ -175,48 +144,14 @@ export const IssueLabelSelect: React.FC = ({ value, onChange, projectId } ) : (

Loading...

)} - {/*
- {isOpen ? ( -
- - - -
- ) : ( - - )} -
*/} +
diff --git a/apps/app/components/labels/create-label-modal.tsx b/apps/app/components/labels/create-label-modal.tsx new file mode 100644 index 000000000..89c286012 --- /dev/null +++ b/apps/app/components/labels/create-label-modal.tsx @@ -0,0 +1,189 @@ +import React, { useEffect } from "react"; + +import { useRouter } from "next/router"; + +import { mutate } from "swr"; + +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// react-color +import { TwitterPicker } from "react-color"; +// headless ui +import { Dialog, Popover, Transition } from "@headlessui/react"; +// services +import issuesService from "services/issues.service"; +// ui +import { Button, Input } from "components/ui"; +// icons +import { ChevronDownIcon } from "@heroicons/react/24/outline"; +// types +import type { IIssueLabels, IState } from "types"; +// constants +import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; + +// types +type Props = { + isOpen: boolean; + projectId: string; + handleClose: () => void; +}; + +const defaultValues: Partial = { + name: "", + color: "#000000", +}; + +export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClose }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { + register, + formState: { errors, isSubmitting }, + handleSubmit, + watch, + control, + reset, + setError, + } = useForm({ + defaultValues, + }); + + const onClose = () => { + handleClose(); + reset(defaultValues); + }; + + const onSubmit = async (formData: IIssueLabels) => { + if (!workspaceSlug) return; + + await issuesService + .createIssueLabel(workspaceSlug as string, projectId as string, formData) + .then((res) => { + mutate( + PROJECT_ISSUE_LABELS(projectId), + (prevData) => [res, ...(prevData ?? [])], + false + ); + onClose(); + }) + .catch((error) => { + console.log(error); + }); + }; + + return ( + + + +
+ + +
+
+ + + +
+ + Create Label + +
+ + {({ open }) => ( + <> + + Color + {watch("color") && watch("color") !== "" && ( + + )} + + + + + ( + onChange(value.hex)} + /> + )} + /> + + + + )} + + +
+
+
+ + +
+ +
+
+
+
+
+
+ ); +}; diff --git a/apps/app/components/labels/index.ts b/apps/app/components/labels/index.ts index d407cd074..db02d29f0 100644 --- a/apps/app/components/labels/index.ts +++ b/apps/app/components/labels/index.ts @@ -1,3 +1,4 @@ +export * from "./create-label-modal"; export * from "./create-update-label-inline"; export * from "./labels-list-modal"; export * from "./single-label-group"; diff --git a/apps/app/components/modules/delete-module-modal.tsx b/apps/app/components/modules/delete-module-modal.tsx index 317f49a68..05ed67089 100644 --- a/apps/app/components/modules/delete-module-modal.tsx +++ b/apps/app/components/modules/delete-module-modal.tsx @@ -65,10 +65,6 @@ export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data }) }); }; - useEffect(() => { - data && setIsOpen(true); - }, [data, setIsOpen]); - return ( void; }; -export const ModuleDetailsSidebar: React.FC = ({ - issues, - module, - isOpen, - moduleIssues, - handleDeleteModule, -}) => { +export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, moduleIssues }) => { + const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false); const router = useRouter(); @@ -127,6 +122,11 @@ export const ModuleDetailsSidebar: React.FC = ({ handleClose={() => setModuleLinkModal(false)} module={module} /> +
= ({ diff --git a/apps/app/components/modules/single-module-card.tsx b/apps/app/components/modules/single-module-card.tsx index ed0d027b5..a53fc4353 100644 --- a/apps/app/components/modules/single-module-card.tsx +++ b/apps/app/components/modules/single-module-card.tsx @@ -1,7 +1,6 @@ import React, { useState } from "react"; import Link from "next/link"; -import Image from "next/image"; import { useRouter } from "next/router"; // components @@ -13,7 +12,7 @@ import { CalendarDaysIcon, TrashIcon } from "@heroicons/react/24/outline"; // helpers import { renderShortNumericDateFormat } from "helpers/date-time.helper"; // types -import { IModule, SelectModuleType } from "types"; +import { IModule } from "types"; // common import { MODULE_STATUS } from "constants/module"; @@ -23,7 +22,6 @@ type Props = { export const SingleModuleCard: React.FC = ({ module }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); - const [selectedModuleForDelete, setSelectedModuleForDelete] = useState(); const router = useRouter(); const { workspaceSlug } = router.query; @@ -31,23 +29,18 @@ export const SingleModuleCard: React.FC = ({ module }) => { const handleDeleteModule = () => { if (!module) return; - setSelectedModuleForDelete({ ...module, actionType: "delete" }); setModuleDeleteModal(true); }; return ( <>
-
+