Skip to content

Commit c9ff6f4

Browse files
authored
Merge pull request #4151 from topcoder-platform/develop
Feature : notifications
2 parents b262215 + b51436e commit c9ff6f4

File tree

16 files changed

+858
-14
lines changed

16 files changed

+858
-14
lines changed

.circleci/config.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,15 @@ workflows:
175175
branches:
176176
only:
177177
- develop
178+
- feature-stats-history
178179
# This is alternate dev env for parallel testing
179180
- "build-test":
180181
context : org-global
181182
filters:
182183
branches:
183184
only:
184-
- nav-hot-fix
185+
- develop
186+
- notifications
185187
# This is beta env for production soft releases
186188
- "build-prod-beta":
187189
context : org-global

__tests__/shared/components/Header/__snapshots__/index.jsx.snap

+3-2
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,15 @@ exports[`Default render 1`] = `
155155
},
156156
]
157157
}
158+
auth={null}
158159
authURLs={
159160
Object {
160161
"href": "https://accounts.topcoder-dev.com/member/registration?utm_source=community-app-main",
161162
"location": "https://accounts.topcoder-dev.com/member?retUrl=%S&utm_source=community-app-main",
162163
}
163164
}
164165
loggedIn={true}
165-
notificationButtonState="none"
166+
notificationButtonState="new"
166167
notifications={Array []}
167168
onMenuOpen={[Function]}
168169
onSwitch={[Function]}
@@ -174,7 +175,7 @@ exports[`Default render 1`] = `
174175
"photoURL": "https://d1aahxkjiobka8.cloudfront.net/avatar/https%3A%2F%2Ftopcoder-dev-media.s3.amazonaws.com%2Fmember%2Fprofile%2Fhuanner-1552562543506.png?size=32",
175176
}
176177
}
177-
showNotification={false}
178+
showNotification={true}
178179
switchText={
179180
Object {
180181
"href": "https://connect.topcoder-dev.com",

__tests__/shared/containers/__snapshots__/TopcoderHeader.jsx.snap

+11
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,20 @@
22

33
exports[`Matches shallow snapshot 1`] = `
44
<Header
5+
auth={
6+
Object {
7+
"profile": Object {},
8+
}
9+
}
510
closeMenu={[Function]}
611
closeMobileMenu={[Function]}
712
closeSearch={[Function]}
13+
dismissChallengeNotifications={[Function]}
14+
loadNotifications={[Function]}
15+
markAllNotificationAsRead={[Function]}
16+
markAllNotificationAsSeen={[Function]}
17+
markNotificationAsRead={[Function]}
18+
notifications={Array []}
819
openMenu={[Function]}
920
openMobileMenu={[Function]}
1021
openSearch={[Function]}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@
127127
"supertest": "^3.1.0",
128128
"tc-accounts": "git+https://github.com/appirio-tech/accounts-app.git#dev",
129129
"tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3",
130+
"topcoder-react-lib": "0.13.0",
130131
"tc-ui": "^1.0.12",
131-
"topcoder-react-lib": "0.12.0",
132132
"topcoder-react-ui-kit": "^1.0.11",
133133
"topcoder-react-utils": "0.7.8",
134134
"turndown": "^4.0.2",
Loading

src/shared/components/Header/index.jsx

+32-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ try {
1616
// window is undefined
1717
}
1818

19-
const Header = ({ profile }) => {
19+
const Header = ({
20+
profile, auth, notifications, loadNotifications, markNotificationAsRead,
21+
markAllNotificationAsRead, markAllNotificationAsSeen, dismissChallengeNotifications,
22+
}) => {
2023
const [activeLevel1Id, setActiveLevel1Id] = useState();
2124
const [path, setPath] = useState();
2225
const [openMore, setOpenMore] = useState(true);
@@ -48,6 +51,17 @@ const Header = ({ profile }) => {
4851
useEffect(() => {
4952
setPath(window.location.pathname);
5053
}, []);
54+
55+
/*
56+
* Reload notificaitons if token was changed
57+
* This prevent to use expired token in API call
58+
*/
59+
if (auth) {
60+
useEffect(() => {
61+
loadNotifications(auth.tokenV3);
62+
}, [auth.tokenV3]);
63+
}
64+
5165
if (TopNavRef) {
5266
return (
5367
<div>
@@ -56,13 +70,19 @@ const Header = ({ profile }) => {
5670
rightMenu={(
5771
<LoginNavRef
5872
loggedIn={!_.isEmpty(profile)}
59-
notificationButtonState="none"
60-
notifications={[]}
73+
notificationButtonState="new"
74+
notifications={notifications || []}
75+
loadNotifications={loadNotifications}
76+
markNotificationAsRead={markNotificationAsRead}
77+
markAllNotificationAsRead={markAllNotificationAsRead}
78+
markAllNotificationAsSeen={markAllNotificationAsSeen}
79+
dismissChallengeNotifications={dismissChallengeNotifications}
6180
accountMenu={config.ACCOUNT_MENU}
6281
switchText={config.ACCOUNT_MENU_SWITCH_TEXT}
6382
onSwitch={handleSwitchMenu}
6483
onMenuOpen={handleCloseOpenMore}
65-
showNotification={false}
84+
showNotification
85+
auth={auth}
6686
profile={normalizedProfile}
6787
authURLs={config.HEADER_AUTH_URLS}
6888
/>
@@ -86,13 +106,21 @@ const Header = ({ profile }) => {
86106

87107
Header.defaultProps = {
88108
profile: null,
109+
auth: null,
89110
};
90111

91112
Header.propTypes = {
92113
profile: PT.shape({
93114
photoURL: PT.string,
94115
handle: PT.string,
95116
}),
117+
auth: PT.shape(),
118+
notifications: PT.arrayOf(PT.object).isRequired,
119+
loadNotifications: PT.func.isRequired,
120+
markNotificationAsRead: PT.func.isRequired,
121+
markAllNotificationAsRead: PT.func.isRequired,
122+
markAllNotificationAsSeen: PT.func.isRequired,
123+
dismissChallengeNotifications: PT.func.isRequired,
96124
};
97125

98126
export default Header;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import cn from 'classnames';
4+
import styles from './style.scss';
5+
6+
7+
const TABS = {
8+
COMPLETED: 'completed',
9+
BROADCAST: 'broadcast',
10+
ACTIVE: 'active',
11+
};
12+
13+
export default class TabsPanel extends React.Component {
14+
constructor(props) {
15+
super(props);
16+
this.state = {
17+
tab: TABS.ACTIVE,
18+
};
19+
}
20+
21+
22+
render() {
23+
const { changeTab } = this.props;
24+
const { tab } = this.state;
25+
return (
26+
<div className={styles.container}>
27+
<div className={styles.lefts}>
28+
<div
29+
className={cn([styles.btn, tab === TABS.ACTIVE && styles.active])}
30+
role="tab"
31+
tabIndex="0"
32+
onClick={
33+
() => {
34+
this.setState({ tab: TABS.ACTIVE });
35+
changeTab(TABS.ACTIVE);
36+
}
37+
}
38+
onKeyPress={
39+
() => {
40+
this.setState({ tab: TABS.ACTIVE });
41+
changeTab(TABS.ACTIVE);
42+
}
43+
}
44+
>CHALLENGES
45+
</div>
46+
<div
47+
className={cn([styles.btn, tab === TABS.BROADCAST && styles.active])}
48+
role="tab"
49+
tabIndex="0"
50+
onClick={
51+
() => {
52+
this.setState({ tab: TABS.BROADCAST });
53+
changeTab(TABS.BROADCAST);
54+
}
55+
}
56+
onKeyPress={
57+
() => {
58+
this.setState({ tab: TABS.BROADCAST });
59+
changeTab(TABS.BROADCAST);
60+
}
61+
}
62+
>NOTIFICATIONS
63+
</div>
64+
{/*
65+
* Disabled until Backend updated (add flag completed in notifications)
66+
*
67+
<div
68+
className={cn([styles.btn, tab === TABS.COMPLETED && styles.active])}
69+
role="tab"
70+
tabIndex="0"
71+
onClick={
72+
() => {
73+
this.setState({ tab: TABS.COMPLETED });
74+
changeTab(TABS.COMPLETED);
75+
}
76+
}
77+
onKeyPress={
78+
() => {
79+
this.setState({ tab: TABS.COMPLETED });
80+
changeTab(TABS.COMPLETED);
81+
}
82+
}
83+
>COMPLETED CHALLENGES
84+
</div>
85+
*/}
86+
</div>
87+
{/*
88+
* Disabled until Settings page is ready
89+
*
90+
<div className={styles.rights}>
91+
<div className={styles['notification-setting']}>Notification Settings</div>
92+
</div>
93+
*/}
94+
</div>
95+
);
96+
}
97+
}
98+
99+
100+
TabsPanel.propTypes = {
101+
changeTab: PropTypes.func.isRequired,
102+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
@import "~styles/mixins";
2+
3+
.container {
4+
display: flex;
5+
justify-content: space-between;
6+
width: 100%;
7+
height: 30px;
8+
margin-top: 50px;
9+
margin-bottom: 20px;
10+
11+
.lefts {
12+
display: flex;
13+
justify-content: space-between;
14+
15+
.btn {
16+
@include roboto-bold;
17+
18+
color: #2a2a2a;
19+
background-color: $tc-white;
20+
font-size: 12px;
21+
font-weight: 400;
22+
text-transform: uppercase;
23+
line-height: 30px;
24+
text-align: center;
25+
height: 30px;
26+
padding: 0 15px;
27+
cursor: pointer;
28+
29+
&:not(:first-of-type) {
30+
margin-left: 5px;
31+
}
32+
}
33+
34+
.active {
35+
color: #fff;
36+
background-color: #7f7f7f;
37+
box-shadow: inset 0 0 2px 0 rgba(0, 0, 0, 0.25);
38+
border-radius: 15px;
39+
}
40+
}
41+
42+
.rights {
43+
.notification-setting {
44+
color: #0d61bf;
45+
46+
@include roboto-bold;
47+
48+
font-size: 14px;
49+
font-weight: 400;
50+
line-height: 22px;
51+
text-align: left;
52+
text-decoration: underline;
53+
cursor: pointer;
54+
}
55+
}
56+
}
57+
58+
@media (max-width: $screen-sm + 1px) {
59+
.container {
60+
margin: 15px 0;
61+
}
62+
}

0 commit comments

Comments
 (0)