diff --git a/.eslintrc b/.eslintrc index b5f69f0..c9245ff 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,15 +1,3 @@ -// { -// "parserOptions": { -// "ecmaVersion": 6, -// "sourceType": "module", -// "ecmaFeatures": { -// "jsx": true -// } -// }, -// "rules": { -// "semi": 2 -// } -// } { "extends": "eslint:recommended", "env": { diff --git a/.gitignore b/.gitignore index 3600beb..621c9d0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,11 @@ node_modules dist .*/ -icomoon/demo-files -.ideaicomoon/demo-filesicomoon/ie7 -icomoon/demo.html -icomoon/Read Me.txt -icomoon/selection.json -icomoon/style.css +client/lib/icomoon/demo-files +.idea +client/lib/icomoon/demo-filesicomoon/ie7 +client/lib/icomoon/demo.html +client/lib/icomoon/Read Me.txt +client/lib/icomoon/selection.json +client/lib/icomoon/style.css +client/dist diff --git a/src/actions.js b/client/actions.js similarity index 82% rename from src/actions.js rename to client/actions.js index 5026e2f..85cc99e 100644 --- a/src/actions.js +++ b/client/actions.js @@ -3,36 +3,37 @@ This module contains action creators. They are functions which will return an ob These actions are imported by Redux-aware components who need them, in our case it is just Home. */ -var C = require('./constants'); +import C from './config/constants'; import fetch from 'isomorphic-fetch'; require('es6-promise').polyfill(); import jwtDecode from 'jwt-decode'; import { pushState } from 'redux-router'; module.exports = { - reset: function() { + reset: () => { // A normal action creator, returns a simple object describing the action. return { type: C.RESET }; }, - addMember: function(member) { - return function(dispatch, getState) { + addMember: (member) => { + return (dispatch, getState) => { dispatch({ type: C.ADD_MEMBER, member: member }); }; }, - removeMember: function(member) { - return function(dispatch, getState) { + removeMember: (member) => { + return (dispatch, getState) => { dispatch({ type: C.REMOVE_MEMBER, member: member }); }; }, - getInitialMembers: function() { - return function(dispatch, getState) { - return fetch('http://localhost:8080/api/members') + getInitialMembers: () => { + return (dispatch, getState) => { + return fetch('/api/members') .then(response => response.json()) .then(json => dispatch({ type: C.INIT_MEMBERS_LIST, data: json })); }; }, - changeLanguage: function(language) { - return function(dispatch, getState) { + changeLanguage: (language) => { + return (dispatch, getState) => { + console.warn('CL ACTION'); dispatch({ type: C.CHANGE_LANGUAGE, language: language }); }; }, @@ -44,11 +45,11 @@ module.exports = { logout: logout, logoutAndRedirect: logoutAndRedirect, - doLogin: function(usr, pwd, redirect = '/') { - return function(dispatch, getState) { + doLogin: (usr, pwd, redirect = '/') => { + return (dispatch, getState) => { dispatch(loginUserRequest()); - return fetch('http://localhost:8080/api/auth/login', { + return fetch('/api/auth/login', { method: 'post', credentials: 'include', headers: { @@ -59,7 +60,6 @@ module.exports = { }) .then(response => response.json()) .then(response => { - try { jwtDecode(response.token); dispatch(loginUserSuccess(response.token)); @@ -78,8 +78,8 @@ module.exports = { }); }; }, - editMembers: function(token) { - return function(dispatch, getState) { + editMembers: (token) => { + return function (dispatch, getState) { return fetch('http://localhost:8080/api/editMembers', { headers: { 'x-access-token': token, diff --git a/res/img/projects/adaptabi.png b/client/assets/img/projects/adaptabi.png similarity index 100% rename from res/img/projects/adaptabi.png rename to client/assets/img/projects/adaptabi.png diff --git a/res/img/projects/safetybank.png b/client/assets/img/projects/safetybank.png similarity index 100% rename from res/img/projects/safetybank.png rename to client/assets/img/projects/safetybank.png diff --git a/res/img/projects/squires.png b/client/assets/img/projects/squires.png similarity index 100% rename from res/img/projects/squires.png rename to client/assets/img/projects/squires.png diff --git a/src/components/aboutDetails.js b/client/components/aboutDetails.js similarity index 83% rename from src/components/aboutDetails.js rename to client/components/aboutDetails.js index 37ae181..9a75bfa 100644 --- a/src/components/aboutDetails.js +++ b/client/components/aboutDetails.js @@ -1,5 +1,4 @@ import React, { Component, PropTypes } from 'react'; -import translate from '../hoc/translate'; class aboutDetails extends Component { render() { @@ -19,4 +18,4 @@ aboutDetails.defaultProps = { }, }; -export default translate('aboutDetails')(aboutDetails); \ No newline at end of file +export default aboutDetails; \ No newline at end of file diff --git a/src/containers/aboutList.js b/client/components/aboutList.js similarity index 66% rename from src/containers/aboutList.js rename to client/components/aboutList.js index 2861a7a..318c7ef 100644 --- a/src/containers/aboutList.js +++ b/client/components/aboutList.js @@ -1,6 +1,4 @@ import React, { PropTypes as ptypes} from 'react'; -import * as ReactRedux from 'react-redux'; -import actions from '../actions'; import _ from 'lodash'; import {Link} from 'react-router'; @@ -47,25 +45,4 @@ var aboutList = React.createClass({ }, }); -var mapStateToProps = function(state) { - return { - aboutState: state.about, - }; -}; - -var mapDispatchToProps = function(dispatch) { - return { - addMember: function(member) { - dispatch(actions.addMember(this.state.newItemText)); - }, - removeMember: function(member) { - dispatch(actions.removeMember(member)); - }, - getInitialMembers:function() { - dispatch(actions.getInitialMembers()); - }, - }; -}; - -module.exports.rawComponent = aboutList; -module.exports.component = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(aboutList); +module.exports.component = aboutList; diff --git a/client/components/adminHome.js b/client/components/adminHome.js new file mode 100644 index 0000000..d47ea2c --- /dev/null +++ b/client/components/adminHome.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +class AdminHome extends Component { + + componentWillMount () { + this.fetchData(); + } + + fetchData () { + let token = this.props.token; + this.props.fetchProtectedData(token); + } + + render () { + return ( +
+ + {/* {this.props.isFetching === true?

Loading data...

: */} +
+

Welcome back, + {this.props.userName}!

+

{this.props.data.members}

