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: added notification preference ui #784

Merged
merged 1 commit into from
May 22, 2023
Merged

Conversation

muhammadadeeltajamul
Copy link
Contributor

@muhammadadeeltajamul muhammadadeeltajamul commented May 4, 2023

Added Notification Preferences UI components.

  • JumpNav component will have a new option
  • Created new page that will all the active courses in which user is enrolled in
  • When a user will select a course, he/she will be redirected to preferences page of the selected course

Tests will be added after api integration

@codecov
Copy link

codecov bot commented May 4, 2023

Codecov Report

Patch coverage: 1.17% and project coverage change: -2.60 ⚠️

Comparison is base (f2f761e) 38.63% compared to head (01f24b4) 36.04%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #784      +/-   ##
==========================================
- Coverage   38.63%   36.04%   -2.60%     
==========================================
  Files         110      121      +11     
  Lines        2288     2458     +170     
  Branches      624      652      +28     
==========================================
+ Hits          884      886       +2     
- Misses       1319     1483     +164     
- Partials       85       89       +4     
Impacted Files Coverage Δ
src/account-settings/AccountSettingsPage.jsx 0.00% <ø> (ø)
.../account-settings/AccountSettingsPage.messages.jsx 100.00% <ø> (ø)
src/data/reducers.js 0.00% <ø> (ø)
src/index.jsx 0.00% <0.00%> (ø)
...c/notification-preferences/NotificationCourses.jsx 0.00% <0.00%> (ø)
...cation-preferences/NotificationPreferenceGroup.jsx 0.00% <0.00%> (ø)
...fication-preferences/NotificationPreferenceRow.jsx 0.00% <0.00%> (ø)
...tification-preferences/NotificationPreferences.jsx 0.00% <0.00%> (ø)
src/notification-preferences/ToggleSwitch.jsx 0.00% <0.00%> (ø)
src/notification-preferences/data/actions.js 0.00% <0.00%> (ø)
... and 6 more

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.


