Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mark all notifications as read #1982

Merged
merged 1 commit into from
Aug 28, 2023
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
48 changes: 34 additions & 14 deletions apps/app/components/notifications/notification-header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";

// components
import { Icon, Tooltip } from "components/ui";
import { CustomMenu, Icon, Tooltip } from "components/ui";
// helpers
import { getNumberCount } from "helpers/string.helper";

Expand All @@ -21,6 +21,7 @@ type NotificationHeaderProps = {
setArchived: React.Dispatch<React.SetStateAction<boolean>>;
setReadNotification: React.Dispatch<React.SetStateAction<boolean>>;
setSelectedTab: React.Dispatch<React.SetStateAction<NotificationType>>;
markAllNotificationsAsRead: () => Promise<void>;
};

export const NotificationHeader: React.FC<NotificationHeaderProps> = (props) => {
Expand All @@ -37,6 +38,7 @@ export const NotificationHeader: React.FC<NotificationHeaderProps> = (props) =>
setArchived,
setReadNotification,
setSelectedTab,
markAllNotificationsAsRead,
} = props;

const notificationTabs: Array<{
Expand Down Expand Up @@ -88,33 +90,51 @@ export const NotificationHeader: React.FC<NotificationHeaderProps> = (props) =>
<Icon iconName="filter_list" />
</button>
</Tooltip>
<Tooltip tooltipContent="Snoozed notifications">
<button
type="button"
<CustomMenu
customButton={
<div className="grid place-items-center ">
<Icon iconName="more_vert" />
</div>
}
>
<CustomMenu.MenuItem renderAs="button" onClick={markAllNotificationsAsRead}>
<div className="flex items-center gap-2">
<Icon iconName="done_all" />
Mark all as read
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
renderAs="button"
onClick={() => {
setArchived(false);
setReadNotification(false);
setSnoozed((prev) => !prev);
}}
>
<Icon iconName="schedule" />
</button>
</Tooltip>
<Tooltip tooltipContent="Archived notifications">
<button
type="button"
<div className="flex items-center gap-2">
<Icon iconName="schedule" />
Show snoozed
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
renderAs="button"
onClick={() => {
setSnoozed(false);
setReadNotification(false);
setArchived((prev) => !prev);
}}
>
<Icon iconName="archive" />
<div className="flex items-center gap-2">
<Icon iconName="archive" />
Show archived
</div>
</CustomMenu.MenuItem>
</CustomMenu>
<Tooltip tooltipContent="Close">
<button type="button" onClick={() => closePopover()}>
<Icon iconName="close" />
</button>
</Tooltip>
<button type="button" onClick={() => closePopover()}>
<Icon iconName="close" />
</button>
</div>
</div>
<div className="border-b border-custom-border-300 w-full px-5 mt-5">
Expand Down
4 changes: 3 additions & 1 deletion apps/app/components/notifications/notification-popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const NotificationPopover = () => {
hasMore,
isRefreshing,
setFetchNotifications,
markAllNotificationsAsRead,
} = useUserNotification();

// theme context
Expand Down Expand Up @@ -112,7 +113,7 @@ export const NotificationPopover = () => {
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute bg-custom-background-100 flex flex-col left-0 md:left-full ml-8 z-10 -top-44 md:w-[36rem] w-[20rem] h-[75vh] border border-custom-border-300 shadow-lg rounded-xl">
<Popover.Panel className="absolute bg-custom-background-100 flex flex-col left-0 md:left-full ml-8 z-10 -top-36 md:w-[36rem] w-[20rem] h-[50vh] border border-custom-border-300 shadow-lg rounded-xl">
<NotificationHeader
notificationCount={notificationCount}
notificationMutate={notificationMutate}
Expand All @@ -126,6 +127,7 @@ export const NotificationPopover = () => {
setArchived={setArchived}
setReadNotification={setReadNotification}
setSelectedTab={setSelectedTab}
markAllNotificationsAsRead={markAllNotificationsAsRead}
/>

{notifications ? (
Expand Down
31 changes: 30 additions & 1 deletion apps/app/hooks/use-user-notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ import useSWRInfinite from "swr/infinite";
// services
import userNotificationServices from "services/notifications.service";

// hooks
import useToast from "./use-toast";

// fetch-keys
import { UNREAD_NOTIFICATIONS_COUNT, getPaginatedNotificationKey } from "constants/fetch-keys";

// type
import type { NotificationType, NotificationCount } from "types";
import type { NotificationType, NotificationCount, IMarkAllAsReadPayload } from "types";

const PER_PAGE = 30;

const useUserNotification = () => {
const router = useRouter();
const { workspaceSlug } = router.query;

const { setToastAlert } = useToast();

const [snoozed, setSnoozed] = useState<boolean>(false);
const [archived, setArchived] = useState<boolean>(false);
const [readNotification, setReadNotification] = useState<boolean>(false);
Expand Down Expand Up @@ -274,6 +279,29 @@ const useUserNotification = () => {
}
};

const markAllNotificationsAsRead = async () => {
if (!workspaceSlug) return;

let markAsReadParams: IMarkAllAsReadPayload;

if (snoozed) markAsReadParams = { archived: false, snoozed: true };
else if (archived) markAsReadParams = { archived: true, snoozed: false };
else markAsReadParams = { archived: false, snoozed: false, type: selectedTab };

await userNotificationServices
.markAllNotificationsAsRead(workspaceSlug.toString(), markAsReadParams)
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Something went wrong. Please try again.",
});
})
.finally(() => {
notificationMutate();
});
};

return {
notifications,
notificationMutate,
Expand Down Expand Up @@ -304,6 +332,7 @@ const useUserNotification = () => {
isRefreshing,
setFetchNotifications,
markNotificationAsRead,
markAllNotificationsAsRead,
};
};

Expand Down
14 changes: 14 additions & 0 deletions apps/app/services/notifications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
INotificationParams,
NotificationCount,
PaginatedUserNotification,
IMarkAllAsReadPayload,
} from "types";

class UserNotificationsServices extends APIService {
Expand Down Expand Up @@ -172,6 +173,19 @@ class UserNotificationsServices extends APIService {
throw error?.response?.data;
});
}

async markAllNotificationsAsRead(
workspaceSlug: string,
payload: IMarkAllAsReadPayload
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, {
...payload,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

const userNotificationServices = new UserNotificationsServices();
Expand Down
6 changes: 6 additions & 0 deletions apps/app/types/notifications.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ export type NotificationCount = {
my_issues: number;
watching_issues: number;
};

export interface IMarkAllAsReadPayload {
archived?: boolean;
snoozed?: boolean;
type?: NotificationType;
}