forked from github/plane
fix: inbox mutation fixes (#1324)
* chore: inbox status update mutation * fix: inbox issue activity mutation * refactor: code structure * chore: snoozed status message * chore: disable older dates for snoozing * chore: extend snooze time * chore: hide copy link from inbox
This commit is contained in:
parent
cf8c902473
commit
7d29a89eed
@ -130,7 +130,8 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
|||||||
<span className="break-all font-medium text-brand-base">
|
<span className="break-all font-medium text-brand-base">
|
||||||
{data?.project_detail?.identifier}-{data?.sequence_id}
|
{data?.project_detail?.identifier}-{data?.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
{""}? This action cannot be undone.
|
{""}? The issue will only be deleted from the inbox and this action cannot be
|
||||||
|
undone.
|
||||||
</p>
|
</p>
|
||||||
</span>
|
</span>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
|
@ -76,6 +76,11 @@ export const InboxActionHeader: React.FC<Props> = (props) => {
|
|||||||
const issueStatus = issue?.issue_inbox[0].status;
|
const issueStatus = issue?.issue_inbox[0].status;
|
||||||
const isAllowed = memberRole.isMember || memberRole.isOwner;
|
const isAllowed = memberRole.isMember || memberRole.isOwner;
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
const tomorrow = new Date(today);
|
||||||
|
|
||||||
|
tomorrow.setDate(today.getDate() + 1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-4 border-b border-brand-base divide-x divide-brand-base">
|
<div className="grid grid-cols-4 border-b border-brand-base divide-x divide-brand-base">
|
||||||
<div className="col-span-1 flex justify-between p-4">
|
<div className="col-span-1 flex justify-between p-4">
|
||||||
@ -142,12 +147,20 @@ export const InboxActionHeader: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3 flex-wrap">
|
<div className="flex items-center gap-3 flex-wrap">
|
||||||
{isAllowed && (
|
{isAllowed && (
|
||||||
<div className={`flex gap-3 flex-wrap ${issueStatus !== -2 ? "opacity-70" : ""}`}>
|
<div
|
||||||
|
className={`flex-shrink-0 ${
|
||||||
|
issueStatus === 0 || issueStatus === -2 ? "" : "opacity-70"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<Popover className="relative">
|
<Popover className="relative">
|
||||||
<Popover.Button as="button" type="button" disabled={issueStatus !== -2}>
|
<Popover.Button
|
||||||
|
as="button"
|
||||||
|
type="button"
|
||||||
|
disabled={!(issueStatus === 0 || issueStatus === -2)}
|
||||||
|
>
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
className={`flex gap-x-1 items-center ${
|
className={`flex gap-x-1 items-center ${
|
||||||
issueStatus !== -2 ? "cursor-not-allowed" : ""
|
issueStatus === 0 || issueStatus === -2 ? "" : "cursor-not-allowed"
|
||||||
}`}
|
}`}
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
@ -165,6 +178,7 @@ export const InboxActionHeader: React.FC<Props> = (props) => {
|
|||||||
setDate(val);
|
setDate(val);
|
||||||
}}
|
}}
|
||||||
dateFormat="dd-MM-yyyy"
|
dateFormat="dd-MM-yyyy"
|
||||||
|
minDate={tomorrow}
|
||||||
inline
|
inline
|
||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
@ -180,6 +194,10 @@ export const InboxActionHeader: React.FC<Props> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</Popover.Panel>
|
</Popover.Panel>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isAllowed && (
|
||||||
|
<div className={`flex gap-3 flex-wrap ${issueStatus !== -2 ? "opacity-70" : ""}`}>
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
size="sm"
|
size="sm"
|
||||||
className="flex gap-2 items-center"
|
className="flex gap-2 items-center"
|
||||||
|
@ -101,7 +101,13 @@ export const InboxIssueCard: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{issue.issue_inbox[0].snoozed_till && (
|
{issue.issue_inbox[0].snoozed_till && (
|
||||||
<div className="text-xs flex items-center gap-1 text-brand-accent">
|
<div
|
||||||
|
className={`text-xs flex items-center gap-1 ${
|
||||||
|
new Date(issue.issue_inbox[0].snoozed_till ?? "") < new Date()
|
||||||
|
? "text-red-500"
|
||||||
|
: "text-blue-500"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<ClockIcon className="h-3.5 w-3.5" />
|
<ClockIcon className="h-3.5 w-3.5" />
|
||||||
<span>
|
<span>
|
||||||
Snoozed till {renderShortNumericDateFormat(issue.issue_inbox[0].snoozed_till)}
|
Snoozed till {renderShortNumericDateFormat(issue.issue_inbox[0].snoozed_till)}
|
||||||
|
@ -36,7 +36,7 @@ import { renderShortNumericDateFormat } from "helpers/date-time.helper";
|
|||||||
// types
|
// types
|
||||||
import type { IInboxIssue, IIssue } from "types";
|
import type { IInboxIssue, IIssue } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { INBOX_ISSUES, INBOX_ISSUE_DETAILS } from "constants/fetch-keys";
|
import { INBOX_ISSUES, INBOX_ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
name: "",
|
name: "",
|
||||||
@ -129,6 +129,7 @@ export const InboxMainContent: React.FC = () => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
mutateIssueDetails();
|
mutateIssueDetails();
|
||||||
mutate(INBOX_ISSUES(inboxId.toString(), params));
|
mutate(INBOX_ISSUES(inboxId.toString(), params));
|
||||||
|
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -157,7 +158,9 @@ export const InboxMainContent: React.FC = () => {
|
|||||||
: issueStatus === -1
|
: issueStatus === -1
|
||||||
? "text-red-500 border-red-500 bg-red-500/10"
|
? "text-red-500 border-red-500 bg-red-500/10"
|
||||||
: issueStatus === 0
|
: issueStatus === 0
|
||||||
? "text-blue-500 border-blue-500 bg-blue-500/10"
|
? new Date(issueDetails.issue_inbox[0].snoozed_till ?? "") < new Date()
|
||||||
|
? "text-red-500 border-red-500 bg-red-500/10"
|
||||||
|
: "text-blue-500 border-blue-500 bg-blue-500/10"
|
||||||
: issueStatus === 1
|
: issueStatus === 1
|
||||||
? "text-green-500 border-green-500 bg-green-500/10"
|
? "text-green-500 border-green-500 bg-green-500/10"
|
||||||
: issueStatus === 2
|
: issueStatus === 2
|
||||||
@ -178,10 +181,19 @@ export const InboxMainContent: React.FC = () => {
|
|||||||
) : issueStatus === 0 ? (
|
) : issueStatus === 0 ? (
|
||||||
<>
|
<>
|
||||||
<ClockIcon className="h-5 w-5" />
|
<ClockIcon className="h-5 w-5" />
|
||||||
<p>
|
{new Date(issueDetails.issue_inbox[0].snoozed_till ?? "") < new Date() ? (
|
||||||
This issue has been snoozed till{" "}
|
<p>
|
||||||
{renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}.
|
This issue was snoozed till{" "}
|
||||||
</p>
|
{renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>
|
||||||
|
This issue has been snoozed till{" "}
|
||||||
|
{renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : issueStatus === 1 ? (
|
) : issueStatus === 1 ? (
|
||||||
<>
|
<>
|
||||||
|
@ -76,7 +76,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
|
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
|
||||||
<div className="flex flex-wrap items-start py-2">
|
<div className="flex flex-wrap items-start">
|
||||||
<div className="space-y-1 sm:basis-1/2">
|
<div className="space-y-1 sm:basis-1/2">
|
||||||
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
|
@ -287,13 +287,15 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
{issueDetail?.project_detail?.identifier}-{issueDetail?.sequence_id}
|
{issueDetail?.project_detail?.identifier}-{issueDetail?.sequence_id}
|
||||||
</h4>
|
</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<button
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
|
||||||
type="button"
|
<button
|
||||||
className="rounded-md border border-brand-base p-2 shadow-sm duration-300 hover:bg-brand-surface-1 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent"
|
type="button"
|
||||||
onClick={handleCopyText}
|
className="rounded-md border border-brand-base p-2 shadow-sm duration-300 hover:bg-brand-surface-1 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent"
|
||||||
>
|
onClick={handleCopyText}
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
>
|
||||||
</button>
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{!isNotAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
{!isNotAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -10,6 +10,7 @@ import projectService from "services/project.service";
|
|||||||
// hooks
|
// hooks
|
||||||
import useInboxView from "hooks/use-inbox-view";
|
import useInboxView from "hooks/use-inbox-view";
|
||||||
import useUserAuth from "hooks/use-user-auth";
|
import useUserAuth from "hooks/use-user-auth";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// layouts
|
// layouts
|
||||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||||
// contexts
|
// contexts
|
||||||
@ -47,6 +48,7 @@ const ProjectInbox: NextPage = () => {
|
|||||||
|
|
||||||
const { user } = useUserAuth();
|
const { user } = useUserAuth();
|
||||||
const { issues: inboxIssues, mutate: mutateInboxIssues } = useInboxView();
|
const { issues: inboxIssues, mutate: mutateInboxIssues } = useInboxView();
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
const { data: projectDetails } = useSWR(
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||||
@ -103,6 +105,28 @@ const ProjectInbox: NextPage = () => {
|
|||||||
const markInboxStatus = async (data: TInboxStatus) => {
|
const markInboxStatus = async (data: TInboxStatus) => {
|
||||||
if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId) return;
|
if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId) return;
|
||||||
|
|
||||||
|
mutate<IInboxIssueDetail>(
|
||||||
|
INBOX_ISSUE_DETAILS(inboxId as string, inboxIssueId as string),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prevData,
|
||||||
|
issue_inbox: [{ ...prevData.issue_inbox[0], ...data }],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
mutateInboxIssues(
|
||||||
|
(prevData) =>
|
||||||
|
(prevData ?? []).map((i) =>
|
||||||
|
i.bridge_id === inboxIssueId
|
||||||
|
? { ...i, issue_inbox: [{ ...i.issue_inbox[0], ...data }] }
|
||||||
|
: i
|
||||||
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
await inboxServices
|
await inboxServices
|
||||||
.markInboxStatus(
|
.markInboxStatus(
|
||||||
workspaceSlug.toString(),
|
workspaceSlug.toString(),
|
||||||
@ -112,28 +136,16 @@ const ProjectInbox: NextPage = () => {
|
|||||||
data,
|
data,
|
||||||
user
|
user
|
||||||
)
|
)
|
||||||
.then(() => {
|
.catch(() =>
|
||||||
mutate<IInboxIssueDetail>(
|
setToastAlert({
|
||||||
INBOX_ISSUE_DETAILS(inboxId as string, inboxIssueId as string),
|
type: "error",
|
||||||
(prevData) => {
|
title: "Error!",
|
||||||
if (!prevData) return prevData;
|
message: "Something went wrong while updating inbox status. Please try again.",
|
||||||
|
})
|
||||||
return {
|
)
|
||||||
...prevData,
|
.finally(() => {
|
||||||
issue_inbox: [{ ...prevData.issue_inbox[0], ...data }],
|
mutate(INBOX_ISSUE_DETAILS(inboxId as string, inboxIssueId as string));
|
||||||
};
|
mutateInboxIssues();
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
mutateInboxIssues(
|
|
||||||
(prevData) =>
|
|
||||||
(prevData ?? []).map((i) =>
|
|
||||||
i.bridge_id === inboxIssueId
|
|
||||||
? { ...i, issue_inbox: [{ ...i.issue_inbox[0], ...data }] }
|
|
||||||
: i
|
|
||||||
),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,11 +104,19 @@
|
|||||||
color: rgba(var(--color-text-base)) !important;
|
color: rgba(var(--color-text-base)) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-datepicker__day--selected {
|
.react-datepicker__day--selected,
|
||||||
|
.react-datepicker__day--selected:hover {
|
||||||
background-color: #216ba5 !important;
|
background-color: #216ba5 !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-datepicker__day--disabled,
|
||||||
|
.react-datepicker__day--disabled:hover {
|
||||||
|
background: transparent !important;
|
||||||
|
color: rgba(var(--color-text-secondary)) !important;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.react-datepicker__day--today {
|
.react-datepicker__day--today {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user