// eslint-disable-next-line import/prefer-default-export
export const messages = defineMessages({
notificationHeading: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "Notifications" instead of "Notification" as defaultMessage: 'Notification',

Comment on lines 28 to 53
<Link
to={`/notifications/${course.id}`}
>
<div className="mb-4">
{course.name}
</div>
</Link>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forward arrow as per figma is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

if (notificationStatus === IDLE_STATUS) {
dispatch(fetchCourseNotificationPreferences(courseId));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this lint disable next line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependencies it requires will cause few extra re-renders. So disabling lint for this line is better.

return null;
}
return (
<div className="ml-auto mr-auto" style={{ width: '828px' }}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can add css class for width 828px because same width is using in NotificationCourses.jsx also.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added class

<span className="ml-auto mr-0 pr-2.5">{intl.formatMessage(messages.notificationHelpPush)}</span>
</span>
</div>
<div className="mt-3 pb-5.5">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

padding bottom is 48px in figma currently its showing 64px

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

Comment on lines +3 to +4
// import { getConfig } from '@edx/frontend-platform';
// import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented code if they are of no use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are required imports that will be added when integrating API's.

Comment on lines +7 to +8
// const url = `${getConfig().LMS_BASE_URL}/api/notifications/${courseId}`;
// const { data } = await getAuthenticatedHttpClient().get(url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented code if they are of no use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is API call for it that will bring data whose structure will be same as dummy data. It will be removed when integrating API's

// const { data } = await getAuthenticatedHttpClient().get(url);
return [
{ id: 'course-v1:edX+Supply+Demo_Course', name: 'Supply Chain Analytics' },
{ id: 'course-v1:edX+Happiness+At+Work_Course', name: 'The Foundation of Happiness At Work' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

title issue replace with "The Foundations of Happiness at Work"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a dummy data... it will be removed when integrating api's.

return [
{ id: 'course-v1:edX+Supply+Demo_Course', name: 'Supply Chain Analytics' },
{ id: 'course-v1:edX+Happiness+At+Work_Course', name: 'The Foundation of Happiness At Work' },
{ id: 'course-v1:edX+Empathy+At+Work_Course', name: 'Empathy and Emotional Intelligence At Work' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

title issue kindly replace with "Empathy and Emotional Intelligence at Work"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. This is also dummy data...

@@ -565,6 +565,11 @@ const messages = defineMessages({
defaultMessage: 'No value set.',
description: 'The placeholder for an empty but uneditable field when there is no administrator',
},
'notification.preferences.notifications.text': {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notification.preferences.notifications.label

{showNotificationMenu
&& (
<>
<hr className="ml-0" style={{ width: '180px' }} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not add specific width for the divider. It should inherit the width from a parent. Adjust the parent width according to Figma.

@@ -1,11 +1,16 @@
/* eslint-disable import/no-named-default */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default export the notificationPreferencesReducer from the component.

Comment on lines 8 to 10
import {
default as notificationPreferencesReducer,
} from '../notification-preferences/data/reducers';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import notificationPreferencesReducer from '../notification-preferences/data/reducers';

src/index.scss Outdated
Comment on lines 78 to 80
.w-66 {
width: 66%;
}

.w-34 {
width: 34%;
}

.w-828px {
width: 828px;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using responsive class from paragon.

preferenceName: PropTypes.string.isRequired,
};

export default injectIntl(NotificationPreferenceRow);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memoize this component

Comment on lines 13 to 15
const onToggle = (checked, notificationFor) => {
dispatch(updatePreferenceValue(groupKey, preferenceName, notificationFor, checked));
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memoize this callback

};
return (
<div className="d-flex flex-row mb-3">
<span className="w-66">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use col class from paragon

onChange: () => null,
};

export default ToggleSwitch;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memoize this component

Comment on lines 7 to 21
export const getCourse = courseId => state => (
state.notificationPreferences.courses.courses.find(
element => element.id === courseId,
)
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change element to course.
call getCourseList selector instead of state.notificationPreferences.courses.courses

Comment on lines +22 to +33
if (courseStatus === LOADING_STATUS) {
return (
<div className="d-flex h-100">
<Spinner
variant="primary"
animation="border"
className="mx-auto my-auto"
style={{ width: '4rem', height: '4rem' }}
/>
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can memo this like

const SpinnerComp = useMemo(() => {
if (courseStatus === LOADING_STATUS) {
return (


<Spinner
variant="primary"
animation="border"
className="mx-auto my-auto"
style={{ width: '4rem', height: '4rem' }}
/>

);
}
return null;
}, [courseStatus]);
if (SpinnerComp) { return SpinnerComp; }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this component is not being rendered multiple times, hence memoization is not required. Excessive memoization should be avoided in code

intl: intlShape.isRequired,
};

export default injectIntl(NotificationCourses);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo this
export default injectIntl(React.memo(NotificationCourses));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotificationCourses component is not taking any props (except intl). I don't think that React.memo will be helpful

const preference = useSelector(getPreferenceAttribute(groupId, preferenceName));
const onToggle = useCallback((checked, notificationChannel) => {
dispatch(updatePreferenceValue(groupId, preferenceName, notificationChannel, checked));
}, [dispatch, groupId, preferenceName]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to pass dispatch here, instead pass updatePreferenceValue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updatePreferenceValue is a function. I don't think we need to pass function in dependency list. Added dispatch to avoid disabling lint for this line

Comment on lines +43 to +57
if (notificationStatus === LOADING_STATUS) {
return (
<div className="d-flex h-100">
<Spinner
variant="primary"
animation="border"
className="mx-auto my-auto"
style={{ width: '4rem', height: '4rem' }}
/>
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can memo this like

const SpinnerComp = useMemo(() => {
if (notificationStatus === LOADING_STATUS) {
return (


<Spinner
variant="primary"
animation="border"
className="mx-auto my-auto"
style={{ width: '4rem', height: '4rem' }}
/>

);
}
return null;
}, [notificationStatus]);
if (SpinnerComp) { return SpinnerComp; }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memoization not required here

);
};

export default NotificationPreferences;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo this component
export default React.memo(NotificationPreferences);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotificationPreferences component has no props. React.memo will not be of any use

import PropTypes from 'prop-types';

const ToggleSwitch = ({ value, onChange }) => (
<Form.Switch checked={value} onChange={(event) => onChange(event.target.checked)} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add callback function for onChange

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onChange is being passed as prop from NotificationPreferenceGroup and from NotificationPreferenceRow. These calls have been wrapped in useCallback there

Comment on lines 27 to 37
const preferenceGroups = useSelector(getPreferenceGroupIds());
const preferencesList = useMemo(() => (
preferenceGroups.map(key => (
<NotificationPreferenceGroup groupId={key} key={key} />
))
), [preferenceGroups]);
useEffect(() => {
dispatch(updateSelectedCourse(courseId));
if (courseStatus !== SUCCESS_STATUS) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add newline between logics

@muhammadadeeltajamul muhammadadeeltajamul merged commit 1927146 into master May 22, 2023
@muhammadadeeltajamul muhammadadeeltajamul deleted the inf-863 branch May 22, 2023 01:17
snglth pushed a commit to Abstract-Tech/community-theme-account that referenced this pull request Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants