2023-07-26 06:32:14 +00:00
|
|
|
import { createContext, useCallback, useEffect, useReducer } from "react";
|
|
|
|
|
|
|
|
import { useRouter } from "next/router";
|
|
|
|
import useSWR from "swr";
|
|
|
|
// services
|
2023-12-04 06:41:36 +00:00
|
|
|
import { NotificationService } from "services/notification.service";
|
2023-07-26 06:32:14 +00:00
|
|
|
// fetch-keys
|
|
|
|
import { UNREAD_NOTIFICATIONS_COUNT, USER_WORKSPACE_NOTIFICATIONS } from "constants/fetch-keys";
|
|
|
|
// type
|
|
|
|
import type { NotificationType, NotificationCount, IUserNotification } from "types";
|
|
|
|
|
2023-12-04 06:41:36 +00:00
|
|
|
const notificationService = new NotificationService();
|
|
|
|
|
2023-07-26 06:32:14 +00:00
|
|
|
export const userNotificationContext = createContext<ContextType>({} as ContextType);
|
|
|
|
|
|
|
|
type UserNotificationProps = {
|
|
|
|
selectedTab: NotificationType;
|
|
|
|
snoozed: boolean;
|
|
|
|
archived: boolean;
|
|
|
|
readNotification: boolean;
|
|
|
|
selectedNotificationForSnooze: string | null;
|
|
|
|
};
|
|
|
|
|
|
|
|
type ReducerActionType = {
|
|
|
|
type:
|
|
|
|
| "READ_NOTIFICATION_COUNT"
|
|
|
|
| "SET_SELECTED_TAB"
|
|
|
|
| "SET_SNOOZED"
|
|
|
|
| "SET_ARCHIVED"
|
|
|
|
| "SET_READ_NOTIFICATION"
|
|
|
|
| "SET_SELECTED_NOTIFICATION_FOR_SNOOZE"
|
|
|
|
| "SET_NOTIFICATIONS";
|
|
|
|
payload?: Partial<ContextType>;
|
|
|
|
};
|
|
|
|
|
|
|
|
type ContextType = UserNotificationProps & {
|
|
|
|
notifications?: IUserNotification[];
|
|
|
|
notificationCount?: NotificationCount | null;
|
|
|
|
setSelectedTab: (tab: NotificationType) => void;
|
|
|
|
setSnoozed: (snoozed: boolean) => void;
|
|
|
|
setArchived: (archived: boolean) => void;
|
|
|
|
setReadNotification: (readNotification: boolean) => void;
|
|
|
|
setSelectedNotificationForSnooze: (notificationId: string | null) => void;
|
|
|
|
markNotificationReadStatus: (notificationId: string) => void;
|
|
|
|
markNotificationArchivedStatus: (notificationId: string) => void;
|
|
|
|
markSnoozeNotification: (notificationId: string, dateTime?: Date) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
type StateType = {
|
|
|
|
selectedTab: NotificationType;
|
|
|
|
snoozed: boolean;
|
|
|
|
archived: boolean;
|
|
|
|
readNotification: boolean;
|
|
|
|
selectedNotificationForSnooze: string | null;
|
|
|
|
};
|
|
|
|
|
|
|
|
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
|
|
|
|
|
|
|
export const initialState: StateType = {
|
|
|
|
selectedTab: "assigned",
|
|
|
|
snoozed: false,
|
|
|
|
archived: false,
|
|
|
|
readNotification: false,
|
|
|
|
selectedNotificationForSnooze: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const reducer: ReducerFunctionType = (state, action) => {
|
|
|
|
const { type, payload } = action;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case "READ_NOTIFICATION_COUNT":
|
|
|
|
case "SET_SELECTED_TAB":
|
|
|
|
case "SET_SNOOZED":
|
|
|
|
case "SET_ARCHIVED":
|
|
|
|
case "SET_READ_NOTIFICATION":
|
|
|
|
case "SET_SELECTED_NOTIFICATION_FOR_SNOOZE":
|
|
|
|
case "SET_NOTIFICATIONS": {
|
|
|
|
return { ...state, ...payload };
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const UserNotificationContextProvider: React.FC<{
|
|
|
|
children: React.ReactNode;
|
|
|
|
}> = ({ children }) => {
|
|
|
|
const router = useRouter();
|
|
|
|
const { workspaceSlug } = router.query;
|
|
|
|
|
|
|
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
|
|
|
|
|
|
const { selectedTab, snoozed, archived, readNotification, selectedNotificationForSnooze } = state;
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
type: snoozed || archived || readNotification ? undefined : selectedTab,
|
|
|
|
snoozed,
|
|
|
|
archived,
|
|
|
|
read: !readNotification ? undefined : false,
|
|
|
|
};
|
|
|
|
|
|
|
|
const { data: notifications, mutate: notificationsMutate } = useSWR(
|
|
|
|
workspaceSlug ? USER_WORKSPACE_NOTIFICATIONS(workspaceSlug.toString(), params) : null,
|
2023-12-04 06:41:36 +00:00
|
|
|
workspaceSlug ? () => notificationService.getUserNotifications(workspaceSlug.toString(), params) : null
|
2023-07-26 06:32:14 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const { data: notificationCount, mutate: mutateNotificationCount } = useSWR(
|
|
|
|
workspaceSlug ? UNREAD_NOTIFICATIONS_COUNT(workspaceSlug.toString()) : null,
|
2023-12-04 06:41:36 +00:00
|
|
|
() => (workspaceSlug ? notificationService.getUnreadNotificationsCount(workspaceSlug.toString()) : null)
|
2023-07-26 06:32:14 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const handleReadMutation = (action: "read" | "unread") => {
|
|
|
|
const notificationCountNumber = action === "read" ? -1 : 1;
|
|
|
|
|
2023-08-15 09:34:46 +00:00
|
|
|
mutateNotificationCount((prev: any) => {
|
2023-07-26 06:32:14 +00:00
|
|
|
if (!prev) return prev;
|
|
|
|
|
|
|
|
const notificationType: keyof NotificationCount =
|
2023-12-04 06:41:36 +00:00
|
|
|
selectedTab === "assigned" ? "my_issues" : selectedTab === "created" ? "created_issues" : "watching_issues";
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
...prev,
|
|
|
|
[notificationType]: prev[notificationType] + notificationCountNumber,
|
|
|
|
};
|
|
|
|
}, false);
|
|
|
|
};
|
|
|
|
|
|
|
|
const markNotificationReadStatus = async (notificationId: string) => {
|
|
|
|
if (!workspaceSlug) return;
|
2023-12-04 06:41:36 +00:00
|
|
|
const isRead = notifications?.find((notification) => notification.id === notificationId)?.read_at !== null;
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
notificationsMutate(
|
2023-08-15 09:34:46 +00:00
|
|
|
(previousNotifications: any) =>
|
|
|
|
previousNotifications?.map((notification: any) =>
|
2023-12-04 06:41:36 +00:00
|
|
|
notification.id === notificationId ? { ...notification, read_at: isRead ? null : new Date() } : notification
|
2023-07-26 06:32:14 +00:00
|
|
|
),
|
|
|
|
false
|
|
|
|
);
|
|
|
|
|
|
|
|
handleReadMutation(isRead ? "unread" : "read");
|
|
|
|
|
|
|
|
if (isRead) {
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.markUserNotificationAsUnread(workspaceSlug.toString(), notificationId)
|
|
|
|
.catch(() => {
|
|
|
|
throw new Error("Something went wrong");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
mutateNotificationCount();
|
|
|
|
});
|
|
|
|
} else {
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.markUserNotificationAsRead(workspaceSlug.toString(), notificationId)
|
|
|
|
.catch(() => {
|
|
|
|
throw new Error("Something went wrong");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
mutateNotificationCount();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const markNotificationArchivedStatus = async (notificationId: string) => {
|
|
|
|
if (!workspaceSlug) return;
|
2023-12-04 06:41:36 +00:00
|
|
|
const isArchived = notifications?.find((notification) => notification.id === notificationId)?.archived_at !== null;
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
if (!isArchived) {
|
|
|
|
handleReadMutation("read");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isArchived) {
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.markUserNotificationAsUnarchived(workspaceSlug.toString(), notificationId)
|
|
|
|
.catch(() => {
|
|
|
|
throw new Error("Something went wrong");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
mutateNotificationCount();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
notificationsMutate(
|
2023-12-04 06:41:36 +00:00
|
|
|
(prev: any) => prev?.filter((prevNotification: any) => prevNotification.id !== notificationId),
|
2023-07-26 06:32:14 +00:00
|
|
|
false
|
|
|
|
);
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.markUserNotificationAsArchived(workspaceSlug.toString(), notificationId)
|
|
|
|
.catch(() => {
|
|
|
|
throw new Error("Something went wrong");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
mutateNotificationCount();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const markSnoozeNotification = async (notificationId: string, dateTime?: Date) => {
|
|
|
|
if (!workspaceSlug) return;
|
|
|
|
|
2023-12-04 06:41:36 +00:00
|
|
|
const isSnoozed = notifications?.find((notification) => notification.id === notificationId)?.snoozed_till !== null;
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
notificationsMutate(
|
2023-08-15 09:34:46 +00:00
|
|
|
(previousNotifications: any) =>
|
|
|
|
previousNotifications?.map((notification: any) =>
|
2023-07-26 06:32:14 +00:00
|
|
|
notification.id === notificationId
|
|
|
|
? { ...notification, snoozed_till: isSnoozed ? null : new Date(dateTime!) }
|
|
|
|
: notification
|
|
|
|
) || [],
|
|
|
|
false
|
|
|
|
);
|
|
|
|
|
|
|
|
if (isSnoozed) {
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.patchUserNotification(workspaceSlug.toString(), notificationId, {
|
|
|
|
snoozed_till: null,
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
});
|
|
|
|
} else {
|
2023-12-04 06:41:36 +00:00
|
|
|
await notificationService
|
2023-07-26 06:32:14 +00:00
|
|
|
.patchUserNotification(workspaceSlug.toString(), notificationId, {
|
|
|
|
snoozed_till: dateTime,
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
new Error("Something went wrong");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
notificationsMutate();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const setSelectedTab = useCallback((tab: NotificationType) => {
|
|
|
|
dispatch({ type: "SET_SELECTED_TAB", payload: { selectedTab: tab } });
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const setSnoozed = useCallback((snoozed: boolean) => {
|
|
|
|
dispatch({ type: "SET_SNOOZED", payload: { snoozed } });
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const setArchived = useCallback((archived: boolean) => {
|
|
|
|
dispatch({ type: "SET_ARCHIVED", payload: { archived } });
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const setReadNotification = useCallback((readNotification: boolean) => {
|
|
|
|
dispatch({ type: "SET_READ_NOTIFICATION", payload: { readNotification } });
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const setSelectedNotificationForSnooze = useCallback((notificationId: string | null) => {
|
|
|
|
dispatch({
|
|
|
|
type: "SET_SELECTED_NOTIFICATION_FOR_SNOOZE",
|
|
|
|
payload: { selectedNotificationForSnooze: notificationId },
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
dispatch({ type: "SET_NOTIFICATIONS", payload: { notifications } });
|
|
|
|
}, [notifications]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
dispatch({ type: "READ_NOTIFICATION_COUNT", payload: { notificationCount } });
|
|
|
|
}, [notificationCount]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<userNotificationContext.Provider
|
|
|
|
value={{
|
|
|
|
...state,
|
|
|
|
notifications,
|
|
|
|
notificationCount,
|
|
|
|
setSelectedTab,
|
|
|
|
setSnoozed,
|
|
|
|
setArchived,
|
|
|
|
setReadNotification,
|
|
|
|
setSelectedNotificationForSnooze,
|
|
|
|
markNotificationReadStatus,
|
|
|
|
markNotificationArchivedStatus,
|
|
|
|
markSnoozeNotification,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</userNotificationContext.Provider>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default UserNotificationContextProvider;
|