Add main chat toggle

This commit is contained in:
Berkeley Martinez
2016-06-03 23:34:28 -07:00
parent 253fb52c50
commit 1acd3139c3
9 changed files with 117 additions and 14 deletions

View File

@ -0,0 +1,61 @@
import { Observable } from 'rx';
import Chat from 'gitter-sidecar';
import types from '../../common/app/redux/types';
function createHeader(document) {
const div = document.createElement('div');
const span = document.createElement('span');
const actionBar = document.querySelector(
'#chat-embed-main > .gitter-chat-embed-action-bar'
);
span.appendChild(document.createTextNode('Free Code Camp\'s Main Chat'));
div.className = 'chat-embed-main-title';
div.appendChild(span);
actionBar.insertBefore(div, actionBar.firstChild);
}
export default function gitterSaga(actions$, getState, { document }) {
let mainChatTitleAdded = false;
const mainChatContainer = document.createElement('aside');
mainChatContainer.id = 'chat-embed-main';
mainChatContainer.className = 'gitter-chat-embed is-collapsed';
document.body.appendChild(mainChatContainer);
const mainChat = new Chat({
room: 'freecodecamp/freecodecamp',
activationElement: false,
targetElement: mainChatContainer
});
const mainChatToggle$ = Observable.fromEventPattern(
h => mainChatContainer.addEventListener('gitter-chat-toggle', h),
h => mainChatContainer.removeEventListener('gitter-chat-toggle', h)
)
.map(e => {
const { isMainChatOpen } = getState().app;
if (!mainChatTitleAdded) {
mainChatTitleAdded = true;
createHeader(document);
}
if (isMainChatOpen === e.detail.state) {
return null;
}
return { type: types.toggleMainChat };
});
return Observable.merge(
mainChatToggle$,
actions$
.filter(({ type }) => (
type === types.openMainChat ||
type === types.closeMainChat ||
type === types.toggleMainChat
))
.map(() => {
const { isMainChatOpen } = getState().app;
mainChat.toggleChat(isMainChatOpen);
if (!isMainChatOpen) {
document.activeElement.blur();
}
return null;
})
);
}

View File

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

View File

@ -11,7 +11,8 @@ import {
fetchUser,
initWindowHeight,
updateNavHeight,
toggleMapDrawer
toggleMapDrawer,
toggleMainChat
} from './redux/actions';
import { submitChallenge } from './routes/challenges/redux/actions';
@ -53,7 +54,8 @@ const bindableActions = {
updateNavHeight,
fetchUser,
submitChallenge,
toggleMapDrawer
toggleMapDrawer,
toggleMainChat
};
const fetchContainerOptions = {
@ -79,7 +81,8 @@ export class FreeCodeCamp extends React.Component {
submitChallenge: PropTypes.func,
isMapDrawerOpen: PropTypes.bool,
isMapAlreadyLoaded: PropTypes.bool,
toggleMapDrawer: PropTypes.func
toggleMapDrawer: PropTypes.func,
toggleMainChat: PropTypes.func
};
componentWillReceiveProps({
@ -141,14 +144,16 @@ export class FreeCodeCamp extends React.Component {
updateNavHeight,
isMapDrawerOpen,
isMapAlreadyLoaded,
toggleMapDrawer
toggleMapDrawer,
toggleMainChat
} = this.props;
const navProps = {
username,
points,
picture,
updateNavHeight,
toggleMapDrawer
toggleMapDrawer,
toggleMainChat
};
return (

View File

@ -40,7 +40,8 @@ export default class extends React.Component {
signedIn: PropTypes.bool,
username: PropTypes.string,
updateNavHeight: PropTypes.func,
toggleMapDrawer: PropTypes.func
toggleMapDrawer: PropTypes.func,
toggleMainChat: PropTypes.func
};
componentDidMount() {
@ -75,6 +76,19 @@ export default class extends React.Component {
);
}
renderChat(toggleMainChat) {
return (
<NavItem
eventKey={ 2 }
href='//gitter.im/freecodecamp/freecodecamp'
onClick={ toggleMainChat }
target='_blank'
>
Chat
</NavItem>
);
}
renderLinks() {
return navLinks.map(({ content, link, react, target }, index) => {
if (react) {
@ -144,7 +158,8 @@ export default class extends React.Component {
username,
points,
picture,
toggleMapDrawer
toggleMapDrawer,
toggleMainChat
} = this.props;
const { router } = this.context;
const isOnMap = router.isActive('/map');
@ -161,6 +176,7 @@ export default class extends React.Component {
navbar={ true }
pullRight={ true }>
{ this.renderMapLink(isOnMap, toggleMapDrawer) }
{ this.renderChat(toggleMainChat) }
{ this.renderLinks() }
{ this.renderPoints(username, points) }
{ this.renderSignin(username, picture) }

View File

@ -1,8 +1,4 @@
[{
"content": "Chat",
"link": "//gitter.im/FreeCodeCamp/FreeCodeCamp",
"target": "_blank"
},{
"content": "Forum",
"link": "http://forum.freecodecamp.com/",
"target": "_blank"

View File

@ -53,3 +53,14 @@ export const toggleMapDrawer = createAction(
types.toggleMapDrawer,
e => e.preventDefault()
);
export const toggleWikiDrawer = createAction(types.toggleWikiDrawer);
// chat
export const toggleMainChat = createAction(
types.toggleMainChat,
e => {
if (!(e.ctrlKey || e.metaKey)) {
e.preventDefault();
}
}
);

View File

@ -9,7 +9,8 @@ const initialState = {
isSignedIn: false,
csrfToken: '',
windowHeight: 0,
navHeight: 0
navHeight: 0,
isMainChatOpen: false
};
export default handleActions(
@ -46,6 +47,10 @@ export default handleActions(
...state,
isMapAlreadyLoaded: true,
isMapDrawerOpen: !state.isMapDrawerOpen
}),
[types.toggleMainChat]: state => ({
...state,
isMainChatOpen: !state.isMainChatOpen
})
},
initialState

View File

@ -22,5 +22,11 @@ export default createTypes([
'updateHikesData',
// drawers
'toggleMapDrawer'
'toggleMapDrawer',
'toggleWikiDrawer',
// main chat
'openMainChat',
'closeMainChat',
'toggleMainChat'
], 'app');

View File

@ -50,6 +50,7 @@
"express-validator": "^2.18.0",
"fetchr": "~0.5.12",
"frameguard": "^2.0.0",
"gitter-sidecar": "^1.2.3",
"helmet": "^2.0.0",
"helmet-csp": "^1.0.3",
"history": "^2.0.0",