forked from github/plane
fix: peek overview bugs (#2043)
* fix: side peek modal shaking * refactor: peek overview layout * fix: date selector, activity mutation * fix: delete issue handler * fix: assignees mutation
This commit is contained in:
parent
c6d9ace6a2
commit
4ba3ef5c24
@ -33,10 +33,17 @@ type Props = {
|
||||
isOpen: boolean;
|
||||
handleClose: () => void;
|
||||
data: IIssue | null;
|
||||
onSubmit?: () => Promise<void>;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
};
|
||||
|
||||
export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, user }) => {
|
||||
export const DeleteIssueModal: React.FC<Props> = ({
|
||||
isOpen,
|
||||
handleClose,
|
||||
data,
|
||||
onSubmit,
|
||||
user,
|
||||
}) => {
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
@ -116,6 +123,8 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, u
|
||||
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, params));
|
||||
}
|
||||
|
||||
if (onSubmit) onSubmit();
|
||||
|
||||
handleClose();
|
||||
setToastAlert({
|
||||
title: "Success",
|
||||
|
@ -103,7 +103,7 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({
|
||||
</div>
|
||||
<div className="w-3/4">
|
||||
<SidebarAssigneeSelect
|
||||
value={issue.assignees_list}
|
||||
value={issue.assignees}
|
||||
onChange={(val: string[]) => handleUpdateIssue({ assignees_list: val })}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
@ -128,23 +128,18 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({
|
||||
<span className="flex-grow truncate">Start date</span>
|
||||
</div>
|
||||
<div>
|
||||
{issue.start_date ? (
|
||||
<CustomDatePicker
|
||||
placeholder="Start date"
|
||||
value={issue.start_date}
|
||||
onChange={(val) =>
|
||||
handleUpdateIssue({
|
||||
start_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-100"
|
||||
wrapperClassName="w-full"
|
||||
maxDate={maxDate ?? undefined}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-custom-text-200">Empty</span>
|
||||
)}
|
||||
<CustomDatePicker
|
||||
placeholder="Select start date"
|
||||
value={issue.start_date}
|
||||
onChange={(val) =>
|
||||
handleUpdateIssue({
|
||||
start_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-80 border-none"
|
||||
maxDate={maxDate ?? undefined}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
@ -153,23 +148,18 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({
|
||||
<span className="flex-grow truncate">Due date</span>
|
||||
</div>
|
||||
<div>
|
||||
{issue.target_date ? (
|
||||
<CustomDatePicker
|
||||
placeholder="Due date"
|
||||
value={issue.target_date}
|
||||
onChange={(val) =>
|
||||
handleUpdateIssue({
|
||||
target_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-100"
|
||||
wrapperClassName="w-full"
|
||||
minDate={minDate ?? undefined}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-custom-text-200">Empty</span>
|
||||
)}
|
||||
<CustomDatePicker
|
||||
placeholder="Select due date"
|
||||
value={issue.target_date}
|
||||
onChange={(val) =>
|
||||
handleUpdateIssue({
|
||||
target_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-80 border-none"
|
||||
minDate={minDate ?? undefined}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="flex items-center gap-2 text-sm">
|
||||
|
@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { mutate } from "swr";
|
||||
// mobx
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
@ -10,9 +11,11 @@ import { Dialog, Transition } from "@headlessui/react";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
// components
|
||||
import { FullScreenPeekView, SidePeekView } from "components/issues";
|
||||
import { DeleteIssueModal, FullScreenPeekView, SidePeekView } from "components/issues";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
// fetch-keys
|
||||
import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||
|
||||
type Props = {
|
||||
handleMutation: () => void;
|
||||
@ -28,6 +31,7 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
||||
const [isSidePeekOpen, setIsSidePeekOpen] = useState(false);
|
||||
const [isModalPeekOpen, setIsModalPeekOpen] = useState(false);
|
||||
const [peekOverviewMode, setPeekOverviewMode] = useState<TPeekOverviewModes>("side");
|
||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const { peekIssue } = router.query;
|
||||
@ -53,6 +57,7 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
||||
if (!issue || !user) return;
|
||||
|
||||
await updateIssue(workspaceSlug, projectId, issue.id, formData, user);
|
||||
mutate(PROJECT_ISSUES_ACTIVITY(issue.id));
|
||||
handleMutation();
|
||||
};
|
||||
|
||||
@ -81,7 +86,6 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
||||
setIsSidePeekOpen(false);
|
||||
}
|
||||
} else {
|
||||
console.log("Triggered");
|
||||
setIsSidePeekOpen(false);
|
||||
setIsModalPeekOpen(false);
|
||||
}
|
||||
@ -89,33 +93,38 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
||||
|
||||
return (
|
||||
<>
|
||||
<DeleteIssueModal
|
||||
isOpen={deleteIssueModal}
|
||||
handleClose={() => setDeleteIssueModal(false)}
|
||||
data={issue ? { ...issue } : null}
|
||||
onSubmit={handleDeleteIssue}
|
||||
user={user}
|
||||
/>
|
||||
<Transition.Root appear show={isSidePeekOpen} as={React.Fragment}>
|
||||
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||
<div className="relative h-full w-full">
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="transition-transform duration-300"
|
||||
enterFrom="translate-x-full"
|
||||
enterTo="translate-x-0"
|
||||
leave="transition-transform duration-200"
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<Dialog.Panel className="absolute z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
|
||||
<SidePeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={handleDeleteIssue}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="transition-transform duration-300"
|
||||
enterFrom="translate-x-full"
|
||||
enterTo="translate-x-0"
|
||||
leave="transition-transform duration-200"
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<Dialog.Panel className="fixed z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
|
||||
<SidePeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={() => setDeleteIssueModal(true)}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
@ -132,49 +141,47 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
||||
>
|
||||
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||
</Transition.Child>
|
||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||
<div className="relative h-full w-full">
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Dialog.Panel
|
||||
className={`fixed z-20 bg-custom-background-100 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg shadow-custom-shadow-xl transition-all duration-300 ${
|
||||
peekOverviewMode === "modal" ? "h-[70%] w-3/5" : "h-[95%] w-[95%]"
|
||||
}`}
|
||||
>
|
||||
<Dialog.Panel
|
||||
className={`absolute z-20 bg-custom-background-100 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg shadow-custom-shadow-xl transition-all duration-300 ${
|
||||
peekOverviewMode === "modal" ? "h-[70%] w-3/5" : "h-[95%] w-[95%]"
|
||||
}`}
|
||||
>
|
||||
{peekOverviewMode === "modal" && (
|
||||
<SidePeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={handleDeleteIssue}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
)}
|
||||
{peekOverviewMode === "full" && (
|
||||
<FullScreenPeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={handleDeleteIssue}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
{peekOverviewMode === "modal" && (
|
||||
<SidePeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={() => setDeleteIssueModal(true)}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
)}
|
||||
{peekOverviewMode === "full" && (
|
||||
<FullScreenPeekView
|
||||
handleClose={handleClose}
|
||||
handleDeleteIssue={() => setDeleteIssueModal(true)}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
issue={issue}
|
||||
mode={peekOverviewMode}
|
||||
readOnly={readOnly}
|
||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
|
@ -51,7 +51,10 @@ export const SidebarAssigneeSelect: React.FC<Props> = ({ value, onChange, disabl
|
||||
<span className="text-custom-text-100 text-xs">{value.length} Assignees</span>
|
||||
</div>
|
||||
) : (
|
||||
<button type="button" className="bg-custom-background-80 px-2.5 py-0.5 text-xs rounded">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-custom-background-80 px-2.5 py-0.5 text-xs rounded text-custom-text-200"
|
||||
>
|
||||
No assignees
|
||||
</button>
|
||||
)}
|
||||
|
@ -27,7 +27,7 @@ export const SidebarPrioritySelect: React.FC<Props> = ({ value, onChange, disabl
|
||||
? "border-yellow-500/20 bg-yellow-500/20 text-yellow-500"
|
||||
: value === "low"
|
||||
? "border-green-500/20 bg-green-500/20 text-green-500"
|
||||
: "bg-custom-background-80 border-custom-border-200"
|
||||
: "bg-custom-background-80 border-custom-border-200 text-custom-text-200"
|
||||
}`}
|
||||
>
|
||||
<span className="grid place-items-center -my-1">
|
||||
|
@ -41,7 +41,7 @@ const CustomSelect = ({
|
||||
>
|
||||
<>
|
||||
{customButton ? (
|
||||
<Listbox.Button as="div">{customButton}</Listbox.Button>
|
||||
<Listbox.Button as={React.Fragment}>{customButton}</Listbox.Button>
|
||||
) : (
|
||||
<Listbox.Button
|
||||
type="button"
|
||||
|
@ -116,11 +116,12 @@ class IssuesStore {
|
||||
const originalIssue = { ...this.issues[issueId] };
|
||||
|
||||
// immediately update the issue in the store
|
||||
const updatedIssue = { ...originalIssue, ...issueForm };
|
||||
const updatedIssue = { ...this.issues[issueId], ...issueForm };
|
||||
if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list;
|
||||
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.issues[issueId] = updatedIssue;
|
||||
this.issues[issueId] = { ...updatedIssue };
|
||||
});
|
||||
|
||||
// make a patch request to update the issue
|
||||
|
Loading…
Reference in New Issue
Block a user