forked from steemit/condenser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UniversalRender.jsx
197 lines (182 loc) · 7.75 KB
/
UniversalRender.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* eslint react/display-name: 0 */
/* eslint space-before-function-paren:0 */
// https://github.com/eslint/eslint/issues/4442
import Iso from 'iso';
import React from 'react';
import { render } from 'react-dom';
import { renderToString } from 'react-dom/server';
import { Router, RouterContext, match, applyRouterMiddleware } from 'react-router';
import Apis from './api_client/ApiInstances';
import { Provider } from 'react-redux';
import RootRoute from 'app/RootRoute';
import ErrorPage from 'server/server-error';
import {createStore, applyMiddleware, compose} from 'redux';
import { browserHistory } from 'react-router';
//import useScroll from 'scroll-behavior/lib/useStandardScroll';
import useScroll from 'react-router-scroll';
import createSagaMiddleware from 'redux-saga';
import { syncHistoryWithStore } from 'react-router-redux';
import rootReducer from 'app/redux/RootReducer';
// import DevTools from 'app/redux/DevTools';
import {fetchDataWatches} from 'app/redux/FetchDataSaga';
import {marketWatches} from 'app/redux/MarketSaga';
import {sharedWatches} from 'app/redux/SagaShared';
import {userWatches} from 'app/redux/UserSaga';
import {authWatches} from 'app/redux/AuthSaga';
import {transactionWatches} from 'app/redux/TransactionSaga';
import PollDataSaga from 'app/redux/PollDataSaga';
import {component as NotFound} from 'app/components/pages/NotFound';
import extractMeta from 'app/utils/ExtractMeta';
import {serverApiRecordEvent} from 'app/utils/ServerApiClient';
import Translator from 'app/Translator';
const sagaMiddleware = createSagaMiddleware(
...userWatches, // keep first to remove keys early when a page change happens
...fetchDataWatches,
...sharedWatches,
...authWatches,
...transactionWatches,
...marketWatches
);
let middleware;
if (process.env.BROWSER && process.env.NODE_ENV === 'development') {
middleware = compose(
applyMiddleware(sagaMiddleware)
// DevTools.instrument()
);
} else {
middleware = applyMiddleware(sagaMiddleware);
}
const runRouter = (location, routes) => {
return new Promise((resolve) =>
match({routes, location}, (...args) => resolve(args)));
};
const onRouterError = (error) => {
console.error('onRouterError', error);
};
async function universalRender({ location, initial_state, offchain }) {
let error, redirect, renderProps;
try {
[error, redirect, renderProps] = await runRouter(location, RootRoute);
} catch (e) {
console.error('Router error:', e.toString(), location);
return {
title: 'Server error (500) - Steemit',
statusCode: 500,
body: renderToString(<ErrorPage />)
};
}
if (error || !renderProps) {
// debug('error')('Router error', error);
return {
title: 'Page Not Found (404) - Steemit',
statusCode: 404,
body: renderToString(<NotFound />)
};
}
if (process.env.BROWSER) {
const store = createStore(rootReducer, initial_state, middleware);
sagaMiddleware.run(PollDataSaga).done
.then(() => console.log('PollDataSaga is finished'))
.catch(err => console.log('PollDataSaga is finished with error', err));
const ws_connection_status_cb = status => {
store.dispatch({type: 'WS_CONNECTION_STATUS', payload: {status}});
};
const ws_request_status_cb = payload => {
store.dispatch({type: 'RPC_REQUEST_STATUS', payload});
};
try {
await Apis.instance(ws_connection_status_cb, ws_request_status_cb).init();
} catch (e) {
console.error('Api init error: ', e);
if (e.toString && e.toString().match(/ReferenceError.+WebSocket/)) {
const message = 'Warning! This browser does not support web sockets communication, some elements of the website may not be displayed properly. Please upgrade your browser.';
store.dispatch({type: 'ADD_NOTIFICATION', payload: {key: 'websocket', message}});
} else {
serverApiRecordEvent('client_error', e);
}
}
const history = syncHistoryWithStore(browserHistory, store);
// const scrollHistory = useScroll(() => history)();
window.store = {
getState: () => {debugger}
}
// Bump transaction (for live UI testing).. Put 0 in now (no effect),
// to enable browser's autocomplete and help prevent typos.
window.bump = parseInt(localStorage.getItem('bump') || 0);
const scroll = useScroll((prevLocation, {location}) => {
if (location.hash || location.action === 'POP') return false;
return !prevLocation || prevLocation.location.pathname !== location.pathname;
});
if (process.env.NODE_ENV === 'production') {
console.log('%c%s','color: red; background: yellow; font-size: 24px;', 'WARNING!');
console.log('%c%s','color: black; font-size: 16px;', 'This is a developer console, you must read and understand anything you paste or type here or you could compromise your account and your private keys.');
}
return render(
<Provider store={store}>
<Translator>
<Router
routes={RootRoute}
history={history}
onError={onRouterError}
render={applyRouterMiddleware(scroll)} />
</Translator>
</Provider>,
document.getElementById('content')
);
}
// below is only executed on the server
let server_store, onchain;
try {
let url = location === '/' ? 'trending' : location;
// Replace /curation-rewards and /author-rewards with /transfers for UserProfile
// to resolve data correctly
if (url.indexOf('/curation-rewards') !== -1) url = url.replace(/\/curation-rewards$/, '/transfers');
if (url.indexOf('/author-rewards') !== -1) url = url.replace(/\/author-rewards$/, '/transfers');
onchain = await Apis.instance().db_api.exec('get_state', [url]);
// Calculate signup bonus
const fee = parseFloat($STM_Config.registrar_fee.split(' ')[0]),
{base, quote} = onchain.feed_price,
feed = parseFloat(base.split(' ')[0]) / parseFloat(quote.split(' ')[0]);
const sd = fee * feed,
sdInt = parseInt(sd),
sdDec = (sd - sdInt),
sdDisp = '$' + sdInt + (sdInt < 5 && sdDec >= 0.5 ? '.50' : '');
offchain.signup_bonus = sdDisp;
offchain.server_location = location;
server_store = createStore(rootReducer, { global: onchain, offchain});
server_store.dispatch({type: '@@router/LOCATION_CHANGE', payload: {pathname: location}});
} catch (e) {
const msg = (e.toString && e.toString()) || e.message || e;
const stack_trace = e.stack || '[no stack]';
console.error('State/store error: ', msg, stack_trace);
return {
title: 'Server error (500) - Steemit',
statusCode: 500,
body: renderToString(<ErrorPage />)
};
}
let app, status, meta;
try {
app = renderToString(
<Provider store={server_store}>
<Translator>
<RouterContext { ...renderProps } />
</Translator>
</Provider>
);
meta = extractMeta(onchain, renderProps.params);
status = 200;
} catch (re) {
console.error('Rendering error: ', re, re.stack);
app = renderToString(<ErrorPage />);
status = 500;
}
return {
title: 'Steemit',
titleBase: 'Steemit - ',
meta,
statusCode: status,
body: Iso.render(app, server_store.getState())
};
}
export default universalRender;