+
+ +
+ ); + } +} + +export default AdminHome; diff --git a/src/components/contact.js b/client/components/contact.js similarity index 50% rename from src/components/contact.js rename to client/components/contact.js index 34b285f..f6b0214 100644 --- a/src/components/contact.js +++ b/client/components/contact.js @@ -1,34 +1,14 @@ -import React, { PropTypes as pt} from 'react'; -import {reduxForm} from 'redux-form'; -import fetch from 'isomorphic-fetch'; -require('es6-promise').polyfill(); +import React, { Component } from 'react'; -const validate = require('../../common/validators').contact; -const fields = ['name', 'email', 'message']; +class Contact extends Component { + submit(values, dispatch) { } //noop -class Contact extends React.Component { - submit(values, dispatch) { - return new Promise((resolve, reject) => { - fetch('http://localhost:8080/api/contact', { - method: 'post', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify(values), - }) - .then(response => response.json()) - .then(response => { - response.success && resolve() || reject(response.errors); - }); - }); - } render() { const {fields: {name, email, message}, handleSubmit} = this.props; return (

{'Contact'}

-
+
{name.touched && name.error && {name.error}} @@ -48,11 +28,4 @@ class Contact extends React.Component { } } -Contact = reduxForm({ - form: 'contact', - fields, - //toggle commenting the next line. Commented = will use server-side validation. Uncommented = will use client-side validation. - validate, -})(Contact); - export default Contact; diff --git a/src/components/culture.js b/client/components/culture.js similarity index 60% rename from src/components/culture.js rename to client/components/culture.js index f348742..1546b01 100644 --- a/src/components/culture.js +++ b/client/components/culture.js @@ -1,9 +1,4 @@ import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -const stateToProps = state => ({ - culture: state.team.culture, -}); class Culture extends Component { render() { @@ -16,4 +11,4 @@ class Culture extends Component { } } -export default connect(stateToProps)(Culture); \ No newline at end of file +export default Culture; \ No newline at end of file diff --git a/src/containers/footer.js b/client/components/footer.js similarity index 81% rename from src/containers/footer.js rename to client/components/footer.js index 369b6bd..66f99c8 100644 --- a/src/containers/footer.js +++ b/client/components/footer.js @@ -1,5 +1,4 @@ import React, { PropTypes, Component } from 'react'; -import translate from '../hoc/translate'; class Footer extends Component { render() { @@ -18,4 +17,4 @@ Footer.defaultProps = { }, }; -export default translate('Footer')(Footer); \ No newline at end of file +export default Footer; \ No newline at end of file diff --git a/src/containers/gallery.js b/client/components/gallery.js similarity index 66% rename from src/containers/gallery.js rename to client/components/gallery.js index e38fd3b..3c454f9 100644 --- a/src/containers/gallery.js +++ b/client/components/gallery.js @@ -1,14 +1,5 @@ -import SimpleGrid from '../components/simpleList'; import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -const stateToProps = state => ({ - items: state.team.gallery, -}); - -// const actionsToProps = dispatch => ({ -// handleChange: event => dispatch(changeLanguage(event.target.value)), -// }); +import SimpleGrid from '../components/simpleList'; class Gallery extends Component { @@ -30,4 +21,4 @@ class Gallery extends Component { } } -export default connect(stateToProps)(Gallery); \ No newline at end of file +export default Gallery; \ No newline at end of file diff --git a/client/components/galleryExample.js b/client/components/galleryExample.js new file mode 100644 index 0000000..496b9f6 --- /dev/null +++ b/client/components/galleryExample.js @@ -0,0 +1,50 @@ +import React, { Component } from 'react'; +import { PhotoSwipeGallery } from 'react-photoswipe'; + +class GalleryExample extends Component { + constructor() { + super(); + } + render() { + let items = [ + { + src: '/client/dist/img/gallery/1.png', + thumbnail: '/client/dist/img/gallery/1.png', + w: 1200, + h: 900, + title: 'Image 1', + }, { + src: '/client/dist/img/gallery/2.png', + thumbnail: '/client/dist/img/gallery/2.png', + w: 1200, + h: 900, + title: 'Image 2', + }, { + src: '/client/dist/img/gallery/3.png', + thumbnail: '/client/dist/img/gallery/3.png', + w: 1200, + h: 900, + title: 'Image 3', + }, + ]; + + let options = { + //http://photoswipe.com/documentation/options.html + }; + + const getThumbnailContent = (item) => { + return ; + }; + + return (
+ {'Show PhotoSwipe'} + +
+ ); + } +} + +export default GalleryExample; diff --git a/src/containers/gridsPage.js b/client/components/gridsPage.js similarity index 100% rename from src/containers/gridsPage.js rename to client/components/gridsPage.js diff --git a/src/containers/header.js b/client/components/header.js similarity index 72% rename from src/containers/header.js rename to client/components/header.js index a6d7df7..8137fe4 100644 --- a/src/containers/header.js +++ b/client/components/header.js @@ -1,7 +1,6 @@ import React, { PropTypes, Component } from 'react'; -import HeaderLinks from '../components/headerLinks'; -import LanguagePicker from '../components/languagePicker'; -import translate from '../hoc/translate'; +import HeaderLinks from '../containers/headerLinksContainer'; +import LanguagePicker from '../containers/languagePickerContainer'; class Header extends Component { render() { @@ -26,4 +25,4 @@ Header.defaultProps = { }, }; -export default translate('Header')(Header); \ No newline at end of file +export default Header; \ No newline at end of file diff --git a/src/components/headerLinks.js b/client/components/headerLinks.js similarity index 92% rename from src/components/headerLinks.js rename to client/components/headerLinks.js index 87d8dbb..fe5aa53 100644 --- a/src/components/headerLinks.js +++ b/client/components/headerLinks.js @@ -1,6 +1,5 @@ import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router'; -import translate from '../hoc/translate'; const routePaths = require('../../common/routePaths'); class HeaderLinks extends Component { @@ -34,4 +33,4 @@ HeaderLinks.defaultProps = { }, }; -export default translate('HeaderLinks')(HeaderLinks); \ No newline at end of file +export default HeaderLinks; \ No newline at end of file diff --git a/src/components/home.js b/client/components/home.js similarity index 80% rename from src/components/home.js rename to client/components/home.js index 6beaa7b..ead204f 100644 --- a/src/components/home.js +++ b/client/components/home.js @@ -1,5 +1,4 @@ import React, { PropTypes, Component } from 'react'; -import translate from '../hoc/translate'; class Home extends Component { render() { @@ -18,4 +17,4 @@ Home.defaultProps = { }, }; -export default translate('Home')(Home); +export default Home; diff --git a/src/components/languagePicker.js b/client/components/languagePicker.js similarity index 55% rename from src/components/languagePicker.js rename to client/components/languagePicker.js index 4a18d8e..a6fa685 100644 --- a/src/components/languagePicker.js +++ b/client/components/languagePicker.js @@ -1,15 +1,5 @@ import React, { Component } from 'react'; -import languages from '../../lang/languages.json'; -import { changeLanguage } from '../actions'; -import { connect } from 'react-redux'; - -const stateToProps = state => ({ - currentLanguage: state.lang.current, -}); - -const actionsToProps = dispatch => ({ - handleChange: event => dispatch(changeLanguage(event.target.value)), -}); +import languages from '../lang/languages.json'; class LanguagePicker extends Component { render() { @@ -26,4 +16,4 @@ class LanguagePicker extends Component { } } -export default connect(stateToProps, actionsToProps)(LanguagePicker); \ No newline at end of file +export default LanguagePicker; \ No newline at end of file diff --git a/client/components/login.js b/client/components/login.js new file mode 100644 index 0000000..c85cec1 --- /dev/null +++ b/client/components/login.js @@ -0,0 +1,32 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router'; + +class Login extends Component { + handleUserChange(e) { + this.setState({ user: e.target.value }); + } + handlePwdChange(e) { + this.setState({ password: e.target.value }); + } + doLogin() { + this.props.doLogin(this.state.user, this.state.password); + } + + //lifecycle events + render() { + return ( +
+ +
+ +
+ +
{this.props.authState.isAuthenticated + ? {'adminHome'} + : null} +
+ ); + } +} + +export default Login; diff --git a/src/components/memberDetails.js b/client/components/memberDetails.js similarity index 81% rename from src/components/memberDetails.js rename to client/components/memberDetails.js index b4676ba..c3c7639 100644 --- a/src/components/memberDetails.js +++ b/client/components/memberDetails.js @@ -1,14 +1,8 @@ import React, { PropTypes, Component } from 'react'; import { Link } from 'react-router'; -import { connect } from 'react-redux'; -import translate from '../hoc/translate'; import _ from 'lodash'; const routePaths = require('../../common/routePaths'); -const stateToProps = state => ({ - items: state.team.members, -}); - class MemberDetails extends Component { render() { const s = this.props.strings, @@ -40,4 +34,4 @@ MemberDetails.defaultProps = { }, }; -export default connect(stateToProps)(translate('MemberDetails')(MemberDetails)); \ No newline at end of file +export default MemberDetails; \ No newline at end of file diff --git a/src/containers/members.js b/client/components/members.js similarity index 86% rename from src/containers/members.js rename to client/components/members.js index 5b6a80b..22f13c3 100644 --- a/src/containers/members.js +++ b/client/components/members.js @@ -1,14 +1,8 @@ import SimpleGrid from '../components/simpleList'; import React, { Component } from 'react'; import { Link } from 'react-router'; -import { connect } from 'react-redux'; -import translate from '../hoc/translate'; const routePaths = require('../../common/routePaths'); -const stateToProps = state => ({ - items: state.team.members, -}); - class Members extends Component { renderRow(item) { @@ -44,4 +38,4 @@ class Members extends Component { } } -export default connect(stateToProps)(translate('Members')(Members)); \ No newline at end of file +export default Members; \ No newline at end of file diff --git a/src/containers/page.js b/client/components/page.js similarity index 100% rename from src/containers/page.js rename to client/components/page.js diff --git a/src/components/projectDetails.js b/client/components/projectDetails.js similarity index 84% rename from src/components/projectDetails.js rename to client/components/projectDetails.js index a0603bb..24ca974 100644 --- a/src/components/projectDetails.js +++ b/client/components/projectDetails.js @@ -1,14 +1,8 @@ import React, { PropTypes, Component } from 'react'; import { Link } from 'react-router'; -import { connect } from 'react-redux'; -import translate from '../hoc/translate'; import _ from 'lodash'; const routePaths = require('../../common/routePaths'); -const stateToProps = state => ({ - items: state.projects.items, -}); - class ProjectDetails extends Component { render() { const s = this.props.strings, @@ -44,4 +38,4 @@ ProjectDetails.defaultProps = { }, }; -export default connect(stateToProps)(translate('ProjectDetails')(ProjectDetails)); \ No newline at end of file +export default ProjectDetails; \ No newline at end of file diff --git a/src/containers/projectsList.js b/client/components/projectsList.js similarity index 82% rename from src/containers/projectsList.js rename to client/components/projectsList.js index 25b5e35..e5c6e5d 100644 --- a/src/containers/projectsList.js +++ b/client/components/projectsList.js @@ -1,18 +1,8 @@ import SimpleGrid from '../components/simpleList'; import React, { PropTypes, Component } from 'react'; import { Link } from 'react-router'; -import { connect } from 'react-redux'; -import translate from '../hoc/translate'; const routePaths = require('../../common/routePaths'); -const stateToProps = state => ({ - items: state.projects.items, -}); - -// const actionsToProps = dispatch => ({ -// handleChange: event => dispatch(changeLanguage(event.target.value)), -// }); - class ProjectsList extends Component { renderRow(item) { @@ -59,4 +49,4 @@ ProjectsList.defaultProps = { }, }; -export default connect(stateToProps)(translate('ProjectsList')(ProjectsList)); \ No newline at end of file +export default ProjectsList; \ No newline at end of file diff --git a/src/containers/services.js b/client/components/services.js similarity index 77% rename from src/containers/services.js rename to client/components/services.js index 792fc25..954c00e 100644 --- a/src/containers/services.js +++ b/client/components/services.js @@ -1,12 +1,5 @@ import SimpleGrid from '../components/simpleList'; import React, { PropTypes, Component } from 'react'; -import { connect } from 'react-redux'; -import translate from '../hoc/translate'; -const routePaths = require('../../common/routePaths'); - -const stateToProps = state => ({ - items: state.services.items, -}); class Services extends Component { renderRow(item) { @@ -42,4 +35,4 @@ Services.defaultProps = { }, }; -export default connect(stateToProps)(translate('Services')(Services)); \ No newline at end of file +export default Services; \ No newline at end of file diff --git a/src/components/showMore.js b/client/components/showMore.js similarity index 76% rename from src/components/showMore.js rename to client/components/showMore.js index a9b1c44..185d280 100644 --- a/src/components/showMore.js +++ b/client/components/showMore.js @@ -1,13 +1,8 @@ -var React = require('react'), - ptypes = React.PropTypes, - _ = require('lodash'); +import React, { PropTypes } from 'react'; class ShowMore extends React.Component { - render() { - var p = this.props; - return (
@@ -21,7 +16,7 @@ class ShowMore extends React.Component { } ShowMore.propTypes = { - onShowMore: ptypes.func.isRequired, + onShowMore: PropTypes.func.isRequired, }; export default ShowMore; diff --git a/src/components/simpleList.js b/client/components/simpleList.js similarity index 100% rename from src/components/simpleList.js rename to client/components/simpleList.js diff --git a/src/containers/team.js b/client/components/team.js similarity index 94% rename from src/containers/team.js rename to client/components/team.js index a9fdaf3..24aabfc 100644 --- a/src/containers/team.js +++ b/client/components/team.js @@ -1,6 +1,5 @@ import React, { PropTypes, Component } from 'react'; import { Link } from 'react-router'; -import translate from '../hoc/translate'; const routePaths = require('../../common/routePaths'); class Team extends Component { @@ -40,4 +39,4 @@ Team.defaultProps = { }, }; -export default translate('Team')(Team); \ No newline at end of file +export default Team; \ No newline at end of file diff --git a/src/containers/wrapper.js b/client/components/wrapper.js similarity index 77% rename from src/containers/wrapper.js rename to client/components/wrapper.js index b8933b5..ed2f809 100644 --- a/src/containers/wrapper.js +++ b/client/components/wrapper.js @@ -1,12 +1,12 @@ import React, { Component } from 'react'; import TranslationProvider from '../containers/translationProvider'; -import Header from './header'; +import Header from '../containers/headerContainer'; +import Footer from '../containers/footerContainer'; import Page from './page'; -import Footer from './footer'; class Wrapper extends Component { render() { - var p = this.props, s = p.strings; + var p = this.props; return (
diff --git a/src/constants.js b/client/config/constants.js similarity index 100% rename from src/constants.js rename to client/config/constants.js diff --git a/client/config/data.js b/client/config/data.js new file mode 100644 index 0000000..499af23 --- /dev/null +++ b/client/config/data.js @@ -0,0 +1,118 @@ +/* +This is the initial state of the Redux Store and default values for individual reduces + +Structure: reducer name => { default reducer data } +*/ +let data = {}; + +export const about = data.about = { + membersInfo: { description: 'about description' }, + members: [], +}; + +export const auth = data.auth = { + token: null, + userName: null, + isAuthenticated: false, + isAuthenticating: false, + statusText: null, +}; + +export const lang = data.lang = { + current: 'en', +}; + +export const projects = data.projects = { + items: [ + { + key: 'adaptabi', + name: 'Adaptabi', + description: 'New company site', + website: 'http://adaptabi.com', + img: '/client/assets/img/projects/adaptabi.png', + }, + { + key: 'safetybank', + name: 'Safetybank', + description: 'Best H&S system for construction companies', + website: 'http://safetybank.co.uk', + img: '/client/assets/img/projects/safetybank.png', + }, + { + key: 'squires', + name: 'Squires Kitchen', + description: 'Largest kitchen supply store in UK', + website: 'http://squires-shop.com', + img: '/client/assets/img/projects/squires.png', + }, + ], +}; + +export const services = data.services = { + items: [ + { + key: 'innovation', + name: 'Innovation', + icon: 'cog', + description: 'We boost startup recognition by creating unique, innovative apps!', + }, + { + key: 'maintenance', + name: 'Maintenance', + icon: 'save', + description: 'We keep your project running at peak performance forever!', + }, + { + key: 'consulting', + name: 'Consulting', + icon: 'comments', + description: 'Don\'t know how to make your dream idea come true? We do!', + }, + { + key: 'cooking', + name: 'Cooking', + icon: 'pie-chart', + description: 'We\'ll slap you with the best pizza in town!', + }, + ], +}; + +export const team = data.team = { + culture: 'Lorem ipsum organizational culture text', + members: [ + { + key: 'ionut', + name: 'Ionut Mandra', + img: '/client/assets/img/projects/safetybank.png', + position: 'Developer', + }, + { + key: 'marius', + name: 'Mihai-Marius Baciu', + img: '/client/assets/img/projects/safetybank.png', + position: 'Developer', + }, + { + key: 'teodor', + name: 'Teodor Sandu', + img: '/client/assets/img/projects/safetybank.png', + position: 'Developer', + }, + ], + gallery: [ + { + key: '1', + img: '/client/assets/img/projects/adaptabi.png', + }, + { + key: '2', + img: '/client/assets/img/projects/safetybank.png', + }, + { + key: '3', + img: '/client/assets/img/projects/squires.png', + }, + ], +}; + +export default data; \ No newline at end of file diff --git a/client/containers/aboutDetailsContainer.js b/client/containers/aboutDetailsContainer.js new file mode 100644 index 0000000..0c7fc0e --- /dev/null +++ b/client/containers/aboutDetailsContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import aboutDetails from '../components/aboutDetails'; + +export default translate('aboutDetails')(aboutDetails); \ No newline at end of file diff --git a/client/containers/aboutListContainer.js b/client/containers/aboutListContainer.js new file mode 100644 index 0000000..37fbfa7 --- /dev/null +++ b/client/containers/aboutListContainer.js @@ -0,0 +1,25 @@ +import * as ReactRedux from 'react-redux'; +import actions from '../actions'; +import AboutList from '../components/aboutList'; + +var mapStateToProps = function(state) { + return { + aboutState: state.about, + }; +}; + +var mapDispatchToProps = function(dispatch) { + return { + addMember: function(member) { + dispatch(actions.addMember(this.state.newItemText)); + }, + removeMember: function(member) { + dispatch(actions.removeMember(member)); + }, + getInitialMembers:function() { + dispatch(actions.getInitialMembers()); + }, + }; +}; + +module.exports.component = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(AboutList); diff --git a/client/containers/adminHomeContainer.js b/client/containers/adminHomeContainer.js new file mode 100644 index 0000000..e6da575 --- /dev/null +++ b/client/containers/adminHomeContainer.js @@ -0,0 +1,17 @@ +import {connect} from 'react-redux'; +import * as actions from '../actions'; +import AdminHome from '../components/adminHome'; + +const mapStateToProps = (state) => ({ + data: state.about, +}); + +const mapDispatchToProps = (dispatch) => { + return { + fetchProtectedData: function (token) { + dispatch(actions.editMembers(token)); + }, + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(AdminHome); diff --git a/src/components/AuthenticatedComponent.js b/client/containers/authenticatedContainer.js similarity index 86% rename from src/components/AuthenticatedComponent.js rename to client/containers/authenticatedContainer.js index 9e5fe72..db7c6e7 100644 --- a/src/components/AuthenticatedComponent.js +++ b/client/containers/authenticatedContainer.js @@ -2,26 +2,20 @@ import React from 'react'; import {connect} from 'react-redux'; import {pushState} from 'redux-router'; -export function requireAuthentication(Component) { - +export default (Component) => { class AuthenticatedComponent extends React.Component { - componentWillMount() { this.checkAuth(); } - componentWillReceiveProps(nextProps) { this.checkAuth(); } - checkAuth() { if (!this.props.isAuthenticated) { let redirectAfterLogin = this.props.location.pathname; this.props.dispatch(pushState(null, `/login?next=${redirectAfterLogin}`)); } } - - /// ... is jsx spread operator render() { return (
@@ -30,17 +24,15 @@ export function requireAuthentication(Component) { : null }
- ) - + ); } } const mapStateToProps = (state) => ({ token: state.auth.token, userName: state.auth.userName, - isAuthenticated: state.auth.isAuthenticated + isAuthenticated: state.auth.isAuthenticated, }); return connect(mapStateToProps)(AuthenticatedComponent); - -} \ No newline at end of file +}; \ No newline at end of file diff --git a/client/containers/contactContainer.js b/client/containers/contactContainer.js new file mode 100644 index 0000000..29d5f4f --- /dev/null +++ b/client/containers/contactContainer.js @@ -0,0 +1,36 @@ +import {reduxForm} from 'redux-form'; +import fetch from 'isomorphic-fetch'; +import { contact as validate } from '../../common/validators'; +import Contact from '../components/contact'; + +require('es6-promise').polyfill(); + +const fields = ['name', 'email', 'message']; + +class ContactContainer extends Contact { + submit(values, dispatch) { + return new Promise((resolve, reject) => { + fetch('/api/contact', { + method: 'post', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }) + .then(response => response.json()) + .then(response => { + response.success && resolve() || reject(response.errors); + }); + }); + } +} + +ContactContainer = reduxForm({ + form: 'contact', + fields, + //toggle commenting the next line. Commented = will use server-side validation. Uncommented = will use client-side validation. + validate, +})(ContactContainer); + +export default ContactContainer; diff --git a/client/containers/cultureContainer.js b/client/containers/cultureContainer.js new file mode 100644 index 0000000..6dae8eb --- /dev/null +++ b/client/containers/cultureContainer.js @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import Culture from '../components/culture'; + +const stateToProps = state => ({ + culture: state.team.culture, +}); + +export default connect(stateToProps)(Culture); \ No newline at end of file diff --git a/client/containers/footerContainer.js b/client/containers/footerContainer.js new file mode 100644 index 0000000..79f95f7 --- /dev/null +++ b/client/containers/footerContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import Footer from '../components/footer'; + +export default translate('Footer')(Footer); \ No newline at end of file diff --git a/client/containers/galleryContainer.js b/client/containers/galleryContainer.js new file mode 100644 index 0000000..c8ddfa3 --- /dev/null +++ b/client/containers/galleryContainer.js @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import Gallery from '../components/gallery'; + +const stateToProps = state => ({ + items: state.team.gallery, +}); + +export default connect(stateToProps)(Gallery); \ No newline at end of file diff --git a/client/containers/headerContainer.js b/client/containers/headerContainer.js new file mode 100644 index 0000000..87f2142 --- /dev/null +++ b/client/containers/headerContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import Header from '../components/header'; + +export default translate('Header')(Header); \ No newline at end of file diff --git a/client/containers/headerLinksContainer.js b/client/containers/headerLinksContainer.js new file mode 100644 index 0000000..28f7811 --- /dev/null +++ b/client/containers/headerLinksContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import HeaderLinks from '../components/headerLinks'; + +export default translate('HeaderLinks')(HeaderLinks); \ No newline at end of file diff --git a/client/containers/homeContainer.js b/client/containers/homeContainer.js new file mode 100644 index 0000000..42647b0 --- /dev/null +++ b/client/containers/homeContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import Home from '../components/home'; + +export default translate('Home')(Home); diff --git a/client/containers/languagePickerContainer.js b/client/containers/languagePickerContainer.js new file mode 100644 index 0000000..b86c9d3 --- /dev/null +++ b/client/containers/languagePickerContainer.js @@ -0,0 +1,13 @@ +import { changeLanguage } from '../actions'; +import { connect } from 'react-redux'; +import LanguagePicker from '../components/languagePicker'; + +const stateToProps = state => ({ + currentLanguage: state.lang.current, +}); + +const actionsToProps = dispatch => ({ + handleChange: event => dispatch(changeLanguage(event.target.value)), +}); + +export default connect(stateToProps, actionsToProps)(LanguagePicker); \ No newline at end of file diff --git a/client/containers/loginContainer.js b/client/containers/loginContainer.js new file mode 100644 index 0000000..e78753b --- /dev/null +++ b/client/containers/loginContainer.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux'; +import actions from '../actions'; +import Login from '../components/login'; + +const mapStateToProps = (state) => { + return { authState: state.auth }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + doLogin: (usr, pwd) => { + dispatch(actions.doLogin(usr, pwd)); + }, + }; +}; + +module.exports = connect(mapStateToProps, mapDispatchToProps)(Login); diff --git a/client/containers/memberDetailsContainer.js b/client/containers/memberDetailsContainer.js new file mode 100644 index 0000000..0ee29a5 --- /dev/null +++ b/client/containers/memberDetailsContainer.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import translate from './translate'; +import MemberDetails from '../components/memberDetails'; + +const stateToProps = state => ({ + items: state.team.members, +}); + +export default connect(stateToProps)(translate('MemberDetails')(MemberDetails)); \ No newline at end of file diff --git a/client/containers/membersContainer.js b/client/containers/membersContainer.js new file mode 100644 index 0000000..1909705 --- /dev/null +++ b/client/containers/membersContainer.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import translate from './translate'; +import Members from '../components/members'; + +const stateToProps = state => ({ + items: state.team.members, +}); + +export default connect(stateToProps)(translate('Members')(Members)); \ No newline at end of file diff --git a/client/containers/projectDetailsContainer.js b/client/containers/projectDetailsContainer.js new file mode 100644 index 0000000..b09f14b --- /dev/null +++ b/client/containers/projectDetailsContainer.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import translate from './translate'; +import ProjectDetails from '../components/projectDetails'; + +const stateToProps = state => ({ + items: state.projects.items, +}); + +export default connect(stateToProps)(translate('ProjectDetails')(ProjectDetails)); \ No newline at end of file diff --git a/client/containers/projectsListContainer.js b/client/containers/projectsListContainer.js new file mode 100644 index 0000000..449a2bf --- /dev/null +++ b/client/containers/projectsListContainer.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import translate from './translate'; +import ProjectsList from '../components/projectsList'; + +const stateToProps = state => ({ + items: state.projects.items, +}); + +export default connect(stateToProps)(translate('ProjectsList')(ProjectsList)); \ No newline at end of file diff --git a/client/containers/servicesContainer.js b/client/containers/servicesContainer.js new file mode 100644 index 0000000..e36d288 --- /dev/null +++ b/client/containers/servicesContainer.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import translate from './translate'; +import Services from '../components/services'; + +const stateToProps = state => ({ + items: state.services.items, +}); + +export default connect(stateToProps)(translate('Services')(Services)); \ No newline at end of file diff --git a/client/containers/teamContainer.js b/client/containers/teamContainer.js new file mode 100644 index 0000000..ed8b7ff --- /dev/null +++ b/client/containers/teamContainer.js @@ -0,0 +1,4 @@ +import translate from './translate'; +import Team from '../components/team'; + +export default translate('Team')(Team); \ No newline at end of file diff --git a/src/hoc/translate.js b/client/containers/translate.js similarity index 87% rename from src/hoc/translate.js rename to client/containers/translate.js index 2005f9b..39e41c2 100644 --- a/src/hoc/translate.js +++ b/client/containers/translate.js @@ -1,10 +1,10 @@ import React from 'react'; -import en from '../../lang/en'; -import ro from '../../lang/ro'; +import en from '../lang/en'; +import ro from '../lang/ro'; const languages = { en, ro }; -export default function translate(key) { +export default (key) => { return Component => { class TranslationComponent extends React.Component { render() { @@ -23,4 +23,4 @@ export default function translate(key) { return TranslationComponent; }; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/containers/translationProvider.js b/client/containers/translationProvider.js similarity index 100% rename from src/containers/translationProvider.js rename to client/containers/translationProvider.js diff --git a/src/index.js b/client/index.js similarity index 63% rename from src/index.js rename to client/index.js index cfbd951..8b59516 100644 --- a/src/index.js +++ b/client/index.js @@ -3,15 +3,14 @@ This is the entry point for the app! From here we merely import our routes defin then use React and React-DOM to render it. */ -import { browserHistory } from 'react-router' -import * as actions from './actions' - -var React = require('react'), - ReactDOM = require('react-dom'), - Router = require('react-router').Router, - Provider = require('react-redux').Provider, - store = require('./store'), - routes = require('./routes'); +import { browserHistory } from 'react-router'; +import * as actions from './actions'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router } from 'react-router'; +import { Provider } from 'react-redux'; +import store from './store'; +import routes from './routes'; ReactDOM.render( // The top-level Provider is what allows us to `connect` components to the store using ReactRedux.connect @@ -24,4 +23,4 @@ ReactDOM.render( let token = localStorage.getItem('token'); if (token !== null) { store.dispatch(actions.loginUserSuccess(token)); -} +} \ No newline at end of file diff --git a/lang/en.js b/client/lang/en.js similarity index 100% rename from lang/en.js rename to client/lang/en.js diff --git a/lang/languages.json b/client/lang/languages.json similarity index 100% rename from lang/languages.json rename to client/lang/languages.json diff --git a/lang/ro.js b/client/lang/ro.js similarity index 100% rename from lang/ro.js rename to client/lang/ro.js diff --git a/lib/bootstrap/LICENSE b/client/lib/bootstrap/LICENSE similarity index 100% rename from lib/bootstrap/LICENSE rename to client/lib/bootstrap/LICENSE diff --git a/lib/bootstrap/js/src/alert.js b/client/lib/bootstrap/js/src/alert.js similarity index 100% rename from lib/bootstrap/js/src/alert.js rename to client/lib/bootstrap/js/src/alert.js diff --git a/lib/bootstrap/js/src/button.js b/client/lib/bootstrap/js/src/button.js similarity index 100% rename from lib/bootstrap/js/src/button.js rename to client/lib/bootstrap/js/src/button.js diff --git a/lib/bootstrap/js/src/carousel.js b/client/lib/bootstrap/js/src/carousel.js similarity index 100% rename from lib/bootstrap/js/src/carousel.js rename to client/lib/bootstrap/js/src/carousel.js diff --git a/lib/bootstrap/js/src/collapse.js b/client/lib/bootstrap/js/src/collapse.js similarity index 100% rename from lib/bootstrap/js/src/collapse.js rename to client/lib/bootstrap/js/src/collapse.js diff --git a/lib/bootstrap/js/src/dropdown.js b/client/lib/bootstrap/js/src/dropdown.js similarity index 100% rename from lib/bootstrap/js/src/dropdown.js rename to client/lib/bootstrap/js/src/dropdown.js diff --git a/lib/bootstrap/js/src/modal.js b/client/lib/bootstrap/js/src/modal.js similarity index 100% rename from lib/bootstrap/js/src/modal.js rename to client/lib/bootstrap/js/src/modal.js diff --git a/lib/bootstrap/js/src/popover.js b/client/lib/bootstrap/js/src/popover.js similarity index 100% rename from lib/bootstrap/js/src/popover.js rename to client/lib/bootstrap/js/src/popover.js diff --git a/lib/bootstrap/js/src/scrollspy.js b/client/lib/bootstrap/js/src/scrollspy.js similarity index 100% rename from lib/bootstrap/js/src/scrollspy.js rename to client/lib/bootstrap/js/src/scrollspy.js diff --git a/lib/bootstrap/js/src/tab.js b/client/lib/bootstrap/js/src/tab.js similarity index 100% rename from lib/bootstrap/js/src/tab.js rename to client/lib/bootstrap/js/src/tab.js diff --git a/lib/bootstrap/js/src/tooltip.js b/client/lib/bootstrap/js/src/tooltip.js similarity index 100% rename from lib/bootstrap/js/src/tooltip.js rename to client/lib/bootstrap/js/src/tooltip.js diff --git a/lib/bootstrap/js/src/util.js b/client/lib/bootstrap/js/src/util.js similarity index 100% rename from lib/bootstrap/js/src/util.js rename to client/lib/bootstrap/js/src/util.js diff --git a/lib/bootstrap/scss/_alert.scss b/client/lib/bootstrap/scss/_alert.scss similarity index 100% rename from lib/bootstrap/scss/_alert.scss rename to client/lib/bootstrap/scss/_alert.scss diff --git a/lib/bootstrap/scss/_animation.scss b/client/lib/bootstrap/scss/_animation.scss similarity index 100% rename from lib/bootstrap/scss/_animation.scss rename to client/lib/bootstrap/scss/_animation.scss diff --git a/lib/bootstrap/scss/_bootstrap-flex.scss b/client/lib/bootstrap/scss/_bootstrap-flex.scss similarity index 100% rename from lib/bootstrap/scss/_bootstrap-flex.scss rename to client/lib/bootstrap/scss/_bootstrap-flex.scss diff --git a/lib/bootstrap/scss/_bootstrap-grid.scss b/client/lib/bootstrap/scss/_bootstrap-grid.scss similarity index 100% rename from lib/bootstrap/scss/_bootstrap-grid.scss rename to client/lib/bootstrap/scss/_bootstrap-grid.scss diff --git a/lib/bootstrap/scss/_bootstrap-reboot.scss b/client/lib/bootstrap/scss/_bootstrap-reboot.scss similarity index 100% rename from lib/bootstrap/scss/_bootstrap-reboot.scss rename to client/lib/bootstrap/scss/_bootstrap-reboot.scss diff --git a/lib/bootstrap/scss/_bootstrap.scss b/client/lib/bootstrap/scss/_bootstrap.scss similarity index 100% rename from lib/bootstrap/scss/_bootstrap.scss rename to client/lib/bootstrap/scss/_bootstrap.scss diff --git a/lib/bootstrap/scss/_breadcrumb.scss b/client/lib/bootstrap/scss/_breadcrumb.scss similarity index 100% rename from lib/bootstrap/scss/_breadcrumb.scss rename to client/lib/bootstrap/scss/_breadcrumb.scss diff --git a/lib/bootstrap/scss/_button-group.scss b/client/lib/bootstrap/scss/_button-group.scss similarity index 100% rename from lib/bootstrap/scss/_button-group.scss rename to client/lib/bootstrap/scss/_button-group.scss diff --git a/lib/bootstrap/scss/_buttons.scss b/client/lib/bootstrap/scss/_buttons.scss similarity index 100% rename from lib/bootstrap/scss/_buttons.scss rename to client/lib/bootstrap/scss/_buttons.scss diff --git a/lib/bootstrap/scss/_card.scss b/client/lib/bootstrap/scss/_card.scss similarity index 100% rename from lib/bootstrap/scss/_card.scss rename to client/lib/bootstrap/scss/_card.scss diff --git a/lib/bootstrap/scss/_carousel.scss b/client/lib/bootstrap/scss/_carousel.scss similarity index 100% rename from lib/bootstrap/scss/_carousel.scss rename to client/lib/bootstrap/scss/_carousel.scss diff --git a/lib/bootstrap/scss/_close.scss b/client/lib/bootstrap/scss/_close.scss similarity index 100% rename from lib/bootstrap/scss/_close.scss rename to client/lib/bootstrap/scss/_close.scss diff --git a/lib/bootstrap/scss/_code.scss b/client/lib/bootstrap/scss/_code.scss similarity index 100% rename from lib/bootstrap/scss/_code.scss rename to client/lib/bootstrap/scss/_code.scss diff --git a/lib/bootstrap/scss/_custom-forms.scss b/client/lib/bootstrap/scss/_custom-forms.scss similarity index 100% rename from lib/bootstrap/scss/_custom-forms.scss rename to client/lib/bootstrap/scss/_custom-forms.scss diff --git a/lib/bootstrap/scss/_dropdown.scss b/client/lib/bootstrap/scss/_dropdown.scss similarity index 100% rename from lib/bootstrap/scss/_dropdown.scss rename to client/lib/bootstrap/scss/_dropdown.scss diff --git a/lib/bootstrap/scss/_forms.scss b/client/lib/bootstrap/scss/_forms.scss similarity index 100% rename from lib/bootstrap/scss/_forms.scss rename to client/lib/bootstrap/scss/_forms.scss diff --git a/lib/bootstrap/scss/_grid.scss b/client/lib/bootstrap/scss/_grid.scss similarity index 100% rename from lib/bootstrap/scss/_grid.scss rename to client/lib/bootstrap/scss/_grid.scss diff --git a/lib/bootstrap/scss/_images.scss b/client/lib/bootstrap/scss/_images.scss similarity index 100% rename from lib/bootstrap/scss/_images.scss rename to client/lib/bootstrap/scss/_images.scss diff --git a/lib/bootstrap/scss/_input-group.scss b/client/lib/bootstrap/scss/_input-group.scss similarity index 100% rename from lib/bootstrap/scss/_input-group.scss rename to client/lib/bootstrap/scss/_input-group.scss diff --git a/lib/bootstrap/scss/_jumbotron.scss b/client/lib/bootstrap/scss/_jumbotron.scss similarity index 100% rename from lib/bootstrap/scss/_jumbotron.scss rename to client/lib/bootstrap/scss/_jumbotron.scss diff --git a/lib/bootstrap/scss/_labels.scss b/client/lib/bootstrap/scss/_labels.scss similarity index 100% rename from lib/bootstrap/scss/_labels.scss rename to client/lib/bootstrap/scss/_labels.scss diff --git a/lib/bootstrap/scss/_list-group.scss b/client/lib/bootstrap/scss/_list-group.scss similarity index 100% rename from lib/bootstrap/scss/_list-group.scss rename to client/lib/bootstrap/scss/_list-group.scss diff --git a/lib/bootstrap/scss/_media.scss b/client/lib/bootstrap/scss/_media.scss similarity index 100% rename from lib/bootstrap/scss/_media.scss rename to client/lib/bootstrap/scss/_media.scss diff --git a/lib/bootstrap/scss/_mixins.scss b/client/lib/bootstrap/scss/_mixins.scss similarity index 100% rename from lib/bootstrap/scss/_mixins.scss rename to client/lib/bootstrap/scss/_mixins.scss diff --git a/lib/bootstrap/scss/_modal.scss b/client/lib/bootstrap/scss/_modal.scss similarity index 100% rename from lib/bootstrap/scss/_modal.scss rename to client/lib/bootstrap/scss/_modal.scss diff --git a/lib/bootstrap/scss/_nav.scss b/client/lib/bootstrap/scss/_nav.scss similarity index 100% rename from lib/bootstrap/scss/_nav.scss rename to client/lib/bootstrap/scss/_nav.scss diff --git a/lib/bootstrap/scss/_navbar.scss b/client/lib/bootstrap/scss/_navbar.scss similarity index 100% rename from lib/bootstrap/scss/_navbar.scss rename to client/lib/bootstrap/scss/_navbar.scss diff --git a/lib/bootstrap/scss/_normalize.scss b/client/lib/bootstrap/scss/_normalize.scss similarity index 100% rename from lib/bootstrap/scss/_normalize.scss rename to client/lib/bootstrap/scss/_normalize.scss diff --git a/lib/bootstrap/scss/_pager.scss b/client/lib/bootstrap/scss/_pager.scss similarity index 100% rename from lib/bootstrap/scss/_pager.scss rename to client/lib/bootstrap/scss/_pager.scss diff --git a/lib/bootstrap/scss/_pagination.scss b/client/lib/bootstrap/scss/_pagination.scss similarity index 100% rename from lib/bootstrap/scss/_pagination.scss rename to client/lib/bootstrap/scss/_pagination.scss diff --git a/lib/bootstrap/scss/_popover.scss b/client/lib/bootstrap/scss/_popover.scss similarity index 100% rename from lib/bootstrap/scss/_popover.scss rename to client/lib/bootstrap/scss/_popover.scss diff --git a/lib/bootstrap/scss/_print.scss b/client/lib/bootstrap/scss/_print.scss similarity index 100% rename from lib/bootstrap/scss/_print.scss rename to client/lib/bootstrap/scss/_print.scss diff --git a/lib/bootstrap/scss/_progress.scss b/client/lib/bootstrap/scss/_progress.scss similarity index 100% rename from lib/bootstrap/scss/_progress.scss rename to client/lib/bootstrap/scss/_progress.scss diff --git a/lib/bootstrap/scss/_reboot.scss b/client/lib/bootstrap/scss/_reboot.scss similarity index 100% rename from lib/bootstrap/scss/_reboot.scss rename to client/lib/bootstrap/scss/_reboot.scss diff --git a/lib/bootstrap/scss/_responsive-embed.scss b/client/lib/bootstrap/scss/_responsive-embed.scss similarity index 100% rename from lib/bootstrap/scss/_responsive-embed.scss rename to client/lib/bootstrap/scss/_responsive-embed.scss diff --git a/lib/bootstrap/scss/_tables.scss b/client/lib/bootstrap/scss/_tables.scss similarity index 100% rename from lib/bootstrap/scss/_tables.scss rename to client/lib/bootstrap/scss/_tables.scss diff --git a/lib/bootstrap/scss/_tooltip.scss b/client/lib/bootstrap/scss/_tooltip.scss similarity index 100% rename from lib/bootstrap/scss/_tooltip.scss rename to client/lib/bootstrap/scss/_tooltip.scss diff --git a/lib/bootstrap/scss/_type.scss b/client/lib/bootstrap/scss/_type.scss similarity index 100% rename from lib/bootstrap/scss/_type.scss rename to client/lib/bootstrap/scss/_type.scss diff --git a/lib/bootstrap/scss/_utilities-background.scss b/client/lib/bootstrap/scss/_utilities-background.scss similarity index 100% rename from lib/bootstrap/scss/_utilities-background.scss rename to client/lib/bootstrap/scss/_utilities-background.scss diff --git a/lib/bootstrap/scss/_utilities-responsive.scss b/client/lib/bootstrap/scss/_utilities-responsive.scss similarity index 100% rename from lib/bootstrap/scss/_utilities-responsive.scss rename to client/lib/bootstrap/scss/_utilities-responsive.scss diff --git a/lib/bootstrap/scss/_utilities-spacing.scss b/client/lib/bootstrap/scss/_utilities-spacing.scss similarity index 100% rename from lib/bootstrap/scss/_utilities-spacing.scss rename to client/lib/bootstrap/scss/_utilities-spacing.scss diff --git a/lib/bootstrap/scss/_utilities.scss b/client/lib/bootstrap/scss/_utilities.scss similarity index 100% rename from lib/bootstrap/scss/_utilities.scss rename to client/lib/bootstrap/scss/_utilities.scss diff --git a/lib/bootstrap/scss/_variables.scss b/client/lib/bootstrap/scss/_variables.scss similarity index 100% rename from lib/bootstrap/scss/_variables.scss rename to client/lib/bootstrap/scss/_variables.scss diff --git a/lib/bootstrap/scss/mixins/_alert.scss b/client/lib/bootstrap/scss/mixins/_alert.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_alert.scss rename to client/lib/bootstrap/scss/mixins/_alert.scss diff --git a/lib/bootstrap/scss/mixins/_background-variant.scss b/client/lib/bootstrap/scss/mixins/_background-variant.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_background-variant.scss rename to client/lib/bootstrap/scss/mixins/_background-variant.scss diff --git a/lib/bootstrap/scss/mixins/_border-radius.scss b/client/lib/bootstrap/scss/mixins/_border-radius.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_border-radius.scss rename to client/lib/bootstrap/scss/mixins/_border-radius.scss diff --git a/lib/bootstrap/scss/mixins/_breakpoints.scss b/client/lib/bootstrap/scss/mixins/_breakpoints.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_breakpoints.scss rename to client/lib/bootstrap/scss/mixins/_breakpoints.scss diff --git a/lib/bootstrap/scss/mixins/_buttons.scss b/client/lib/bootstrap/scss/mixins/_buttons.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_buttons.scss rename to client/lib/bootstrap/scss/mixins/_buttons.scss diff --git a/lib/bootstrap/scss/mixins/_cards.scss b/client/lib/bootstrap/scss/mixins/_cards.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_cards.scss rename to client/lib/bootstrap/scss/mixins/_cards.scss diff --git a/lib/bootstrap/scss/mixins/_center-block.scss b/client/lib/bootstrap/scss/mixins/_center-block.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_center-block.scss rename to client/lib/bootstrap/scss/mixins/_center-block.scss diff --git a/lib/bootstrap/scss/mixins/_clearfix.scss b/client/lib/bootstrap/scss/mixins/_clearfix.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_clearfix.scss rename to client/lib/bootstrap/scss/mixins/_clearfix.scss diff --git a/lib/bootstrap/scss/mixins/_forms.scss b/client/lib/bootstrap/scss/mixins/_forms.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_forms.scss rename to client/lib/bootstrap/scss/mixins/_forms.scss diff --git a/lib/bootstrap/scss/mixins/_gradients.scss b/client/lib/bootstrap/scss/mixins/_gradients.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_gradients.scss rename to client/lib/bootstrap/scss/mixins/_gradients.scss diff --git a/lib/bootstrap/scss/mixins/_grid-framework.scss b/client/lib/bootstrap/scss/mixins/_grid-framework.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_grid-framework.scss rename to client/lib/bootstrap/scss/mixins/_grid-framework.scss diff --git a/lib/bootstrap/scss/mixins/_grid.scss b/client/lib/bootstrap/scss/mixins/_grid.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_grid.scss rename to client/lib/bootstrap/scss/mixins/_grid.scss diff --git a/lib/bootstrap/scss/mixins/_hover.scss b/client/lib/bootstrap/scss/mixins/_hover.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_hover.scss rename to client/lib/bootstrap/scss/mixins/_hover.scss diff --git a/lib/bootstrap/scss/mixins/_image.scss b/client/lib/bootstrap/scss/mixins/_image.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_image.scss rename to client/lib/bootstrap/scss/mixins/_image.scss diff --git a/lib/bootstrap/scss/mixins/_label.scss b/client/lib/bootstrap/scss/mixins/_label.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_label.scss rename to client/lib/bootstrap/scss/mixins/_label.scss diff --git a/lib/bootstrap/scss/mixins/_list-group.scss b/client/lib/bootstrap/scss/mixins/_list-group.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_list-group.scss rename to client/lib/bootstrap/scss/mixins/_list-group.scss diff --git a/lib/bootstrap/scss/mixins/_lists.scss b/client/lib/bootstrap/scss/mixins/_lists.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_lists.scss rename to client/lib/bootstrap/scss/mixins/_lists.scss diff --git a/lib/bootstrap/scss/mixins/_nav-divider.scss b/client/lib/bootstrap/scss/mixins/_nav-divider.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_nav-divider.scss rename to client/lib/bootstrap/scss/mixins/_nav-divider.scss diff --git a/lib/bootstrap/scss/mixins/_navbar-align.scss b/client/lib/bootstrap/scss/mixins/_navbar-align.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_navbar-align.scss rename to client/lib/bootstrap/scss/mixins/_navbar-align.scss diff --git a/lib/bootstrap/scss/mixins/_pagination.scss b/client/lib/bootstrap/scss/mixins/_pagination.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_pagination.scss rename to client/lib/bootstrap/scss/mixins/_pagination.scss diff --git a/lib/bootstrap/scss/mixins/_progress.scss b/client/lib/bootstrap/scss/mixins/_progress.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_progress.scss rename to client/lib/bootstrap/scss/mixins/_progress.scss diff --git a/lib/bootstrap/scss/mixins/_pulls.scss b/client/lib/bootstrap/scss/mixins/_pulls.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_pulls.scss rename to client/lib/bootstrap/scss/mixins/_pulls.scss diff --git a/lib/bootstrap/scss/mixins/_reset-filter.scss b/client/lib/bootstrap/scss/mixins/_reset-filter.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_reset-filter.scss rename to client/lib/bootstrap/scss/mixins/_reset-filter.scss diff --git a/lib/bootstrap/scss/mixins/_reset-text.scss b/client/lib/bootstrap/scss/mixins/_reset-text.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_reset-text.scss rename to client/lib/bootstrap/scss/mixins/_reset-text.scss diff --git a/lib/bootstrap/scss/mixins/_resize.scss b/client/lib/bootstrap/scss/mixins/_resize.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_resize.scss rename to client/lib/bootstrap/scss/mixins/_resize.scss diff --git a/lib/bootstrap/scss/mixins/_screen-reader.scss b/client/lib/bootstrap/scss/mixins/_screen-reader.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_screen-reader.scss rename to client/lib/bootstrap/scss/mixins/_screen-reader.scss diff --git a/lib/bootstrap/scss/mixins/_size.scss b/client/lib/bootstrap/scss/mixins/_size.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_size.scss rename to client/lib/bootstrap/scss/mixins/_size.scss diff --git a/lib/bootstrap/scss/mixins/_tab-focus.scss b/client/lib/bootstrap/scss/mixins/_tab-focus.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_tab-focus.scss rename to client/lib/bootstrap/scss/mixins/_tab-focus.scss diff --git a/lib/bootstrap/scss/mixins/_table-row.scss b/client/lib/bootstrap/scss/mixins/_table-row.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_table-row.scss rename to client/lib/bootstrap/scss/mixins/_table-row.scss diff --git a/lib/bootstrap/scss/mixins/_text-emphasis.scss b/client/lib/bootstrap/scss/mixins/_text-emphasis.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_text-emphasis.scss rename to client/lib/bootstrap/scss/mixins/_text-emphasis.scss diff --git a/lib/bootstrap/scss/mixins/_text-hide.scss b/client/lib/bootstrap/scss/mixins/_text-hide.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_text-hide.scss rename to client/lib/bootstrap/scss/mixins/_text-hide.scss diff --git a/lib/bootstrap/scss/mixins/_text-truncate.scss b/client/lib/bootstrap/scss/mixins/_text-truncate.scss similarity index 100% rename from lib/bootstrap/scss/mixins/_text-truncate.scss rename to client/lib/bootstrap/scss/mixins/_text-truncate.scss diff --git a/icomoon/fonts/new-company-site.eot b/client/lib/icomoon/fonts/new-company-site.eot similarity index 100% rename from icomoon/fonts/new-company-site.eot rename to client/lib/icomoon/fonts/new-company-site.eot diff --git a/icomoon/fonts/new-company-site.svg b/client/lib/icomoon/fonts/new-company-site.svg similarity index 100% rename from icomoon/fonts/new-company-site.svg rename to client/lib/icomoon/fonts/new-company-site.svg diff --git a/icomoon/fonts/new-company-site.ttf b/client/lib/icomoon/fonts/new-company-site.ttf similarity index 100% rename from icomoon/fonts/new-company-site.ttf rename to client/lib/icomoon/fonts/new-company-site.ttf diff --git a/icomoon/fonts/new-company-site.woff b/client/lib/icomoon/fonts/new-company-site.woff similarity index 100% rename from icomoon/fonts/new-company-site.woff rename to client/lib/icomoon/fonts/new-company-site.woff diff --git a/icomoon/project-details/new-company-site.json b/client/lib/icomoon/project-details/new-company-site.json similarity index 100% rename from icomoon/project-details/new-company-site.json rename to client/lib/icomoon/project-details/new-company-site.json diff --git a/icomoon/style.scss b/client/lib/icomoon/style.scss similarity index 100% rename from icomoon/style.scss rename to client/lib/icomoon/style.scss diff --git a/icomoon/variables.scss b/client/lib/icomoon/variables.scss similarity index 100% rename from icomoon/variables.scss rename to client/lib/icomoon/variables.scss diff --git a/lib/photoswipe/_photoswipe.css b/client/lib/photoswipe/_photoswipe.css similarity index 100% rename from lib/photoswipe/_photoswipe.css rename to client/lib/photoswipe/_photoswipe.css diff --git a/lib/photoswipe/_photoswipe.scss b/client/lib/photoswipe/_photoswipe.scss similarity index 100% rename from lib/photoswipe/_photoswipe.scss rename to client/lib/photoswipe/_photoswipe.scss diff --git a/lib/photoswipe/default-skin.png b/client/lib/photoswipe/default-skin.png similarity index 100% rename from lib/photoswipe/default-skin.png rename to client/lib/photoswipe/default-skin.png diff --git a/lib/photoswipe/preloader.gif b/client/lib/photoswipe/preloader.gif similarity index 100% rename from lib/photoswipe/preloader.gif rename to client/lib/photoswipe/preloader.gif diff --git a/client/reducers/about.js b/client/reducers/about.js new file mode 100644 index 0000000..3328cae --- /dev/null +++ b/client/reducers/about.js @@ -0,0 +1,32 @@ +import C from '../config/constants'; +import { about as data } from '../config/data'; + +export default (state, action) => { + let newstate = Object.assign({}, state); + + switch (action.type) { + case C.GET_MEMBERS: + return data.about.members; + + case C.ADD_MEMBER: + newstate.members = state.members.concat({ + id: newstate.members.length + 1, + name: action.member, + email: 'c@c.com', + }); + return newstate; + + case C.REMOVE_MEMBER: { + const index = state.members.map(function (x) { return x.id; }).indexOf(action.member); + newstate.members = state.members.slice(0, index) + .concat(state.members.slice(index + 1)); + return newstate; + } + case C.INIT_MEMBERS_LIST: + newstate.members = action.data.members; + newstate.membersInfo = action.data.membersInfo; + return newstate; + + default: return state || data; + } +}; diff --git a/client/reducers/auth.js b/client/reducers/auth.js new file mode 100644 index 0000000..6abdbdb --- /dev/null +++ b/client/reducers/auth.js @@ -0,0 +1,44 @@ +import jwtDecode from 'jwt-decode'; +import C from '../config/constants'; +import { auth as data } from '../config/data'; + +export default (state, action) => { + + switch (action.type) { + case C.LOGIN_USER_REQUEST: + return Object.assign({}, state, { + 'isAuthenticating': true, + 'statusText': null, + }); + + case C.LOGIN_USER_SUCCESS: + return Object.assign({}, state, { + 'isAuthenticating': false, + 'isAuthenticated': true, + 'token': action.payload.token, + 'userName': jwtDecode(action.payload.token).userName, + 'statusText': 'You have been successfully logged in.', + }); + + + case C.LOGIN_USER_FAILURE: + return Object.assign({}, state, { + 'isAuthenticating': false, + 'isAuthenticated': false, + 'token': null, + 'userName': null, + 'statusText': `Authentication Error: ${action.payload.status} ${action.payload.statusText}`, + }); + + + case C.LOGOUT_USER: + return Object.assign({}, state, { + 'isAuthenticated': false, + 'token': null, + 'userName': null, + 'statusText': 'You have been successfully logged out.', + }); + + default: return state || data; + } +}; \ No newline at end of file diff --git a/client/reducers/lang.js b/client/reducers/lang.js new file mode 100644 index 0000000..3ee21b5 --- /dev/null +++ b/client/reducers/lang.js @@ -0,0 +1,14 @@ +import C from '../config/constants'; +import { lang as data } from '../config/data'; + +export default (state, action) => { + let newState = Object.assign({}, data, state); + + switch (action.type) { + case C.CHANGE_LANGUAGE: + newState.current = action.language || data.current; + return newState; + + default: return state || data; + } +}; \ No newline at end of file diff --git a/client/reducers/projects.js b/client/reducers/projects.js new file mode 100644 index 0000000..8382cb1 --- /dev/null +++ b/client/reducers/projects.js @@ -0,0 +1,7 @@ +import { projects as data } from '../config/data'; + +export default (state, action) => { + switch (action.type) { + default: return state || data; + } +}; \ No newline at end of file diff --git a/client/reducers/services.js b/client/reducers/services.js new file mode 100644 index 0000000..e84115b --- /dev/null +++ b/client/reducers/services.js @@ -0,0 +1,7 @@ +import { services as data } from '../config/data'; + +export default (state, action) => { + switch (action.type) { + default: return state || data; + } +}; \ No newline at end of file diff --git a/client/reducers/team.js b/client/reducers/team.js new file mode 100644 index 0000000..32f390b --- /dev/null +++ b/client/reducers/team.js @@ -0,0 +1,7 @@ +import { team as data } from '../config/data'; + +export default (state, action) => { + switch (action.type) { + default: return state || data; + } +}; \ No newline at end of file diff --git a/src/routes.js b/client/routes.js similarity index 59% rename from src/routes.js rename to client/routes.js index 1277c37..982e7b5 100644 --- a/src/routes.js +++ b/client/routes.js @@ -1,30 +1,30 @@ /* -This is the "sitemap" of our app! +This is the "sitemap" of the client side of our app! */ -var React = require('react'), - ReactRouter = require('react-router'), - Route = ReactRouter.Route, - IndexRedirect = ReactRouter.IndexRedirect, - AdminHome = require('./containers/adminHome'), - AboutList = require('./containers/aboutList').component, - LoginComponent = require('./components/LoginComponent'), -routePaths = require('../common/routePaths'); -import AboutDetails from './components/aboutDetails'; -import ContactPage from './components/contact'; +import React from 'react'; +import { Route, IndexRedirect } from 'react-router'; +import routePaths from '../common/routePaths'; + +import requireAuthentication from './containers/authenticatedContainer'; + +import Home from './containers/homeContainer'; +import AdminHome from './containers/adminHomeContainer'; +import { component as AboutList } from './containers/aboutListContainer'; +import LoginComponent from './containers/loginContainer'; +import AboutDetails from './containers/aboutDetailsContainer'; +import ContactPage from './containers/contactContainer'; import GalleryExample from './components/galleryExample'; -import {requireAuthentication} from './components/AuthenticatedComponent'; -import GridsPage from './containers/gridsPage'; -import ProjectsList from './containers/projectsList'; -import ServicesList from './containers/services'; -import ProjectDetails from './components/projectDetails'; -import Team from './containers/team'; -import Members from './containers/members'; -import MemberDetails from './components/memberDetails'; -import Culture from './components/culture'; -import Gallery from './containers/gallery'; -import Wrapper from './containers/wrapper'; -import Home from './components/home'; +import GridsPage from './components/gridsPage'; +import ProjectsList from './containers/projectsListContainer'; +import ServicesList from './containers/servicesContainer'; +import ProjectDetails from './containers/projectDetailsContainer'; +import Team from './containers/teamContainer'; +import Members from './containers/membersContainer'; +import MemberDetails from './containers/memberDetailsContainer'; +import Culture from './containers/cultureContainer'; +import Gallery from './containers/galleryContainer'; +import Wrapper from './components/wrapper'; module.exports = (
diff --git a/scss/_custom.scss b/client/scss/_custom.scss similarity index 100% rename from scss/_custom.scss rename to client/scss/_custom.scss diff --git a/scss/_global.scss b/client/scss/_global.scss similarity index 100% rename from scss/_global.scss rename to client/scss/_global.scss diff --git a/scss/_layout.scss b/client/scss/_layout.scss similarity index 100% rename from scss/_layout.scss rename to client/scss/_layout.scss diff --git a/scss/_mixins.scss b/client/scss/_mixins.scss similarity index 100% rename from scss/_mixins.scss rename to client/scss/_mixins.scss diff --git a/scss/_variables.scss b/client/scss/_variables.scss similarity index 100% rename from scss/_variables.scss rename to client/scss/_variables.scss diff --git a/src/containers/_footer.scss b/client/scss/components/_footer.scss similarity index 100% rename from src/containers/_footer.scss rename to client/scss/components/_footer.scss diff --git a/src/containers/_header.scss b/client/scss/components/_header.scss similarity index 100% rename from src/containers/_header.scss rename to client/scss/components/_header.scss diff --git a/src/containers/_page.scss b/client/scss/components/_page.scss similarity index 100% rename from src/containers/_page.scss rename to client/scss/components/_page.scss diff --git a/src/containers/_projects.scss b/client/scss/components/_projects.scss similarity index 100% rename from src/containers/_projects.scss rename to client/scss/components/_projects.scss diff --git a/src/containers/_services.scss b/client/scss/components/_services.scss similarity index 100% rename from src/containers/_services.scss rename to client/scss/components/_services.scss diff --git a/client/scss/style.scss b/client/scss/style.scss new file mode 100644 index 0000000..4bc9d32 --- /dev/null +++ b/client/scss/style.scss @@ -0,0 +1,20 @@ +//Framework +@import "../lib/bootstrap/scss/bootstrap"; //v4 +@import "../lib/icomoon/style.scss"; //icons font +@import "../lib/photoswipe/_photoswipe.scss"; //photo gallery + +//Site-specific vars & mixins +@import "./variables"; +@import "./mixins"; + +//Site layout, globals and components +@import "./global"; +@import "./layout"; +@import "components/header"; +@import "components/footer"; +@import "components/page"; +@import "components/projects"; +@import "components/services"; + +//One-off rules (use sparingly) +@import "./custom"; \ No newline at end of file diff --git a/src/store.js b/client/store.js similarity index 64% rename from src/store.js rename to client/store.js index bd9763a..1d28ad4 100644 --- a/src/store.js +++ b/client/store.js @@ -2,21 +2,18 @@ This file defines the main Redux Store. It will be required by all 'smart' components in the app */ -var aboutReducer = require('./reducers/about'), - authReducer = require('./reducers/auth'), - thunk = require('redux-thunk'); // allows us to use asynchronous actions +import aboutReducer from './reducers/about'; +import authReducer from './reducers/auth'; +import thunk from 'redux-thunk'; // allows us to use asynchronous actions import * as Redux from 'redux'; import {reducer as formReducer} from 'redux-form'; import langReducer from './reducers/lang'; import projectsReducer from './reducers/projects'; import servicesReducer from './reducers/services'; import teamReducer from './reducers/team'; -import initialState from './initialstate'; - -initialState[authReducer.reducerName] = authReducer.initialState; const rootReducer = Redux.combineReducers({ - about: aboutReducer,// about will operate on appState.about, + about: aboutReducer, form: formReducer, lang: langReducer, projects: projectsReducer, @@ -27,7 +24,6 @@ const rootReducer = Redux.combineReducers({ const store = Redux.createStore( rootReducer, - initialState, //TODO: remove initialState from here and fix Reducers to provide initial state on their own Redux.compose( Redux.applyMiddleware(thunk), window.devToolsExtension ? window.devToolsExtension() : f => f diff --git a/client/test/actionCreators.spec.js b/client/test/actionCreators.spec.js new file mode 100644 index 0000000..80c3271 --- /dev/null +++ b/client/test/actionCreators.spec.js @@ -0,0 +1,40 @@ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import nock from 'nock'; +import * as jwt from 'jsonwebtoken'; +import {expect} from 'chai'; + +import * as actions from '../actions'; +import * as types from '../constants'; +import * as mockLocalStore from './mock-localstorage'; + +const mockStore = configureMockStore([thunk]); + +var user = { usr: 421431, pwd: 64354353 }; + +const serverToken = jwt.sign(user, 'superSecret', { expiresIn: 6000 }); + +global.localStorage = mockLocalStore.createNewMock(); + +describe('Async actions', () => { + afterEach(() => { + nock.cleanAll(); + }); + + it('like LOGIN_USER_SUCCESS should do login with success', (done) => { + + nock('http://localhost:8080/').post('/auth/login').reply(200, { token: serverToken }) + + const store = mockStore({}) + + store.dispatch(actions.doLogin(user.usr, user.pwd)) + .then(() => { + var resultActions = store.getActions(); + expect(resultActions[0].type).equal(types.LOGIN_USER_REQUEST); + expect(resultActions[1].type).equal(types.LOGIN_USER_SUCCESS); + expect(resultActions[1].payload.token).equal(serverToken); + done(); + }) + .catch(done); + }); +}); \ No newline at end of file diff --git a/src/test/components.spec.js b/client/test/components.spec.js similarity index 52% rename from src/test/components.spec.js rename to client/test/components.spec.js index 6624647..95544b0 100644 --- a/src/test/components.spec.js +++ b/client/test/components.spec.js @@ -1,39 +1,39 @@ -import {expect} from 'chai' -import React from 'react' -import TestUtils from 'react-addons-test-utils' -import aboutDetails from '../components/aboutDetails' +import {expect} from 'chai'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import aboutDetails from '../containers/aboutDetailsContainer'; function setup() { let props = { - params:{name: 'xxx'} - } + params: { name: 'xxx' }, + }; + + let renderer = TestUtils.createRenderer(); - let renderer = TestUtils.createRenderer() - renderer.render(React.createElement(aboutDetails, props)); - - let output = renderer.getRenderOutput() + + let output = renderer.getRenderOutput(); return { props, output, - renderer - } + renderer, + }; } describe('components', () => { describe('about details', () => { it('should render correctly', () => { - const { output } = setup() + const { output } = setup(); + + expect(output.type).equal('div'); + + let [lbl, nameVal] = output.props.children; - expect(output.type).equal('div') - - let [ lbl, nameVal ] = output.props.children - - expect(lbl).to.equal('Details for ') + expect(lbl).to.equal('Details for '); - expect(nameVal).to.equal('xxx') - }) + expect(nameVal).to.equal('xxx'); + }); // it('should call addTodo if length of text is greater than 0', () => { // const { output, props } = setup() @@ -43,5 +43,5 @@ describe('components', () => { // input.props.onSave('Use Redux') // expect(props.addTodo.calls.length).toBe(1) // }) - }) -}) \ No newline at end of file + }); +}); \ No newline at end of file diff --git a/client/test/mock-localstorage.js b/client/test/mock-localstorage.js new file mode 100644 index 0000000..eb2ce7d --- /dev/null +++ b/client/test/mock-localstorage.js @@ -0,0 +1,72 @@ +'use strict'; + +export default () => { + let oStorage = {}; + + Object.defineProperty(oStorage, 'key', { + value: (nKeyId) => { + var key = Object.keys(oStorage)[nKeyId]; + return (typeof key === 'undefined') ? null : unescape(key); + }, + writable: false, + configurable: false, + enumerable: false, + }); + + Object.defineProperty(oStorage, 'getItem', { + value: (sKey) => { + var key = sKey + ''; + return (oStorage[escape(key)] === null) ? 'null' : oStorage[escape(key)]; + }, + writable: false, + configurable: false, + enumerable: false, + }); + + Object.defineProperty(oStorage, 'setItem', { + value: (sKey, sValue) => { + if (typeof sValue !== 'object') { + oStorage[escape(sKey)] = sValue + ''; + } else { + oStorage[escape(sKey)] = sValue; + } + }, + writable: false, + configurable: false, + enumerable: false, + }); + + Object.defineProperty(oStorage, 'removeItem', { + value: (sKey) => { + if (!sKey) { + return; + } + delete oStorage[escape(sKey)]; + }, + writable: false, + configurable: false, + enumerable: false, + }); + + Object.defineProperty(oStorage, 'length', { + get: () => { + return Object.keys(oStorage).length; + }, + configurable: false, + enumerable: false, + }); + + Object.defineProperty(oStorage, 'clear', { + value: () => { + Object.keys(oStorage).forEach(function (key) { + + delete oStorage[key]; + }); + }, + writable: false, + configurable: false, + enumerable: false, + }); + + return oStorage; +}; \ No newline at end of file diff --git a/client/test/reducers.about.spec.js b/client/test/reducers.about.spec.js new file mode 100644 index 0000000..49e631c --- /dev/null +++ b/client/test/reducers.about.spec.js @@ -0,0 +1,39 @@ +let chai = require('chai'); + +chai.config.includeStack = true; + +let expect = require('chai').expect; + +describe('About reducer', () => { + let sut; + + before(() => { + sut = require('../reducers/about'); + }); + + it('should add member', () => { + const action = { + type: 'ADD_MEMBER', + member: { + name: 3, + email: 3, + }, + }; + + const initialState = { + members: [{ + name: 1, + email: 3, + id: 1, + }, { + name: 2, + email: 4, + id: 2, + }], + }; + + const result = sut(initialState, action); + + expect(result.members.length).equal(3); + }); +}); \ No newline at end of file diff --git a/docs/Production Environment Configuration.md b/docs/Production Environment Configuration.md new file mode 100644 index 0000000..ea14de2 --- /dev/null +++ b/docs/Production Environment Configuration.md @@ -0,0 +1,24 @@ +This document provides the necessary steps taken in order to deploy this app on a server running Windows and IIS. +These steps include the build process which can later be automatized. + +Steps are done on a VM which runs on top of `dnwserver`. Unless specified otherwise, assume each step is done on the VM and not on the server itself. + +#1. Setup Windows VM and IIS site + +- we had the `teamcity` VM running on `dnwserver` and used that. Optionally create a blank VM and install IIS, ASP.NET, etc. +- create site in IIS for the app, on a custom port (> 1024) +- **on `dnwserver`** setup ARR to forward requests to our app on port 80 to the VM on the custom port (Lau did it this time) +- in IIS make sure that the `Application Pool Identity` for the site is set to `Local System` + +#2. Installing technology stack components + +- install node.js [from here](https://nodejs.org/en/download/). At the time of this writing it was [version 4.4.4](https://nodejs.org/dist/v4.4.4/node-v4.4.4-x64.msi) +- for older node versions `node -v` use [NVM](https://github.com/coreybutler/nvm-windows) to update `nvm install latest` then `nvm use ` +- install [iisnode](https://github.com/Azure/iisnode) +- in root add `web.config` adapted [from here](https://tomasz.janczuk.org/2012/05/yaml-configuration-support-in-iisnode.html) +- in root add `iisnode.yml` adapted [from here](https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml) +- make sure the application does `app.listen(port);` the port is coming from `process.env.PORT` if specified, this is needed for `iisnode` to make use of clustering processes + +#3. Launch + +Fire up the site and have fun. Add solutions to any issues you encouter to this document. diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 64e7cb6..d3c8016 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -1,4 +1,4 @@ -import "babel-polyfill"; +import 'babel-polyfill'; import gulp from 'gulp'; import browserify from 'browserify'; import babelify from 'babelify'; @@ -7,18 +7,31 @@ import sass from 'gulp-sass'; import sourcemaps from 'gulp-sourcemaps'; import watchify from 'watchify'; import notify from 'gulp-notify'; -import reload from 'browser-sync'; import duration from 'gulp-duration'; import change from 'gulp-change'; -import rename from 'gulp-rename'; import runSequence from 'run-sequence'; +import clean from 'gulp-clean'; +import buffer from 'vinyl-buffer'; +import uglify from 'gulp-uglify'; +import cleanCSS from 'gulp-clean-css'; +import debug from 'gulp-debug'; +import mocha from 'gulp-mocha'; +import rename from 'gulp-rename'; +//import reload from 'browser-sync'; + const opts = Object.assign({}, watchify.args, { - entries: 'src/index.js', - debug: true, + entries: 'client/index.js', }); gulp.task('watchify', () => { + + console.log('NODE_ENV is', process.env.NODE_ENV); + + opts.debug = !(process.env.NODE_ENV == 'production'); + + console.log('browserify debug mode is ', opts.debug); + let bundler = watchify(browserify(opts)); bundler.transform(babelify).on('update', rebundle); return rebundle(); @@ -28,48 +41,61 @@ gulp.task('watchify', () => { return bundler.bundle() .on('error', notify.onError()) .pipe(source('bundle.js')) + .pipe(buffer()) + .pipe(sourcemaps.init({ loadMaps: true })) + .pipe(sourcemaps.write('./')) .pipe(duration('rebuilding files')) - .pipe(gulp.dest('./dist/js')); + .pipe(gulp.dest('./client/dist/js')); } }); -gulp.task('icomoon-variables', function() { - return gulp.src(['./icomoon/variables.scss']) - .pipe(change(function(content){ - return content.replace('$icomoon-font-path: "fonts" !default;', '$icomoon-font-path: "./../fonts" !default;') +gulp.task('icomoon-variables', function () { + return gulp.src(['./client/lib/icomoon/variables.scss']) + .pipe(change(function (content) { + return content.replace('$icomoon-font-path: "fonts" !default;', '$icomoon-font-path: "./../fonts" !default;'); })) - .pipe(gulp.dest('./icomoon/')); + .pipe(gulp.dest('./client/lib/icomoon/')); }); -gulp.task('icomoon-fonts', function() { - gulp.src('./icomoon/fonts/*') - .pipe(gulp.dest('./dist/fonts')); +gulp.task('icomoon-fonts', function () { + gulp.src('./client/lib/icomoon/fonts/*') + .pipe(gulp.dest('./client/dist/fonts')); }); -const scssPaths = ['./lib/**/*.scss', './scss/**/*.scss', './src/**/*.scss']; -gulp.task('sass', function() { - gulp.src(scssPaths) - .pipe(sourcemaps.init()) - .pipe(sass().on('error', notify.onError())) - .pipe(sourcemaps.write()) - .pipe(gulp.dest('./dist/css')); +const scssPaths = ['./client/lib/**/*.scss', './client/scss/**/*.scss']; +gulp.task('sass', function () { + var piped = gulp.src(scssPaths); + + if (process.env.NODE_ENV !== 'production') { + piped = piped.pipe(sourcemaps.init()); + } + + piped = piped.pipe(sass().on('error', notify.onError())); + + if (process.env.NODE_ENV !== 'production') { + piped = piped.pipe(sourcemaps.write()); + } + + piped = piped.pipe(gulp.dest('./client/dist/css')); + + return piped; }); -gulp.task('app-sass', function(callback){ - runSequence('icomoon-variables','icomoon-fonts', 'sass', callback); +gulp.task('app-sass', function (callback) { + runSequence('icomoon-variables', 'icomoon-fonts', 'sass', callback); }); -const imagePaths = ['./img/**']; +const imagePaths = ['./client/assets/img/**']; gulp.task('move-image-files', (callback) => { gulp.src(imagePaths) - .pipe(gulp.dest('./dist/img')) + .pipe(gulp.dest('./client/dist/img')); }); // Due to photoswipe css we will add the needed images near the css -const photoSwipeimagePaths = ['./lib/photoswipe/default-skin.png', './lib/photoswipe/preloader.gif']; +const photoSwipeimagePaths = ['./client/lib/photoswipe/default-skin.png', './client/lib/photoswipe/preloader.gif']; gulp.task('move-photoswipe-files', (callback) => { gulp.src(photoSwipeimagePaths) - .pipe(gulp.dest('./dist/css')) + .pipe(gulp.dest('./client/dist/css')); }); @@ -80,11 +106,76 @@ gulp.task('test', (callback) => { path.basename = '_' + path.basename; path.extname = '.scss'; })) - .pipe(gulp.dest('./lib/test')) + .pipe(gulp.dest('./client/lib/test')); }); -const scssPathsToWatch = ['./lib/**/*.scss', './scss/**/*.scss', './src/**/*.scss', './icomoon/*']; +const scssPathsToWatch = ['./client/lib/**/*.scss', './client/scss/**/*.scss']; gulp.task('default', ['watchify', 'app-sass'], function() { gulp.watch(scssPathsToWatch, ['app-sass']); }); + +gulp.task('clean', function () { + gulp.src('./client/dist', { read: false }) + .pipe(clean()); +}); +gulp.task('build', function () { + + console.log('NODE_ENV is', process.env.NODE_ENV); + + opts.debug = !(process.env.NODE_ENV == 'production'); + + console.log('browserify debug mode is ', opts.debug); + + var bundler = browserify(opts) + .transform(babelify) + .bundle() + .pipe(source('bundle.js')); + + if (process.env.NODE_ENV !== 'production') { + + console.log('extracting source maps for dev mode'); + + bundler = bundler.pipe(buffer()) + .pipe(sourcemaps.init({ loadMaps: true })) + .pipe(sourcemaps.write('./')); + } + + if (process.env.NODE_ENV === 'production') { + console.log('uglifying'); + bundler = bundler.pipe(buffer()).pipe(uglify()); + } + + bundler.pipe(duration('rebuilding files')) + .pipe(gulp.dest('./client/dist/js')); +}); + +//PRODUCTION +gulp.task('minify-css', function () { + return gulp.src('./client/dist/css/*.css') + .pipe(debug({ title: 'Minifying css:' })) + .pipe(cleanCSS({ compatibility: 'ie8' }, function (details) { + console.log(details.name + ': ' + details.stats.originalSize); + console.log(details.name + ': ' + details.stats.minifiedSize); + })) + .pipe(gulp.dest('./client/dist/css')); +}); + +gulp.task('apply-prod-environment', function () { + //setting this value would make some changes in react code (https://facebook.github.io/react/downloads.html) + process.env.NODE_ENV = 'production'; +}); + +gulp.task('unit-tests', function () { + //mocha src/test --reporter spec --compilers js:babel-register --recursive --watch + return gulp.src('./client/test/*.js') + .pipe(debug({ title: 'running tests:' })) + .pipe(mocha( + { + compilers: 'js:babel-register', + })); +}); + +gulp.task('deploy', function () { + return runSequence('apply-prod-environment', 'clean', 'build', 'app-sass', 'minify-css','unit-tests'); +}); \ No newline at end of file diff --git a/gulpfile.server.babel.js b/gulpfile.server.babel.js deleted file mode 100644 index 092d6a6..0000000 --- a/gulpfile.server.babel.js +++ /dev/null @@ -1,35 +0,0 @@ -require("babel-polyfill"); -var gulp = require('gulp'); -var babel = require('gulp-babel'); -var babelify = require('babelify'); -var source = require('vinyl-source-stream'); -var watchify = require('watchify'); -var notify = require('gulp-notify'); -var reload = require('browser-sync'); -var rename = require('gulp-rename'); -var duration = require('gulp-duration'); -var browserify = require('browserify'); - -gulp.task('build', function() { - return gulp.src('server.js') - .pipe(babel()) - .pipe(duration('rebuilding files')) - .pipe(rename('serveres5.js')) - .pipe(gulp.dest('./')); -}); - -gulp.task('watchify', function() { - var bundler = watchify(browserify(opts)); - function rebundle() { - console.log('recreating bundle'); - return bundler.bundle() - .on('error', notify.onError()) - .pipe(source('bundle.js')) - .pipe(duration('rebuilding files')) - .pipe(gulp.dest('dist')); - } - bundler.transform(babelify).on('update', rebundle); - return rebundle(); -}); - -gulp.task('default', ['build']); diff --git a/index.html b/index.html index 534a19b..e5b2b31 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,12 @@ - +
- + diff --git a/package.json b/package.json index d7fc8b5..80fba9c 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,18 @@ "gulp": "^3.9.1", "gulp-babel": "^6.1.2", "gulp-change": "^1.0.0", + "gulp-clean": "^0.3.2", + "gulp-clean-css": "^2.0.6", + "gulp-debug": "^2.1.2", "gulp-duration": "0.0.0", + "gulp-mocha": "^2.2.0", "gulp-notify": "^2.2.0", "gulp-rename": "^1.2.2", "gulp-sass": "^2.2.0", "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.3", "lodash": "^4.0.0", "mocha": "^2.4.5", - "mongodb": "^2.1.18", "nock": "^7.2.2", "path-to-regexp": "^1.2.1", "photoswipe": "^4.1.1", @@ -40,14 +44,15 @@ "redux-thunk": "^1.0.3", "run-sequence": "^1.1.5", "sinon": "^1.17.3", + "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", "watchify": "^3.7.0", "winston": "^2.2.0" }, - "scripts": { - "build": "browserify --debug -t [babelify] src/index.js > bundle.js", - "watchify": "watchify -t [babelify] src/index.js -o bundle.js -dv" - }, + "__commented__scripts": { + "build": "browserify --debug -t [babelify] client/index.js > client/dist/js/bundle.js", + "watchify": "watchify -t [babelify] client/index.js -o client/dist/js/bundle.js -dv" + }, "dependencies": { "async": "^1.5.2", "body-parser": "^1.15.0", diff --git a/scss/style.scss b/scss/style.scss deleted file mode 100644 index 2f395b0..0000000 --- a/scss/style.scss +++ /dev/null @@ -1,20 +0,0 @@ -//Framework -@import "../lib/bootstrap/scss/bootstrap"; //v4 -@import "../icomoon/style.scss"; //icons font -@import "../lib/photoswipe/_photoswipe.scss"; - -//Site-specific vars & mixins -@import "./variables"; -@import "./mixins"; - -//Site layout, globals and containers -@import "./global"; -@import "./layout"; -@import "../src/containers/header"; -@import "../src/containers/footer"; -@import "../src/containers/page"; -@import "../src/containers/projects"; -@import "../src/containers/services"; - -//One-off rules (use sparingly) -@import "./custom"; \ No newline at end of file diff --git a/server.js b/server.js index 1094071..e3a5f73 100644 --- a/server.js +++ b/server.js @@ -1,19 +1,19 @@ -"use strict"; +'use strict'; // nodemon server.js //node modules var express = require('express'); -var bodyParser = require('body-parser'); +var bodyParser = require('body-parser'); //cust modules -var config = require('./server/config'); -var login = require('./server/routesLogin'); +var config = require('./server/config'); +var login = require('./server/routesLogin'); var authCheck = require('./server/authenticationCheck'); //vars -var app = express(); -var router = express.Router(); -var port = process.env.PORT || 8080; +var app = express(); +var router = express.Router(); +var port = process.env.PORT || 8080; app.set('superSecret', config.secret); @@ -37,4 +37,4 @@ routes.setAdminRoutes(router); app.use('/', router); app.listen(port); -console.log('listeninng on port... ' + port ); +console.log('listening on port ' + port); diff --git a/server/authenticationCheck.js b/server/authenticationCheck.js index a0b96d2..b529a4a 100644 --- a/server/authenticationCheck.js +++ b/server/authenticationCheck.js @@ -2,28 +2,29 @@ var jwt = require('jsonwebtoken'); module.exports = { - configure:function (app, routes){ + configure: function (app, routes) { - routes.use(function(req, res, next) { + routes.use(function (req, res, next) { var token = req.body.token || req.query.token || req.headers['x-access-token']; - + if (token) { - jwt.verify(token, app.get('superSecret'), function(err, decoded) { - - if (err) { return res.json({ success: false, message: 'Failed to authenticate token.' });} - else { - req.decoded = decoded; - next(); - }}); - } - else { - return res.status(403).send({ - success: false, - message: 'No token provided.' + jwt.verify(token, app.get('superSecret'), function (err, decoded) { + + if (err) { return res.json({ success: false, message: 'Failed to authenticate token.' }); } + else { + req.decoded = decoded; + next(); + } + }); + } + else { + return res.status(403).send({ + success: false, + message: 'No token provided.', + }); + } }); - } - }); - } -} \ No newline at end of file + }, +}; \ No newline at end of file diff --git a/server/config.js b/server/config.js index 0b81b32..604d50a 100644 --- a/server/config.js +++ b/server/config.js @@ -1,4 +1,3 @@ module.exports = { 'secret': 'bestSecretForBestApp', - }; diff --git a/server/respository.js b/server/respository.js index 04dfd93..114f5e3 100644 --- a/server/respository.js +++ b/server/respository.js @@ -1,88 +1,88 @@ var assert = require('assert'); var db = { - membersInfo: { - description: 'fuisabfiusabfasui' - }, - members: [{ - name: 'ionut', - email: 'ionut@ionut.com', - id: 1 - }, { - name: 'tudrel', - email: 'tudrel@tudrel.com', - id: 2 - }, { - name: 'marusica', - email: 'marusciac@tudrel.com', - id: 3 - }], - users: [{}, {}] + membersInfo: { + description: 'fuisabfiusabfasui', + }, + members: [{ + name: 'ionut', + email: 'ionut@ionut.com', + id: 1, + }, { + name: 'tudrel', + email: 'tudrel@tudrel.com', + id: 2, + }, { + name: 'marusica', + email: 'marusciac@tudrel.com', + id: 3, + }], + users: [{}, {}], }; var MongoClient = require('mongodb').MongoClient; var url = 'mongodb://superadmin:dnwCSiteSa@localhost:27017/companysite'; -var findUsers = function(args) { - var con = MongoClient.connect(url, function(err, db) { +var findUsers = function (args) { + var con = MongoClient.connect(url, function (err, db) { //TODO refactor err==null check with assert without identation if (err == null) { - db.collection('users').find().toArray(function(err, allUsers) { + db.collection('users').find().toArray(function (err, allUsers) { console.log(allUsers); args.callback && args.callback(null, { - data: allUsers + data: allUsers, }); db.close(); }); } }); -} +}; -var insertContactDetailsInDB = function(details) { - var con = MongoClient.connect(url, function(err, db) { +var insertContactDetailsInDB = function (details) { + var con = MongoClient.connect(url, function (err, db) { if (err == null) { var colection = db.collection('contacts'); colection.insert(details); } }); -} +}; + +var insertInitMembers = function () { + var con = MongoClient.connect(url, function (err, db) { -var insertInitMembers = function(){ - var con = MongoClient.connect(url, function(err, db) { - - assert.equal(null, err); - - var colection = db.collection('users'); - - colection.remove({}); - colection.insert({id:2, name:'Ionut Mandra'}); - colection.insert({id:3, name:'Teodor Sandu'}); + assert.equal(null, err); + + var colection = db.collection('users'); + + colection.remove({}); + colection.insert({ id: 2, name: 'Ionut Mandra' }); + colection.insert({ id: 3, name: 'Teodor Sandu' }); }); }; module.exports = { - create: function(repo) { + create: function (repo) { return { repoName: repo, - find: function(callback) { + find: function (callback) { callback(null, { data: db[this.repoName] }); - } + }, }; }, - getAllUsers: function(callback) { + getAllUsers: function (callback) { findUsers({ data: {}, - callback: callback + callback: callback, }); }, - insertContactDetails: function(details) { + insertContactDetails: function (details) { insertContactDetailsInDB(details); }, //init - one time only - initUsers: function(){ + initUsers: function () { insertInitMembers(); - } + }, }; diff --git a/server/routesCustom.js b/server/routesCustom.js index cbfb8f4..050c96a 100644 --- a/server/routesCustom.js +++ b/server/routesCustom.js @@ -19,101 +19,115 @@ for (var r in routes) { } } -function setApiRoutes(router){ +module.exports = { + init: function (rootPathParam) { + rootPath = rootPathParam; + + return { + setClientRoutes: setClientRoutes, + setApiRoutes: setApiRoutes, + setFileRoutes: setFileRoutes, + setAdminRoutes: setAdminRoutes, + catch404: catch404, + }; + }, +}; - winston.log('info', 'setting api routes ', {timestamp: Date.now(), pid: process.pid}); +function setApiRoutes(router) { - router.get('/api/members', function(req, res) { + winston.log('info', 'setting api routes ', { timestamp: Date.now(), pid: process.pid }); + + router.get('/api/members', function (req, res) { var membersRepo = new db.create('members'); var memberslInfo = new db.create('membersInfo'); async.parallel([ - function(cb) { db.getAllUsers(cb) }, - function(cb) { memberslInfo.find( cb) } - ], function(err, dataResult) { - if (!err) { - - var result = Object.assign({}, - {members:dataResult[0].data}, - {membersInfo:dataResult[1].data}); - - res.json(result); - } - else{ - res.json({Err:err}); - } - }); + function (cb) { db.getAllUsers(cb); }, + function (cb) { memberslInfo.find(cb); }, + ], function (err, dataResult) { + if (!err) { + + var result = Object.assign({}, + { members: dataResult[0].data }, + { membersInfo: dataResult[1].data }); + + res.json(result); + } + else { + res.json({ Err: err }); + } + }); }); - router.get('/api/about', function(req, res) { + router.get('/api/about', function (req, res) { res.send('im the about page2!'); }); - router.get('/api/hello/:name', function(req, res) { + router.get('/api/hello/:name', function (req, res) { res.send('hello ' + req.params.name + '!'); }); - router.post('/api/contact', function(req, res) { + router.post('/api/contact', function (req, res) { var errors = validators.contact(req.body), success = _.isEmpty(errors); - db.insertContactDetails(req.body); - res.send({success, errors}); + db.insertContactDetails(req.body); + res.send({ success, errors }); }); //init - router.get('/api/initUsers', function(req, res) { + router.get('/api/initUsers', function (req, res) { db.initUsers(); }); - } -function setClientRoutes(router, routes){ +function setClientRoutes(router, routes) { routes = routes || routePaths.client; for (var r in routes) { if (routes.hasOwnProperty(r)) { if (_.isString(routes[r])) { router.all(routes[r], serveIndex); - } + } if (_.isObject(routes[r])) { setClientRoutes(router, routes[r]); } } } - + function serveIndex(req, res) { fs.readFile('../index.html', 'utf-8', function (error, data) { - winston.log('index html ', {timestamp: Date.now(), pid: process.pid}); + winston.log('index html ', { timestamp: Date.now(), pid: process.pid }); res.sendFile(path.join(rootPath + '/index.html')); //https://www.npmjs.com/package/serve-static }); } } -function setFileRoutes(app){ - app.use('/dist', express.static(path.join(rootPath + '/dist'))); - app.use('/res', express.static(path.join(rootPath + '/res'))); -}; +function setFileRoutes(app) { + app.use('/client/dist', express.static(path.join(rootPath + '/client/dist'))); + app.use('/client/assets', express.static(path.join(rootPath + '/client/assets'))); +} -function setAdminRoutes(router){ - router.get(routePaths.serverAuthorized.apiEditMembers, function(req, res) { +function setAdminRoutes(router) { + router.get(routePaths.serverAuthorized.apiEditMembers, function (req, res) { var initialState = { - generalInfo:{description: 'fuisabfiusabfasui'}, - members:[ - {name:'ionut',email:'ionut@ionut.com',id:1}, - {name:'tudrel',email:'tudrel@tudrel.com',id:2}, - {name:'marusica',email:'marusciac@tudrel.com',id:3}]}; + generalInfo: { description: 'fuisabfiusabfasui' }, + members: [ + { name: 'ionut', email: 'ionut@ionut.com', id: 1 }, + { name: 'tudrel', email: 'tudrel@tudrel.com', id: 2 }, + { name: 'marusica', email: 'marusciac@tudrel.com', id: 3 }], + }; - res.json(initialState); - }); -}; + res.json(initialState); + }); +} -function catch404(router){ - router.use(function(req, res, next){ +function catch404(router) { + router.use(function (req, res, next) { for (var r of skip404regexes) { - if (r.test(req.path)){ + if (r.test(req.path)) { next(); return; } @@ -123,18 +137,4 @@ function catch404(router){ message: '404 Not found', }); }); -} - -module.exports = { - init:function(rootPathParam){ - rootPath =rootPathParam; - - return{ - setClientRoutes:setClientRoutes, - setApiRoutes:setApiRoutes, - setFileRoutes:setFileRoutes, - setAdminRoutes: setAdminRoutes, - catch404: catch404, - }; - } -}; +} \ No newline at end of file diff --git a/server/routesLogin.js b/server/routesLogin.js index 72bb8ad..becd0bb 100644 --- a/server/routesLogin.js +++ b/server/routesLogin.js @@ -1,41 +1,41 @@ var jwt = require('jsonwebtoken'); module.exports = { - setLoginRoutes:function(app, router){ + setLoginRoutes: function (app, router) { - router.post('/api/auth/login', function(req, res) { + router.post('/api/auth/login', function (req, res) { var usr = req.body.user; var pwd = req.body.password; console.log('server login got ', usr, pwd); - var user ={ - name:'admin', - pwd:123 + var user = { + name: 'admin', + pwd: 123, }; - if(usr!='admin' || pwd!='123'){ + if (usr != 'admin' || pwd != '123') { res.json({ success: false, message: 'Authentication failed. User not found.' }); return; } var token = jwt.sign(user, app.get('superSecret'), { - expiresIn: 6000 // expires in seconds - }); - - // return the information including token as JSON - res.json({ - success: true, - message: 'Enjoy your token!', - token: token - }); + expiresIn: 6000, // expires in seconds }); - router.post('/api/auth/logout', function(req, res) { - }); + // return the information including token as JSON + res.json({ + success: true, + message: 'Enjoy your token!', + token: token, + }); + }); + + router.post('/api/auth/logout', function (req, res) { + }); - router.post('/api/auth/register', function(req, res) { - }); - } + router.post('/api/auth/register', function (req, res) { + }); + }, }; \ No newline at end of file diff --git a/server/test/repository.spec.js b/server/test/repository.spec.js index b980166..08f88cf 100644 --- a/server/test/repository.spec.js +++ b/server/test/repository.spec.js @@ -2,7 +2,7 @@ var chai = require('chai'); chai.config.includeStack = true; -var expect = require("chai").expect; +var expect = require('chai').expect; var repo = require('../respository'); @@ -15,8 +15,8 @@ describe('When using dummy repo', function () { it('should result in some result', function () { var result = 0; - sut.find(function(err,data){ - result = data.data; + sut.find(function (err, data) { + result = data.data; }); expect(result.length).equal(3); }); diff --git a/src/components/LoginComponent.js b/src/components/LoginComponent.js deleted file mode 100644 index 83e2bc1..0000000 --- a/src/components/LoginComponent.js +++ /dev/null @@ -1,52 +0,0 @@ -var React = require("react"), - ptypes = React.PropTypes, - ReactRedux = require("react-redux"), - actions = require("../actions"), - Link = require("react-router").Link; - -var comp = React.createClass({ - propTypes: {}, - - //customEvents - handleUserChange: function(e) { - this.setState({user: e.target.value}) - }, - handlePwdChange: function(e) { - this.setState({password: e.target.value}) - }, - doLogin: function() { - this.props.doLogin(this.state.user, this.state.password); - }, - - //lifecycle events - render: function() { - var p = this.props.params; - - return ( -
- -
- -
- -
{this.props.authState.isAuthenticated - ? adminHome - : null} -
- ); - } -}); - -const mapStateToProps = (state) => { - return {authState: state.auth}; -}; - -const mapDispatchToProps = (dispatch) => { - return { - doLogin: (usr, pwd) => { - dispatch(actions.doLogin(usr, pwd)); - } - }; -}; - -module.exports = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(comp); diff --git a/src/components/galleryExample.js b/src/components/galleryExample.js deleted file mode 100644 index c43fea3..0000000 --- a/src/components/galleryExample.js +++ /dev/null @@ -1,65 +0,0 @@ -import { PhotoSwipe } from 'react-photoswipe'; -import { PhotoSwipeGallery } from 'react-photoswipe'; -var React = require('react'); - -class GalleryExample extends React.Component { - constructor() { - super(); - } - render() { - let items = [ - { - src: '/dist/img/gallery/1.png', - thumbnail: '/dist/img/gallery/1.png', - w: 1200, - h: 900, - title: 'Image 1' - }, { - src: '/dist/img/gallery/2.png', - thumbnail: '/dist/img/gallery/2.png', - w: 1200, - h: 900, - title: 'Image 2' - }, { - src: '/dist/img/gallery/3.png', - thumbnail: '/dist/img/gallery/3.png', - w: 1200, - h: 900, - title: 'Image 2' - }, - ]; - - let options = { - //http://photoswipe.com/documentation/options.html - }; - - const getThumbnailContent = (item) => { - return ( < img src = { - item.thumbnail - } - width = { - 120 - } - height = { - 90 - } - /> - ); - } - - return ( < div > - < a > Show PhotoSwipe < /a> < PhotoSwipeGallery items = { - items - } - options = { - options - } - thumbnailContent = { - getThumbnailContent - } - /> < /div> - ) - } -} - -export default GalleryExample; diff --git a/src/containers/adminHome.js b/src/containers/adminHome.js deleted file mode 100644 index 83d09dd..0000000 --- a/src/containers/adminHome.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import {connect} from 'react-redux'; -import { bindActionCreators } from 'redux'; -import * as actions from '../actions'; - -class AdminHome extends React.Component { - - componentWillMount () { - this.fetchData(); - } - - fetchData () { - let token = this.props.token; - this.props.fetchProtectedData(token); - } - - render () { - return ( -
- - {/* {this.props.isFetching === true?

Loading data...

: */} -
-

Welcome back, - {this.props.userName}!

-

{this.props.data.members}

-
- -
- ); - } -} - -const mapStateToProps = (state) => ({ - data: state.about, - // isFetching: state.data.isFetching -}); - -const mapDispatchToProps = (dispatch) => { - return { - fetchProtectedData: function(token){ - dispatch(actions.editMembers(token)); }, - }; - }; - - - - module.exports = connect(mapStateToProps, mapDispatchToProps)(AdminHome); diff --git a/src/initialstate.js b/src/initialstate.js deleted file mode 100644 index 54bd409..0000000 --- a/src/initialstate.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -This is the initial state of the Redux Store. I store it in a separate file because I also use -it in the reducers when we do the Reset action. - -It returns a function instead of an object to make sure no one can change the initial state. - -Shape of the state object matches the keys of the passed reducers -*/ - -var C = require('./constants'); - -export default { - about: { - membersInfo: { description: 'about description' }, - members: [], - }, -}; \ No newline at end of file diff --git a/src/reducers/about.js b/src/reducers/about.js deleted file mode 100644 index a60e9fd..0000000 --- a/src/reducers/about.js +++ /dev/null @@ -1,34 +0,0 @@ -var C = require("../constants"), -initialState = require("../initialstate"); - -/* -A reducer is a function that takes the current state and an action, and then returns a -new state. This reducer is responsible for appState.battlefield data. -See `initialstate.js` for a clear view of what it looks like! -*/ -module.exports = function(state,action){ - var newstate = Object.assign({},state); // sloppily copying the old state here, so we never mutate it - switch(action.type){ - case C.GET_MEMBERS: - return initialState.about.members; - - case C.ADD_MEMBER: - var index = newstate.members.length + 1; - //new obj in memory - newstate.members = state.members.concat({name:action.member,email:'c@c.com',id:index}); - return newstate; - - case C.REMOVE_MEMBER: - var index = state.members.map(function(x) {return x.id; }).indexOf(action.member); - newstate.members = state.members - .slice(0, index) - .concat(state.members.slice(index+1)); - return newstate; - - case C.INIT_MEMBERS_LIST: - newstate.members = action.data.members; - newstate.membersInfo = action.data.membersInfo; - return newstate; - default: return state || initialState; - } -}; diff --git a/src/reducers/auth.js b/src/reducers/auth.js deleted file mode 100644 index ae8ced1..0000000 --- a/src/reducers/auth.js +++ /dev/null @@ -1,57 +0,0 @@ -import {pushState} from 'redux-router'; -import jwtDecode from 'jwt-decode'; -import * as C from "../constants"; - - -module.exports.reducerName = 'auth'; - -var initState = { - token: null, - userName: null, - isAuthenticated: false, - isAuthenticating: false, - statusText: null -}; -module.exports.intialState = initState; - -module.exports.createReducer = function(state,action){ - - switch(action.type){ - - case C.LOGIN_USER_REQUEST: - return Object.assign({}, state, { - 'isAuthenticating': true, - 'statusText': null - }); - - case C.LOGIN_USER_SUCCESS: - return Object.assign({}, state, { - 'isAuthenticating': false, - 'isAuthenticated': true, - 'token': action.payload.token, - 'userName': jwtDecode(action.payload.token).userName, - 'statusText': 'You have been successfully logged in.' - }); - - - case C.LOGIN_USER_FAILURE: - return Object.assign({}, state, { - 'isAuthenticating': false, - 'isAuthenticated': false, - 'token': null, - 'userName': null, - 'statusText': `Authentication Error: ${action.payload.status} ${action.payload.statusText}` - }); - - - case C.LOGOUT_USER: - return Object.assign({}, state, { - 'isAuthenticated': false, - 'token': null, - 'userName': null, - 'statusText': 'You have been successfully logged out.' - }); - - default: return state ||initState; - } -}; \ No newline at end of file diff --git a/src/reducers/defaults.js b/src/reducers/defaults.js deleted file mode 100644 index eeff3ec..0000000 --- a/src/reducers/defaults.js +++ /dev/null @@ -1,100 +0,0 @@ -//Default values for reducers -//Structure: reduce name => { default reducer data } -const defaults = { - lang: { - current: 'en', - }, - projects: { - items: [ - { - key: 'adaptabi', - name: 'Adaptabi', - description: 'New company site', - website: 'http://adaptabi.com', - img: '/res/img/projects/adaptabi.png', - }, - { - key: 'safetybank', - name: 'Safetybank', - description: 'Best H&S system for construction companies', - website: 'http://safetybank.co.uk', - img: '/res/img/projects/safetybank.png', - }, - { - key: 'squires', - name: 'Squires Kitchen', - description: 'Largest kitchen supply store in UK', - website: 'http://squires-shop.com', - img: '/res/img/projects/squires.png', - }, - ], - }, - services: { - items: [ - { - key: 'innovation', - name: 'Innovation', - icon: 'cog', - description: 'We boost startup recognition by creating unique, innovative apps!', - }, - { - key: 'maintenance', - name: 'Maintenance', - icon: 'save', - description: 'We keep your project running at peak performance forever!', - }, - { - key: 'consulting', - name: 'Consulting', - icon: 'comments', - description: 'Don\'t know how to make your dream idea come true? We do!', - }, - { - key: 'cooking', - name: 'Cooking', - icon: 'pie-chart', - description: 'We\'ll slap you with the best pizza in town!', - }, - ], - }, - team: { - culture: 'Lorem ipsum organizational culture text', - members: [ - { - key: 'ionut', - name: 'Ionut Mandra', - img: '/res/img/projects/safetybank.png', - position: 'Developer', - }, - { - key: 'marius', - name: 'Mihai-Marius Baciu', - img: '/res/img/projects/safetybank.png', - position: 'Developer', - }, - { - key: 'teodor', - name: 'Teodor Sandu', - img: '/res/img/projects/safetybank.png', - position: 'Developer', - }, - ], - gallery: [ - { - key: '1', - img: '/res/img/projects/adaptabi.png', - }, - { - key: '2', - img: '/res/img/projects/safetybank.png', - }, - { - key: '3', - img: '/res/img/projects/squires.png', - }, - ], - }, -}; - -export default defaults; -export let {lang, projects, services, team} = defaults; \ No newline at end of file diff --git a/src/reducers/lang.js b/src/reducers/lang.js deleted file mode 100644 index 81d0c76..0000000 --- a/src/reducers/lang.js +++ /dev/null @@ -1,14 +0,0 @@ -import C from '../constants'; -import { lang as defaults } from './defaults'; - -export default (state, action) => { - let newState = Object.assign({}, defaults, state); - - switch (action.type) { - case C.CHANGE_LANGUAGE: - newState.current = action.language || defaults.current; - return newState; - default: - return defaults; - } -}; \ No newline at end of file diff --git a/src/reducers/projects.js b/src/reducers/projects.js deleted file mode 100644 index 46fcd89..0000000 --- a/src/reducers/projects.js +++ /dev/null @@ -1,14 +0,0 @@ -import C from '../constants'; -import { projects as defaults } from './defaults'; - -export default (state, action) => { - //let newState = Object.assign({}, defaults, state); - - switch (action.type) { - // case C.CHANGE_LANGUAGE: - // newState.current = action.language || defaults.current; - // return newState; - default: - return defaults; - } -}; \ No newline at end of file diff --git a/src/reducers/services.js b/src/reducers/services.js deleted file mode 100644 index b6210e4..0000000 --- a/src/reducers/services.js +++ /dev/null @@ -1,14 +0,0 @@ -import C from '../constants'; -import { services as defaults } from './defaults'; - -export default (state, action) => { - //let newState = Object.assign({}, defaults, state); - - switch (action.type) { - // case C.CHANGE_LANGUAGE: - // newState.current = action.language || defaults.current; - // return newState; - default: - return defaults; - } -}; \ No newline at end of file diff --git a/src/reducers/team.js b/src/reducers/team.js deleted file mode 100644 index 9d3b06b..0000000 --- a/src/reducers/team.js +++ /dev/null @@ -1,14 +0,0 @@ -import C from '../constants'; -import { team as defaults } from './defaults'; - -export default (state, action) => { - //let newState = Object.assign({}, defaults, state); - - switch (action.type) { - // case C.CHANGE_LANGUAGE: - // newState.current = action.language || defaults.current; - // return newState; - default: - return defaults; - } -}; \ No newline at end of file diff --git a/src/test/actionCreators.spec.js b/src/test/actionCreators.spec.js deleted file mode 100644 index f9fb097..0000000 --- a/src/test/actionCreators.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import nock from 'nock' -import * as jwt from 'jsonwebtoken'; -import {expect} from 'chai'; - -import * as actions from '../actions' -import * as types from '../constants' -import * as mockLocalStore from './mock-localstorage' - -const mockStore = configureMockStore([ thunk ]) - -var user = {usr:421431, pwd:64354353}; - -const serverToken = jwt.sign(user, 'superSecret', { expiresIn: 6000 }); - -global.localStorage = mockLocalStore.createNewMock(); - - -describe('Async actions', () => { - afterEach(() => { - nock.cleanAll() - }) - - it('like LOGIN_USER_SUCCESS should do login with success', (done) => { - - nock('http://localhost:8080/').post('/auth/login').reply(200, { token: serverToken }) - - const store = mockStore({ }) - - store.dispatch(actions.doLogin(user.usr, user.pwd)) - .then( () => { - var resultActions = store.getActions(); - expect(resultActions[0].type).equal( types.LOGIN_USER_REQUEST) - expect(resultActions[1].type).equal( types.LOGIN_USER_SUCCESS) - expect(resultActions[1].payload.token).equal(serverToken) - done(); - }) - .catch(done); - }) -}) \ No newline at end of file diff --git a/src/test/mock-localstorage.js b/src/test/mock-localstorage.js deleted file mode 100644 index 8b51b97..0000000 --- a/src/test/mock-localstorage.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; - -function createNewMock() { - var oStorage = { - }; - Object.defineProperty(oStorage, "key", { - value: function (nKeyId) { - var key = Object.keys(oStorage)[nKeyId]; - return (typeof key === "undefined") ? null : unescape(key); - }, - writable: false, - configurable: false, - enumerable: false - }); - Object.defineProperty(oStorage, "getItem", { - value: function (sKey) { - var key = sKey + ""; - return (oStorage[escape(key)] === null) ? "null" : oStorage[escape(key)]; - }, - writable: false, - configurable: false, - enumerable: false - }); - Object.defineProperty(oStorage, "setItem", { - value: function (sKey, sValue) { - if (typeof sValue !== "object") { - oStorage[escape(sKey)] = sValue + ""; - } else { - oStorage[escape(sKey)] = sValue; - } - }, - writable: false, - configurable: false, - enumerable: false - }); - Object.defineProperty(oStorage, "removeItem", { - value: function (sKey) { - if (!sKey) { - return; - } - delete oStorage[escape(sKey)] - }, - writable: false, - configurable: false, - enumerable: false - }); - Object.defineProperty(oStorage, "length", { - get: function () { - return Object.keys(oStorage).length; - }, - configurable: false, - enumerable: false - }); - Object.defineProperty(oStorage, "clear", { - value: function () { - Object.keys(oStorage).forEach(function (key) { - - delete oStorage[key]; - }); - }, - writable: false, - configurable: false, - enumerable: false - }); - return oStorage; -} - -module.exports ={ -createNewMock:createNewMock -}; \ No newline at end of file diff --git a/src/test/reducers.about.spec.js b/src/test/reducers.about.spec.js deleted file mode 100644 index 184ece9..0000000 --- a/src/test/reducers.about.spec.js +++ /dev/null @@ -1,28 +0,0 @@ -var chai = require('chai'); - -chai.config.includeStack = true; - -var expect = require("chai").expect; - -describe('About reducer', function () { - var sut; - - before(function () { - sut = require('../reducers/about'); - }); - - it('should add member', function () { - - var action = { - type:'ADD_MEMBER', - member:{name:3,email:3} - }; - - var initialState = {members:[{name:1,email:3,id:1},{name:2,email:4,id:2}]}; - - var result = sut(initialState,action); - - - expect(result.members.length).equal(3); - }); -}); \ No newline at end of file diff --git a/unitTestsClient.bat b/unitTestsClient.bat index 25c5968..65369a7 100644 --- a/unitTestsClient.bat +++ b/unitTestsClient.bat @@ -1 +1 @@ -mocha src/test --reporter spec --compilers js:babel-register --recursive --watch \ No newline at end of file +mocha client/test --reporter spec --compilers js:babel-register --recursive --watch \ No newline at end of file