import React from "react"; import Link from "next/link"; import Image from "next/image"; import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // react-beautiful-dnd import { DraggableStateSnapshot } from "react-beautiful-dnd"; // headless ui import { Listbox, Transition } from "@headlessui/react"; // constants import { TrashIcon } from "@heroicons/react/24/outline"; // services import issuesService from "services/issues.service"; import stateService from "services/state.service"; import projectService from "services/project.service"; // components import { AssigneesList, CustomDatePicker } from "components/ui"; // helpers import { findHowManyDaysLeft } from "helpers/date-time.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper"; // types import { CycleIssueResponse, IIssue, IProjectMember, IssueResponse, IUserLite, ModuleIssueResponse, Properties, UserAuth, } from "types"; // common import { PRIORITIES } from "constants/"; import { STATE_LIST, PROJECT_DETAILS, CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST, } from "constants/fetch-keys"; import { getPriorityIcon } from "constants/global"; type Props = { type?: string; typeId?: string; issue: IIssue; properties: Properties; snapshot: DraggableStateSnapshot; assignees: Partial[] | (Partial | undefined)[]; people: IProjectMember[] | undefined; handleDeleteIssue: (issue: IIssue) => void; userAuth: UserAuth; }; export const SingleBoardIssue: React.FC = ({ type, typeId, issue, properties, snapshot, assignees, people, handleDeleteIssue, userAuth, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; const { data: states } = useSWR( workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); const partialUpdateIssue = (formData: Partial) => { if (!workspaceSlug || !projectId) return; if (typeId) { mutate( CYCLE_ISSUES(typeId ?? ""), (prevData) => { const updatedIssues = (prevData ?? []).map((p) => { if (p.issue_detail.id === issue.id) { return { ...p, issue_detail: { ...p.issue_detail, ...formData, }, }; } return p; }); return [...updatedIssues]; }, false ); mutate( MODULE_ISSUES(typeId ?? ""), (prevData) => { const updatedIssues = (prevData ?? []).map((p) => { if (p.issue_detail.id === issue.id) { return { ...p, issue_detail: { ...p.issue_detail, ...formData, }, }; } return p; }); return [...updatedIssues]; }, false ); } mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), (prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((p) => { if (p.id === issue.id) return { ...p, ...formData }; return p; }), }), false ); issuesService .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .then((res) => { if (typeId) { mutate(CYCLE_ISSUES(typeId ?? "")); mutate(MODULE_ISSUES(typeId ?? "")); } mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); }) .catch((error) => { console.log(error); }); }; const isNotAllowed = userAuth.isGuest || userAuth.isViewer; return (
{!isNotAllowed && (
)} {properties.key && (
{projectDetails?.identifier}-{issue.sequence_id}
)}
{issue.name}
{properties.priority && ( { partialUpdateIssue({ priority: data }); }} className="group relative flex-shrink-0" disabled={isNotAllowed} > {({ open }) => ( <>
{getPriorityIcon(issue?.priority ?? "None")} {PRIORITIES?.map((priority) => ( `flex cursor-pointer select-none items-center gap-2 px-3 py-2 capitalize ${ active ? "bg-indigo-50" : "bg-white" }` } value={priority} > {getPriorityIcon(priority)} {priority} ))}
)}
)} {properties.state && ( { partialUpdateIssue({ state: data }); }} className="group relative flex-shrink-0" disabled={isNotAllowed} > {({ open }) => ( <>
{addSpaceIfCamelCase(issue.state_detail.name)} {states?.map((state) => ( `flex cursor-pointer select-none items-center gap-2 px-3 py-2 ${ active ? "bg-indigo-50" : "bg-white" }` } value={state.id} > {addSpaceIfCamelCase(state.name)} ))}
)}
)} {/* {properties.cycle && !typeId && (
{issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
)} */} {properties.due_date && (
partialUpdateIssue({ target_date: val, }) } className={issue?.target_date ? "w-[6.5rem]" : "w-[3rem] text-center"} /> {/* { partialUpdateIssue({ target_date: val ? `${val.getFullYear()}-${val.getMonth() + 1}-${val.getDate()}` : null, }); }} dateFormat="dd-MM-yyyy" className={`cursor-pointer rounded-md border px-2 py-[3px] text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${ issue?.target_date ? "w-[4.5rem]" : "w-[3rem] text-center" }`} isClearable /> */}
)} {properties.sub_issue_count && (
{issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
)} {properties.assignee && ( { const newData = issue.assignees ?? []; if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); else newData.push(data); partialUpdateIssue({ assignees_list: newData }); }} className="group relative flex-shrink-0" disabled={isNotAllowed} > {({ open }) => (
{people?.map((person) => ( `cursor-pointer select-none p-2 ${active ? "bg-indigo-50" : "bg-white"}` } value={person.member.id} >
{person.member.avatar && person.member.avatar !== "" ? (
avatar
) : (
{person.member.first_name && person.member.first_name !== "" ? person.member.first_name.charAt(0) : person.member.email.charAt(0)}
)}

{person.member.first_name && person.member.first_name !== "" ? person.member.first_name : person.member.email}

))}
)}
)}
); };