diff --git a/client/coral-admin/src/components/Comment.js b/client/coral-admin/src/components/Comment.js index 2b0b7561b..e5a753f80 100644 --- a/client/coral-admin/src/components/Comment.js +++ b/client/coral-admin/src/components/Comment.js @@ -3,7 +3,7 @@ import React from 'react'; import {Button, Icon} from 'react-mdl'; import timeago from 'timeago.js'; import styles from './CommentList.css'; -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; // Render a single comment for the list diff --git a/client/coral-admin/src/components/ModerationKeysModal.js b/client/coral-admin/src/components/ModerationKeysModal.js index 5cf9fe17e..b1282e5d6 100644 --- a/client/coral-admin/src/components/ModerationKeysModal.js +++ b/client/coral-admin/src/components/ModerationKeysModal.js @@ -1,4 +1,4 @@ -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; import React from 'react'; import Modal from 'components/Modal'; diff --git a/client/coral-admin/src/containers/Community/Community.js b/client/coral-admin/src/containers/Community/Community.js index 8e0b955a4..5c1bb2e19 100644 --- a/client/coral-admin/src/containers/Community/Community.js +++ b/client/coral-admin/src/containers/Community/Community.js @@ -1,5 +1,5 @@ import React from 'react'; -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../../translations'; import {Grid, Cell} from 'react-mdl'; diff --git a/client/coral-admin/src/containers/Configure.js b/client/coral-admin/src/containers/Configure.js index 229c4e948..952e2acd1 100644 --- a/client/coral-admin/src/containers/Configure.js +++ b/client/coral-admin/src/containers/Configure.js @@ -13,7 +13,7 @@ import { Icon } from 'react-mdl'; import styles from './Configure.css'; -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; class Configure extends React.Component { diff --git a/client/coral-admin/src/containers/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue.js index 9178bda57..a92080c39 100644 --- a/client/coral-admin/src/containers/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue.js @@ -5,7 +5,7 @@ import CommentList from 'components/CommentList'; import {updateStatus} from 'actions/comments'; import styles from './ModerationQueue.css'; import key from 'keymaster'; -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; /* diff --git a/client/coral-embed-stream/src/CommentStream.js b/client/coral-embed-stream/src/CommentStream.js index bfccf7cfc..31457787a 100644 --- a/client/coral-embed-stream/src/CommentStream.js +++ b/client/coral-embed-stream/src/CommentStream.js @@ -15,6 +15,7 @@ import {ReplyBox, ReplyButton} from '../../coral-plugin-replies'; import Pym from 'pym.js'; import FlagButton from '../../coral-plugin-flags/FlagButton'; import PermalinkButton from '../../coral-plugin-permalinks/PermalinkButton'; +import SignInContainer from '../../coral-sign-in/containers/SignInContainer'; const {addItem, updateItem, postItem, getStream, postAction, appendItemArray} = itemActions; const {addNotification, clearNotification} = notificationActions; @@ -111,6 +112,7 @@ class CommentStream extends Component { id={rootItemId} premod={this.props.config.moderation} reply={false}/> + { rootItem.comments.map((commentId) => { diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js new file mode 100644 index 000000000..9b1053161 --- /dev/null +++ b/client/coral-framework/actions/auth.js @@ -0,0 +1,61 @@ +import * as actions from '../constants/auth'; +import {base, handleResp} from '../helpers'; + +export const loginFacebook = () => dispatch => { + dispatch(loginFacebookRequest()); + window.open( + `${base}/auth/facebook`, + 'Continue with Facebook', + 'menubar=0,resizable=0,width=500,height=500,top=200,left=500' + ); +}; + +export const loginFacebookCallback = (err, data) => { + let user; + + if (err) { + console.error(err); + return; + } + + try { + user = JSON.parse(data); + } catch (err) { + console.error('Can\'t parse the user json', err); + return; + } + + console.log('User was loaded!', user); +}; + +export const logout = () => dispatch => { + dispatch(logoutRequest()); + fetch(`${base}/api/v1/auth`, { + method: 'DELETE', + credentials: 'same-origin' + }) + .then(handleResp) + .then(() => dispatch(dispatch(logoutSuccess()))) + .catch(error => dispatch(logoutFailure(error))); +}; + +const logoutRequest = () => ({ + type: actions.USER_LOGOUT_SUCCESS +}); + +const logoutSuccess = () => ({ + type: actions.USER_LOGOUT_SUCCESS +}); + +const logoutFailure = (error) => ({ + type: actions.USER_LOGOUT_SUCCESS, + error +}); + +export const loginFacebookRequest = () => ({ + type: actions.USER_FACEBOOK_LOGIN_REQUEST +}); + +export const loginRequest = () => ({ + type: actions.USER_SIGNIN_REQUEST +}); diff --git a/client/coral-framework/store/actions/config.js b/client/coral-framework/actions/config.js similarity index 98% rename from client/coral-framework/store/actions/config.js rename to client/coral-framework/actions/config.js index f131b8c82..d8fd886be 100644 --- a/client/coral-framework/store/actions/config.js +++ b/client/coral-framework/actions/config.js @@ -1,5 +1,3 @@ -/* @flow */ - import {fromJS} from 'immutable'; /** diff --git a/client/coral-framework/store/actions/items.js b/client/coral-framework/actions/items.js similarity index 100% rename from client/coral-framework/store/actions/items.js rename to client/coral-framework/actions/items.js diff --git a/client/coral-framework/store/actions/notification.js b/client/coral-framework/actions/notification.js similarity index 92% rename from client/coral-framework/store/actions/notification.js rename to client/coral-framework/actions/notification.js index c34adc414..4edc17601 100644 --- a/client/coral-framework/store/actions/notification.js +++ b/client/coral-framework/actions/notification.js @@ -1,5 +1,3 @@ -/* Notification Actions */ - export const ADD_NOTIFICATION = 'ADD_NOTIFICATION'; export const CLEAR_NOTIFICATION = 'CLEAR_NOTIFICATION'; diff --git a/client/coral-framework/constants/auth.js b/client/coral-framework/constants/auth.js new file mode 100644 index 000000000..7f93a51fe --- /dev/null +++ b/client/coral-framework/constants/auth.js @@ -0,0 +1,9 @@ +export const USER_LOGIN_REQUEST = 'USER_LOGIN_REQUEST'; +export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS'; +export const USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE'; +export const USER_FACEBOOK_LOGIN_REQUEST = 'USER_FACEBOOK_LOGIN_REQUEST'; +export const USER_FACEBOOK_SUCCESS = 'USER_FACEBOOK_SUCCESS'; +export const USER_FACEBOOK_FAILURE = 'USER_FACEBOOK_FAILURE'; +export const USER_LOGOUT_REQUEST = 'USER_LOGOUT_REQUEST'; +export const USER_LOGOUT_SUCCESS = 'USER_LOGOUT_SUCCESS'; +export const USER_LOGOUT_FAILURE = 'USER_LOGOUT_FAILURE'; diff --git a/client/coral-framework/helpers/index.js b/client/coral-framework/helpers/index.js new file mode 100644 index 000000000..439ba5a8a --- /dev/null +++ b/client/coral-framework/helpers/index.js @@ -0,0 +1,27 @@ +export const base = '/api/v1'; + +export const getInit = (method, body) => { + const headers = new Headers({ + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }); + + const init = {method, headers}; + if (method.toLowerCase() !== 'get') { + init.body = JSON.stringify(body); + } + + return init; +}; + +export const handleResp = res => { + if (res.status === 401) { + throw new Error('Not Authorized to make this request'); + } else if (res.status > 399) { + throw new Error('Error! Status ', res.status); + } else if (res.status === 204) { + return res.text(); + } else { + return res.json(); + } +}; diff --git a/client/coral-framework/index.js b/client/coral-framework/index.js index 118935c50..4c6ae741f 100644 --- a/client/coral-framework/index.js +++ b/client/coral-framework/index.js @@ -1,10 +1,10 @@ -import Notification from './notification/Notification'; -import store from './store/store'; -import {fetchConfig} from './store/actions/config'; -import * as itemActions from './store/actions/items'; -import I18n from './i18n/i18n'; -import * as notificationActions from './store/actions/notification'; -import * as authActions from './store/actions/auth'; +import Notification from './modules/notification/Notification'; +import store from './store'; +import {fetchConfig} from './actions/config'; +import * as itemActions from './actions/items'; +import I18n from './modules/i18n/i18n'; +import * as notificationActions from './actions/notification'; +import * as authActions from './actions/auth'; export { Notification, diff --git a/client/coral-framework/i18n/i18n.js b/client/coral-framework/modules/i18n/i18n.js similarity index 96% rename from client/coral-framework/i18n/i18n.js rename to client/coral-framework/modules/i18n/i18n.js index 43144f3a6..afe8606d1 100644 --- a/client/coral-framework/i18n/i18n.js +++ b/client/coral-framework/modules/i18n/i18n.js @@ -1,5 +1,5 @@ import timeago from 'timeago.js'; -import esTA from 'timeago.js/locales/es'; +import esTA from '../../../../node_modules/timeago.js/locales/es'; /** * Default locales, this should be overriden by config file diff --git a/client/coral-framework/notification/Notification.js b/client/coral-framework/modules/notification/Notification.js similarity index 100% rename from client/coral-framework/notification/Notification.js rename to client/coral-framework/modules/notification/Notification.js diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js new file mode 100644 index 000000000..c585ea237 --- /dev/null +++ b/client/coral-framework/reducers/auth.js @@ -0,0 +1,22 @@ +import {Map} from 'immutable'; +// +//import { +// FETCH_COMMENTERS_REQUEST, +// FETCH_COMMENTERS_FAILURE, +// FETCH_COMMENTERS_SUCCESS, +// SORT_UPDATE +//} from '../constants/community'; +// +const initialState = Map({ + auth: Map(), + loggedIn: false, + error: '', + user: {} +}); + +export default function community (state = initialState, action) { + switch (action.type) { + default : + return state; + } +} diff --git a/client/coral-framework/store/reducers/config.js b/client/coral-framework/reducers/config.js similarity index 100% rename from client/coral-framework/store/reducers/config.js rename to client/coral-framework/reducers/config.js diff --git a/client/coral-framework/store/reducers/index.js b/client/coral-framework/reducers/index.js similarity index 100% rename from client/coral-framework/store/reducers/index.js rename to client/coral-framework/reducers/index.js diff --git a/client/coral-framework/store/reducers/items.js b/client/coral-framework/reducers/items.js similarity index 100% rename from client/coral-framework/store/reducers/items.js rename to client/coral-framework/reducers/items.js diff --git a/client/coral-framework/store/reducers/notification.js b/client/coral-framework/reducers/notification.js similarity index 100% rename from client/coral-framework/store/reducers/notification.js rename to client/coral-framework/reducers/notification.js diff --git a/client/coral-framework/store/store.js b/client/coral-framework/store.js similarity index 99% rename from client/coral-framework/store/store.js rename to client/coral-framework/store.js index 33cc9efb5..8c3f9edc1 100644 --- a/client/coral-framework/store/store.js +++ b/client/coral-framework/store.js @@ -1,4 +1,3 @@ - import {createStore, applyMiddleware} from 'redux'; import thunk from 'redux-thunk'; import mainReducer from './reducers'; diff --git a/client/coral-framework/store/actions/auth.js b/client/coral-framework/store/actions/auth.js deleted file mode 100644 index af1e3cb34..000000000 --- a/client/coral-framework/store/actions/auth.js +++ /dev/null @@ -1,17 +0,0 @@ -/* Auth Actions */ - -export const SET_LOGGED_IN_USER = 'SET_LOGGED_IN_USER'; -export const LOG_OUT_USER = 'LOG_OUT_USER'; - -export const setLoggedInUser = (user_id) => { - return { - type: SET_LOGGED_IN_USER, - user_id - }; -}; - -export const LogOutUser = () => { - return { - type: LOG_OUT_USER - }; -}; diff --git a/client/coral-framework/store/reducers/auth.js b/client/coral-framework/store/reducers/auth.js deleted file mode 100644 index b79444cc9..000000000 --- a/client/coral-framework/store/reducers/auth.js +++ /dev/null @@ -1,17 +0,0 @@ -/* Auth */ - -import * as actions from '../actions/auth'; -import {fromJS} from 'immutable'; - -const initialState = fromJS({}); - -export default (state = initialState, action) => { - switch (action.type) { - case actions.SET_LOGGED_IN_USER: - return state.set('user', action.user_id); - case actions.LOG_OUT_USER: - return initialState; - default: - return state; - } -}; diff --git a/client/coral-plugin-permalinks/PermalinkButton.js b/client/coral-plugin-permalinks/PermalinkButton.js index 978a6dd03..2372e2035 100644 --- a/client/coral-plugin-permalinks/PermalinkButton.js +++ b/client/coral-plugin-permalinks/PermalinkButton.js @@ -1,5 +1,5 @@ import React, {PropTypes} from 'react'; -import I18n from 'coral-framework/i18n/i18n'; +import I18n from 'coral-framework/modules/i18n/i18n'; import translations from './translations'; import onClickOutside from 'react-onclickoutside'; const name = 'coral-plugin-permalinks'; diff --git a/client/coral-sign-in/components/Button.js b/client/coral-sign-in/components/Button.js new file mode 100644 index 000000000..fd8cc85c7 --- /dev/null +++ b/client/coral-sign-in/components/Button.js @@ -0,0 +1,13 @@ +import React from 'react'; +import styles from './styles.css'; + +const Button = ({type = 'local', children, ...props}) => ( + +); + +export default Button; diff --git a/client/coral-sign-in/components/SignIn.js b/client/coral-sign-in/components/SignIn.js new file mode 100644 index 000000000..61f1e387e --- /dev/null +++ b/client/coral-sign-in/components/SignIn.js @@ -0,0 +1,15 @@ +import React from 'react'; +import Button from './Button'; + +const SignIn = ({openFacebookWindow, logout}) => ( +
+ + + Logout + +
+); + +export default SignIn; diff --git a/client/coral-sign-in/components/styles.css b/client/coral-sign-in/components/styles.css new file mode 100644 index 000000000..6dbbd5b2f --- /dev/null +++ b/client/coral-sign-in/components/styles.css @@ -0,0 +1,43 @@ +.button { + background: 0 0; + border: none; + border-radius: 2px; + color: #000; + display: block; + position: relative; + height: 36px; + min-width: 64px; + padding: 0 8px; + display: inline-block; + font-family: 'Roboto','Helvetica','Arial',sans-serif; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0; + overflow: hidden; + will-change: box-shadow,transform; + -webkit-transition: box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1); + transition: box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1); + outline: none; + cursor: pointer; + text-decoration: none; + text-align: center; + line-height: 36px; + vertical-align: middle; +} + +.local { + background: #E0E0E0; + color: #212121; +} + +.facebook { + background-color: #4267b2; + border-color: #4267b2; + color: rgb(255, 255, 255); +} + +.facebook:hover { + background-color: #365899; + border-color: #365899; +} \ No newline at end of file diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js new file mode 100644 index 000000000..72b46536e --- /dev/null +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -0,0 +1,37 @@ +import React, {Component} from 'react'; +import {connect} from 'react-redux'; + +import SignIn from '../components/SignIn'; + +import { + loginFacebookCallback, + loginFacebook, + logout +} from '../../coral-framework/actions/auth'; + +class SignInContainer extends Component { + constructor(props) { + super(props); + + this.openFacebookWindow = this.openFacebookWindow.bind(this); + this.logout = this.logout.bind(this); + } + + componentDidMount() { + window.authCallback = loginFacebookCallback; + } + + openFacebookWindow() { + this.props.dispatch(loginFacebook()); + } + + logout() { + this.props.dispatch(logout()); + } + + render() { + return ; + } +} + +export default connect(({auth}) => ({auth}))(SignInContainer); diff --git a/tests/client/coral-framework/store/authReducer.js b/tests/client/coral-framework/store/authReducer.js deleted file mode 100644 index aaebe1897..000000000 --- a/tests/client/coral-framework/store/authReducer.js +++ /dev/null @@ -1,31 +0,0 @@ -import {Map} from 'immutable'; -import {expect} from 'chai'; -import authReducer from '../../../../client/coral-framework/store/reducers/auth'; -import * as actions from '../../../../client/coral-framework/store/actions/auth'; - -describe ('authReducer', () => { - describe('SET_LOGGED_IN_USER', () => { - it('should set a logged in user', () => { - const action = { - type: actions.SET_LOGGED_IN_USER, - user_id: '123' - }; - const store = new Map({}); - const result = authReducer(store, action); - expect(result.get('user')).to.equal(action.user_id); - }); - }); - - describe('LOG_OUT_USER', () => { - it('should clear the user store', () => { - const action = { - type: actions.LOG_OUT_USER - }; - const store = new Map({ - user: '123' - }); - const result = authReducer(store, action); - expect(result.get('user')).to.equal(undefined); - }); - }); -}); diff --git a/tests/client/coral-framework/store/itemActions.spec.js b/tests/client/coral-framework/store/itemActions.spec.js index d45212794..e50b82344 100644 --- a/tests/client/coral-framework/store/itemActions.spec.js +++ b/tests/client/coral-framework/store/itemActions.spec.js @@ -2,7 +2,7 @@ import 'react'; import 'redux'; import {expect} from 'chai'; import fetchMock from 'fetch-mock'; -import * as actions from '../../../../client/coral-framework/store/actions/items'; +import * as actions from '../../../../client/coral-framework/actions/items'; import {Map} from 'immutable'; import configureStore from 'redux-mock-store'; diff --git a/tests/client/coral-framework/store/itemReducer.spec.js b/tests/client/coral-framework/store/itemReducer.spec.js index 9aea845f3..16377327b 100644 --- a/tests/client/coral-framework/store/itemReducer.spec.js +++ b/tests/client/coral-framework/store/itemReducer.spec.js @@ -1,6 +1,6 @@ import {Map, fromJS} from 'immutable'; import {expect} from 'chai'; -import itemsReducer from '../../../../client/coral-framework/store/reducers/items'; +import itemsReducer from '../../../../client/coral-framework/reducers/items'; describe ('itemsReducer', () => { describe('ADD_ITEM', () => { diff --git a/tests/client/coral-framework/store/notificationReducer.spec.js b/tests/client/coral-framework/store/notificationReducer.spec.js index 60b944a33..960034119 100644 --- a/tests/client/coral-framework/store/notificationReducer.spec.js +++ b/tests/client/coral-framework/store/notificationReducer.spec.js @@ -1,7 +1,7 @@ import {Map} from 'immutable'; import {expect} from 'chai'; -import notificationReducer from '../../../../client/coral-framework/store/reducers/notification'; -import * as actions from '../../../../client/coral-framework/store/actions/notification'; +import notificationReducer from '../../../../client/coral-framework/reducers/notification'; +import * as actions from '../../../../client/coral-framework/actions/notification'; describe ('notificationsReducer', () => { describe('ADD_NOTIFICATION', () => {