import React, { useState } from "react"; // swr import useSWR from "swr"; // headless ui import { Listbox, Transition } from "@headlessui/react"; // react hook form import { useForm, Controller, UseFormWatch } from "react-hook-form"; // services import stateServices from "lib/services/state.service"; import issuesServices from "lib/services/issues.service"; import workspaceService from "lib/services/workspace.service"; // hooks import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; // components import IssuesListModal from "components/project/issues/IssuesListModal"; // fetching keys import { PROJECT_ISSUES_LIST, STATE_LIST, WORKSPACE_MEMBERS, PROJECT_ISSUE_LABELS, } from "constants/fetch-keys"; // commons import { classNames, copyTextToClipboard } from "constants/common"; import { PRIORITIES } from "constants/"; // ui import { Input, Button, Spinner } from "ui"; import { Popover } from "@headlessui/react"; // icons import { UserIcon, TagIcon, UserGroupIcon, ChevronDownIcon, Squares2X2Icon, ChartBarIcon, ClipboardDocumentIcon, LinkIcon, ArrowPathIcon, CalendarDaysIcon, TrashIcon, PlusIcon, XMarkIcon, } from "@heroicons/react/24/outline"; // types import type { Control } from "react-hook-form"; import type { IIssue, IIssueLabels, IssueResponse, IState, NestedKeyOf } from "types"; import { TwitterPicker } from "react-color"; import { positionEditorElement } from "components/lexical/helpers/editor"; type Props = { control: Control; submitChanges: (formData: Partial) => void; issueDetail: IIssue | undefined; watch: UseFormWatch; setDeleteIssueModal: React.Dispatch>; }; const defaultValues: Partial = { name: "", colour: "#ff0000", }; const IssueDetailSidebar: React.FC = ({ control, submitChanges, issueDetail, watch: watchIssue, setDeleteIssueModal, }) => { const [isBlockerModalOpen, setIsBlockerModalOpen] = useState(false); const [isBlockedModalOpen, setIsBlockedModalOpen] = useState(false); const [isParentModalOpen, setIsParentModalOpen] = useState(false); const [createLabelForm, setCreateLabelForm] = useState(false); const { activeWorkspace, activeProject, cycles, issues } = useUser(); const { setToastAlert } = useToast(); const { data: states } = useSWR( activeWorkspace && activeProject ? STATE_LIST(activeProject.id) : null, activeWorkspace && activeProject ? () => stateServices.getStates(activeWorkspace.slug, activeProject.id) : null ); const { data: people } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null ); const { data: issueLabels, mutate: issueLabelMutate } = useSWR( activeProject && activeWorkspace ? PROJECT_ISSUE_LABELS(activeProject.id) : null, activeProject && activeWorkspace ? () => issuesServices.getIssueLabels(activeWorkspace.slug, activeProject.id) : null ); const { register, handleSubmit, formState: { isSubmitting }, reset, watch, control: controlLabel, } = useForm({ defaultValues, }); const onSubmit = (formData: any) => { if (!activeWorkspace || !activeProject || isSubmitting) return; issuesServices .createIssueLabel(activeWorkspace.slug, activeProject.id, formData) .then((res) => { console.log(res); reset(defaultValues); issueLabelMutate((prevData) => [...(prevData ?? []), res], false); }); }; const sidebarSections: Array< Array<{ label: string; name: NestedKeyOf; canSelectMultipleOptions: boolean; icon: (props: any) => JSX.Element; options?: Array<{ label: string; value: any; color?: string }>; modal: boolean; issuesList?: Array; isOpen?: boolean; setIsOpen?: (arg: boolean) => void; }> > = [ [ { label: "Status", name: "state", canSelectMultipleOptions: false, icon: Squares2X2Icon, options: states?.map((state) => ({ label: state.name, value: state.id, color: state.color, })), modal: false, }, { label: "Assignees", name: "assignees_list", canSelectMultipleOptions: true, icon: UserGroupIcon, options: people?.map((person) => ({ label: person.member.first_name, value: person.member.id, })), modal: false, }, { label: "Priority", name: "priority", canSelectMultipleOptions: false, icon: ChartBarIcon, options: PRIORITIES.map((property) => ({ label: property, value: property, })), modal: false, }, ], [ { label: "Parent", name: "parent", canSelectMultipleOptions: false, icon: UserIcon, issuesList: issues?.results.filter( (i) => i.id !== issueDetail?.id && i.id !== issueDetail?.parent && i.parent !== issueDetail?.id ) ?? [], modal: true, isOpen: isParentModalOpen, setIsOpen: setIsParentModalOpen, }, // { // label: "Blocker", // name: "blockers_list", // canSelectMultipleOptions: true, // icon: UserIcon, // issuesList: issues?.results.filter((i) => i.id !== issueDetail?.id) ?? [], // modal: true, // isOpen: isBlockerModalOpen, // setIsOpen: setIsBlockerModalOpen, // }, // { // label: "Blocked", // name: "blocked_list", // canSelectMultipleOptions: true, // icon: UserIcon, // issuesList: issues?.results.filter((i) => i.id !== issueDetail?.id) ?? [], // modal: true, // isOpen: isBlockedModalOpen, // setIsOpen: setIsBlockedModalOpen, // }, { label: "Target Date", name: "target_date", canSelectMultipleOptions: true, icon: CalendarDaysIcon, modal: false, }, ], [ { label: "Cycle", name: "cycle", canSelectMultipleOptions: false, icon: ArrowPathIcon, options: cycles?.map((cycle) => ({ label: cycle.name, value: cycle.id, })), modal: false, }, ], ]; const handleCycleChange = (cycleId: string) => { if (activeWorkspace && activeProject && issueDetail) issuesServices.addIssueToCycle(activeWorkspace.slug, activeProject.id, cycleId, { issue: issueDetail.id, }); }; return ( <>

