Skip to content

Commit 588ed26

Browse files
committed
SSR fixes
1 parent a28aff4 commit 588ed26

File tree

5 files changed

+65
-85
lines changed

5 files changed

+65
-85
lines changed

package-lock.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
"topcoder-react-ui-kit": "2.0.1",
169169
"topcoder-react-utils": "0.7.8",
170170
"turndown": "^4.0.2",
171+
"uninav-react": "git+https://github.com/topcoder-platform/uninav-react.git#0.0.1",
171172
"url-parse": "^1.4.1",
172173
"uuid": "^3.3.2",
173174
"valid-url": "^1.0.9",
Lines changed: 49 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,51 @@
1-
/* global tcUniNav */
2-
import React, { useEffect, useMemo, useRef } from 'react';
1+
import React, { useMemo } from 'react';
32
import PT from 'prop-types';
43
import { connect } from 'react-redux';
4+
import { withRouter } from 'react-router-dom';
55
import { config } from 'topcoder-react-utils';
66
import LoadingIndicator from 'components/LoadingIndicator';
77
import _ from 'lodash';
8-
import { getInitials, getSubPageConfiguration } from '../../utils/url';
9-
import { SSRPlaceholder } from '../../utils/SSR';
8+
import { MarketingNavigation, ToolNavigation } from 'uninav-react';
9+
import { getSubPageConfiguration } from '../../utils/url';
1010
import './styles.scss';
1111

