Feature(mousetrap): Add mousetrap features to redux

This commit is contained in:
Berkeley Martinez
2016-06-17 22:20:20 -07:00
parent d1b78eba9b
commit d9e9af0a0f
11 changed files with 82 additions and 36 deletions

View File

@ -45,7 +45,8 @@ const sagaOptions = {
isDev,
window,
document: window.document,
location: window.location
location: window.location,
history: window.history
};

View File

@ -1,16 +1,10 @@
import { hardGoTo } from '../../common/app/redux/types';
export default function hardGoToSaga(action$, getState, { location }) {
export default function hardGoToSaga(action$, getState, { history }) {
return action$
.filter(({ type }) => type === hardGoTo)
.map(({ payload = '/map' }) => {
if (!location.pathname) {
return {
type: 'app.error',
error: new Error('no location object found')
};
}
location.pathname = payload;
.map(({ payload = '/settings' }) => {
history.push(history.state, null, payload);
return null;
});
}

View File

@ -6,6 +6,7 @@ import executeChallengeSaga from './execute-challenge-saga';
import frameSaga from './frame-saga';
import codeStorageSaga from './code-storage-saga';
import gitterSaga from './gitter-saga';
import mouseTrapSaga from './mouse-trap-saga';
export default [
errSaga,
@ -15,5 +16,6 @@ export default [
executeChallengeSaga,
frameSaga,
codeStorageSaga,
gitterSaga
gitterSaga,
mouseTrapSaga
];

View File

@ -0,0 +1,41 @@
import { Observable } from 'rx';
import MouseTrap from 'mousetrap';
import { push } from 'react-router-redux';
import {
toggleNightMode,
toggleMapDrawer,
toggleMainChat,
hardGoTo
} from '../../common/app/redux/actions';
function bindKey$(key, actionCreator) {
return Observable.fromEventPattern(
h => MouseTrap.bind(key, h),
h => MouseTrap.unbind(key, h)
)
.map(actionCreator);
}
const softRedirects = {
'g n n': '/challenges/next-challenge',
'g n a': '/about',
'g n m': '/map',
'g n w': '/wiki',
'g n s': '/shop',
'g n o': '/settings'
};
export default function mouseTrapSaga(actions$) {
const traps$ = [
...Object.keys(softRedirects)
.map(key => bindKey$(key, () => push(softRedirects[key]))),
bindKey$(
'g n r',
() => hardGoTo('https://github.com/freecodecamp/freecodecamp')
),
bindKey$('g m', toggleMapDrawer),
bindKey$('g t n', toggleNightMode),
bindKey$('g c', toggleMainChat)
];
return Observable.merge(traps$).takeUntil(actions$.last());
}

View File

@ -1,26 +1,22 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { hardGoTo } from '../../redux/actions';
const win = typeof window !== 'undefined' ? window : {};
function goToServer(path) {
win.location = '/' + path;
}
export default class extends React.Component {
export class NotFound extends React.Component {
static displayName = 'NotFound';
static propTypes = {
params: PropTypes.object
location: PropTypes.object,
hardGoTo: PropTypes.func
};
componentWillMount() {
goToServer(this.props.params.splat);
}
componentDidMount() {
this.props.hardGoTo(this.props.location.pathname);
}
render() {
return <span></span>;
}
}
export default connect(null, { hardGoTo })(NotFound);

View File

@ -56,3 +56,4 @@ export const toggleWikiDrawer = createAction(types.toggleWikiDrawer);
// chat
export const toggleMainChat = createAction(types.toggleMainChat);
export const toggleNightMode = createAction(types.toggleNightMode);

View File

@ -9,6 +9,7 @@ export default createTypes([
'makeToast',
'updatePoints',
'handleError',
'toggleNightMode',
// used to hit the server
'hardGoTo',
'delayedRedirect',

View File

@ -1,8 +1,16 @@
import { modernChallenges, map, challenges } from './challenges';
import NotFound from '../components/NotFound/index.jsx';
import { addLang } from '../utils/add-lang';
export default {
path: '/:lang',
indexRoute: {
onEnter(nextState, replace) {
const { lang } = nextState.params;
const { pathname } = nextState.location;
replace(addLang(pathname, lang));
}
},
childRoutes: [
challenges,
modernChallenges,

View File

@ -1,19 +1,7 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import supportedLanguages from '../../utils/supported-languages';
const toLowerCase = String.prototype.toLowerCase;
function addLang(url, lang) {
const maybeLang = toLowerCase.call(url.split('/')[1]);
if (supportedLanguages[maybeLang]) {
return url;
}
if (supportedLanguages[lang]) {
return `/${lang}${url}`;
}
return `/en${url}`;
}
import { addLang } from './add-lang';
const mapStateToProps = state => ({ lang: state.app.lang });

View File

@ -0,0 +1,13 @@
import supportedLanguages from '../../utils/supported-languages';
const toLowerCase = String.prototype.toLowerCase;
export function addLang(url, lang) {
const maybeLang = toLowerCase.call(url.split('/')[1]);
if (supportedLanguages[maybeLang]) {
return url;
}
if (supportedLanguages[lang]) {
return `/${lang}${url}`;
}
return `/en${url}`;
}

View File

@ -66,6 +66,7 @@
"moment-timezone": "^0.5.0",
"mongodb": "^2.0.33",
"morgan": "^1.6.1",
"mousetrap": "^1.6.0",
"node-uuid": "^1.4.3",
"nodemailer": "^2.1.0",
"nodemailer-ses-transport": "^1.3.0",