From 72e82005c0a4e4afc9630e5873e7c60543a7073a Mon Sep 17 00:00:00 2001 From: SundasNoreen Date: Wed, 31 May 2023 11:50:42 +0500 Subject: [PATCH] feat: added notification APIs --- src/Notifications/NotificationTabs.jsx | 21 ++++++++++++------- src/Notifications/data/api.js | 29 ++++++++++++++++++++------ src/Notifications/data/selectors.js | 2 +- src/Notifications/data/slice.js | 24 +++++++++++++++++---- src/Notifications/data/thunks.js | 26 +++++++++++++++++++---- src/index.scss | 3 +-- 6 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/Notifications/NotificationTabs.jsx b/src/Notifications/NotificationTabs.jsx index 4a2748a..4e9cdd2 100644 --- a/src/Notifications/NotificationTabs.jsx +++ b/src/Notifications/NotificationTabs.jsx @@ -4,21 +4,25 @@ import React, { import { Tabs, Tab } from '@edx/paragon'; import { useSelector, useDispatch } from 'react-redux'; import NotificationSections from './NotificationSections'; -import { getNotificationTotalUnseenCounts, getSelectedNotificationType } from './data/selectors'; -import { fetchNotificationList } from './data/thunks'; +import { getNotificationTotalUnseenCounts, getSelectedAppName } from './data/selectors'; +import { fetchNotificationList, markNotificationsAsSeen } from './data/thunks'; import { notificationTabsOptions } from './data/constants'; const NotificationTabs = () => { const notificationUnseenCounts = useSelector(getNotificationTotalUnseenCounts()); - const selectedNotificationType = useSelector(getSelectedNotificationType()); + const selectedappName = useSelector(getSelectedAppName()); const [activeTab, setActiveTab] = useState(notificationTabsOptions[0].key); const [loadMoreCount, setLoadMoreCount] = useState(10); + const [page, setPage] = useState(1); const dispatch = useDispatch(); useEffect(() => { - dispatch(fetchNotificationList({ notificationType: activeTab, notificationCount: loadMoreCount })); - }, [dispatch, activeTab, loadMoreCount]); + dispatch(fetchNotificationList({ + appName: activeTab, notificationCount: loadMoreCount, page, pageSize: 10, + })); + dispatch(markNotificationsAsSeen(activeTab)); + }, [dispatch, activeTab, loadMoreCount, page]); const handleActiveTab = useCallback((tab) => { setActiveTab(tab); @@ -26,7 +30,8 @@ const NotificationTabs = () => { const handleLoadMoreNotification = useCallback((count) => { setLoadMoreCount(count); - }, []); + setPage(page + 1); + }, [page]); const tabArray = useMemo(() => notificationTabsOptions.map((option) => ( { notification={notificationUnseenCounts.countByAppName[option.key]} tabClassName="pt-0 pb-2.5 px-2.5 d-flex flex-row align-items-center line-height-24" > - {option.key === selectedNotificationType + {option.key === selectedappName && } - )), [notificationUnseenCounts, handleLoadMoreNotification, loadMoreCount, selectedNotificationType]); + )), [notificationUnseenCounts, handleLoadMoreNotification, loadMoreCount, selectedappName]); // This code is used to replace More... text to More to match the UI const buttons = document.getElementsByClassName('dropdown-toggle'); diff --git a/src/Notifications/data/api.js b/src/Notifications/data/api.js index ff3e680..efaf7d8 100644 --- a/src/Notifications/data/api.js +++ b/src/Notifications/data/api.js @@ -1,4 +1,9 @@ -import { camelCaseObject } from '@edx/frontend-platform'; +import { camelCaseObject, getConfig, snakeCaseObject } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +export const getNotificationsCountApiUrl = () => `${getConfig().LMS_BASE_URL}/api/notifications/count/`; +export const getNotificationsApiUrl = () => `${getConfig().LMS_BASE_URL}/api/notifications/`; +export const markNotificationsSeenApiUrl = (appName) => `${getConfig().LMS_BASE_URL}/api/notifications/mark-notifications-unseen/${appName}/`; const parseNotificationList = (notificationList) => { const currentTime = Date.now(); @@ -11,7 +16,12 @@ const parseNotificationList = (notificationList) => { }); return { today, earlier }; }; -export async function getNotifications(notificationType, notificationCount) { + +export async function getNotifications(appName, notificationCount, page, pageSize) { + const params = snakeCaseObject({ page, pageSize }); + + let { data } = await getAuthenticatedHttpClient().get(getNotificationsApiUrl(), { params }); + const notificationData = [ { type: 'post', @@ -194,8 +204,7 @@ export async function getNotifications(notificationType, notificationCount) { ]; const { today, earlier } = parseNotificationList(camelCaseObject(notificationData)); - - const data = { + data = { discussions: { TODAY: today, EARLIER: earlier, @@ -205,7 +214,8 @@ export async function getNotifications(notificationType, notificationCount) { EARLIER: earlier, }, }; - const notifications = data[notificationType]; + + const notifications = data[appName]; const { TODAY = [], EARLIER = [] } = notifications || []; let todayNotifications = TODAY; let earlierNotifications = []; @@ -225,7 +235,8 @@ export async function getNotifications(notificationType, notificationCount) { } export async function getNotificationCounts() { - const data = { + let { data } = await getAuthenticatedHttpClient().get(getNotificationsCountApiUrl()); + data = { count: 25, count_by_app_name: { reminders: 10, @@ -236,3 +247,9 @@ export async function getNotificationCounts() { }; return camelCaseObject(data); } + +export async function markNotificationSeen(appName) { + const { data } = await getAuthenticatedHttpClient() + .put(`${markNotificationsSeenApiUrl(appName)}`); + return camelCaseObject(data); +} diff --git a/src/Notifications/data/selectors.js b/src/Notifications/data/selectors.js index d62a52b..295dfc1 100644 --- a/src/Notifications/data/selectors.js +++ b/src/Notifications/data/selectors.js @@ -1,4 +1,4 @@ export const getNotificationStatus = () => state => state.notifications.notificationStatus; export const getNotificationTotalUnseenCounts = () => state => state.notifications.totalUnseenCounts; export const getNotifications = () => state => state.notifications.notifications; -export const getSelectedNotificationType = () => state => state.notifications.notificationType; +export const getSelectedAppName = () => state => state.notifications.appName; diff --git a/src/Notifications/data/slice.js b/src/Notifications/data/slice.js index b302f99..ac0fa6c 100644 --- a/src/Notifications/data/slice.js +++ b/src/Notifications/data/slice.js @@ -12,19 +12,19 @@ const slice = createSlice({ notificationStatus: 'idle', notifications: {}, totalUnseenCounts: {}, - notificationType: '', + appName: '', }, reducers: { fetchNotificationDenied: (state, { payload }) => { - state.notificationType = payload.notificationType; + state.appName = payload.appName; state.notificationStatus = DENIED; }, fetchNotificationFailure: (state, { payload }) => { - state.notificationType = payload.notificationType; + state.appName = payload.appName; state.notificationStatus = FAILED; }, fetchNotificationRequest: (state, { payload }) => { - state.notificationType = payload.notificationType; + state.appName = payload.appName; state.notificationStatus = LOADING; }, fetchNotificationSuccess: (state, { payload }) => { @@ -45,6 +45,18 @@ const slice = createSlice({ state.notificationStatus = LOADED; state.totalUnseenCounts = payload; }, + markNotificationsAsSeenRequest: (state) => { + state.notificationStatus = LOADING; + }, + markNotificationsAsSeenSuccess: (state) => { + state.notificationStatus = LOADED; + }, + markNotificationsAsSeenDenied: (state) => { + state.notificationStatus = DENIED; + }, + markNotificationsAsSeenFailure: (state) => { + state.notificationStatus = FAILED; + }, }, }); @@ -57,6 +69,10 @@ export const { fetchNotificationsCountFailure, fetchNotificationsCountRequest, fetchNotificationsCountSuccess, + markNotificationsAsSeenRequest, + markNotificationsAsSeenSuccess, + markNotificationsAsSeenFailure, + markNotificationsAsSeenDenied, } = slice.actions; export const notificationsReducer = slice.reducer; diff --git a/src/Notifications/data/thunks.js b/src/Notifications/data/thunks.js index 3e6f55b..4c61ee4 100644 --- a/src/Notifications/data/thunks.js +++ b/src/Notifications/data/thunks.js @@ -5,20 +5,26 @@ import { fetchNotificationsCountFailure, fetchNotificationsCountRequest, fetchNotificationsCountSuccess, + markNotificationsAsSeenRequest, + markNotificationsAsSeenSuccess, + markNotificationsAsSeenFailure, } from './slice'; import { getNotifications, getNotificationCounts, + markNotificationSeen, } from './api'; -export const fetchNotificationList = ({ notificationType, notificationCount }) => ( +export const fetchNotificationList = ({ + appName, notificationCount, page, pageSize, +}) => ( async (dispatch) => { try { - dispatch(fetchNotificationRequest({ notificationType })); - const data = await getNotifications(notificationType, notificationCount); + dispatch(fetchNotificationRequest({ appName })); + const data = await getNotifications(appName, notificationCount, page, pageSize); dispatch(fetchNotificationSuccess(data)); } catch (errors) { - dispatch(fetchNotificationFailure({ notificationType })); + dispatch(fetchNotificationFailure({ appName })); } } ); @@ -34,3 +40,15 @@ export const fetchNotificationsCountsList = () => ( } } ); + +export const markNotificationsAsSeen = (appName) => ( + async (dispatch) => { + try { + dispatch(markNotificationsAsSeenRequest({ appName })); + const data = await markNotificationSeen(appName); + dispatch(markNotificationsAsSeenSuccess(data)); + } catch (errors) { + dispatch(markNotificationsAsSeenFailure({ appName })); + } + } +); diff --git a/src/index.scss b/src/index.scss index 11ccaf4..d6689f9 100644 --- a/src/index.scss +++ b/src/index.scss @@ -128,7 +128,6 @@ $white: #fff; .font-size-12{ font-size: 12px; } - .font-size-9{ font-size: 9px; } @@ -155,7 +154,7 @@ $white: #fff; .expandable{ position: relative !important; margin-left: 4px; - padding: 2px 6px; + padding: 2px 5px; border-radius: 10rem; font-size: 9px; }