From 7d29a89eed4da2280b0699454afd66e16cbe0382 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:10:52 +0530 Subject: [PATCH 1/3] 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 --- .../components/inbox/delete-issue-modal.tsx | 3 +- .../components/inbox/inbox-action-headers.tsx | 24 +++++++- .../app/components/inbox/inbox-issue-card.tsx | 8 ++- .../components/inbox/inbox-main-content.tsx | 24 ++++++-- .../app/components/inbox/select-duplicate.tsx | 2 +- apps/app/components/issues/sidebar.tsx | 16 +++--- .../projects/[projectId]/inbox/[inboxId].tsx | 56 +++++++++++-------- apps/app/styles/react-datepicker.css | 10 +++- 8 files changed, 101 insertions(+), 42 deletions(-) diff --git a/apps/app/components/inbox/delete-issue-modal.tsx b/apps/app/components/inbox/delete-issue-modal.tsx index 46ba1ebdd..c6f5320a2 100644 --- a/apps/app/components/inbox/delete-issue-modal.tsx +++ b/apps/app/components/inbox/delete-issue-modal.tsx @@ -130,7 +130,8 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data }) {data?.project_detail?.identifier}-{data?.sequence_id} - {""}? This action cannot be undone. + {""}? The issue will only be deleted from the inbox and this action cannot be + undone.

