forked from github/plane
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:
parent
e01a0d20fe
commit
cdfff12f4f
@ -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);
|
||||||
|
@ -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"
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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(() => {
|
||||||
|
@ -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",
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user