fix: fields not getting selected in the create issue form (#2212)

* fix: hydration error and draft issue workflow

* fix: build error

* fix: properties getting de-selected after create, module & cycle not getting auto-select on the form

* fix: display layout, props being updated directly
This commit is contained in:
Dakshesh Jain 2023-09-20 13:06:51 +05:30 committed by GitHub
parent e01a0d20fe
commit cdfff12f4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 284 additions and 110 deletions

View File

@ -1,4 +1,4 @@
import { useCallback, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -87,8 +87,16 @@ export const IssuesView: React.FC<Props> = ({
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } = const {
useIssuesView(); groupedByIssues,
mutateIssues,
displayFilters,
filters,
isEmpty,
setFilters,
params,
setDisplayFilters,
} = useIssuesView();
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string); const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
const { data: stateGroups } = useSWR( const { data: stateGroups } = useSWR(
@ -108,6 +116,17 @@ export const IssuesView: React.FC<Props> = ({
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString()); const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
useEffect(() => {
if (!isDraftIssues) return;
if (
displayFilters.layout === "calendar" ||
displayFilters.layout === "gantt_chart" ||
displayFilters.layout === "spreadsheet"
)
setDisplayFilters({ layout: "list" });
}, [isDraftIssues, displayFilters, setDisplayFilters]);
const handleDeleteIssue = useCallback( const handleDeleteIssue = useCallback(
(issue: IIssue) => { (issue: IIssue) => {
setDeleteIssueModal(true); setDeleteIssueModal(true);

View File

@ -57,7 +57,7 @@ export const ConfirmIssueDiscard: React.FC<Props> = (props) => {
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-custom-border-200 bg-custom-background-100 text-left shadow-xl transition-all sm:my-8 sm:w-[40rem]"> <Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-custom-border-200 bg-custom-background-100 text-left shadow-xl transition-all sm:my-8 sm:w-[40rem]">
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start"> <div className="sm:flex sm:items-start">
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> <div className="mt-3 text-center sm:mt-0 sm:text-left">
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-medium leading-6 text-custom-text-100" className="text-lg font-medium leading-6 text-custom-text-100"

View File

@ -55,7 +55,10 @@ const defaultValues: Partial<IIssue> = {
}; };
interface IssueFormProps { interface IssueFormProps {
handleFormSubmit: (formData: Partial<IIssue>) => Promise<void>; handleFormSubmit: (
formData: Partial<IIssue>,
action?: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue"
) => Promise<void>;
data?: Partial<IIssue> | null; data?: Partial<IIssue> | null;
prePopulatedData?: Partial<IIssue> | null; prePopulatedData?: Partial<IIssue> | null;
projectId: string; projectId: string;
@ -134,12 +137,16 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
const handleCreateUpdateIssue = async ( const handleCreateUpdateIssue = async (
formData: Partial<IIssue>, formData: Partial<IIssue>,
action: "saveDraft" | "createToNewIssue" = "saveDraft" action: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" = "createDraft"
) => { ) => {
await handleFormSubmit({ await handleFormSubmit(
...formData, {
is_draft: action === "saveDraft", ...(data ?? {}),
}); ...formData,
is_draft: action === "createDraft" || action === "updateDraft",
},
action
);
setGptAssistantModal(false); setGptAssistantModal(false);
@ -263,7 +270,9 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
</> </>
)} )}
<form <form
onSubmit={handleSubmit((formData) => handleCreateUpdateIssue(formData, "createToNewIssue"))} onSubmit={handleSubmit((formData) =>
handleCreateUpdateIssue(formData, "convertToNewIssue")
)}
> >
<div className="space-y-5"> <div className="space-y-5">
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
@ -563,15 +572,20 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
<SecondaryButton onClick={onClose}>Discard</SecondaryButton> <SecondaryButton onClick={onClose}>Discard</SecondaryButton>
<SecondaryButton <SecondaryButton
loading={isSubmitting} loading={isSubmitting}
onClick={handleSubmit((formData) => handleCreateUpdateIssue(formData, "saveDraft"))} onClick={handleSubmit((formData) =>
handleCreateUpdateIssue(formData, data?.id ? "updateDraft" : "createDraft")
)}
> >
{isSubmitting ? "Saving..." : "Save Draft"} {isSubmitting ? "Saving..." : "Save Draft"}
</SecondaryButton> </SecondaryButton>
{data && ( <PrimaryButton
<PrimaryButton type="submit" loading={isSubmitting}> loading={isSubmitting}
{isSubmitting ? "Saving..." : "Add Issue"} onClick={handleSubmit((formData) =>
</PrimaryButton> handleCreateUpdateIssue(formData, data ? "convertToNewIssue" : "createNewIssue")
)} )}
>
{isSubmitting ? "Saving..." : "Add Issue"}
</PrimaryButton>
</div> </div>
</div> </div>
</form> </form>

View File

@ -31,7 +31,10 @@ import {
MODULE_ISSUES_WITH_PARAMS, MODULE_ISSUES_WITH_PARAMS,
VIEW_ISSUES, VIEW_ISSUES,
PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS, PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS,
CYCLE_DETAILS,
MODULE_DETAILS,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
import modulesService from "services/modules.service";
interface IssuesModalProps { interface IssuesModalProps {
data?: IIssue | null; data?: IIssue | null;
@ -56,18 +59,21 @@ interface IssuesModalProps {
onSubmit?: (data: Partial<IIssue>) => Promise<void> | void; onSubmit?: (data: Partial<IIssue>) => Promise<void> | void;
} }
export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) => {
data, const {
handleClose, data,
isOpen, handleClose,
isUpdatingSingleIssue = false, isOpen,
prePopulateData, isUpdatingSingleIssue = false,
fieldsToShow = ["all"], prePopulateData: prePopulateDataProps,
onSubmit, fieldsToShow = ["all"],
}) => { onSubmit,
} = props;
// states // states
const [createMore, setCreateMore] = useState(false); const [createMore, setCreateMore] = useState(false);
const [activeProject, setActiveProject] = useState<string | null>(null); const [activeProject, setActiveProject] = useState<string | null>(null);
const [prePopulateData, setPreloadedData] = useState<Partial<IIssue> | undefined>(undefined);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
@ -86,19 +92,40 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string };
if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string };
if (router.asPath.includes("my-issues") || router.asPath.includes("assigned"))
prePopulateData = {
...prePopulateData,
assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""],
};
const onClose = () => { const onClose = () => {
handleClose(); handleClose();
setActiveProject(null); setActiveProject(null);
}; };
useEffect(() => {
setPreloadedData(prePopulateDataProps ?? {});
if (cycleId && !prePopulateDataProps?.cycle) {
setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
cycle: cycleId.toString(),
}));
}
if (moduleId && !prePopulateDataProps?.module) {
setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
module: moduleId.toString(),
}));
}
if (
(router.asPath.includes("my-issues") || router.asPath.includes("assigned")) &&
!prePopulateDataProps?.assignees
) {
setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
assignees: prePopulateDataProps?.assignees ?? [user?.id ?? ""],
}));
}
}, [prePopulateDataProps, cycleId, moduleId, router.asPath, user?.id]);
useEffect(() => { useEffect(() => {
// if modal is closed, reset active project to null // if modal is closed, reset active project to null
// and return to avoid activeProject being set to some other project // and return to avoid activeProject being set to some other project
@ -109,10 +136,10 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
// if data is present, set active project to the project of the // if data is present, set active project to the project of the
// issue. This has more priority than the project in the url. // issue. This has more priority than the project in the url.
if (data && data.project) { if (data && data.project) return setActiveProject(data.project);
setActiveProject(data.project);
return; if (prePopulateData && prePopulateData.project && !activeProject)
} return setActiveProject(prePopulateData.project);
if (prePopulateData && prePopulateData.project) if (prePopulateData && prePopulateData.project)
return setActiveProject(prePopulateData.project); return setActiveProject(prePopulateData.project);
@ -147,7 +174,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
? VIEW_ISSUES(viewId.toString(), viewGanttParams) ? VIEW_ISSUES(viewId.toString(), viewGanttParams)
: PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? ""); : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? "");
const createIssue = async (payload: Partial<IIssue>) => { const createDraftIssue = async (payload: Partial<IIssue>) => {
if (!workspaceSlug || !activeProject || !user) return; if (!workspaceSlug || !activeProject || !user) return;
await issuesService await issuesService
@ -187,7 +214,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
if (!createMore) onClose(); if (!createMore) onClose();
}; };
const updateIssue = async (payload: Partial<IIssue>) => { const updateDraftIssue = async (payload: Partial<IIssue>) => {
if (!user) return; if (!user) return;
await issuesService await issuesService
@ -203,6 +230,11 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
} }
if (!payload.is_draft) {
if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module);
}
if (!createMore) onClose(); if (!createMore) onClose();
setToastAlert({ setToastAlert({
@ -220,7 +252,93 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
}); });
}; };
const handleFormSubmit = async (formData: Partial<IIssue>) => { const addIssueToCycle = async (issueId: string, cycleId: string) => {
if (!workspaceSlug || !activeProject) return;
await issuesService
.addIssueToCycle(
workspaceSlug as string,
activeProject ?? "",
cycleId,
{
issues: [issueId],
},
user
)
.then(() => {
if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params));
mutate(CYCLE_DETAILS(cycleId as string));
}
});
};
const addIssueToModule = async (issueId: string, moduleId: string) => {
if (!workspaceSlug || !activeProject) return;
await modulesService
.addIssuesToModule(
workspaceSlug as string,
activeProject ?? "",
moduleId as string,
{
issues: [issueId],
},
user
)
.then(() => {
if (moduleId) {
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
mutate(MODULE_DETAILS(moduleId as string));
}
});
};
const createIssue = async (payload: Partial<IIssue>) => {
if (!workspaceSlug || !activeProject) return;
await issuesService
.createIssues(workspaceSlug as string, activeProject ?? "", payload, user)
.then(async (res) => {
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module);
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
if (displayFilters.layout === "gantt_chart")
mutate(ganttFetchKey, {
start_target_date: true,
order_by: "sort_order",
});
if (displayFilters.layout === "spreadsheet") mutate(spreadsheetFetchKey);
if (groupedIssues) mutateMyIssues();
setToastAlert({
type: "success",
title: "Success!",
message: "Issue created successfully.",
});
if (!createMore) onClose();
if (payload.assignees_list?.some((assignee) => assignee === user?.id))
mutate(USER_ISSUE(workspaceSlug as string));
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Issue could not be created. Please try again.",
});
});
};
const handleFormSubmit = async (
formData: Partial<IIssue>,
action: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" = "createDraft"
) => {
if (!workspaceSlug || !activeProject) return; if (!workspaceSlug || !activeProject) return;
const payload: Partial<IIssue> = { const payload: Partial<IIssue> = {
@ -231,8 +349,10 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
description_html: formData.description_html ?? "<p></p>", description_html: formData.description_html ?? "<p></p>",
}; };
if (!data) await createIssue(payload); if (action === "createDraft") await createDraftIssue(payload);
else await updateIssue(payload); else if (action === "updateDraft" || action === "convertToNewIssue")
await updateDraftIssue(payload);
else if (action === "createNewIssue") await createIssue(payload);
clearDraftIssueLocalStorage(); clearDraftIssueLocalStorage();

View File

@ -139,6 +139,8 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
target_date: getValues("target_date"), target_date: getValues("target_date"),
project: getValues("project"), project: getValues("project"),
parent: getValues("parent"), parent: getValues("parent"),
cycle: getValues("cycle"),
module: getValues("module"),
}; };
useEffect(() => { useEffect(() => {

View File

@ -69,7 +69,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
handleClose, handleClose,
isOpen, isOpen,
isUpdatingSingleIssue = false, isUpdatingSingleIssue = false,
prePopulateData, prePopulateData: prePopulateDataProps,
fieldsToShow = ["all"], fieldsToShow = ["all"],
onSubmit, onSubmit,
}) => { }) => {
@ -78,6 +78,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
const [formDirtyState, setFormDirtyState] = useState<any>(null); const [formDirtyState, setFormDirtyState] = useState<any>(null);
const [showConfirmDiscard, setShowConfirmDiscard] = useState(false); const [showConfirmDiscard, setShowConfirmDiscard] = useState(false);
const [activeProject, setActiveProject] = useState<string | null>(null); const [activeProject, setActiveProject] = useState<string | null>(null);
const [prePopulateData, setPreloadedData] = useState<Partial<IIssue>>({});
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId, inboxId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId, viewId, inboxId } = router.query;
@ -98,11 +99,40 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
if (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) useEffect(() => {
prePopulateData = { setPreloadedData(prePopulateDataProps ?? {});
...prePopulateData,
assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""], if (cycleId && !prePopulateDataProps?.cycle) {
}; setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
cycle: cycleId.toString(),
}));
}
if (moduleId && !prePopulateDataProps?.module) {
setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
module: moduleId.toString(),
}));
}
if (
(router.asPath.includes("my-issues") || router.asPath.includes("assigned")) &&
!prePopulateDataProps?.assignees
) {
setPreloadedData((prevData) => ({
...(prevData ?? {}),
...prePopulateDataProps,
assignees: prePopulateDataProps?.assignees ?? [user?.id ?? ""],
}));
}
}, [prePopulateDataProps, cycleId, moduleId, router.asPath, user?.id]);
/**
*
* @description This function is used to close the modals. This function will show a confirm discard modal if the form is dirty.
* @returns void
*/
const onClose = () => { const onClose = () => {
if (!showConfirmDiscard) handleClose(); if (!showConfirmDiscard) handleClose();
@ -111,6 +141,22 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
setValueInLocalStorage(data); setValueInLocalStorage(data);
}; };
/**
* @description This function is used to close the modals. This function is to be used when the form is submitted,
* meaning we don't need to show the confirm discard modal or store the form data in local storage.
*/
const onFormSubmitClose = () => {
setFormDirtyState(null);
handleClose();
};
/**
* @description This function is used to close the modals. This function is to be used when we click outside the modal,
* meaning we don't need to show the confirm discard modal but will store the form data in local storage.
* Use this function when you want to store the form data in local storage.
*/
const onDiscardClose = () => { const onDiscardClose = () => {
if (formDirtyState !== null) { if (formDirtyState !== null) {
setShowConfirmDiscard(true); setShowConfirmDiscard(true);
@ -295,7 +341,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
}); });
}); });
if (!createMore) onDiscardClose(); if (!createMore) onFormSubmitClose();
}; };
const createDraftIssue = async () => { const createDraftIssue = async () => {
@ -354,7 +400,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module);
if (!createMore) onDiscardClose(); if (!createMore) onFormSubmitClose();
setToastAlert({ setToastAlert({
type: "success", type: "success",

View File

@ -3,8 +3,6 @@ import React, { useState } from "react";
// ui // ui
import { Icon } from "components/ui"; import { Icon } from "components/ui";
import { ChevronDown, PenSquare } from "lucide-react"; import { ChevronDown, PenSquare } from "lucide-react";
// headless ui
import { Menu, Transition } from "@headlessui/react";
// hooks // hooks
import useLocalStorage from "hooks/use-local-storage"; import useLocalStorage from "hooks/use-local-storage";
// components // components
@ -17,10 +15,7 @@ export const WorkspaceSidebarQuickAction = () => {
const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false); const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false);
const { storedValue, clearValue } = useLocalStorage<any>( const { storedValue, clearValue } = useLocalStorage<any>("draftedIssue", JSON.stringify({}));
"draftedIssue",
JSON.stringify(undefined)
);
return ( return (
<> <>
@ -31,18 +26,17 @@ export const WorkspaceSidebarQuickAction = () => {
onSubmit={() => { onSubmit={() => {
localStorage.removeItem("draftedIssue"); localStorage.removeItem("draftedIssue");
clearValue(); clearValue();
setIsDraftIssueModalOpen(false);
}} }}
fieldsToShow={["all"]} fieldsToShow={["all"]}
/> />
<div <div
className={`relative flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${ className={`flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${
store?.theme?.sidebarCollapsed ? "flex-col gap-1" : "gap-2" store?.theme?.sidebarCollapsed ? "flex-col gap-1" : "gap-2"
}`} }`}
> >
<div <div
className={`flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${ className={`relative flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${
store?.theme?.sidebarCollapsed store?.theme?.sidebarCollapsed
? "px-2 hover:bg-custom-sidebar-background-80" ? "px-2 hover:bg-custom-sidebar-background-80"
: "px-3 shadow border-[0.5px] border-custom-border-300" : "px-3 shadow border-[0.5px] border-custom-border-300"
@ -50,7 +44,7 @@ export const WorkspaceSidebarQuickAction = () => {
> >
<button <button
type="button" type="button"
className="flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5" className="relative flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5"
onClick={() => { onClick={() => {
const e = new KeyboardEvent("keydown", { key: "c" }); const e = new KeyboardEvent("keydown", { key: "c" });
document.dispatchEvent(e); document.dispatchEvent(e);
@ -65,56 +59,35 @@ export const WorkspaceSidebarQuickAction = () => {
)} )}
</button> </button>
{storedValue && <div className="h-8 w-0.5 bg-custom-sidebar-background-80" />} {storedValue && Object.keys(JSON.parse(storedValue)).length > 0 && (
<>
<div className="h-8 w-0.5 bg-custom-sidebar-background-80" />
{storedValue && ( <button
<div className="relative"> type="button"
<Menu as={React.Fragment}> className="flex items-center justify-center rounded flex-shrink-0 py-1.5 ml-1.5"
{({ open }) => ( >
<> <ChevronDown
<div> size={16}
<Menu.Button className="!text-custom-sidebar-text-300 transform transition-transform duration-300 group-hover:rotate-180 rotate-0"
type="button" />
className={`flex items-center justify-center rounded flex-shrink-0 p-1.5 ${ </button>
open ? "rotate-180 pl-0" : "rotate-0 pr-0"
}`} <div className="absolute w-full h-10 pt-2 top-full left-0 opacity-0 group-hover:opacity-100 mt-0 pointer-events-none group-hover:pointer-events-auto">
> <div className="w-full h-full">
<ChevronDown <button
size={16} onClick={() => setIsDraftIssueModalOpen(true)}
className="!text-custom-sidebar-text-300 transform transition-transform duration-300" className="w-full flex text-sm items-center rounded flex-shrink-0 py-[10px] px-3 bg-custom-background-100 shadow border-[0.5px] border-custom-border-300 text-custom-text-300"
/> >
</Menu.Button> <PenSquare
</div> size={16}
<Transition className="!text-lg !leading-4 text-custom-sidebar-text-300 mr-2"
as={React.Fragment} />
enter="transition ease-out duration-100" Last Drafted Issue
enterFrom="transform opacity-0 scale-95" </button>
enterTo="transform opacity-100 scale-100" </div>
leave="transition ease-in duration-75" </div>
leaveFrom="transform opacity-100 scale-100" </>
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute -right-4 mt-1 w-52 bg-custom-background-300">
<div className="px-1 py-1 ">
<Menu.Item>
<button
onClick={() => setIsDraftIssueModalOpen(true)}
className="w-full flex text-sm items-center rounded flex-shrink-0 py-[10px] px-3 bg-custom-background-100 shadow border-[0.5px] border-custom-border-300 text-custom-text-300"
>
<PenSquare
size={16}
className="!text-lg !leading-4 text-custom-sidebar-text-300 mr-2"
/>
Last Drafted Issue
</button>
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
</div>
)} )}
</div> </div>