Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions web/components/core/views/issues-view.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useState } from "react";
import { useCallback, useEffect, useState } from "react";

import { useRouter } from "next/router";

Expand Down Expand Up @@ -87,8 +87,16 @@ export const IssuesView: React.FC<Props> = ({

const { setToastAlert } = useToast();

const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } =
useIssuesView();
const {
groupedByIssues,
mutateIssues,
displayFilters,
filters,
isEmpty,
setFilters,
params,
setDisplayFilters,
} = useIssuesView();
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);

const { data: stateGroups } = useSWR(
Expand All @@ -108,6 +116,17 @@ export const IssuesView: React.FC<Props> = ({

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(
(issue: IIssue) => {
setDeleteIssueModal(true);
Expand Down
2 changes: 1 addition & 1 deletion web/components/issues/confirm-issue-discard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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]">
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<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
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
Expand Down
40 changes: 27 additions & 13 deletions web/components/issues/draft-issue-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ const defaultValues: Partial<IIssue> = {
};

interface IssueFormProps {
handleFormSubmit: (formData: Partial<IIssue>) => Promise<void>;
handleFormSubmit: (
formData: Partial<IIssue>,
action?: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue"
) => Promise<void>;
data?: Partial<IIssue> | null;
prePopulatedData?: Partial<IIssue> | null;
projectId: string;
Expand Down Expand Up @@ -134,12 +137,16 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {

const handleCreateUpdateIssue = async (
formData: Partial<IIssue>,
action: "saveDraft" | "createToNewIssue" = "saveDraft"
action: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" = "createDraft"
) => {
await handleFormSubmit({
...formData,
is_draft: action === "saveDraft",
});
await handleFormSubmit(
{
...(data ?? {}),
...formData,
is_draft: action === "createDraft" || action === "updateDraft",
},
action
);

setGptAssistantModal(false);

Expand Down Expand Up @@ -263,7 +270,9 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
</>
)}
<form
onSubmit={handleSubmit((formData) => handleCreateUpdateIssue(formData, "createToNewIssue"))}
onSubmit={handleSubmit((formData) =>
handleCreateUpdateIssue(formData, "convertToNewIssue")
)}
>
<div className="space-y-5">
<div className="flex items-center gap-x-2">
Expand Down Expand Up @@ -563,15 +572,20 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
<SecondaryButton onClick={onClose}>Discard</SecondaryButton>
<SecondaryButton
loading={isSubmitting}
onClick={handleSubmit((formData) => handleCreateUpdateIssue(formData, "saveDraft"))}
onClick={handleSubmit((formData) =>
handleCreateUpdateIssue(formData, data?.id ? "updateDraft" : "createDraft")
)}
>
{isSubmitting ? "Saving..." : "Save Draft"}
</SecondaryButton>
{data && (
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Saving..." : "Add Issue"}
</PrimaryButton>
)}
<PrimaryButton
loading={isSubmitting}
onClick={handleSubmit((formData) =>
handleCreateUpdateIssue(formData, data ? "convertToNewIssue" : "createNewIssue")
)}
>
{isSubmitting ? "Saving..." : "Add Issue"}
</PrimaryButton>
</div>
</div>
</form>
Expand Down
172 changes: 146 additions & 26 deletions web/components/issues/draft-issue-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ import {
MODULE_ISSUES_WITH_PARAMS,
VIEW_ISSUES,
PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS,
CYCLE_DETAILS,
MODULE_DETAILS,
} from "constants/fetch-keys";
import modulesService from "services/modules.service";

interface IssuesModalProps {
data?: IIssue | null;
Expand All @@ -56,18 +59,21 @@ interface IssuesModalProps {
onSubmit?: (data: Partial<IIssue>) => Promise<void> | void;
}

export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
data,
handleClose,
isOpen,
isUpdatingSingleIssue = false,
prePopulateData,
fieldsToShow = ["all"],
onSubmit,
}) => {
export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) => {
const {
data,
handleClose,
isOpen,
isUpdatingSingleIssue = false,
prePopulateData: prePopulateDataProps,
fieldsToShow = ["all"],
onSubmit,
} = props;

// states
const [createMore, setCreateMore] = useState(false);
const [activeProject, setActiveProject] = useState<string | null>(null);
const [prePopulateData, setPreloadedData] = useState<Partial<IIssue> | undefined>(undefined);

const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
Expand All @@ -86,19 +92,40 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({

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 = () => {
handleClose();
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(() => {
// if modal is closed, reset active project to null
// and return to avoid activeProject being set to some other project
Expand All @@ -109,10 +136,10 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({

// if data is present, set active project to the project of the
// issue. This has more priority than the project in the url.
if (data && data.project) {
setActiveProject(data.project);
return;
}
if (data && data.project) return setActiveProject(data.project);

if (prePopulateData && prePopulateData.project && !activeProject)
return setActiveProject(prePopulateData.project);

if (prePopulateData && prePopulateData.project)
return setActiveProject(prePopulateData.project);
Expand Down Expand Up @@ -147,7 +174,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
? VIEW_ISSUES(viewId.toString(), viewGanttParams)
: PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? "");

const createIssue = async (payload: Partial<IIssue>) => {
const createDraftIssue = async (payload: Partial<IIssue>) => {
if (!workspaceSlug || !activeProject || !user) return;

await issuesService
Expand Down Expand Up @@ -187,7 +214,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
if (!createMore) onClose();
};

const updateIssue = async (payload: Partial<IIssue>) => {
const updateDraftIssue = async (payload: Partial<IIssue>) => {
if (!user) return;

await issuesService
Expand All @@ -203,6 +230,11 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
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();

setToastAlert({
Expand All @@ -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;

const payload: Partial<IIssue> = {
Expand All @@ -231,8 +349,10 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
description_html: formData.description_html ?? "<p></p>",
};

if (!data) await createIssue(payload);
else await updateIssue(payload);
if (action === "createDraft") await createDraftIssue(payload);
else if (action === "updateDraft" || action === "convertToNewIssue")
await updateDraftIssue(payload);
else if (action === "createNewIssue") await createIssue(payload);

clearDraftIssueLocalStorage();

Expand Down
2 changes: 2 additions & 0 deletions web/components/issues/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
target_date: getValues("target_date"),
project: getValues("project"),
parent: getValues("parent"),
cycle: getValues("cycle"),
module: getValues("module"),
};

useEffect(() => {
Expand Down
Loading