refactor: fixed all review points
This commit is contained in:
@@ -7,7 +7,7 @@ import { Link } from 'react-router-dom';
|
|||||||
import * as timeago from 'timeago.js';
|
import * as timeago from 'timeago.js';
|
||||||
import { getIconByType } from './utils';
|
import { getIconByType } from './utils';
|
||||||
import { markNotificationsAsRead } from './data/thunks';
|
import { markNotificationsAsRead } from './data/thunks';
|
||||||
import { messages } from './messages';
|
import messages from './messages';
|
||||||
import timeLocale from '../common/time-locale';
|
import timeLocale from '../common/time-locale';
|
||||||
|
|
||||||
const NotificationRowItem = ({
|
const NotificationRowItem = ({
|
||||||
@@ -21,15 +21,16 @@ const NotificationRowItem = ({
|
|||||||
dispatch(markNotificationsAsRead(id));
|
dispatch(markNotificationsAsRead(id));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const iconComponent = getIconByType(type);
|
const { icon: iconComponent, class: iconClass } = getIconByType(type);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link className="d-flex mb-2 align-items-center text-decoration-none" to={contentUrl} onClick={handleMarkAsRead}>
|
<Link
|
||||||
<Icon
|
target="_blank"
|
||||||
src={iconComponent && iconComponent.icon}
|
className="d-flex mb-2 align-items-center text-decoration-none"
|
||||||
style={{ height: '23.33px', width: '23.33px' }}
|
to={contentUrl}
|
||||||
className={iconComponent && `${iconComponent.class} mr-4`}
|
onClick={handleMarkAsRead}
|
||||||
/>
|
>
|
||||||
|
<Icon src={iconComponent} className={`${iconClass} mr-4 notification-icon`} />
|
||||||
<div className="d-flex w-100">
|
<div className="d-flex w-100">
|
||||||
<div className="d-flex align-items-center w-100">
|
<div className="d-flex align-items-center w-100">
|
||||||
<div className="py-10px w-100 px-0 cursor-pointer">
|
<div className="py-10px w-100 px-0 cursor-pointer">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Button } from '@edx/paragon';
|
|||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { messages } from './messages';
|
import messages from './messages';
|
||||||
import NotificationRowItem from './NotificationRowItem';
|
import NotificationRowItem from './NotificationRowItem';
|
||||||
import { markAllNotificationsAsRead } from './data/thunks';
|
import { markAllNotificationsAsRead } from './data/thunks';
|
||||||
import { selectNotificationsByIds, selectPaginationData, selectSelectedAppName } from './data/selectors';
|
import { selectNotificationsByIds, selectPaginationData, selectSelectedAppName } from './data/selectors';
|
||||||
@@ -14,8 +14,8 @@ const NotificationSections = () => {
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const selectedAppName = useSelector(selectSelectedAppName());
|
const selectedAppName = useSelector(selectSelectedAppName());
|
||||||
const notifications = useSelector(selectNotificationsByIds);
|
const notifications = useSelector(selectNotificationsByIds(selectedAppName));
|
||||||
const paginationData = useSelector(selectPaginationData());
|
const { currentPage, numPages } = useSelector(selectPaginationData());
|
||||||
const { today = [], earlier = [] } = useMemo(
|
const { today = [], earlier = [] } = useMemo(
|
||||||
() => splitNotificationsByTime(notifications),
|
() => splitNotificationsByTime(notifications),
|
||||||
[notifications],
|
[notifications],
|
||||||
@@ -69,7 +69,7 @@ const NotificationSections = () => {
|
|||||||
<div className="mt-4 px-4">
|
<div className="mt-4 px-4">
|
||||||
{renderNotificationSection('today', today)}
|
{renderNotificationSection('today', today)}
|
||||||
{renderNotificationSection('earlier', earlier)}
|
{renderNotificationSection('earlier', earlier)}
|
||||||
{paginationData.currentPage < paginationData.numPages && (
|
{currentPage < numPages && (
|
||||||
<Button variant="primary" className="w-100 bg-primary-500" onClick={updatePagination}>
|
<Button variant="primary" className="w-100 bg-primary-500" onClick={updatePagination}>
|
||||||
{intl.formatMessage(messages.loadMoreNotifications)}
|
{intl.formatMessage(messages.loadMoreNotifications)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { Tab, Tabs } from '@edx/paragon';
|
import { Tab, Tabs } from '@edx/paragon';
|
||||||
@@ -13,16 +14,16 @@ const NotificationTabs = () => {
|
|||||||
const selectedAppName = useSelector(selectSelectedAppName());
|
const selectedAppName = useSelector(selectSelectedAppName());
|
||||||
const notificationUnseenCounts = useSelector(selectNotificationTabsCount());
|
const notificationUnseenCounts = useSelector(selectNotificationTabsCount());
|
||||||
const notificationTabs = useSelector(selectNotificationTabs());
|
const notificationTabs = useSelector(selectNotificationTabs());
|
||||||
const paginationData = useSelector(selectPaginationData());
|
const { currentPage } = useSelector(selectPaginationData());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchNotificationList({ appName: selectedAppName, page: paginationData.currentPage, pageSize: 10 }));
|
dispatch(fetchNotificationList({ appName: selectedAppName, page: currentPage, pageSize: 10 }));
|
||||||
if (selectedAppName) { dispatch(markNotificationsAsSeen(selectedAppName)); }
|
if (selectedAppName) { dispatch(markNotificationsAsSeen(selectedAppName)); }
|
||||||
}, [dispatch, paginationData.currentPage, selectedAppName]);
|
}, [currentPage, selectedAppName]);
|
||||||
|
|
||||||
const handleActiveTab = useCallback((appName) => {
|
const handleActiveTab = useCallback((appName) => {
|
||||||
dispatch(updateAppNameRequest({ appName }));
|
dispatch(updateAppNameRequest({ appName }));
|
||||||
}, [dispatch]);
|
}, []);
|
||||||
|
|
||||||
const tabArray = useMemo(() => notificationTabs?.map((appName) => (
|
const tabArray = useMemo(() => notificationTabs?.map((appName) => (
|
||||||
<Tab
|
<Tab
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ export const selectSelectedAppNotificationIds = (appName) => state => state.noti
|
|||||||
|
|
||||||
export const selectShowNotificationTray = () => state => state.notifications.showNotificationTray;
|
export const selectShowNotificationTray = () => state => state.notifications.showNotificationTray;
|
||||||
|
|
||||||
export const selectNotifications = () => state => state.notifications.notification;
|
export const selectNotifications = () => state => state.notifications.notifications;
|
||||||
|
|
||||||
export const selectNotificationsByIds = createSelector(
|
export const selectNotificationsByIds = (appName) => createSelector(
|
||||||
state => state.notifications.notifications,
|
selectNotifications(),
|
||||||
state => state.notifications.apps[state.notifications.appName] || [],
|
selectSelectedAppNotificationIds(appName),
|
||||||
(notifications, notificationIds) => notificationIds.map(notificationId => notifications[notificationId]),
|
(notifications, notificationIds) => notificationIds.map((notificationId) => notifications[notificationId]) || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectSelectedAppName = () => state => state.notifications.appName;
|
export const selectSelectedAppName = () => state => state.notifications.appName;
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
export const IDLE = 'idle';
|
export const RequestStatus = {
|
||||||
export const LOADING = 'loading';
|
IDLE: 'idle',
|
||||||
export const LOADED = 'loaded';
|
LOADING: 'in-progress',
|
||||||
export const FAILED = 'failed';
|
LOADED: 'successful',
|
||||||
export const DENIED = 'denied';
|
FAILED: 'failed',
|
||||||
|
DENIED: 'denied',
|
||||||
|
};
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
notificationStatus: 'idle',
|
notificationStatus: 'idle',
|
||||||
appName: 'reminders',
|
appName: 'discussions',
|
||||||
appsId: [],
|
appsId: [],
|
||||||
apps: {},
|
apps: {},
|
||||||
notifications: {},
|
notifications: {},
|
||||||
@@ -26,65 +28,62 @@ const slice = createSlice({
|
|||||||
name: 'notifications',
|
name: 'notifications',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
fetchNotificationDenied: (state, { payload }) => {
|
fetchNotificationDenied: (state) => {
|
||||||
state.appName = payload.appName;
|
state.notificationStatus = RequestStatus.DENIED;
|
||||||
state.notificationStatus = DENIED;
|
|
||||||
},
|
},
|
||||||
fetchNotificationFailure: (state, { payload }) => {
|
fetchNotificationFailure: (state) => {
|
||||||
state.appName = payload.appName;
|
state.notificationStatus = RequestStatus.FAILED;
|
||||||
state.notificationStatus = FAILED;
|
|
||||||
},
|
},
|
||||||
fetchNotificationRequest: (state, { payload }) => {
|
fetchNotificationRequest: (state) => {
|
||||||
if (state.appName !== payload.appName) { state.apps[payload.appName] = []; }
|
state.notificationStatus = RequestStatus.LOADING;
|
||||||
state.appName = payload.appName;
|
|
||||||
state.notificationStatus = LOADING;
|
|
||||||
},
|
},
|
||||||
fetchNotificationSuccess: (state, { payload }) => {
|
fetchNotificationSuccess: (state, { payload }) => {
|
||||||
const { notifications, numPages, currentPage } = payload;
|
const {
|
||||||
const newNotificationIds = notifications.map(notification => notification.id.toString());
|
newNotificationIds, notificationsKeyValuePair, numPages, currentPage,
|
||||||
|
} = payload;
|
||||||
const existingNotificationIds = state.apps[state.appName];
|
const existingNotificationIds = state.apps[state.appName];
|
||||||
const notificationsKeyValuePair = notifications.reduce((acc, obj) => { acc[obj.id] = obj; return acc; }, {});
|
|
||||||
const currentAppCount = state.tabsCount[state.appName];
|
|
||||||
|
|
||||||
state.apps[state.appName] = Array.from(new Set([...existingNotificationIds, ...newNotificationIds]));
|
state.apps[state.appName] = Array.from(new Set([...existingNotificationIds, ...newNotificationIds]));
|
||||||
state.notifications = { ...state.notifications, ...notificationsKeyValuePair };
|
state.notifications = { ...state.notifications, ...notificationsKeyValuePair };
|
||||||
state.tabsCount.count -= currentAppCount;
|
state.tabsCount.count -= state.tabsCount[state.appName];
|
||||||
state.tabsCount[state.appName] = 0;
|
state.tabsCount[state.appName] = 0;
|
||||||
state.notificationStatus = LOADED;
|
state.notificationStatus = RequestStatus.LOADED;
|
||||||
state.pagination.numPages = numPages;
|
state.pagination.numPages = numPages;
|
||||||
state.pagination.currentPage = currentPage;
|
state.pagination.currentPage = currentPage;
|
||||||
},
|
},
|
||||||
fetchNotificationsCountDenied: (state) => {
|
fetchNotificationsCountDenied: (state) => {
|
||||||
state.notificationStatus = DENIED;
|
state.notificationStatus = RequestStatus.DENIED;
|
||||||
},
|
},
|
||||||
fetchNotificationsCountFailure: (state) => {
|
fetchNotificationsCountFailure: (state) => {
|
||||||
state.notificationStatus = FAILED;
|
state.notificationStatus = RequestStatus.FAILED;
|
||||||
},
|
},
|
||||||
fetchNotificationsCountRequest: (state) => {
|
fetchNotificationsCountRequest: (state) => {
|
||||||
state.notificationStatus = LOADING;
|
state.notificationStatus = RequestStatus.LOADING;
|
||||||
},
|
},
|
||||||
fetchNotificationsCountSuccess: (state, { payload }) => {
|
fetchNotificationsCountSuccess: (state, { payload }) => {
|
||||||
const { countByAppName, count, showNotificationTray } = payload;
|
const {
|
||||||
|
countByAppName, appIds, apps, count, showNotificationTray,
|
||||||
|
} = payload;
|
||||||
state.tabsCount = { count, ...countByAppName };
|
state.tabsCount = { count, ...countByAppName };
|
||||||
state.appsId = Object.keys(countByAppName);
|
state.appsId = appIds;
|
||||||
state.apps = Object.fromEntries(Object.keys(countByAppName).map(key => [key, []]));
|
state.apps = apps;
|
||||||
state.showNotificationTray = showNotificationTray;
|
state.showNotificationTray = showNotificationTray;
|
||||||
state.notificationStatus = LOADED;
|
state.notificationStatus = RequestStatus.LOADED;
|
||||||
},
|
},
|
||||||
markNotificationsAsSeenRequest: (state) => {
|
markNotificationsAsSeenRequest: (state) => {
|
||||||
state.notificationStatus = LOADING;
|
state.notificationStatus = RequestStatus.LOADING;
|
||||||
},
|
},
|
||||||
markNotificationsAsSeenSuccess: (state) => {
|
markNotificationsAsSeenSuccess: (state) => {
|
||||||
state.notificationStatus = LOADED;
|
state.notificationStatus = RequestStatus.LOADED;
|
||||||
},
|
},
|
||||||
markNotificationsAsSeenDenied: (state) => {
|
markNotificationsAsSeenDenied: (state) => {
|
||||||
state.notificationStatus = DENIED;
|
state.notificationStatus = RequestStatus.DENIED;
|
||||||
},
|
},
|
||||||
markNotificationsAsSeenFailure: (state) => {
|
markNotificationsAsSeenFailure: (state) => {
|
||||||
state.notificationStatus = FAILED;
|
state.notificationStatus = RequestStatus.FAILED;
|
||||||
},
|
},
|
||||||
markAllNotificationsAsReadRequest: (state) => {
|
markAllNotificationsAsReadRequest: (state) => {
|
||||||
state.notificationStatus = LOADING;
|
state.notificationStatus = RequestStatus.LOADING;
|
||||||
},
|
},
|
||||||
markAllNotificationsAsReadSuccess: (state) => {
|
markAllNotificationsAsReadSuccess: (state) => {
|
||||||
const updatedNotifications = Object.fromEntries(
|
const updatedNotifications = Object.fromEntries(
|
||||||
@@ -93,27 +92,27 @@ const slice = createSlice({
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
state.notifications = updatedNotifications;
|
state.notifications = updatedNotifications;
|
||||||
state.notificationStatus = LOADED;
|
state.notificationStatus = RequestStatus.LOADED;
|
||||||
},
|
},
|
||||||
markAllNotificationsAsReadDenied: (state) => {
|
markAllNotificationsAsReadDenied: (state) => {
|
||||||
state.notificationStatus = DENIED;
|
state.notificationStatus = RequestStatus.DENIED;
|
||||||
},
|
},
|
||||||
markAllNotificationsAsReadFailure: (state) => {
|
markAllNotificationsAsReadFailure: (state) => {
|
||||||
state.notificationStatus = FAILED;
|
state.notificationStatus = RequestStatus.FAILED;
|
||||||
},
|
},
|
||||||
markNotificationsAsReadRequest: (state) => {
|
markNotificationsAsReadRequest: (state) => {
|
||||||
state.notificationStatus = LOADING;
|
state.notificationStatus = RequestStatus.LOADING;
|
||||||
},
|
},
|
||||||
markNotificationsAsReadSuccess: (state, { payload }) => {
|
markNotificationsAsReadSuccess: (state, { payload }) => {
|
||||||
const date = new Date().toISOString();
|
const date = new Date().toISOString();
|
||||||
state.notifications[payload.id] = { ...state.notifications[payload.id], lastRead: date };
|
state.notifications[payload.id] = { ...state.notifications[payload.id], lastRead: date };
|
||||||
state.notificationStatus = LOADED;
|
state.notificationStatus = RequestStatus.LOADED;
|
||||||
},
|
},
|
||||||
markNotificationsAsReadDenied: (state) => {
|
markNotificationsAsReadDenied: (state) => {
|
||||||
state.notificationStatus = DENIED;
|
state.notificationStatus = RequestStatus.DENIED;
|
||||||
},
|
},
|
||||||
markNotificationsAsReadFailure: (state) => {
|
markNotificationsAsReadFailure: (state) => {
|
||||||
state.notificationStatus = FAILED;
|
state.notificationStatus = RequestStatus.FAILED;
|
||||||
},
|
},
|
||||||
resetNotificationStateRequest: () => initialState,
|
resetNotificationStateRequest: () => initialState,
|
||||||
updateAppNameRequest: (state, { payload }) => {
|
updateAppNameRequest: (state, { payload }) => {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { camelCaseObject } from '@edx/frontend-platform';
|
|
||||||
import {
|
import {
|
||||||
fetchNotificationSuccess,
|
fetchNotificationSuccess,
|
||||||
fetchNotificationRequest,
|
fetchNotificationRequest,
|
||||||
@@ -27,14 +26,29 @@ import {
|
|||||||
} from './api';
|
} from './api';
|
||||||
import { getHttpErrorStatus } from '../utils';
|
import { getHttpErrorStatus } from '../utils';
|
||||||
|
|
||||||
export const fetchNotificationList = ({
|
const normalizeNotificationCounts = ({ countByAppName, count, showNotificationTray }) => {
|
||||||
appName, page, pageSize,
|
const appIds = Object.keys(countByAppName);
|
||||||
}) => (
|
const apps = appIds.reduce((acc, appId) => { acc[appId] = []; return acc; }, {});
|
||||||
|
return {
|
||||||
|
countByAppName, appIds, apps, count, showNotificationTray,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeNotifications = ({ notifications }) => {
|
||||||
|
const newNotificationIds = notifications.map(notification => notification.id.toString());
|
||||||
|
const notificationsKeyValuePair = notifications.reduce((acc, obj) => { acc[obj.id] = obj; return acc; }, {});
|
||||||
|
return {
|
||||||
|
newNotificationIds, notificationsKeyValuePair,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchNotificationList = ({ appName, page, pageSize }) => (
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
dispatch(fetchNotificationRequest({ appName }));
|
dispatch(fetchNotificationRequest({ appName }));
|
||||||
const data = await getNotifications(appName, page, pageSize);
|
const data = await getNotifications(appName, page, pageSize);
|
||||||
dispatch(fetchNotificationSuccess(data));
|
const normalisedData = normalizeNotifications((data));
|
||||||
|
dispatch(fetchNotificationSuccess({ ...normalisedData, numPages: data.numPages, currentPage: data.currentPage }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (getHttpErrorStatus(error) === 403) {
|
if (getHttpErrorStatus(error) === 403) {
|
||||||
dispatch(fetchNotificationDenied(appName));
|
dispatch(fetchNotificationDenied(appName));
|
||||||
@@ -50,7 +64,13 @@ export const fetchAppsNotificationCount = () => (
|
|||||||
try {
|
try {
|
||||||
dispatch(fetchNotificationsCountRequest());
|
dispatch(fetchNotificationsCountRequest());
|
||||||
const data = await getNotificationCounts();
|
const data = await getNotificationCounts();
|
||||||
dispatch(fetchNotificationsCountSuccess(camelCaseObject(data)));
|
const normalisedData = normalizeNotificationCounts((data));
|
||||||
|
dispatch(fetchNotificationsCountSuccess({
|
||||||
|
...normalisedData,
|
||||||
|
countByAppName: data.countByAppName,
|
||||||
|
count: data.count,
|
||||||
|
showNotificationTray: data.showNotificationTray,
|
||||||
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (getHttpErrorStatus(error) === 403) {
|
if (getHttpErrorStatus(error) === 403) {
|
||||||
dispatch(fetchNotificationsCountDenied());
|
dispatch(fetchNotificationsCountDenied());
|
||||||
|
|||||||
@@ -13,33 +13,33 @@ import { selectNotificationTabsCount } from './data/selectors';
|
|||||||
import { resetNotificationState } from './data/thunks';
|
import { resetNotificationState } from './data/thunks';
|
||||||
import { useIsOnLargeScreen, useIsOnMediumScreen } from './data/hook';
|
import { useIsOnLargeScreen, useIsOnMediumScreen } from './data/hook';
|
||||||
import NotificationTabs from './NotificationTabs';
|
import NotificationTabs from './NotificationTabs';
|
||||||
import { messages } from './messages';
|
import messages from './messages';
|
||||||
|
|
||||||
const Notifications = () => {
|
const Notifications = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const popoverRef = useRef(null);
|
const popoverRef = useRef(null);
|
||||||
const buttonRef = useRef(null);
|
const buttonRef = useRef(null);
|
||||||
const [showNotificationTray, setShowNotificationTray] = useState(false);
|
const [enableNotificationTray, setEnableNotificationTray] = useState(false);
|
||||||
const notificationCounts = useSelector(selectNotificationTabsCount());
|
const notificationCounts = useSelector(selectNotificationTabsCount());
|
||||||
const isOnMediumScreen = useIsOnMediumScreen();
|
const isOnMediumScreen = useIsOnMediumScreen();
|
||||||
const isOnLargeScreen = useIsOnLargeScreen();
|
const isOnLargeScreen = useIsOnLargeScreen();
|
||||||
|
|
||||||
const hideNotificationTray = useCallback(() => {
|
const hideNotificationTray = useCallback(() => {
|
||||||
setShowNotificationTray(prevState => !prevState);
|
setEnableNotificationTray(prevState => !prevState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleClickOutside = useCallback((event) => {
|
const handleClickOutsideNotificationTray = useCallback((event) => {
|
||||||
if (!popoverRef.current?.contains(event.target) && !buttonRef.current?.contains(event.target)) {
|
if (!popoverRef.current?.contains(event.target) && !buttonRef.current?.contains(event.target)) {
|
||||||
setShowNotificationTray(false);
|
setEnableNotificationTray(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('mousedown', handleClickOutside);
|
document.addEventListener('mousedown', handleClickOutsideNotificationTray);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('mousedown', handleClickOutside);
|
document.removeEventListener('mousedown', handleClickOutsideNotificationTray);
|
||||||
dispatch(resetNotificationState());
|
dispatch(resetNotificationState());
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
@@ -50,7 +50,7 @@ const Notifications = () => {
|
|||||||
key="bottom"
|
key="bottom"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
id="notificationTray"
|
id="notificationTray"
|
||||||
show={showNotificationTray}
|
show={enableNotificationTray}
|
||||||
overlay={(
|
overlay={(
|
||||||
<Popover
|
<Popover
|
||||||
id="notificationTray"
|
id="notificationTray"
|
||||||
@@ -75,7 +75,7 @@ const Notifications = () => {
|
|||||||
>
|
>
|
||||||
<div ref={buttonRef}>
|
<div ref={buttonRef}>
|
||||||
<IconButton
|
<IconButton
|
||||||
isActive={showNotificationTray}
|
isActive={enableNotificationTray}
|
||||||
alt="notification bell icon"
|
alt="notification bell icon"
|
||||||
onClick={hideNotificationTray}
|
onClick={hideNotificationTray}
|
||||||
src={NotificationsNone}
|
src={NotificationsNone}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
const messages = defineMessages({
|
||||||
export const messages = defineMessages({
|
|
||||||
notificationTitle: {
|
notificationTitle: {
|
||||||
id: 'notification.title',
|
id: 'notification.title',
|
||||||
defaultMessage: 'Notifications',
|
defaultMessage: 'Notifications',
|
||||||
@@ -33,3 +32,5 @@ export const messages = defineMessages({
|
|||||||
description: 'Load more button to load more notifications',
|
description: 'Load more button to load more notifications',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default messages;
|
||||||
|
|||||||
@@ -48,5 +48,5 @@ export const getIconByType = (type) => {
|
|||||||
commentLiked: { icon: ThumbUpOutline, class: 'text-primary-500' },
|
commentLiked: { icon: ThumbUpOutline, class: 'text-primary-500' },
|
||||||
edited: { icon: EditOutline, class: 'text-primary-500' },
|
edited: { icon: EditOutline, class: 'text-primary-500' },
|
||||||
};
|
};
|
||||||
return iconMap[type] || null;
|
return iconMap[type] || { icon: PostOutline, class: 'text-primary-500' };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// eslint-disable-next-line no-unused-vars
|
export default function timeLocale(number, index) {
|
||||||
export default function timeLocale(number, index, totalSec) {
|
|
||||||
return [
|
return [
|
||||||
['just now', 'right now'],
|
['just now', 'right now'],
|
||||||
['%ss', 'in %s seconds'],
|
['%ss', 'in %s seconds'],
|
||||||
|
|||||||
@@ -122,60 +122,67 @@ $white: #fff;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content{
|
.content {
|
||||||
b{
|
|
||||||
color: #00262B;
|
b {
|
||||||
font-weight: 500;
|
color: #00262B !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-size-18{
|
.font-size-18 {
|
||||||
font-size: 18px !important;
|
font-size: 18px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-size-12{
|
.font-size-12 {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-size-14{
|
.font-size-14 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.py-10px{
|
.py-10px {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
.pb-10px{
|
.pb-10px {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-height-24{
|
.line-height-24 {
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-height-20{
|
.line-height-20 {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-height-10{
|
.line-height-10 {
|
||||||
line-height: 10px !important;
|
line-height: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-size-20{
|
.icon-size-20 {
|
||||||
width: 20px !important;
|
width: 20px !important;
|
||||||
height: 20px !important;
|
height: 20px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cursor-pointer{
|
.cursor-pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-button{
|
.notification-button {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-badge{
|
.notification-icon{
|
||||||
|
height: 23.33px !important;
|
||||||
|
width: 23.33px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
margin-left: -21px;
|
margin-left: -21px;
|
||||||
@@ -183,7 +190,7 @@ $white: #fff;
|
|||||||
font-size: 9px !important;
|
font-size: 9px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover{
|
.popover {
|
||||||
max-height: calc(100% - 68px);
|
max-height: calc(100% - 68px);
|
||||||
min-height: 1220px;
|
min-height: 1220px;
|
||||||
filter: none;
|
filter: none;
|
||||||
@@ -201,7 +208,7 @@ $white: #fff;
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expandable{
|
.expandable {
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
@@ -209,36 +216,42 @@ $white: #fff;
|
|||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-toggle{
|
.dropdown-toggle {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 0px !important;
|
padding-top: 0px !important;
|
||||||
padding-bottom: 12px !important;
|
padding-bottom: 12px !important;
|
||||||
div{
|
|
||||||
|
div {
|
||||||
min-height: 6px !important;
|
min-height: 6px !important;
|
||||||
min-width: 6px !important;
|
min-width: 6px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-item{
|
.dropdown-item {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-content{
|
.notification-content {
|
||||||
.notification-item-content{
|
|
||||||
p{
|
.notification-item-content {
|
||||||
|
|
||||||
|
p {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
b{
|
|
||||||
|
b {
|
||||||
color: #00262B;
|
color: #00262B;
|
||||||
}
|
}
|
||||||
|
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unread{
|
.unread {
|
||||||
height: 10px;
|
height: 10px;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useSelector, useDispatch } from 'react-redux';
|
|||||||
import Notifications from '../Notifications';
|
import Notifications from '../Notifications';
|
||||||
import { selectShowNotificationTray, selectNotificationStatus } from '../Notifications/data/selectors';
|
import { selectShowNotificationTray, selectNotificationStatus } from '../Notifications/data/selectors';
|
||||||
import { fetchAppsNotificationCount } from '../Notifications/data/thunks';
|
import { fetchAppsNotificationCount } from '../Notifications/data/thunks';
|
||||||
import { IDLE } from '../Notifications/data/slice';
|
import { RequestStatus } from '../Notifications/data/slice';
|
||||||
|
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ const AuthenticatedUserDropdown = ({ intl, username }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (notificationStatus === IDLE) {
|
if (notificationStatus === RequestStatus.IDLE) {
|
||||||
dispatch(fetchAppsNotificationCount());
|
dispatch(fetchAppsNotificationCount());
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
|||||||
Reference in New Issue
Block a user