{activeProject?.identifier}-{issueDetail?.sequence_id}

{sidebarSections.map((section, index) => (
{section.map((item) => (

{item.label}

{item.name === "target_date" ? ( ( { submitChanges({ target_date: e.target.value }); onChange(e.target.value); }} className="hover:bg-gray-100 border rounded-md shadow-sm px-2 py-1 cursor-pointer focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-xs duration-300 w-full" /> )} /> ) : item.modal ? ( ( <> item.setIsOpen && item.setIsOpen(false)} onChange={(val) => { console.log(val); // submitChanges({ [item.name]: val }); onChange(val); }} issues={item?.issuesList ?? []} title={`Select ${item.label}`} multiple={item.canSelectMultipleOptions} value={value} /> )} /> ) : ( ( { if (item.name === "cycle") handleCycleChange(value); else submitChanges({ [item.name]: value }); }} className="flex-shrink-0" > {({ open }) => (
{value ? Array.isArray(value) ? value .map( (i: any) => item.options?.find((option) => option.value === i) ?.label ) .join(", ") || item.label : item.options?.find((option) => option.value === value) ?.label : "None"}
{item.options ? ( item.options.length > 0 ? ( item.options.map((option) => ( `${ active || selected ? "text-white bg-theme" : "text-gray-900" } ${ item.label === "Priority" && "capitalize" } flex items-center gap-2 cursor-pointer select-none relative p-2 rounded-md truncate` } value={option.value} > {option.color && ( )} {option.label} )) ) : (
No {item.label}s found
) ) : ( )}
)}
)} /> )}
))}
))}

Label

{issueDetail?.label_details.map((label) => ( // submitChanges({ // labels_list: issueDetail?.labels_list.filter((l) => l !== label.id), // }) // } > {label.name} ))} ( submitChanges({ labels_list: value })} className="flex-shrink-0" > {({ open }) => ( <> Label
Select Label
{issueLabels ? ( issueLabels.length > 0 ? ( issueLabels.map((label: IIssueLabels) => ( `${ active || selected ? "text-white bg-theme" : "text-gray-900" } flex items-center gap-2 cursor-pointer select-none relative p-2 rounded-md truncate` } value={label.id} > {label.name} )) ) : (
No labels found
) ) : ( )}
)}
)} />
{createLabelForm && (
{({ open }) => ( <> {watch("colour") && watch("colour") !== "" && ( )} ( onChange(value.hex)} /> )} /> )}
)}
); }; export default IssueDetailSidebar;