* fix(auth): Route should have specific targets * fix(signup): Redirection should be to signup Closes #16945 * feat(redirect): All fallback redirects to signin * fix: send back to originating route * fix(server,secrets): Specify profile field for LinkedIn provider. * fix(profile): Add route to react profile page
106 lines
2.9 KiB
JavaScript
106 lines
2.9 KiB
JavaScript
import debug from 'debug';
|
|
import { renderToString } from 'react-dom/server';
|
|
import createMemoryHistory from 'history/createMemoryHistory';
|
|
import { NOT_FOUND } from 'redux-first-router';
|
|
import devtoolsEnhancer from 'remote-redux-devtools';
|
|
|
|
import {
|
|
errorThrowerMiddleware
|
|
} from '../utils/react.js';
|
|
import { createApp, provideStore, App } from '../../common/app';
|
|
import waitForEpics from '../../common/utils/wait-for-epics.js';
|
|
import { titleSelector } from '../../common/app/redux';
|
|
|
|
const log = debug('fcc:react-server');
|
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
|
|
// add routes here as they slowly get reactified
|
|
// remove their individual controllers
|
|
const routes = [
|
|
'/challenges',
|
|
'/challenges/*',
|
|
'/map',
|
|
'/settings',
|
|
'/settings/*',
|
|
'/portfolio/:username'
|
|
];
|
|
|
|
const devRoutes = [];
|
|
|
|
const middlewares = isDev ? [errorThrowerMiddleware] : [];
|
|
export default function reactSubRouter(app) {
|
|
var router = app.loopback.Router();
|
|
|
|
router.get('/videos', (req, res) => res.redirect('/map'));
|
|
router.get(
|
|
'/videos/:dashedName',
|
|
(req, res) => res.redirect(`/challenges/${req.params.dashedName}`)
|
|
);
|
|
|
|
// These routes are in production
|
|
routes.forEach((route) => {
|
|
router.get(route, serveReactApp);
|
|
});
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
devRoutes.forEach(function(route) {
|
|
router.get(route, serveReactApp);
|
|
});
|
|
}
|
|
|
|
app.use('/:lang', router);
|
|
|
|
function serveReactApp(req, res, next) {
|
|
const { lang } = req;
|
|
const serviceOptions = { req };
|
|
createApp({
|
|
serviceOptions,
|
|
middlewares,
|
|
enhancers: [
|
|
devtoolsEnhancer({ name: 'server' })
|
|
],
|
|
history: createMemoryHistory({ initialEntries: [ req.originalUrl ] }),
|
|
defaultState: { app: { lang } }
|
|
})
|
|
.filter(({
|
|
location: {
|
|
type,
|
|
kind,
|
|
pathname
|
|
} = {}
|
|
}) => {
|
|
if (kind === 'redirect') {
|
|
log('react found a redirect');
|
|
res.redirect(pathname);
|
|
return false;
|
|
}
|
|
|
|
if (type === NOT_FOUND) {
|
|
log(`react tried to find ${req.path} but got 404`);
|
|
next();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
})
|
|
.flatMap(({ store, epic }) => {
|
|
return waitForEpics(epic)
|
|
.map(() => renderToString(
|
|
provideStore(App, store)
|
|
))
|
|
.map((markup) => ({ markup, store, epic }));
|
|
})
|
|
.do(({ markup, store, epic }) => {
|
|
log('react markup rendered, data fetched');
|
|
const state = store.getState();
|
|
const title = titleSelector(state);
|
|
epic.dispose();
|
|
res.expose(state, 'data', { isJSON: true });
|
|
// note(berks): we render without express-flash dumping our messages
|
|
// the app will query for these on load
|
|
res.renderWithoutFlash('layout-react', { markup, title });
|
|
})
|
|
.subscribe(() => log('html rendered and sent'), next);
|
|
}
|
|
}
|