12-
let counter = 0;
13-
const headerElIdTmpl = 'uninav-headerNav';
14-
15-
const TopcoderHeader = ({ auth }) => {
16-
const uniNavInitialized = useRef(false);
12+
const TopcoderHeader = ({ auth, location }) => {
1713
const user = _.get(auth, 'profile') || {};
1814
const authToken = _.get(auth, 'tokenV3');
1915
const isAuthenticated = !!authToken;
2016
const authURLs = config.HEADER_AUTH_URLS;
21-
const headerRef = useRef();
22-
const headerElId = useRef(`${headerElIdTmpl}-${counter}`);
23-
24-
const navType = useMemo(() => {
25-
if (typeof window === 'undefined') {
26-
return '';
27-
}
28-
29-
let { type } = getSubPageConfiguration();
30-
31-
// if there's a stored nav type in session storage, retrieve it and overwrite type
32-
const sessionNavType = sessionStorage.getItem('uni-nav[navType]');
33-
const url = new URL(window.location.href);
34-
35-
// Only use the set sessionStorage value for navType on the /thrive paths, for now.
36-
// Probably will change in the future...
37-
if (window.location.href.indexOf('/thrive') > -1 && sessionNavType && (sessionNavType === 'tool' || sessionNavType === 'marketing')) {
38-
type = sessionNavType;
17+
const pageCfg = useMemo(() => getSubPageConfiguration(location, user.handle), [location, user]);
18+
const isSSR = typeof window === 'undefined';
19+
20+
const NavComponent = useMemo(() => {
21+
let { type } = pageCfg;
22+
23+
if (!isSSR) {
24+
// if there's a stored nav type in session storage, retrieve it and overwrite type
25+
const sessionNavType = sessionStorage.getItem('uni-nav[navType]');
26+
if (location.pathname.includes() && sessionNavType && (sessionNavType === 'tool' || sessionNavType === 'marketing')) {
27+
type = sessionNavType;
28+
}
3929
}
4030

4131
// If url contains navTool url parameter. Overwrite settings with parameter.
42-
const urlParams = new URLSearchParams(url.search);
43-
if (urlParams.get('navTool')) {
44-
type = urlParams.get('navTool');
32+
const navTool = (location.search.match(/navTool=(tool|marketing)/) || [])[1];
33+
if (navTool) {
34+
type = navTool;
4535
}
4636

47-
// store nav type for current session
48-
sessionStorage.setItem('uni-nav[navType]', type);
49-
return type;
50-
}, []);
51-
52-
const navigationUserInfo = {
53-
...user,
54-
initials: getInitials(user.firstName, user.lastName),
55-
};
56-
57-
useEffect(() => {
58-
if (uniNavInitialized.current) {
59-
return;
37+
if (!isSSR) {
38+
// store nav type for current session
39+
sessionStorage.setItem('uni-nav[navType]', type);
6040
}
61-
headerRef.current.id = headerElId.current;
62-
63-
uniNavInitialized.current = true;
64-
65-
counter += 1;
41+
return type === 'marketing' ? MarketingNavigation : ToolNavigation;
42+
}, [pageCfg, location]);
6643

67-
const regSource = window.location.pathname.split('/')[1];
68-
const retUrl = encodeURIComponent(window.location.href);
44+
const { signOut, signIn, signUp } = useMemo(() => {
45+
const regSource = (location.pathname || '').split('/')[1];
46+
const retUrl = encodeURIComponent(isSSR ? location.href : window.location.href);
6947

70-
tcUniNav('init', headerElId.current, {
71-
type: navType,
72-
toolName: getSubPageConfiguration(user.handle).toolName,
73-
toolRoot: getSubPageConfiguration(user.handle).toolRoot,
74-
user: 'auto',
48+
return {
7549
signOut: () => {
7650
window.location = `${config.URL.BASE}/logout?ref=nav`;
7751
},
@@ -81,41 +55,39 @@ const TopcoderHeader = ({ auth }) => {
8155
signUp: () => {
8256
window.location = `${authURLs.location.replace('%S', retUrl).replace('member?', '#!/member?')}&mode=signUp&regSource=${regSource}`;
8357
},
84-
});
85-
}, [navType]);
86-
87-
useEffect(() => {
88-
tcUniNav('update', headerElId.current, {
89-
toolName: getSubPageConfiguration(user.handle).toolName,
90-
user: isAuthenticated ? navigationUserInfo : null,
91-
});
92-
}, [isAuthenticated, navigationUserInfo]);
58+
};
59+
}, [location]);
9360

9461
return (
95-
<div styleName="header-container" id={headerElId.current} ref={headerRef} />
62+
<div styleName="header-container">
63+
<NavComponent
64+
toolName={pageCfg.toolName}
65+
toolRoot={pageCfg.toolRoot}
66+
user={isAuthenticated ? user : undefined}
67+
signIn={signIn}
68+
signOut={signOut}
69+
signUp={signUp}
70+
currentLocation={location.pathname}
71+
>
72+
<div styleName="loader">
73+
<LoadingIndicator />
74+
</div>
75+
</NavComponent>
76+
</div>
9677
);
9778
};
9879
TopcoderHeader.defaultProps = {
9980
auth: {},
81+
location: typeof window === 'undefined' ? {} : window.location,
10082
};
10183

10284
TopcoderHeader.propTypes = {
10385
auth: PT.shape(),
86+
location: PT.shape(), // sent from withRouter
10487
};
10588

10689
const mapStateToProps = state => ({
10790
auth: state.auth,
10891
});
10992

110-
const TopcoderHeaderConnect = connect(mapStateToProps, null)(TopcoderHeader);
111-
112-
const TopcoderHeaderPlaceholder = () => (
113-
<div styleName="header-container header-container-placeholder">
114-
<LoadingIndicator />
115-
</div>
116-
);
117-
118-
export default SSRPlaceholder()(
119-
TopcoderHeaderConnect,
120-
TopcoderHeaderPlaceholder,
121-
);
93+
export default connect(mapStateToProps, null)(withRouter(TopcoderHeader));
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
@import '~styles/mixins';
2-
31
.header-container {
4-
min-height: 60px;
5-
background-color: #0c0c0c;
2+
position: relative;
63
}
74

8-
.header-container-placeholder {
9-
height: 60px;
5+
.loader {
6+
position: absolute;
7+
top: 0;
8+
left: 0;
9+
right: 0;
10+
bottom: 0;
11+
display: flex;
12+
align-items: center;
13+
justify-content: center;
1014
}

src/shared/utils/url.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ export function getInitials(firstName = '', lastName = '') {
164164

165165
export const DEFAULT_AVATAR_URL = 'https://images.ctfassets.net/b5f1djy59z3a/4PTwZVSf3W7qgs9WssqbVa/4c51312671a4b9acbdfd7f5e22320b62/default_avatar.svg';
166166

167-
export const getSubPageConfiguration = (loginUserHandle) => {
167+
export const getSubPageConfiguration = (location, loginUserHandle) => {
168168
let toolName = 'Community';
169169
let toolRoot = '/';
170170
let loginRedirect = '/';
171171
let type = 'marketing';
172172
let fullFooter = true;
173173

174-
const url = window.location.pathname;
174+
const url = (location || window.location).pathname;
175175

176176
if (url.includes('/gigs')) {
177177
toolName = 'Gigs';

0 commit comments

Comments
 (0)