diff --git a/apps/app/components/inbox/inbox-action-headers.tsx b/apps/app/components/inbox/inbox-action-headers.tsx index 8be550d98..5ceaa8f2c 100644 --- a/apps/app/components/inbox/inbox-action-headers.tsx +++ b/apps/app/components/inbox/inbox-action-headers.tsx @@ -76,6 +76,11 @@ export const InboxActionHeader: React.FC = (props) => { const issueStatus = issue?.issue_inbox[0].status; const isAllowed = memberRole.isMember || memberRole.isOwner; + const today = new Date(); + const tomorrow = new Date(today); + + tomorrow.setDate(today.getDate() + 1); + return (
@@ -142,12 +147,20 @@ export const InboxActionHeader: React.FC = (props) => {
{isAllowed && ( -
+
- + @@ -165,6 +178,7 @@ export const InboxActionHeader: React.FC = (props) => { setDate(val); }} dateFormat="dd-MM-yyyy" + minDate={tomorrow} inline /> = (props) => { )} +
+ )} + {isAllowed && ( +
= (props) => {
{issue.issue_inbox[0].snoozed_till && ( -
+
Snoozed till {renderShortNumericDateFormat(issue.issue_inbox[0].snoozed_till)} diff --git a/apps/app/components/inbox/inbox-main-content.tsx b/apps/app/components/inbox/inbox-main-content.tsx index 1bf330e5e..83948495c 100644 --- a/apps/app/components/inbox/inbox-main-content.tsx +++ b/apps/app/components/inbox/inbox-main-content.tsx @@ -36,7 +36,7 @@ import { renderShortNumericDateFormat } from "helpers/date-time.helper"; // types import type { IInboxIssue, IIssue } from "types"; // 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 = { name: "", @@ -129,6 +129,7 @@ export const InboxMainContent: React.FC = () => { .then(() => { mutateIssueDetails(); mutate(INBOX_ISSUES(inboxId.toString(), params)); + mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); }); }, [ @@ -157,7 +158,9 @@ export const InboxMainContent: React.FC = () => { : issueStatus === -1 ? "text-red-500 border-red-500 bg-red-500/10" : 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 ? "text-green-500 border-green-500 bg-green-500/10" : issueStatus === 2 @@ -178,10 +181,19 @@ export const InboxMainContent: React.FC = () => { ) : issueStatus === 0 ? ( <> -

- This issue has been snoozed till{" "} - {renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}. -

+ {new Date(issueDetails.issue_inbox[0].snoozed_till ?? "") < new Date() ? ( +

+ This issue was snoozed till{" "} + {renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")} + . +

+ ) : ( +

+ This issue has been snoozed till{" "} + {renderShortNumericDateFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")} + . +

+ )} ) : issueStatus === 1 ? ( <> diff --git a/apps/app/components/inbox/select-duplicate.tsx b/apps/app/components/inbox/select-duplicate.tsx index fdf7034df..74409a57f 100644 --- a/apps/app/components/inbox/select-duplicate.tsx +++ b/apps/app/components/inbox/select-duplicate.tsx @@ -76,7 +76,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { return ( setQuery("")} appear> -
+
= ({ {issueDetail?.project_detail?.identifier}-{issueDetail?.sequence_id}
- + {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && ( + + )} {!isNotAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && ( +
+ ))} + +
+ ) : filterKey === "inbox_status" ? ( +
+ {filters.inbox_status?.map((status) => ( +
+ {INBOX_STATUS.find((s) => s.value === status)?.label} + +
+ ))} + +
+ ) : ( + (filters[filterKey] as any)?.join(", ") + )} +
+ )} +
+ ); + })} + +
+ ); +}; diff --git a/apps/app/components/inbox/index.ts b/apps/app/components/inbox/index.ts index 3f66790bc..7cdd8ee9d 100644 --- a/apps/app/components/inbox/index.ts +++ b/apps/app/components/inbox/index.ts @@ -1,6 +1,7 @@ export * from "./decline-issue-modal"; export * from "./delete-issue-modal"; export * from "./filters-dropdown"; +export * from "./filters-list"; export * from "./inbox-action-headers"; export * from "./inbox-issue-card"; export * from "./inbox-main-content"; diff --git a/apps/app/components/inbox/issues-list-sidebar.tsx b/apps/app/components/inbox/issues-list-sidebar.tsx index 02181c02a..9f5c85db1 100644 --- a/apps/app/components/inbox/issues-list-sidebar.tsx +++ b/apps/app/components/inbox/issues-list-sidebar.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; // hooks import useInboxView from "hooks/use-inbox-view"; // components -import { InboxIssueCard } from "components/inbox"; +import { InboxIssueCard, InboxFiltersList } from "components/inbox"; // ui import { Loader } from "components/ui"; @@ -14,10 +14,11 @@ export const IssuesListSidebar = () => { const { issues: inboxIssues } = useInboxView(); return ( - <> +
+ {inboxIssues ? ( inboxIssues.length > 0 ? ( -
+
{inboxIssues.map((issue) => ( { )} - +
); }; diff --git a/apps/app/constants/inbox.ts b/apps/app/constants/inbox.ts index b5731fb89..9bbe8230a 100644 --- a/apps/app/constants/inbox.ts +++ b/apps/app/constants/inbox.ts @@ -1,9 +1,29 @@ -export const STATUS: { [key: string]: number } = { - Pending: -2, - Declined: -1, - Snoozed: 0, - Accepted: 1, - Duplicate: 2, -}; +export const INBOX_STATUS = [ + { + key: "pending", + label: "Pending", + value: -2, + }, + { + key: "declined", + label: "Declined", + value: -1, + }, + { + key: "snoozed", + label: "Snoozed", + value: 0, + }, + { + key: "accepted", + label: "Accepted", + value: 1, + }, + { + key: "duplicate", + label: "Duplicate", + value: 2, + }, +]; export const INBOX_ISSUE_SOURCE = "in-app"; diff --git a/apps/app/contexts/inbox-view-context.tsx b/apps/app/contexts/inbox-view-context.tsx index ff3bebc72..f6201fbb9 100644 --- a/apps/app/contexts/inbox-view-context.tsx +++ b/apps/app/contexts/inbox-view-context.tsx @@ -26,6 +26,7 @@ type ReducerActionType = { type ContextType = InboxViewProps & { setFilters: (filters: Partial) => void; + clearAllFilters: () => void; }; type StateType = { @@ -53,7 +54,7 @@ export const reducer: ReducerFunctionType = (state, action) => { ...state, filters: { ...state.filters, - ...payload, + ...payload?.filters, }, }; @@ -140,6 +141,38 @@ export const InboxViewContextProvider: React.FC<{ children: React.ReactNode }> = [workspaceSlug, projectId, inboxId, mutateInboxDetails, state] ); + const clearAllFilters = useCallback(() => { + dispatch({ + type: "SET_FILTERS", + payload: { + filters: { ...initialState.filters }, + }, + }); + + if (!workspaceSlug || !projectId || !inboxId) return; + + const newViewProps = { + ...state, + filters: { ...initialState.filters }, + }; + + mutateInboxDetails((prevData) => { + if (!prevData) return prevData; + + return { + ...prevData, + view_props: newViewProps, + }; + }, false); + + saveDataToServer( + workspaceSlug.toString(), + projectId.toString(), + inboxId.toString(), + newViewProps + ); + }, [inboxId, mutateInboxDetails, projectId, state, workspaceSlug]); + useEffect(() => { dispatch({ type: "REHYDRATE_THEME", @@ -154,6 +187,7 @@ export const InboxViewContextProvider: React.FC<{ children: React.ReactNode }> = value={{ filters: state.filters, setFilters, + clearAllFilters, }} > diff --git a/apps/app/contexts/issue-view.context.tsx b/apps/app/contexts/issue-view.context.tsx index 6053b8b15..d2a4496c9 100644 --- a/apps/app/contexts/issue-view.context.tsx +++ b/apps/app/contexts/issue-view.context.tsx @@ -168,7 +168,7 @@ export const reducer: ReducerFunctionType = (state, action) => { ...state, filters: { ...state.filters, - ...payload, + ...payload?.filters, }, }; diff --git a/apps/app/hooks/use-inbox-view.tsx b/apps/app/hooks/use-inbox-view.tsx index 4ce6f4859..a5dedc380 100644 --- a/apps/app/hooks/use-inbox-view.tsx +++ b/apps/app/hooks/use-inbox-view.tsx @@ -14,7 +14,7 @@ import { IInboxQueryParams } from "types"; import { INBOX_ISSUES } from "constants/fetch-keys"; const useInboxView = () => { - const { filters, setFilters } = useContext(inboxViewContext); + const { filters, setFilters, clearAllFilters } = useContext(inboxViewContext); const router = useRouter(); const { workspaceSlug, projectId, inboxId } = router.query; @@ -50,10 +50,11 @@ const useInboxView = () => { return { filters, setFilters, + clearAllFilters, + filtersLength, params, issues: inboxIssues, mutate: mutateInboxIssues, - filtersLength, } as const; }; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx index c47e79d06..c08925c0f 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx @@ -222,7 +222,7 @@ const ProjectInbox: NextPage = () => { }} onDelete={() => setDeleteIssueModal(true)} /> -
+
{inboxIssueId ? ( From 2cef6e67d47af9b6adb4f41b0fbd24083b0b8600 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:56:08 +0530 Subject: [PATCH 3/3] chore: decline issue mutation (#1354) --- .../components/inbox/decline-issue-modal.tsx | 79 ++----------------- .../projects/[projectId]/inbox/[inboxId].tsx | 5 ++ 2 files changed, 10 insertions(+), 74 deletions(-) diff --git a/apps/app/components/inbox/decline-issue-modal.tsx b/apps/app/components/inbox/decline-issue-modal.tsx index 64fe1682a..941841659 100644 --- a/apps/app/components/inbox/decline-issue-modal.tsx +++ b/apps/app/components/inbox/decline-issue-modal.tsx @@ -1,102 +1,33 @@ -import React, { useEffect, useState } from "react"; - -import { useRouter } from "next/router"; - -import { mutate } from "swr"; +import React, { useState } from "react"; // headless ui import { Dialog, Transition } from "@headlessui/react"; -// services -import inboxServices from "services/inbox.service"; -// hooks -import useToast from "hooks/use-toast"; -import useInboxView from "hooks/use-inbox-view"; -import useUser from "hooks/use-user"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // ui import { SecondaryButton, DangerButton } from "components/ui"; // types -import type { IInboxIssue, ICurrentUserResponse, IInboxIssueDetail } from "types"; -// fetch-keys -import { INBOX_ISSUES, INBOX_ISSUE_DETAILS } from "constants/fetch-keys"; +import type { IInboxIssue } from "types"; type Props = { isOpen: boolean; handleClose: () => void; data: IInboxIssue | undefined; + onSubmit: () => Promise; }; -export const DeclineIssueModal: React.FC = ({ isOpen, handleClose, data }) => { +export const DeclineIssueModal: React.FC = ({ isOpen, handleClose, data, onSubmit }) => { const [isDeclining, setIsDeclining] = useState(false); - const router = useRouter(); - const { workspaceSlug, projectId, inboxId } = router.query; - - const { user } = useUser(); - const { setToastAlert } = useToast(); - const { params } = useInboxView(); - const onClose = () => { setIsDeclining(false); handleClose(); }; const handleDecline = () => { - if (!workspaceSlug || !projectId || !inboxId || !data) return; - setIsDeclining(true); - inboxServices - .markInboxStatus( - workspaceSlug.toString(), - projectId.toString(), - inboxId.toString(), - data.bridge_id, - { - status: -1, - }, - user - ) - .then(() => { - mutate( - INBOX_ISSUE_DETAILS(inboxId.toString(), data.bridge_id), - (prevData) => { - if (!prevData) return prevData; - - return { - ...prevData, - issue_inbox: [{ ...prevData.issue_inbox[0], status: -1 }], - }; - }, - false - ); - mutate( - INBOX_ISSUES(inboxId.toString(), params), - (prevData) => - prevData?.map((i) => - i.bridge_id === data.bridge_id - ? { ...i, issue_inbox: [{ ...i.issue_inbox[0], status: -1 }] } - : i - ), - false - ); - - setToastAlert({ - type: "success", - title: "Success!", - message: "Issue declined successfully.", - }); - onClose(); - }) - .catch(() => - setToastAlert({ - type: "error", - title: "Error!", - message: "Issue could not be declined. Please try again.", - }) - ) - .finally(() => setIsDeclining(false)); + onSubmit().finally(() => setIsDeclining(false)); }; return ( diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx index c08925c0f..140e704ed 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx @@ -194,6 +194,11 @@ const ProjectInbox: NextPage = () => { isOpen={declineIssueModal} handleClose={() => setDeclineIssueModal(false)} data={inboxIssues?.find((i) => i.bridge_id === inboxIssueId)} + onSubmit={async () => { + await markInboxStatus({ + status: -1, + }).finally(() => setDeclineIssueModal(false)); + }} />