diff --git a/.eslintrc b/.eslintrc index 60e1e2a..f9301e7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -31,38 +31,53 @@ "jsx": true }, "globals": { + "document": false, "window": false, "global": false, "require": false, "expect": false, - "should": false, - "chai": false, - "sinon": false, - "Power2": false, - "Sine": false, "__DEVELOPMENT__": false }, "rules": { "max-len": [0], "new-cap": ["warn", {"capIsNewExceptions": [ - "Immutable", - "Map", - "List", - "Set", - "OrderedSet", - "Range", - "Moment", - "Linker", + "Moment" ]}], "comma-dangle": ["warn", "always-multiline"], // disallow or enforce trailing commas "curly": ["warn", "multi-or-nest"], // specify curly brace conventions for all control statements - "indent": ["warn", 2, {"SwitchCase": 1}], // this option sets a specific tab width for your code (off by default) + "indent": ["warn", 2, { + "SwitchCase": 1, + "MemberExpression": 1, + "FunctionDeclaration": {"parameters": "first"}, + "FunctionExpression": {"parameters": "first"}, + "CallExpression": {"arguments": 1} + }], // this option sets a specific tab width for your code (off by default) "brace-style": ["warn", "1tbs", { "allowSingleLine": true }], // enforce one true brace style (off by default) "key-spacing": ["warn", {"beforeColon": false, "afterColon": true}], // enforces spacing between keys and values in object literal properties "quotes": ["warn", "single", "avoid-escape"], // specify whether double or single quotes should be used "keyword-spacing": ["warn", {"before": true, "after": true}], // require a space after certain keywords (off by default) + "no-underscore-dangle": [0], + "import/no-extraneous-dependencies": [0], // because broken + "import/no-unresolved": [0], // because broken + "import/extensions": [0], + "import/prefer-default-export": [0], + "global-require": [0], + "linebreak-style": "off", // React //"computed-property-spacing": ["warn", "never"], // disallow spaces inside computed properties - "react/jsx-indent-props": ["warn", 2] + "react/jsx-indent-props": ["warn", 2], + "react/forbid-prop-types": [0], + "react/no-unescaped-entities": [0], + "react/no-unused-prop-types": [0], // because broken + "react/sort-comp": [1, { + "order": [ + "static-methods", + "lifecycle", + "/^on.+$/", + "everything-else", + "/^render.+$/", + "render" + ] + }] } } diff --git a/.storybook/stories.js b/.storybook/stories.js index 2f87336..00f5f5f 100644 --- a/.storybook/stories.js +++ b/.storybook/stories.js @@ -1,3 +1,4 @@ +/* eslint-disable import/imports-first */ import jquery from 'jquery'; global.$ = jquery; global.jQuery = jquery; diff --git a/package.json b/package.json index 71578b4..4cb020a 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "copy-mocks": "node scripts/copy-mocks.js", "renderer": "node ./renderer/renderer.js", "clean": "./node_modules/.bin/rimraf ./build integration/main.css integration/static && echo --- Cleaned ---", - "lint": "eslint src", - "lint-fix": "eslint src --fix", + "lint": "eslint --ext .js --ext .jsx src webpack stories", + "lint-fix": "npm run lint -- --fix", "test": "jest --coverage", "test-watch": "jest --watch", "e2e-test": "./node_modules/.bin/nightwatch", @@ -77,7 +77,7 @@ "@kadira/storybook-addon-knobs": "^1.4.1", "babel-cli": "<6.3.0", "babel-core": "<6.3.0", - "babel-eslint": "^6.0.0", + "babel-eslint": "^7.1.0", "babel-loader": "~6.2.1", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-es2015-modules-umd": "^6.8.0", @@ -88,11 +88,11 @@ "copy-webpack-plugin": "^2.1.3", "css-loader": "^0.23.0", "enzyme": "^2.3.0", - "eslint": "^2.5.3", - "eslint-config-airbnb": "^6.2.0", - "eslint-plugin-import": "^1.10.2", - "eslint-plugin-jsx-a11y": "^1.5.5", - "eslint-plugin-react": "^4.2.3", + "eslint": "^3.9.1", + "eslint-config-airbnb": "^12.0.0", + "eslint-plugin-import": "^1.16.0", + "eslint-plugin-jsx-a11y": "^2.2.3", + "eslint-plugin-react": "^6.5.0", "extract-text-webpack-plugin": "^0.9.1", "file-loader": "^0.8.4", "html-webpack-plugin": "^2.15.0", diff --git a/src/Main/Footer/index.jsx b/src/Main/Footer/index.jsx index bf18701..e19804b 100644 --- a/src/Main/Footer/index.jsx +++ b/src/Main/Footer/index.jsx @@ -1,27 +1,28 @@ +/* eslint-disable jsx-a11y/href-no-hash */ import React from 'react'; import paths from 'constants/paths'; import { Link } from 'react-router'; const Footer = () => ( - ); export default Footer; diff --git a/src/Main/Header/ConnectedUserMenu/index.jsx b/src/Main/Header/ConnectedUserMenu/index.jsx index 87b9e10..f46e0eb 100644 --- a/src/Main/Header/ConnectedUserMenu/index.jsx +++ b/src/Main/Header/ConnectedUserMenu/index.jsx @@ -1,23 +1,25 @@ +/* eslint-disable jsx-a11y/href-no-hash */ + import React, { PropTypes } from 'react'; import { Link } from 'react-router'; import paths from 'constants/paths'; const ConnectedUserMenu = ({ user, onLogOut }) => ( -
  • - - {user.name} - - - -
  • +
  • + + {user.name} + + + +
  • ); ConnectedUserMenu.propTypes = { - user: PropTypes.object.isRequired, - onLogOut: PropTypes.func.isRequired, + user: PropTypes.object.isRequired, + onLogOut: PropTypes.func.isRequired, }; export default ConnectedUserMenu; diff --git a/src/Main/Header/index.jsx b/src/Main/Header/index.jsx index b7bbcbe..08193ae 100644 --- a/src/Main/Header/index.jsx +++ b/src/Main/Header/index.jsx @@ -4,18 +4,19 @@ import cssModules from 'react-css-modules'; import { Navbar, Nav, NavItem } from 'react-bootstrap'; import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap'; +import paths from 'constants/paths'; + import ConnectedUserMenu from './'; -import paths from 'constants/paths'; import logoImg from './images/logo_header.png'; import styles from './Header.css'; -const renderUserMenu = (isConnected) => ( +const renderUserMenu = isConnected => ( isConnected ? : [ -
  • Connexion
  • , /* modal ! */ -
  • Inscription
  • , /* modal ! */ +
  • Connexion
  • , /* modal ! */ +
  • Inscription
  • , /* modal ! */ ] ); @@ -25,7 +26,7 @@ const Header = () => ( - + Brand Logo diff --git a/src/Main/Header/stories.js b/src/Main/Header/stories.jsx similarity index 70% rename from src/Main/Header/stories.js rename to src/Main/Header/stories.jsx index 1c88078..a310d2b 100644 --- a/src/Main/Header/stories.js +++ b/src/Main/Header/stories.jsx @@ -1,5 +1,6 @@ +/* eslint-disable no-unused-vars */ + import React from 'react'; -// eslint-disable-next-line no-unused-vars import { storiesOf, action, linkTo } from '@kadira/storybook'; import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs'; @@ -10,9 +11,9 @@ const stories = storiesOf('Header', module); stories.addDecorator(withKnobs); stories.addWithInfo( - 'default header', - 'Description of the story', - () => ( -
    + 'default header', + 'Description of the story', + () => ( +
    ) ); diff --git a/src/Main/index.jsx b/src/Main/index.jsx index 75e7e57..2b95710 100644 --- a/src/Main/index.jsx +++ b/src/Main/index.jsx @@ -5,18 +5,18 @@ import Footer from './Footer'; import GoogleAnalytics from './GoogleAnalytics'; const Main = ({ children }) => ( -
    -
    - -
    - {children} -
    -
    - +
    +
    + +
    + {children}
    +
    + +
    ); Main.propTypes = { - children: PropTypes.node, + children: PropTypes.node, }; export default Main; diff --git a/src/api/debats/index.js b/src/api/debats/index.js index 7766ccf..34feaae 100644 --- a/src/api/debats/index.js +++ b/src/api/debats/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-unused-vars */ + import { curry } from 'ramda'; import axios from 'axios'; import Config from 'Config'; @@ -13,4 +15,3 @@ export const getStatements = () => get('statements'); export const getPublicFiguresAutocomplete = typed => get(`autocomplete/public_figure/${typed}`); export const getSubjectsAutocomplete = typed => get(`autocomplete/subject/${typed}`); export const getPositions = subjectId => get(`subjects/${subjectId}/positions`); - diff --git a/src/api/jsonApiParser.js b/src/api/jsonApiParser.js index e027d16..826c515 100644 --- a/src/api/jsonApiParser.js +++ b/src/api/jsonApiParser.js @@ -14,45 +14,45 @@ const getId = prop('id'); const getAttributesPair = objectWithAttributes => toPairs(objectWithAttributes.attributes); const mergeAttributes = entityWithAttributes => compose( - reduce( - (entity, attributePair) => (assoc(attributePair[0], attributePair[1], entity)), - entityWithAttributes + reduce( + (entity, attributePair) => (assoc(attributePair[0], attributePair[1], entity)), + entityWithAttributes ), - getAttributesPair, + getAttributesPair, )(entityWithAttributes); const overAttributes = over(lensProp('attributes')); const toCamelCase = replace( - /-[a-z]/g, - compose(replace('-', ''), toUpper) + /-[a-z]/g, + compose(replace('-', ''), toUpper) ); const toCamelCaseAttributes = overAttributes(pipe( - toPairs, - map( - ([k, v]) => ([toCamelCase(k), v]) + toPairs, + map( + ([k, v]) => ([toCamelCase(k), v]) ), - fromPairs, + fromPairs, )); export const flattenAttributes = pipe( - map(pipe( - toCamelCaseAttributes, - mergeAttributes, - dissoc('attributes'), + map(pipe( + toCamelCaseAttributes, + mergeAttributes, + dissoc('attributes'), )), ); export const index = pipe( - when(isNotArray, of), - flattenAttributes, - map(indexBy(getId)) + when(isNotArray, of), + flattenAttributes, + map(indexBy(getId)) ); export const indexAndGroup = pipe( - when(isNotArray, of), - flattenAttributes, - groupBy(getType), - map(indexBy(getId)) + when(isNotArray, of), + flattenAttributes, + groupBy(getType), + map(indexBy(getId)) ); diff --git a/src/boot.js b/src/boot.js index 78b3eef..ac88a5b 100644 --- a/src/boot.js +++ b/src/boot.js @@ -1,5 +1,5 @@ -require('bootstrap-loader'); import moment from 'moment'; +import 'bootstrap-loader'; const locale = 'fr'; @@ -16,7 +16,8 @@ moment.locale(locale, { // Install ImmutableDevTools if (process.env.NODE_ENV !== 'production') { // DEBUG/DEV MODE - const Immutable = require('immutable'); - const installDevTools = require('immutable-devtools').default; - installDevTools(Immutable); + const Immutable = require('immutable'); + const installDevTools = require('immutable-devtools').default; + + installDevTools(Immutable); } diff --git a/src/components/AddStatementButton/index.jsx b/src/components/AddStatementButton/index.jsx index 044682c..29fd850 100644 --- a/src/components/AddStatementButton/index.jsx +++ b/src/components/AddStatementButton/index.jsx @@ -1,29 +1,29 @@ -import React, { PropTypes, Component } from 'react'; +import React, { Component } from 'react'; import { Button } from 'react-bootstrap'; import AddStatementModal from 'components/AddStatementModal'; class AddStatementButton extends Component { - state = { - showModal: false, - } + state = { + showModal: false, + } - close = () => this.setState({ showModal: false }); - open = () => this.setState({ showModal: true }); + close = () => this.setState({ showModal: false }); + open = () => this.setState({ showModal: true }); - render() { - return ( -
    - - -
    - ); - } + +
    + ); + } } export default AddStatementButton; diff --git a/src/components/AddStatementModal/SubjectStep/index.jsx b/src/components/AddStatementModal/SubjectStep/index.jsx index e49f8f9..9302a5f 100644 --- a/src/components/AddStatementModal/SubjectStep/index.jsx +++ b/src/components/AddStatementModal/SubjectStep/index.jsx @@ -5,6 +5,7 @@ import AddSubjectFrom from './AddSubjectForm'; const SubjectStep = ({ selected, onSelection }) => ( +<<<<<<< HEAD Quel est le sujet qui fait débat ? {(!selected || !selected.customOption) && @@ -16,6 +17,11 @@ const SubjectStep = ({ selected, onSelection }) => ( onChange={onSelection} onCancel={() => onSelection(null)} />} +======= + + Quel est le sujet qui fait débat ? + +>>>>>>> master ); diff --git a/src/components/AddStatementModal/connector.js b/src/components/AddStatementModal/connector.js index 61ef800..fa13f3d 100644 --- a/src/components/AddStatementModal/connector.js +++ b/src/components/AddStatementModal/connector.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { getAddStatementPublicFigure, getAddStatementSubject, getAddStatementPosition, - getAddStatementEvidenceUrl, getAddStatementEvidenceFile + getAddStatementEvidenceUrl, getAddStatementEvidenceFile, } from 'store/selectors'; import { onAddStatementPublicFigureSelection, onAddStatementSubjectSelection, onAddStatementPositionSelection, @@ -10,20 +10,20 @@ import { } from 'store/actions'; const mapStateToProps = state => ({ - selectedPublicFigure: getAddStatementPublicFigure(state), - selectedSubject: getAddStatementSubject(state), - selectedPosition: getAddStatementPosition(state), - evidenceUrl: getAddStatementEvidenceUrl(state), - evidenceFile: getAddStatementEvidenceFile(state), + selectedPublicFigure: getAddStatementPublicFigure(state), + selectedSubject: getAddStatementSubject(state), + selectedPosition: getAddStatementPosition(state), + evidenceUrl: getAddStatementEvidenceUrl(state), + evidenceFile: getAddStatementEvidenceFile(state), }); const mapDispatchToProps = dispatch => ({ - onPublicFigureSelection: publicFigureId => dispatch(onAddStatementPublicFigureSelection(publicFigureId)), - onSubjectSelection: publicFigureId => dispatch(onAddStatementSubjectSelection(publicFigureId)), - onPositionSelection: publicFigureId => dispatch(onAddStatementPositionSelection(publicFigureId)), - onUpdateEvidenceUrl: url => dispatch(onAddStatementUpdateEvidenceUrl(url)), - onUpdateEvidenceFile: file => dispatch(onAddStatementUpdateEvidenceFile(file)), - onValidate: () => dispatch(onAddStatementValidate()), + onPublicFigureSelection: publicFigureId => dispatch(onAddStatementPublicFigureSelection(publicFigureId)), + onSubjectSelection: publicFigureId => dispatch(onAddStatementSubjectSelection(publicFigureId)), + onPositionSelection: publicFigureId => dispatch(onAddStatementPositionSelection(publicFigureId)), + onUpdateEvidenceUrl: url => dispatch(onAddStatementUpdateEvidenceUrl(url)), + onUpdateEvidenceFile: file => dispatch(onAddStatementUpdateEvidenceFile(file)), + onValidate: () => dispatch(onAddStatementValidate()), }); export default connect(mapStateToProps, mapDispatchToProps); diff --git a/src/components/AssociatedSubjects/index.jsx b/src/components/AssociatedSubjects/index.jsx index 45a5be4..b165166 100644 --- a/src/components/AssociatedSubjects/index.jsx +++ b/src/components/AssociatedSubjects/index.jsx @@ -1,20 +1,20 @@ import React, { PropTypes } from 'react'; -const getText = nb => { - if (nb === 0) - return "Aucun sujet actif"; - else if (nb > 1) - return nb + "sujets actifs"; +const getText = (nb) => { + if (nb === 0) + return 'Aucun sujet actif'; + else if (nb > 1) + return `${nb}sujets actifs`; - return "1 sujet actif"; + return '1 sujet actif'; }; const AssociatedSubjects = ({ publicFigure }) => ( -
    {getText(publicFigure.nbActiveSubjects)}
    +
    {getText(publicFigure.nbActiveSubjects)}
    ); AssociatedSubjects.propTypes = { - publicFigure: PropTypes.object.isRequired + publicFigure: PropTypes.object.isRequired, }; -export default AssociatedSubjects; \ No newline at end of file +export default AssociatedSubjects; diff --git a/src/components/general/Identity/index.js b/src/components/Identity/index.jsx similarity index 88% rename from src/components/general/Identity/index.js rename to src/components/Identity/index.jsx index 64cc6c2..42c9e77 100644 --- a/src/components/general/Identity/index.js +++ b/src/components/Identity/index.jsx @@ -5,7 +5,7 @@ import React, { PropTypes } from 'react'; const Identity = ({ children }) =>
    {children}
    ; Identity.propTypes = { - children: PropTypes.node, + children: PropTypes.node, }; export default Identity; diff --git a/src/components/general/Identity/stories.js b/src/components/Identity/stories.jsx similarity index 85% rename from src/components/general/Identity/stories.js rename to src/components/Identity/stories.jsx index d310743..fcb3ad8 100644 --- a/src/components/general/Identity/stories.js +++ b/src/components/Identity/stories.jsx @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ import React from 'react'; import { storiesOf, action, linkTo } from '@kadira/storybook'; import Identity from './'; diff --git a/src/components/LastStatements/Statement/index.jsx b/src/components/LastStatements/Statement/index.jsx index 8455c4b..86fdaa3 100644 --- a/src/components/LastStatements/Statement/index.jsx +++ b/src/components/LastStatements/Statement/index.jsx @@ -6,28 +6,28 @@ import cssModules from 'react-css-modules'; import style from './Statement.css'; const Statement = ({ statement }) => ( -
  • - -
    - - - {statement.publicFigure.name} - - +
  • + +
    + + + {statement.publicFigure.name} + +   s'est déclaré pour "{statement.position.title}" dans le débat sur - {statement.subject.title} + {statement.subject.title} -
    -
  • + + ); Statement.propTypes = { - statement: PropTypes.shape({ - publicFigure: PropTypes.object, - position: PropTypes.object, - }).isRequired, + statement: PropTypes.shape({ + publicFigure: PropTypes.object, + position: PropTypes.object, + }).isRequired, }; export default cssModules(Statement, style); diff --git a/src/components/LastStatements/connector.js b/src/components/LastStatements/connector.js index d872bc6..4f8d37e 100644 --- a/src/components/LastStatements/connector.js +++ b/src/components/LastStatements/connector.js @@ -3,11 +3,11 @@ import { getLatestStatements } from 'store/selectors'; import { onLastStatementsAccess } from 'store/actions/entities'; const mapStateToProps = state => ({ - statements: getLatestStatements(state), + statements: getLatestStatements(state), }); const mapDispatchToProps = dispatch => ({ - onAccess: () => dispatch(onLastStatementsAccess()), + onAccess: () => dispatch(onLastStatementsAccess()), }); export default connect(mapStateToProps, mapDispatchToProps); diff --git a/src/components/LastStatements/index.jsx b/src/components/LastStatements/index.jsx index 7be4b75..2d17e2d 100644 --- a/src/components/LastStatements/index.jsx +++ b/src/components/LastStatements/index.jsx @@ -1,35 +1,35 @@ import React, { PropTypes, Component } from 'react'; -import CSSModules from 'react-css-modules'; +import cssModules from 'react-css-modules'; import Statement from './Statement'; import LastStatementsStyle from './LastStatements.css'; import connect from './connector'; class LastStatements extends Component { - static propTypes = { - statements: PropTypes.arrayOf(PropTypes.object), - onAccess: PropTypes.func.isRequired, - }; + static propTypes = { + statements: PropTypes.arrayOf(PropTypes.object), + onAccess: PropTypes.func.isRequired, + }; - componentWillMount() { - this.props.onAccess(); - } + componentWillMount() { + this.props.onAccess(); + } - renderStatements = () => this.props.statements.map( - (s, i) => + renderStatements = () => this.props.statements.map( + (s, i) => ); - render() { - if (!this.props.statements) return loading last statements ...; + render() { + if (!this.props.statements) return loading last statements ...; - return ( -
    -

    Les dernières prises de positions

    -
      - { this.renderStatements() }; -
    -
    - ); - } + return ( +
    +

    Les dernières prises de positions

    +
      + { this.renderStatements() }; +
    +
    + ); + } } -export default connect(CSSModules(LastStatements, LastStatementsStyle)); +export default connect(cssModules(LastStatements, LastStatementsStyle)); diff --git a/src/components/PublicFigureAutocompleteInput/index.jsx b/src/components/PublicFigureAutocompleteInput/index.jsx index 2a72801..5c5e343 100644 --- a/src/components/PublicFigureAutocompleteInput/index.jsx +++ b/src/components/PublicFigureAutocompleteInput/index.jsx @@ -1,8 +1,8 @@ -import React, { Component, PropTypes } from 'react'; -import { head, of, compose, when, prop, not, isNil } from 'ramda'; +import React, {Component, PropTypes} from 'react'; +import {head, of, compose, when, prop, not, isNil} from 'ramda'; import Typeahead from 'react-bootstrap-typeahead'; -import { getPublicFiguresAutocomplete } from 'api/debats'; -import { flattenAttributes } from 'api/jsonApiParser'; +import {getPublicFiguresAutocomplete} from 'api/debats'; +import {flattenAttributes} from 'api/jsonApiParser'; import PublicFigureAvatar from 'components/PublicFigureAvatar'; import { makeCancelable } from 'helpers/promises'; diff --git a/src/components/PublicFigureAvatar/index.jsx b/src/components/PublicFigureAvatar/index.jsx index 773e048..d305be8 100644 --- a/src/components/PublicFigureAvatar/index.jsx +++ b/src/components/PublicFigureAvatar/index.jsx @@ -3,17 +3,17 @@ import cssModules from 'react-css-modules'; import styles from './PublicFigureAvatar.css'; const PublicFigureAvatar = ({ publicFigure }) => ( -
    + }} + /> ); PublicFigureAvatar.propTypes = { - publicFigure: PropTypes.object.isRequired, + publicFigure: PropTypes.object.isRequired, }; export default cssModules(PublicFigureAvatar, styles); diff --git a/src/components/PublicFigureAvatar/stories.js b/src/components/PublicFigureAvatar/stories.jsx similarity index 57% rename from src/components/PublicFigureAvatar/stories.js rename to src/components/PublicFigureAvatar/stories.jsx index 130c4a8..ae1c59a 100644 --- a/src/components/PublicFigureAvatar/stories.js +++ b/src/components/PublicFigureAvatar/stories.jsx @@ -1,5 +1,6 @@ +/* eslint-disable no-unused-vars */ import React from 'react'; -// eslint-disable-next-line no-unused-vars + import { storiesOf, action, linkTo } from '@kadira/storybook'; import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs'; import withReadme from 'storybook-readme/with-readme'; @@ -12,15 +13,15 @@ const stories = storiesOf('PublicFigureAvatar', module); stories.addDecorator(withKnobs); stories.addWithInfo( - 'pony avatar', - 'Description of the story', - withReadme(README, - () => ( - + 'pony avatar', + 'Description of the story', + withReadme(README, + () => ( + ) ) ); stories.add('jake avatar', () => ( - + )); diff --git a/src/components/SubjectAutocompleteInput/index.jsx b/src/components/SubjectAutocompleteInput/index.jsx index ddd5a53..05ee6c9 100644 --- a/src/components/SubjectAutocompleteInput/index.jsx +++ b/src/components/SubjectAutocompleteInput/index.jsx @@ -13,7 +13,6 @@ const parseSubjects = raw => pipe( ) )(raw.data); - class SubjectAutocompleteInput extends Component { static propTypes = { @@ -57,23 +56,41 @@ class SubjectAutocompleteInput extends Component { onSelection = compose(this.props.onSelection, head); - render() { - return ( - - ); - } + loadSuggestions = (typed) => { + if (this.props.selected) this.props.onSelection(null); + if (typed.length) { + getSubjectsAutocomplete(typed) + .then((response) => { + this.setState({ + suggestions: flattenAttributes(response.data.data), + }); + }); } + }; + + renderMenuItemChildren = (typeaheadProps, subject) => ( +
    +

    {subject.title}

    + {take(100)(subject.presentation)} +
    + ); + + render() { + return ( + + ); + } } diff --git a/src/components/general/Empty.js b/src/components/general/Empty.js deleted file mode 100644 index 39e62ee..0000000 --- a/src/components/general/Empty.js +++ /dev/null @@ -1,4 +0,0 @@ -import React from 'react'; - -const Empty = () => ; -export default Empty; diff --git a/src/constants/paths.js b/src/constants/paths.js index 77b6cc1..b8cfefc 100644 --- a/src/constants/paths.js +++ b/src/constants/paths.js @@ -1,15 +1,15 @@ export default { - root: '/', - subjects: '/s', - publicFigures: '/p', - getFor: { - subject: (s) => `/s/${s.slug}`, - publicFigure: (pf) => `/p/${pf.slug}`, - }, - manual: '/guide', - about: '/about', - contact: '/contact', - external: { - twitter: 'https://twitter.com/debatsco', - }, + root: '/', + subjects: '/s', + publicFigures: '/p', + getFor: { + subject: s => `/s/${s.slug}`, + publicFigure: pf => `/p/${pf.slug}`, + }, + manual: '/guide', + about: '/about', + contact: '/contact', + external: { + twitter: 'https://twitter.com/debatsco', + }, }; diff --git a/src/helpers/debug/index.js b/src/helpers/debug/index.js index bcd0bb2..59fdb16 100644 --- a/src/helpers/debug/index.js +++ b/src/helpers/debug/index.js @@ -1,14 +1,14 @@ -import { pipe, always } from 'ramda'; +import { pipe } from 'ramda'; -const print = message => x => { - if (!!message) console.warn(message); - return x; +const print = message => (x) => { + if (message) console.warn(message); + return x; }; -const printWithPrefix = (prefix) => (x) => { - console.warn('-------------------------------'); - console.warn(`---- ${prefix}: `, x); - return x; +const printWithPrefix = prefix => (x) => { + console.warn('-------------------------------'); + console.warn(`---- ${prefix}: `, x); + return x; }; const printBefore = printWithPrefix('BEFORE'); @@ -16,5 +16,5 @@ const printAfter = printWithPrefix('AFTER'); export const withConsole = (f, message) => pipe(printBefore, print(message), f, printAfter); -export const log = x => { console.log(x); return x; }; /* eslint no-console: 0 */ -export const warn = x => { console.warn(x); return x; }; /* eslint no-console: 0 */ +export const log = (x) => { console.log(x); return x; }; /* eslint no-console: 0 */ +export const warn = (x) => { console.warn(x); return x; }; /* eslint no-console: 0 */ diff --git a/src/helpers/env.js b/src/helpers/env.js index ffde09c..46a9c65 100644 --- a/src/helpers/env.js +++ b/src/helpers/env.js @@ -1,4 +1,5 @@ import { complement } from 'ramda'; + export const hasWindow = () => (typeof window !== 'undefined'); export const isClientSide = hasWindow; export const isServerSide = complement(hasWindow); diff --git a/src/index.js b/src/index.jsx similarity index 58% rename from src/index.js rename to src/index.jsx index 9158580..53b8f53 100644 --- a/src/index.js +++ b/src/index.jsx @@ -1,9 +1,6 @@ import 'react-hot-loader/patch'; // https://github.com/gaearon/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915 import 'babel-polyfill'; -// First boot side effects -import './boot.js'; - import React from 'react'; import ReactDOM from 'react-dom'; import { AppContainer } from 'react-hot-loader'; @@ -11,6 +8,10 @@ import { match } from 'react-router'; // Styles import 'styles/_main.css'; + +// First boot side effects +import './boot.js'; + // Redux import { store, history } from './store'; // Redux store import Root from './root'; // App root (Router, Provider, Hot reload ... @@ -18,31 +19,31 @@ import routes from './routes'; // React-router routes // Init app function const loadApplication = (DOMElementId) => { - const DOMElement = document.getElementById(DOMElementId); + const DOMElement = document.getElementById(DOMElementId); - match({ history, routes, location }, () => { - ReactDOM.render( - - - , - DOMElement + match({ history, routes }, () => { + ReactDOM.render( + + + , + DOMElement ); - }); + }); - if (module.hot) { - module.hot.accept('./root/index.jsx', () => { + if (module.hot) { + module.hot.accept('./root/index.jsx', () => { // If you use Webpack 2 in ES modules mode, you can // use here rather than require() a . - const NextApp = require('./root/index').default; + const NextApp = require('./root/index').default; - ReactDOM.render( - - - , - DOMElement - ); - }); - } + ReactDOM.render( + + + , + DOMElement + ); + }); + } }; export { store, history }; diff --git a/src/pages/About/index.jsx b/src/pages/About/index.jsx index f4d2c95..8da9534 100644 --- a/src/pages/About/index.jsx +++ b/src/pages/About/index.jsx @@ -3,31 +3,31 @@ import cssModules from 'react-css-modules'; import styles from './About.css'; const About = () => ( -
    -

    Pourquoi Débats.co ?

    -

    - Débats est un projet francophone et participatif, ayant pour objectif d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société. -

    -

    - Dans un monde de plus en plus complexe, les discours simplistes sont légion. Régulièrement, des controverses se construisent sur la base d'arguments à peine vérifiés, ou simplement invérifiables. - C’est ainsi que semblent se développer des idées confuses et des discussions stériles. -

    -

    - L'intelligibilité du débat public et son accessibilité par tous ceux qui aspirent à y participer déterminent la qualité de notre système démocratique. Or, aujourd’hui, aucun outil, simple d’utilisation, ne permet d’accéder à la pluralité des idées de celles et ceux qui font le choix de s’exprimer publiquement. Prendre connaissance de leurs arguments, comprendre ce qu’ils prétendent ou ce qu’ils laissent entendre est un véritable parcours du combattant. Nous cédons ainsi régulièrement à la facilité, en accordant une valeur démesurée à des postures démagogiques ou en laissant à d’autres le soin de les produire. -

    -

    - Pourtant, les ressources sont là, sous nos yeux, elles existent ! Les blogs, les tweets, les journaux télévisés, les discours ou les livres sont un trésor démocratique laissé en jachère, une réserve politique fertile jusqu’ici largement sous-exploitée. Ces traces essaimées tout autour de nous constituent une des clés pour y voir plus clair. -

    -

    - L’ambition de Débats est simple : recenser, sur chaque grand thème qui fait débat, les prises de position de celles et ceux qui décident de s’engager. Cartographier l’évolution de leur pensée, de leurs opinions, des combats qu’ils ont menés. Donner à voir la constance, la progression ou l’incohérence d’un engagement dans le temps. -

    -

    - Rédigé par des volontaires sur une plateforme en ligne, et fonctionnant sur le principe du wiki, Débats a pour objectif d'offrir un contenu libre, impartial et vérifiable des prises de position de celles et ceux qui participent aux débats publics. -

    -

    - Face à ce que nous considérons comme un dévoiement démocratique, nous partageons une conviction : l’information est notre première arme. Redonner à l’engagement la crédibilité et la valeur qui doivent être les siennes : voilà la raison d’être de Débats. -

    -
    +
    +

    Pourquoi Débats.co ?

    +

    + Débats est un projet francophone et participatif, ayant pour objectif d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société. +

    +

    + Dans un monde de plus en plus complexe, les discours simplistes sont légion. Régulièrement, des controverses se construisent sur la base d'arguments à peine vérifiés, ou simplement invérifiables. + C’est ainsi que semblent se développer des idées confuses et des discussions stériles. +

    +

    + L'intelligibilité du débat public et son accessibilité par tous ceux qui aspirent à y participer déterminent la qualité de notre système démocratique. Or, aujourd’hui, aucun outil, simple d’utilisation, ne permet d’accéder à la pluralité des idées de celles et ceux qui font le choix de s’exprimer publiquement. Prendre connaissance de leurs arguments, comprendre ce qu’ils prétendent ou ce qu’ils laissent entendre est un véritable parcours du combattant. Nous cédons ainsi régulièrement à la facilité, en accordant une valeur démesurée à des postures démagogiques ou en laissant à d’autres le soin de les produire. +

    +

    + Pourtant, les ressources sont là, sous nos yeux, elles existent ! Les blogs, les tweets, les journaux télévisés, les discours ou les livres sont un trésor démocratique laissé en jachère, une réserve politique fertile jusqu’ici largement sous-exploitée. Ces traces essaimées tout autour de nous constituent une des clés pour y voir plus clair. +

    +

    + L’ambition de Débats est simple : recenser, sur chaque grand thème qui fait débat, les prises de position de celles et ceux qui décident de s’engager. Cartographier l’évolution de leur pensée, de leurs opinions, des combats qu’ils ont menés. Donner à voir la constance, la progression ou l’incohérence d’un engagement dans le temps. +

    +

    + Rédigé par des volontaires sur une plateforme en ligne, et fonctionnant sur le principe du wiki, Débats a pour objectif d'offrir un contenu libre, impartial et vérifiable des prises de position de celles et ceux qui participent aux débats publics. +

    +

    + Face à ce que nous considérons comme un dévoiement démocratique, nous partageons une conviction : l’information est notre première arme. Redonner à l’engagement la crédibilité et la valeur qui doivent être les siennes : voilà la raison d’être de Débats. +

    +
    ); export default cssModules(About, styles); diff --git a/src/pages/Contact/index.jsx b/src/pages/Contact/index.jsx index b73cfd8..2686645 100644 --- a/src/pages/Contact/index.jsx +++ b/src/pages/Contact/index.jsx @@ -13,12 +13,12 @@ const Contact = () => ( diff --git a/src/pages/Guide/index.jsx b/src/pages/Guide/index.jsx index e17ff21..6595c39 100644 --- a/src/pages/Guide/index.jsx +++ b/src/pages/Guide/index.jsx @@ -3,14 +3,14 @@ import cssModules from 'react-css-modules'; import styles from './Guide.css'; const Guide = () => ( -
    -
    -
    -

    Mode d'emploi

    +
    +
    +
    +

    Mode d'emploi

    -

    Panel de discussion

    +

    Panel de discussion

    -

    +

    La confiance La plateforme Débats.co est basée sur la confiance. C’est-à-dire que le contenu est systématiquement considéré comme a priori valide, mais peut être retiré en cas de signalement. Plusieurs motifs peuvent pousser les autres membres à signaler votre contenu : Le contenu ne respecte pas les règles de rédaction @@ -18,142 +18,142 @@ const Guide = () => ( Le contenu pré-existe autrepart sur la plateforme

    -

    Comment éviter d’être signalé ?

    +

    Comment éviter d’être signalé ?

    -
    +
    -
    - +
    +
    +

    Débats.co n’est pas un site de débats.
    Débats.co a pour objectif de référencer et cartographier les positions prises par des personnalités publiques au cours des débats qui font controverse en France. Ainsi, les contributeurs ne sont pas appelés à donner leur avis mais plutôt à rechercher, collecter et recenser les positions exprimées sur un sujet particulier. Nous invitons les contributeurs de Débats.co à lire ce mode d’emploi et à s’y référer en cas de doute lors de l’utilisation du site.

    -
    -
    -
    +
    +
    +
    -
    - -
    -
    -

    +

    + +
    +
    +

    Le premier usage de Débats.co consiste à consulter la plateforme, en explorant les différents sujets enregistrés et le positionnement des personnalités publiques au sein de ces sujets. Le deuxième usage consiste à contribuer à la plateforme en y apportant le contenu nécessaire pour une synthèse des différents sujets et prises de positions.
    Dans les deux cas, il est important de bien comprendre la structure du site. Sur Débats.co, l’information est articulée autour de plusieurs éléments :

    -
      -
    • Le sujet
    • -
    • La position
    • -
    • La personnalité
    • -
    • La prise de position
    • -
    • L’argument
    • -
    • La source
    • -
    -

    +

      +
    • Le sujet
    • +
    • La position
    • +
    • La personnalité
    • +
    • La prise de position
    • +
    • L’argument
    • +
    • La source
    • +
    +

    Chaque sujet comporte au moins deux positions. Une position peut être "prise" par plusieurs personnalités. A chaque prise de position sont attachés une personnalité et un ensemble d’arguments. Pour que la prise de position puisse être recensée, elle doit être justifiée par au moins une source.
    En somme, pour qu’un sujet puisse être référencé, il est nécessaire d'y recenser au moins une prise de position par au moins une personnalité dans chacune des positions.

    -
    -
    -
    +
    +
    +
    -
    - +
    +
    +

    Une source est un élément permettant d’appuyer une prise de position. La source peut être constituée à partir de toute référence audio, vidéo, article, ou livre dont la diffusion est, ou a été, publique. Il sera demandé au contributeur de retranscrire la citation qui soutient le propos en question, la date à laquelle ce propos a été tenu, et, si possible, de fournir un lien qui permet d'y accéder directement.

    -
    -
    -
    +
    +
    +
    -
    - -
    -
    -

    - +

    + +
    +
    +

    + Préexistence d'un contenu : -
    +
    Tout d'abord, le contributeur peut se demander si le contenu qu'il s'apprête à référencer existe déjà. Lorsqu'il référence un nouveau sujet, il peut vérifier si celui-ci est déjà traité, ou partiellement traité, dans un autre sujet : auquel cas, il pourra enrichir ou modifier le débat déjà existant.
    Lors du recensement d'une prise de position, l'exercice est similaire : il pourra vérifier la pré-existence d'une prise de position pour la personnalité en question, et l'enrichir avec de nouvelles sources le cas échant. Les arguments, matérialisés sur Débats.co par des tags, peuvent être infinis. Le formulaire vous suggérera néanmoins les tags proposés par d'autres utilisateurs.
    -
    - +
    + Notoriété et véracité : -
    +
    Il est nécessaire pour le contributeur de se demander si le contenu est suffisamment important, fiable et pertinent pour être référencé ou recensé sur Débats.co. Basé sur une logique collaborative, le site comporte plusieurs mécanismes d'autorégulation, permettant d’éviter la publication de contenu considérés comme fallacieux ou hors-sujet. Chaque entrée, notamment lors du référencement d’une nouvelle personnalité ou d’un nouveau sujet, sont soumis à l'approbation des utilisateurs expérimentés de la plateforme.
    -
    +
    - Neutralité et cohérence du point de vue -
    + Neutralité et cohérence du point de vue +
    Parler de "cohérence" lorsque l'on tente de référencer des sujets controversées est presque en soi contradictoire. Débats.co a néanmoins comme volonté de tendre un maximum vers l'objectivité.
    Afin de s'en rapprocher, il est nécessaire pour chaque utilisateur de se demander comment exprimer de façon objective l’intitulé des sujets ou les positions des personnalités. Dans un premier temps, et pour simplifier cette démarche "objective", les sujets ainsi que les pages de personnalités peuvent être référencées directement depuis la base de données de Wikipedia. Il suffira donc, après la composition des premières lettres de l'intitulé de la personnalité ou du sujet, de sélectionner l'élément correspondant.
    Lors de la recension d'une prise d'une position ensuite, il est important d'attacher à la source une citation qui justifie la prise de position. La citation doit être isolée, entre guillemets, ne pas être modifiée, et se suffir à elle-même pour être comprise (ne pas être sortie d'un contexte qui peut altérer sa compréhensioin). Pour être valide dans le cadre d’un sujet, un argument doit être explicitement mobilisé par la personnalité publique et répondre à la problématique initiale du débat.
    -

    -
    -
    -
    +

    +
    +
    +
    -
    - -
    -
    -

    +

    + +
    +
    +

    La contribution au site est simple. Toutefois, avant de pouvoir accéder à toutes les fonctions de référencement, de recension et de modification, une phase d’apprentissage est nécessaire. Pour apprendre, il faut s’exercer. Ainsi, pour chaque contribution au site, un nombre de points est attribué à l’utilisateur. L’accumulation de ces points lui donne progressivement accès aux fonctionnalités les plus puissantes de Débats.co. Le signalement par d'autres utilisateurs de la violation des principes inscrits dans ce mode d'emploi peut entraîner la perte de points. Ainsi 5 status existent sur Débats.co :

    -
      -
    • Le Métèque : Son score est neutre. Il vient d'arriver sur la plateforme, et doit encore faire ses preuves. Il peut soumettre des arguments et des sources.
    • -
    • L'Eloquent : Son score est positif, il peut ajouter de nouvelles personnalités, de nouveau sujets, mais également suggérer l'approbation ou le rejet de modifications proposées par d'autres utilisateurs. Par défaut, tous les membres fondateurs inscrits lors de la bêta de Débats.co sont considérés comme Eloquents.
    • -
    • L'Idéaliste : Son score est élevé, il peut instantanément supprimer la plupart des modifications faites par d'autres utilisateurs.
    • -
    • Le Sophiste : son score est négatif, il a tout autant de droits que le nouvel arrivant, mais part avec autant de points de retard pour redevenir Métèque.
    • -
    -
    -
    -
    +
      +
    • Le Métèque : Son score est neutre. Il vient d'arriver sur la plateforme, et doit encore faire ses preuves. Il peut soumettre des arguments et des sources.
    • +
    • L'Eloquent : Son score est positif, il peut ajouter de nouvelles personnalités, de nouveau sujets, mais également suggérer l'approbation ou le rejet de modifications proposées par d'autres utilisateurs. Par défaut, tous les membres fondateurs inscrits lors de la bêta de Débats.co sont considérés comme Eloquents.
    • +
    • L'Idéaliste : Son score est élevé, il peut instantanément supprimer la plupart des modifications faites par d'autres utilisateurs.
    • +
    • Le Sophiste : son score est négatif, il a tout autant de droits que le nouvel arrivant, mais part avec autant de points de retard pour redevenir Métèque.
    • +
    +
    -
    +
    +
    +
    ); export default cssModules(Guide, styles); diff --git a/src/pages/Home/HomeSubjects/HomeSubject/index.jsx b/src/pages/Home/HomeSubjects/HomeSubject/index.jsx index 1202f4b..75a0198 100644 --- a/src/pages/Home/HomeSubjects/HomeSubject/index.jsx +++ b/src/pages/Home/HomeSubjects/HomeSubject/index.jsx @@ -6,40 +6,40 @@ import PublicFigureAvatar from 'components/PublicFigureAvatar'; const PublicFigureAvatarMapper = pf => ; const renderAssociatedPublicFigures = compose( - map(PublicFigureAvatarMapper), - take(5), - prop('remarquablePublicFigures'), + map(PublicFigureAvatarMapper), + take(5), + prop('remarquablePublicFigures'), ); const HomeSubject = ({ subject }) => ( -
  • - - -

    - - {subject.title} - -

    -
    - {`${subject.remarquablePublicFigures.length} personnalité(s)`} -
    - - - {renderAssociatedPublicFigures(subject)} - - -
    - Voir plus de personnalités -
    - - -
  • +
  • + + +

    + + {subject.title} + +

    +
    + {`${subject.remarquablePublicFigures.length} personnalité(s)`} +
    + + + {renderAssociatedPublicFigures(subject)} + + +
    + Voir plus de personnalités +
    + + +
  • ); HomeSubject.propTypes = { - subject: PropTypes.shape({ - title: PropTypes.string.isRequired, - remarquablePublicFigures: PropTypes.arrayOf(PropTypes.object).isRequired, - }).isRequired, + subject: PropTypes.shape({ + title: PropTypes.string.isRequired, + remarquablePublicFigures: PropTypes.arrayOf(PropTypes.object).isRequired, + }).isRequired, }; export default (HomeSubject); diff --git a/src/pages/Home/HomeSubjects/connectors.js b/src/pages/Home/HomeSubjects/connectors.js index 9bd46b6..1d146fe 100644 --- a/src/pages/Home/HomeSubjects/connectors.js +++ b/src/pages/Home/HomeSubjects/connectors.js @@ -3,11 +3,11 @@ import { getHomeSubjectsWithRelations } from 'store/selectors'; import { onHottestSubjectsAccess } from 'store/actions/entities'; const mapStateToProps = state => ({ - subjects: getHomeSubjectsWithRelations(state), + subjects: getHomeSubjectsWithRelations(state), }); const mapDispatchToProps = dispatch => ({ - onAccess: () => dispatch(onHottestSubjectsAccess()), + onAccess: () => dispatch(onHottestSubjectsAccess()), }); export default connect(mapStateToProps, mapDispatchToProps); diff --git a/src/pages/Home/HomeSubjects/index.jsx b/src/pages/Home/HomeSubjects/index.jsx index 0855cf8..8896037 100644 --- a/src/pages/Home/HomeSubjects/index.jsx +++ b/src/pages/Home/HomeSubjects/index.jsx @@ -4,26 +4,26 @@ import connector from './connectors'; class HomeSubjects extends Component { - static propTypes = { - subjects: PropTypes.arrayOf(PropTypes.object).isRequired, - onAccess: PropTypes.func.isRequired, - } + static propTypes = { + subjects: PropTypes.arrayOf(PropTypes.object).isRequired, + onAccess: PropTypes.func.isRequired, + } - componentWillMount() { - this.props.onAccess(); - } + componentWillMount() { + this.props.onAccess(); + } - render() { - if (!this.props.subjects) return loading subjects ...; + render() { + if (!this.props.subjects) return loading subjects ...; - return ( -
    {/* TODO Bootstrap */} - {this.props.subjects.map( - s => + return ( +
    {/* TODO Bootstrap */} + {this.props.subjects.map( + s => )} -
    - ); - } +
    + ); + } } diff --git a/src/pages/Home/index.jsx b/src/pages/Home/index.jsx index be2ef35..458f99a 100644 --- a/src/pages/Home/index.jsx +++ b/src/pages/Home/index.jsx @@ -1,37 +1,37 @@ import React from 'react'; import cssModules from 'react-css-modules'; -import HomeSubjects from './HomeSubjects'; import LastStatements from 'components/LastStatements'; +import HomeSubjects from './HomeSubjects'; import bgSrc from './images/intro-bg.jpg'; import styles from './Home.css'; const Home = () => ( -
    -
    -
    -
    Bienvenue sur Débats.co
    -
    - Débats est un projet francophone et participatif, ayant pour objectif - d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société. -
    -
    +
    +
    +
    +
    Bienvenue sur Débats.co
    +
    + Débats est un projet francophone et participatif, ayant pour objectif + d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société.
    -
    -
    -

    Sujets d'actualité

    - - -
      - -
    - -
    -
    -
    - -
    -
    +
    +
    +
    +

    Sujets d'actualité

    + + +
      + +
    + +
    +
    +
    + +
    +
    +
    ); export default cssModules(Home, styles); diff --git a/src/pages/PublicFigures/PublicFigureInList/index.jsx b/src/pages/PublicFigures/PublicFigureInList/index.jsx index d2e0a47..4f756bc 100644 --- a/src/pages/PublicFigures/PublicFigureInList/index.jsx +++ b/src/pages/PublicFigures/PublicFigureInList/index.jsx @@ -1,55 +1,47 @@ import React, { PropTypes } from 'react'; -import paths from '../../../constants/paths'; +import cssModules from 'react-css-modules'; import { Link } from 'react-router'; + +import paths from 'constants/paths'; import PublicFigureAvatar from 'components/PublicFigureAvatar'; import AssociatedSubjects from 'components/AssociatedSubjects'; + import PublicFigureStyle from './PublicFigure.css'; -import cssModules from 'react-css-modules'; const PublicFigureInList = ({ publicFigure }) => ( - - -
      -
    • +
    + +
      +
    • -
    - - + + - + - - -
    - - +
    + + -

    - - {publicFigure.name} - -

    - +

    + + {publicFigure.name} + +

    +
    -

    - {publicFigure.presentation} -

    +

    + {publicFigure.presentation} +

    + + + ); PublicFigureInList.propTypes = { - publicFigure: PropTypes.object.isRequired, + publicFigure: PropTypes.object.isRequired, }; export default cssModules(PublicFigureInList, PublicFigureStyle); - -/* - - */ diff --git a/src/pages/PublicFigures/connector.js b/src/pages/PublicFigures/connector.js index 971fa63..53a9780 100644 --- a/src/pages/PublicFigures/connector.js +++ b/src/pages/PublicFigures/connector.js @@ -3,11 +3,11 @@ import { getPublicFiguresWithRelations } from 'store/selectors'; import { onPublicFiguresListAccess } from 'store/actions/entities'; const mapStateToProps = state => ({ - publicFigures: getPublicFiguresWithRelations(state), + publicFigures: getPublicFiguresWithRelations(state), }); const mapDispatchToProps = dispatch => ({ - onAccess: () => dispatch(onPublicFiguresListAccess()), + onAccess: () => dispatch(onPublicFiguresListAccess()), }); export default connect(mapStateToProps, mapDispatchToProps); diff --git a/src/pages/PublicFigures/index.jsx b/src/pages/PublicFigures/index.jsx index 830c904..4971c2c 100644 --- a/src/pages/PublicFigures/index.jsx +++ b/src/pages/PublicFigures/index.jsx @@ -1,37 +1,38 @@ import React, { PropTypes, Component } from 'react'; + +import LastStatements from 'components/LastStatements'; import PublicFigureInList from './PublicFigureInList'; import connect from './connector'; -import LastStatements from 'components/LastStatements'; class PublicFigures extends Component { - static propTypes = { - publicFigures: PropTypes.arrayOf(PropTypes.object).isRequired, - onAccess: PropTypes.func.isRequired, - } + static propTypes = { + publicFigures: PropTypes.arrayOf(PropTypes.object).isRequired, + onAccess: PropTypes.func.isRequired, + } - componentWillMount() { - this.props.onAccess(); - } + componentWillMount() { + this.props.onAccess(); + } - render() { - if (!this.props.publicFigures) return loading public figures ...; + render() { + if (!this.props.publicFigures) return loading public figures ...; - const renderChilds = () => this.props.publicFigures.map( - pf => + const renderChilds = () => this.props.publicFigures.map( + pf => ); - return ( -
    -
    - {renderChilds()} -
    -
    - -
    -
    - ); - } + return ( +
    +
    + {renderChilds()} +
    +
    + +
    +
    + ); + } } export default connect(PublicFigures); diff --git a/src/root/index.jsx b/src/root/index.jsx index eecacb6..ae00dde 100644 --- a/src/root/index.jsx +++ b/src/root/index.jsx @@ -4,14 +4,14 @@ import { Router } from 'react-router'; import routes from '../routes'; const Root = ({ store, history }) => ( - - - + + + ); Root.propTypes = { - store: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, + store: PropTypes.object.isRequired, + history: PropTypes.object.isRequired, }; export default Root; diff --git a/src/routes/index.js b/src/routes/index.js deleted file mode 100644 index 733bd87..0000000 --- a/src/routes/index.js +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import { Route, IndexRoute } from 'react-router'; - -// Main Page -import Main from 'Main/index'; -export default ( - - { - require.ensure([], require => { - done(null, require('pages/Home').default); - }, 'home'); - }} - /> - { - require.ensure([], require => { - done(null, require('pages/Contact').default); - }, 'contact'); - }} - /> - { - require.ensure([], require => { - done(null, require('pages/About').default); - }, 'about'); - }} - /> - { - require.ensure([], require => { - done(null, require('pages/Guide').default); - }, 'guide'); - }} - /> - - { - require.ensure([], require => { - done(null, require('pages/Subjects').default); - }, 'subjects.index'); - }} - /> - { - require.ensure([], require => { - done(null, require('pages/Subject').default); - }, 'subjects.page'); - }} - /> - - - { - require.ensure([], require => { - done(null, require('pages/PublicFigures').default); - }, 'publicFigures.index'); - }} - /> - { - require.ensure([], require => { - done(null, require('pages/publicFigure').default); - }, 'publicFigures.page'); - }} - /> - - -); diff --git a/src/routes/index.jsx b/src/routes/index.jsx new file mode 100644 index 0000000..f75a8f2 --- /dev/null +++ b/src/routes/index.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { Route, IndexRoute } from 'react-router'; + +// Main Page +import Main from 'Main/index'; + +export default ( + + { + require.ensure([], (require) => { + done(null, require('pages/Home').default); + }, 'home'); + }} + /> + { + require.ensure([], (require) => { + done(null, require('pages/Contact').default); + }, 'contact'); + }} + /> + { + require.ensure([], (require) => { + done(null, require('pages/About').default); + }, 'about'); + }} + /> + { + require.ensure([], (require) => { + done(null, require('pages/Guide').default); + }, 'guide'); + }} + /> + + { + require.ensure([], (require) => { + done(null, require('pages/Subjects').default); + }, 'subjects.index'); + }} + /> + { + require.ensure([], (require) => { + done(null, require('pages/Subject').default); + }, 'subjects.page'); + }} + /> + + + { + require.ensure([], (require) => { + done(null, require('pages/PublicFigures').default); + }, 'publicFigures.index'); + }} + /> + { + require.ensure([], (require) => { + done(null, require('pages/publicFigure').default); + }, 'publicFigures.page'); + }} + /> + + +); diff --git a/src/store/actions/addStatement.js b/src/store/actions/addStatement.js index e9f51ad..7d705ae 100644 --- a/src/store/actions/addStatement.js +++ b/src/store/actions/addStatement.js @@ -1,27 +1,27 @@ import types from '../actions_types'; -export const onAddStatementPublicFigureSelection = (id) => ({ - type: types.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION, - id +export const onAddStatementPublicFigureSelection = id => ({ + type: types.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION, + id, }); -export const onAddStatementSubjectSelection = (id) => ({ - type: types.ADD_STATEMENT_SUBJECT_SELECTION, - id +export const onAddStatementSubjectSelection = id => ({ + type: types.ADD_STATEMENT_SUBJECT_SELECTION, + id, }); -export const onAddStatementPositionSelection = (id) => ({ - type: types.ADD_STATEMENT_POSITION_SELECTION, - id +export const onAddStatementPositionSelection = id => ({ + type: types.ADD_STATEMENT_POSITION_SELECTION, + id, }); -export const onAddStatementUpdateEvidenceUrl = (url) => ({ - type: types.ADD_STATEMENT_UPDATE_EVIDENCE_URL, - url +export const onAddStatementUpdateEvidenceUrl = url => ({ + type: types.ADD_STATEMENT_UPDATE_EVIDENCE_URL, + url, }); -export const onAddStatementUpdateEvidenceFile = (file) => ({ - type: types.ADD_STATEMENT_UPDATE_EVIDENCE_FILE, - file +export const onAddStatementUpdateEvidenceFile = file => ({ + type: types.ADD_STATEMENT_UPDATE_EVIDENCE_FILE, + file, }); export const onAddStatementValidate = () => ({ - type: types.ADD_STATEMENT_VALIDATE, + type: types.ADD_STATEMENT_VALIDATE, }); diff --git a/src/store/actions/entities.js b/src/store/actions/entities.js index 6af7993..ae10273 100644 --- a/src/store/actions/entities.js +++ b/src/store/actions/entities.js @@ -1,22 +1,22 @@ import actionsTypes from '../actions_types'; export const onLastStatementsAccess = () => ({ - type: actionsTypes.ENTITY_ACCESS, - accessType: 'list', - entityType: 'statements', - listType: 'latest', + type: actionsTypes.ENTITY_ACCESS, + accessType: 'list', + entityType: 'statements', + listType: 'latest', }); export const onHottestSubjectsAccess = () => ({ - type: actionsTypes.ENTITY_ACCESS, - accessType: 'list', - entityType: 'subjects', - listType: 'hottest', + type: actionsTypes.ENTITY_ACCESS, + accessType: 'list', + entityType: 'subjects', + listType: 'hottest', }); export const onPublicFiguresListAccess = () => ({ - type: actionsTypes.ENTITY_ACCESS, - accessType: 'list', - entityType: 'publicFigures', - listType: 'all', + type: actionsTypes.ENTITY_ACCESS, + accessType: 'list', + entityType: 'publicFigures', + listType: 'all', }); diff --git a/src/store/actions_types.js b/src/store/actions_types.js index f77eea6..89ad2d1 100644 --- a/src/store/actions_types.js +++ b/src/store/actions_types.js @@ -1,11 +1,11 @@ export default { - ENTITY_ACCESS: 'ENTITY_ACCESS', - ENTITY_READ: 'ENTITY_READ', - ADD_STATEMENT_NEXT_STEP: 'ADD_STATEMENT_NEXT_STEP', - ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: 'ADD_STATEMENT_PUBLIC_FIGURE_SELECTION', - ADD_STATEMENT_SUBJECT_SELECTION: 'ADD_STATEMENT_SUBJECT_SELECTION', - ADD_STATEMENT_POSITION_SELECTION: 'ADD_STATEMENT_POSITION_SELECTION', - ADD_STATEMENT_UPDATE_EVIDENCE_URL: 'ADD_STATEMENT_UPDATE_EVIDENCE_URL', - ADD_STATEMENT_UPDATE_EVIDENCE_FILE: 'ADD_STATEMENT_UPDATE_EVIDENCE_FILE', - ADD_STATEMENT_VALIDATE: 'ADD_STATEMENT_PUBLIC_FIGURE_SELECTION', + ENTITY_ACCESS: 'ENTITY_ACCESS', + ENTITY_READ: 'ENTITY_READ', + ADD_STATEMENT_NEXT_STEP: 'ADD_STATEMENT_NEXT_STEP', + ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: 'ADD_STATEMENT_PUBLIC_FIGURE_SELECTION', + ADD_STATEMENT_SUBJECT_SELECTION: 'ADD_STATEMENT_SUBJECT_SELECTION', + ADD_STATEMENT_POSITION_SELECTION: 'ADD_STATEMENT_POSITION_SELECTION', + ADD_STATEMENT_UPDATE_EVIDENCE_URL: 'ADD_STATEMENT_UPDATE_EVIDENCE_URL', + ADD_STATEMENT_UPDATE_EVIDENCE_FILE: 'ADD_STATEMENT_UPDATE_EVIDENCE_FILE', + ADD_STATEMENT_VALIDATE: 'ADD_STATEMENT_VALIDATE', }; diff --git a/src/store/index.js b/src/store/index.js index 515ecbf..a991abc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,16 +1,15 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux'; import createSagaMiddleware from 'redux-saga'; -import { routerReducer, routerMiddleware } from 'react-router-redux'; +import { routerReducer, routerMiddleware, syncHistoryWithStore } from 'react-router-redux'; import { map } from 'ramda'; import { isClientSide } from 'helpers/env'; -import rootSaga from './sagas'; -import { entitiesReducer, addStatementReducer } from './reducers'; - import { useRouterHistory } from 'react-router'; -import { syncHistoryWithStore } from 'react-router-redux'; import createHashHistory from 'history/lib/createHashHistory'; import createMemoryHistory from 'history/lib/createMemoryHistory'; +import rootSaga from './sagas'; +import { entitiesReducer, addStatementReducer } from './reducers'; + // Build history const createHistory = isClientSide() ? createHashHistory : createMemoryHistory; // const browserHistory = useScroll(useRouterHistory(createHistory))(); @@ -21,31 +20,31 @@ const initialState = isClientSide() ? window.__INITIAL_STATE__ : {}; // REDUCERS const reducer = combineReducers({ - routing: routerReducer, - entities: entitiesReducer, - addStatement: addStatementReducer, + routing: routerReducer, + entities: entitiesReducer, + addStatement: addStatementReducer, }); // MIDDLEWARE const sagaMiddleware = createSagaMiddleware(); const middlewares = [routerMiddleware(browserHistory), sagaMiddleware]; if (isClientSide() && process.env.NODE_ENV !== 'production') { - middlewares.push(require('redux-logger')({ - stateTransformer: map(state => ((state && state.toJS) ? state.toJS() : state)), - timestamp: true, - duration: true, - collapsed: true, - predicate: (getState, action) => action.type !== 'APP_LOG', - })); + middlewares.push(require('redux-logger')({ + stateTransformer: map(state => ((state && state.toJS) ? state.toJS() : state)), + timestamp: true, + duration: true, + collapsed: true, + predicate: (getState, action) => action.type !== 'APP_LOG', + })); } // STORE const store = createStore( - reducer, - initialState, - compose( - applyMiddleware(...middlewares), - window.devToolsExtension ? window.devToolsExtension() : f => f, + reducer, + initialState, + compose( + applyMiddleware(...middlewares), + window.devToolsExtension ? window.devToolsExtension() : f => f, ) ); const history = syncHistoryWithStore(browserHistory, store); diff --git a/src/store/reducers/addStatement.js b/src/store/reducers/addStatement.js index ceedb44..2c9726b 100644 --- a/src/store/reducers/addStatement.js +++ b/src/store/reducers/addStatement.js @@ -4,42 +4,43 @@ import { import actionsTypes from '../actions_types'; const initialState = { - publicFigureId: null, - subjectId: null, - positionId: null, - statementDate: null, - evidenceUrl: null, - evidenceFile: null, - quote: null, - note: null, - tags: [], + publicFigureId: null, + subjectId: null, + positionId: null, + statementDate: null, + evidenceUrl: null, + evidenceFile: null, + quote: null, + note: null, + tags: [], }; const isPublicFigureChosen = compose(not, isNil, prop('publicFigureId')); const isSubjectChosen = compose(not, isNil, prop('publicFigureId')); const isPositionChosen = compose(not, isNil, prop('publicFigureId')); const isStatementComplete = allPass([ - compose(not, isNil, prop('statementDate')), - compose(not, isNil, prop('quote')), - compose(not, isNil, prop('statementDate')), - either( - compose(not, isNil, prop('evidenceUrl')), - compose(not, isNil, prop('evidenceFile')), - ) + compose(not, isNil, prop('statementDate')), + compose(not, isNil, prop('quote')), + compose(not, isNil, prop('statementDate')), + either( + compose(not, isNil, prop('evidenceUrl')), + compose(not, isNil, prop('evidenceFile')), + ), ]); +/* eslint-disable no-unused-vars */ const isPublicFigureMissing = complement(isPublicFigureChosen); const isSubjectMissing = complement(isSubjectChosen); const isPositionMissing = complement(isPositionChosen); const isStatementIncomplete = complement(isStatementComplete); export const addStatementReducer = (state = initialState, action) => { - switch (action.type) { - case actionsTypes.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: return assoc('publicFigureId', action.id, state); - case actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION: return assoc('subjectId', action.id, state); - case actionsTypes.ADD_STATEMENT_POSITION_SELECTION: return assoc('positionId', action.id, state); - case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_URL: return assoc('evidenceUrl', action.url, state); - case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_FILE: return assoc('evidenceFile', action.file, state); - default: return state; - } + switch (action.type) { + case actionsTypes.ADD_STATEMENT_PUBLIC_FIGURE_SELECTION: return assoc('publicFigureId', action.id, state); + case actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION: return assoc('subjectId', action.id, state); + case actionsTypes.ADD_STATEMENT_POSITION_SELECTION: return assoc('positionId', action.id, state); + case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_URL: return assoc('evidenceUrl', action.url, state); + case actionsTypes.ADD_STATEMENT_UPDATE_EVIDENCE_FILE: return assoc('evidenceFile', action.file, state); + default: return state; + } }; diff --git a/src/store/reducers/entities.js b/src/store/reducers/entities.js index bcc367b..8f4e685 100644 --- a/src/store/reducers/entities.js +++ b/src/store/reducers/entities.js @@ -1,35 +1,36 @@ -import actionsType from '../actions_types'; import { map, compose, prop, merge, assoc, not, isNil, pipe, when } from 'ramda'; -const initialState = {}; import { indexAndGroup } from 'api/jsonApiParser'; +import actionsType from '../actions_types'; + +const initialState = {}; const isNotNil = compose(not, isNil); export const indexAndGroupMainData = compose( - indexAndGroup, - map(assoc('fetched', true)), - prop('data') + indexAndGroup, + map(assoc('fetched', true)), + prop('data') ); const indexAndGroupIncludedData = pipe( - prop('included'), - when( - isNotNil, - compose( - indexAndGroup, - map(assoc('fetched', true)), + prop('included'), + when( + isNotNil, + compose( + indexAndGroup, + map(assoc('fetched', true)), ) ), ); const saveData = data => compose( - merge(indexAndGroupIncludedData(data)), - indexAndGroupMainData, + merge(indexAndGroupIncludedData(data)), + indexAndGroupMainData, )(data); export const entitiesReducer = (state = initialState, action) => { - switch (action.type) { - case actionsType.ENTITY_READ: return merge(state, saveData(action.data)); - default: return state; - } + switch (action.type) { + case actionsType.ENTITY_READ: return merge(state, saveData(action.data)); + default: return state; + } }; diff --git a/src/store/sagas/apiSaga.js b/src/store/sagas/apiSaga.js index 9d51894..b0b2e5b 100644 --- a/src/store/sagas/apiSaga.js +++ b/src/store/sagas/apiSaga.js @@ -1,59 +1,59 @@ import { identity } from 'ramda'; -import actionsTypes from '../actions_types'; import { takeEvery } from 'redux-saga'; import { call, put } from 'redux-saga/effects'; import { getSubjects, getStatements, getPositions } from 'api/debats'; +import actionsTypes from '../actions_types'; + const getApiCallFor = (entityType, entityRequest) => { - switch (entityType) { - case 'statements': return getStatements; - case 'subjects': - switch (entityRequest) { - case 'hottest': return getSubjects; - default: return identity; - } - case 'publicFigures': - switch (entityRequest) { - case 'hottest': return getSubjects; - case 'all': return getSubjects; - default: return identity; - } + switch (entityType) { + case 'statements': return getStatements; + case 'subjects': + switch (entityRequest) { + case 'hottest': return getSubjects; default: return identity; - } + } + case 'publicFigures': + switch (entityRequest) { + case 'hottest': return getSubjects; + case 'all': return getSubjects; + default: return identity; + } + default: return identity; + } }; function* fetchEntityIfNeeded(action) { // Test Do we have to call API - const apiCall = getApiCallFor(action.entityType, ( - action.accessType === 'list' ? action.listType : action.accessedId + const apiCall = getApiCallFor(action.entityType, ( + action.accessType === 'list' ? action.listType : action.accessedId )); // Call API - const response = yield call(apiCall); + const response = yield call(apiCall); // Error actions // Success actions - yield put({ type: actionsTypes.ENTITY_READ, data: response.data }); + yield put({ type: actionsTypes.ENTITY_READ, data: response.data }); } export function* watchEntityAccess() { - yield* takeEvery(actionsTypes.ENTITY_ACCESS, fetchEntityIfNeeded); + yield* takeEvery(actionsTypes.ENTITY_ACCESS, fetchEntityIfNeeded); } - function* fetchPositionsOfSubject(action) { - if (!!action.id) { + if (action.id) { // Call API - const response = yield call(getPositions, action.id); + const response = yield call(getPositions, action.id); // Error actions // Success actions - yield put({ type: actionsTypes.ENTITY_READ, data: response.data }); - } + yield put({ type: actionsTypes.ENTITY_READ, data: response.data }); + } } export function* watchSubjectSelection() { - yield* takeEvery(actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION, fetchPositionsOfSubject); + yield* takeEvery(actionsTypes.ADD_STATEMENT_SUBJECT_SELECTION, fetchPositionsOfSubject); } diff --git a/src/store/sagas/index.js b/src/store/sagas/index.js index eb85014..a64b305 100644 --- a/src/store/sagas/index.js +++ b/src/store/sagas/index.js @@ -2,8 +2,8 @@ import { watchEntityAccess, watchSubjectSelection } from './apiSaga'; export default function* rootSaga() { - yield [ - watchEntityAccess(), - watchSubjectSelection() - ]; + yield [ + watchEntityAccess(), + watchSubjectSelection(), + ]; } diff --git a/src/store/selectors/addStatement.js b/src/store/selectors/addStatement.js index ce7fa70..2c4849f 100644 --- a/src/store/selectors/addStatement.js +++ b/src/store/selectors/addStatement.js @@ -2,8 +2,6 @@ import { createSelector } from 'reselect'; import { prop, propEq, find, pipe, dissoc, when, not, isNil, compose } from 'ramda'; import { getPublicFigures, getSubjects, getPositions, enrichWithRelationships } from './entities'; -import { withConsole } from 'helpers/debug'; - const isNotNil = compose(not, isNil); const getAddState = state => state.addStatement; @@ -11,43 +9,43 @@ const getAddState = state => state.addStatement; const injectPositions = enrichWithRelationships('positions', 'positions'); export const getAddStatementPublicFigure = createSelector( - getAddState, - getPublicFigures, - (addState, publicFigures) => find( - propEq('id', prop('publicFigureId')(addState)) - )(publicFigures) + getAddState, + getPublicFigures, + (addState, publicFigures) => find( + propEq('id', prop('publicFigureId')(addState)) + )(publicFigures) ); export const getAddStatementSubject = createSelector( - getAddState, - getSubjects, - getPositions, - (addState, allSubjects, allPositions) => pipe( - find(propEq('id', prop('subjectId')(addState))), - when( - isNotNil, - pipe( - injectPositions(allPositions), - dissoc('relationthips') - ) - ), - )(allSubjects) + getAddState, + getSubjects, + getPositions, + (addState, allSubjects, allPositions) => pipe( + find(propEq('id', prop('subjectId')(addState))), + when( + isNotNil, + pipe( + injectPositions(allPositions), + dissoc('relationthips') + ) + ), + )(allSubjects) ); export const getAddStatementPosition = createSelector( - getAddState, - getPositions, - (addState, publicFigures) => find( - propEq('id', prop('positionId')(addState)) - )(publicFigures) + getAddState, + getPositions, + (addState, publicFigures) => find( + propEq('id', prop('positionId')(addState)) + )(publicFigures) ); export const getAddStatementEvidenceUrl = createSelector( - getAddState, - prop('evidenceUrl') + getAddState, + prop('evidenceUrl') ); export const getAddStatementEvidenceFile = createSelector( - getAddState, - prop('evidenceFile') + getAddState, + prop('evidenceFile') ); diff --git a/src/store/selectors/entities.js b/src/store/selectors/entities.js index dc6d909..92d27e3 100644 --- a/src/store/selectors/entities.js +++ b/src/store/selectors/entities.js @@ -1,18 +1,18 @@ import { curry, assoc, compose, when, take, path, is, map, isNil, always, values, propEq, ifElse, pipe, find } from 'ramda'; + export const getSubjects = state => values(state.entities.subjects); export const getPositions = state => values(state.entities.positions); export const getStatements = state => values(state.entities.statements); export const getPublicFigures = state => values(state.entities['public-figures']); -import { withConsole, warn } from 'helpers/debug'; const getEntityByRef = curry( - (sourceEntities, entityReference) => ifElse( - isNil, - always(entityReference), // No source entities yet, return reference object - pipe( - find(propEq('id', entityReference.id)), - when(isNil, always(entityReference)), // Entity not fetched yet, return reference object + (sourceEntities, entityReference) => ifElse( + isNil, + always(entityReference), // No source entities yet, return reference object + pipe( + find(propEq('id', entityReference.id)), + when(isNil, always(entityReference)), // Entity not fetched yet, return reference object ), )(sourceEntities) ); @@ -23,14 +23,14 @@ const getEntityByRef = curry( * const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure'); */ export const enrichWithRelationship = curry( - (propertyName, relationshipName, fromCollection, entity) => assoc( - propertyName, - compose( - getEntityByRef(fromCollection), - when(is(Array), take(1)), - path(['relationships', relationshipName, 'data']), + (propertyName, relationshipName, fromCollection, entity) => assoc( + propertyName, + compose( + getEntityByRef(fromCollection), + when(is(Array), take(1)), + path(['relationships', relationshipName, 'data']), )(entity), - entity + entity ) ); @@ -41,13 +41,13 @@ export const enrichWithRelationship = curry( * = enrichWithRelationships('remarquablePublicFigures', 'remarquable-public-figures'); */ export const enrichWithRelationships = curry( - (propertyName, relationshipName, fromCollection, entity) => assoc( - propertyName, - compose( - map(getEntityByRef(fromCollection)), - path(['relationships', relationshipName, 'data']) + (propertyName, relationshipName, fromCollection, entity) => assoc( + propertyName, + compose( + map(getEntityByRef(fromCollection)), + path(['relationships', relationshipName, 'data']) )(entity), - entity + entity ) ); diff --git a/src/store/selectors/index.js b/src/store/selectors/index.js index b40e427..c210d1d 100644 --- a/src/store/selectors/index.js +++ b/src/store/selectors/index.js @@ -1,4 +1,6 @@ +/* eslint-disable import/export */ // since positions.js is an empty file export * from './positions'; + export * from './publicFigures'; export * from './statements'; export * from './subjects'; diff --git a/src/store/selectors/publicFigures.js b/src/store/selectors/publicFigures.js index 759f092..652ea85 100644 --- a/src/store/selectors/publicFigures.js +++ b/src/store/selectors/publicFigures.js @@ -1,4 +1,6 @@ -import { values, pipe, compose, map, dissoc, prop } from 'ramda'; +/* eslint-disable no-unused-vars */ + +import { values, pipe, compose, map, dissoc } from 'ramda'; import { whenNotNil } from 'helpers/ramda-ext'; import { createSelector } from 'reselect'; import { enrichWithRelationships, getSubjects, getPublicFigures } from './entities'; @@ -6,14 +8,14 @@ import { enrichWithRelationships, getSubjects, getPublicFigures } from './entiti const injectSubjects = enrichWithRelationships('subjects', 'subjects'); export const getPublicFiguresWithRelations = createSelector( - getPublicFigures, - getSubjects, - (publicFigures, allSubjects) => whenNotNil( - compose( - values, - map(pipe( + getPublicFigures, + getSubjects, + (publicFigures, allSubjects) => whenNotNil( + compose( + values, + map(pipe( // injectSubjects(allSubjects), - dissoc('relationthips'), + dissoc('relationthips'), )) ) )(publicFigures) diff --git a/src/store/selectors/statements.js b/src/store/selectors/statements.js index 8b1e393..55ee717 100644 --- a/src/store/selectors/statements.js +++ b/src/store/selectors/statements.js @@ -2,7 +2,7 @@ import { values, pipe, map, compose, dissoc } from 'ramda'; import { createSelector } from 'reselect'; import { whenNotNil } from 'helpers/ramda-ext'; import { - enrichWithRelationship, getPublicFigures, getPositions, getSubjects, getStatements + enrichWithRelationship, getPublicFigures, getPositions, getSubjects, getStatements, } from './entities'; const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure'); @@ -10,18 +10,18 @@ const injectPosition = enrichWithRelationship('position', 'position'); const injectSubject = enrichWithRelationship('subject', 'subject'); export const getLatestStatements = createSelector( - getStatements, - getPublicFigures, - getPositions, - getSubjects, - (allStatements, allPublicFigures, allPositions, allSubjects) => whenNotNil( - compose( - values, - map(pipe( - injectPublicFigure(allPublicFigures), - injectSubject(allSubjects), - injectPosition(allPositions), - dissoc('relationthips'), + getStatements, + getPublicFigures, + getPositions, + getSubjects, + (allStatements, allPublicFigures, allPositions, allSubjects) => whenNotNil( + compose( + values, + map(pipe( + injectPublicFigure(allPublicFigures), + injectSubject(allSubjects), + injectPosition(allPositions), + dissoc('relationthips'), )) ) )(allStatements) diff --git a/src/store/selectors/subjects.js b/src/store/selectors/subjects.js index ccd0e69..3599038 100644 --- a/src/store/selectors/subjects.js +++ b/src/store/selectors/subjects.js @@ -1,9 +1,8 @@ -import { values, pipe, compose, map, dissoc, propEq } from 'ramda'; +import { find, values, pipe, compose, map, dissoc, propEq } from 'ramda'; import { createSelector } from 'reselect'; import { whenNotNil } from 'helpers/ramda-ext'; -import { enrichWithRelationships, getPublicFigures, getPositions, getSubjects } from './entities'; -import { withConsole } from 'helpers/debug'; +import { enrichWithRelationships, getPublicFigures, getPositions, getSubjects } from './entities'; export const getHomeSubjects = state => values(getSubjects(state)); @@ -13,29 +12,29 @@ const injectRemarquablePublicFigures const injectPositions = enrichWithRelationships('positions', 'positions'); export const getHomeSubjectsWithRelations = createSelector( - getHomeSubjects, - getPublicFigures, - getPositions, - (homeSubjects, allPublicFigures, allPositions) => whenNotNil( - compose( - values, - map(pipe( - injectRemarquablePublicFigures(allPublicFigures), - injectPositions(allPositions), - dissoc('relationships'), + getHomeSubjects, + getPublicFigures, + getPositions, + (homeSubjects, allPublicFigures, allPositions) => whenNotNil( + compose( + values, + map(pipe( + injectRemarquablePublicFigures(allPublicFigures), + injectPositions(allPositions), + dissoc('relationships'), )) ) )(homeSubjects) ); export const getSubject = (state, props) => createSelector( - getSubjects, - getPositions, - getPublicFigures, - (allSubjects, allPositions, allPublicFigures) => pipe( - find(propEq('id', props.subjectId)), - injectRemarquablePublicFigures(allPublicFigures), - injectPositions(allPositions), - dissoc('relationthips'), + getSubjects, + getPositions, + getPublicFigures, + (allSubjects, allPositions, allPublicFigures) => pipe( + find(propEq('id', props.subjectId)), + injectRemarquablePublicFigures(allPublicFigures), + injectPositions(allPositions), + dissoc('relationthips'), )(allSubjects) ); diff --git a/src/validations/statements.js b/src/validations/statements.js index c40063d..d76f9b7 100644 --- a/src/validations/statements.js +++ b/src/validations/statements.js @@ -1,3 +1,3 @@ import { urlRegex } from './generic'; -export const isValidEvidenceUrl = (tested) => urlRegex.test(tested); +export const isValidEvidenceUrl = tested => urlRegex.test(tested); diff --git a/webpack/constants.js b/webpack/constants.js index 8241e08..f67ff6a 100644 --- a/webpack/constants.js +++ b/webpack/constants.js @@ -4,11 +4,11 @@ const SRC_FOLDER = 'src'; const APP_ROOT = path.normalize(path.join(__dirname, '..')); const constants = Object.freeze({ - APP_NAME: 'debats', - APP_ROOT, - APP_PATH: path.join(APP_ROOT, SRC_FOLDER), - STATIC_PATH: path.join(APP_ROOT, SRC_FOLDER, 'static'), - SRC_FOLDER, + APP_NAME: 'debats', + APP_ROOT, + APP_PATH: path.join(APP_ROOT, SRC_FOLDER), + STATIC_PATH: path.join(APP_ROOT, SRC_FOLDER, 'static'), + SRC_FOLDER, }); module.exports = constants; diff --git a/webpack/loaders.js b/webpack/loaders.js index ba17d26..3b43db8 100644 --- a/webpack/loaders.js +++ b/webpack/loaders.js @@ -1,54 +1,55 @@ const CONSTANTS = require('../webpack/constants'); + const APP_PATH = CONSTANTS.APP_PATH; const loaders = [ - { - test: /\.jsx?$/, - loader: 'babel-loader', - exclude: /node_modules/, - }, - { - test: /src.+\.css$/, - loader: 'style-loader' - + '!css-loader' - + '?modules&localIdentName=[name]__[local]___[hash:base64:5]' - + '&importLoaders=1' - + '!postcss-loader', - }, - { - test: /node_modules.*\.css$/, - loader: 'style-loader' - + '!css-loader' - + '!postcss-loader', - }, - { - test: /\.(png|svg|gif|jpeg|jpg)$/, - include: APP_PATH, - loader: 'file?name=images/[name].[ext]', - }, - { - test: /\.(eot|woff|ttf)$/, - include: APP_PATH, - loader: 'file-loader?name=fonts/[name].[ext]', - }, - { - test: /\.(svg|woff2?)$/, - exclude: APP_PATH, - loader: 'url?limit=10000', - }, - { - test: /\.(ttf|eot)$/, - exclude: APP_PATH, - loader: 'file', - }, - { - test: /\.json$/, - loader: 'json', - }, - { - test: /\.md$/, - loader: 'raw', - }, + { + test: /\.jsx?$/, + loader: 'babel-loader', + exclude: /node_modules/, + }, + { + test: /src.+\.css$/, + loader: 'style-loader' + + '!css-loader' + + '?modules&localIdentName=[name]__[local]___[hash:base64:5]' + + '&importLoaders=1' + + '!postcss-loader', + }, + { + test: /node_modules.*\.css$/, + loader: 'style-loader' + + '!css-loader' + + '!postcss-loader', + }, + { + test: /\.(png|svg|gif|jpeg|jpg)$/, + include: APP_PATH, + loader: 'file?name=images/[name].[ext]', + }, + { + test: /\.(eot|woff|ttf)$/, + include: APP_PATH, + loader: 'file-loader?name=fonts/[name].[ext]', + }, + { + test: /\.(svg|woff2?)$/, + exclude: APP_PATH, + loader: 'url?limit=10000', + }, + { + test: /\.(ttf|eot)$/, + exclude: APP_PATH, + loader: 'file', + }, + { + test: /\.json$/, + loader: 'json', + }, + { + test: /\.md$/, + loader: 'raw', + }, ]; module.exports = loaders; diff --git a/webpack/postcss-processors.js b/webpack/postcss-processors.js index ec64fbd..d8534c6 100644 --- a/webpack/postcss-processors.js +++ b/webpack/postcss-processors.js @@ -12,35 +12,36 @@ const postcssHide = require('postcss-hide'); const CONSTANTS = require('./constants'); -const makeMap = aPath => { - try { - return webpackPostcssTools.makeVarMap(aPath); - } catch (e) { +const makeMap = (aPath) => { + try { + return webpackPostcssTools.makeVarMap(aPath); + } catch (e) { // console.log(`${aPath} not found.`); - process.exit(1); - } - return null; + process.exit(1); + } + return null; }; const map = makeMap('./src/styles/_constants.css'); +// eslint-disable-next-line no-unused-vars module.exports = webpack => [ - postcssMixins({ - mixinsDir: path.join(CONSTANTS.APP_PATH, 'style', 'mixins'), - }), - atImport(), - postcssShortPosition(), - postcssAssets(), - postcssColorFunction(), - postcssNext({ - features: { - customProperties: { - variables: map.vars, - warnings: false, - }, - }, - }), - lost(), - postcssInlineSVG(), - postcssHide(), + postcssMixins({ + mixinsDir: path.join(CONSTANTS.APP_PATH, 'style', 'mixins'), + }), + atImport(), + postcssShortPosition(), + postcssAssets(), + postcssColorFunction(), + postcssNext({ + features: { + customProperties: { + variables: map.vars, + warnings: false, + }, + }, + }), + lost(), + postcssInlineSVG(), + postcssHide(), ]; diff --git a/webpack/resolve.js b/webpack/resolve.js index 9b2f2b7..a4eaa40 100644 --- a/webpack/resolve.js +++ b/webpack/resolve.js @@ -1,12 +1,12 @@ const path = require('path'); - const CONSTANTS = require('./constants'); + const APP_ROOT = CONSTANTS.APP_ROOT; module.exports = { - alias: { - react: path.resolve(APP_ROOT, 'node_modules/react'), - }, - modulesDirectories: ['src', 'web_modules', 'node_modules'], - extensions: ['', '.js', '.jsx'], + alias: { + react: path.resolve(APP_ROOT, 'node_modules/react'), + }, + modulesDirectories: ['src', 'web_modules', 'node_modules'], + extensions: ['', '.js', '.jsx'], }; diff --git a/webpack/webpack.build.dev.config.js b/webpack/webpack.build.dev.config.js index b9917c9..137efa9 100644 --- a/webpack/webpack.build.dev.config.js +++ b/webpack/webpack.build.dev.config.js @@ -5,6 +5,7 @@ const path = require('path'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CONSTANTS = require('./constants'); + const APP_ROOT = CONSTANTS.APP_ROOT; const SRC_FOLDER = CONSTANTS.SRC_FOLDER; diff --git a/webpack/webpack.build.prod.config.js b/webpack/webpack.build.prod.config.js index ff6ea38..81733af 100644 --- a/webpack/webpack.build.prod.config.js +++ b/webpack/webpack.build.prod.config.js @@ -5,6 +5,7 @@ const path = require('path'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CONSTANTS = require('./constants'); + const APP_ROOT = CONSTANTS.APP_ROOT; const APP_PATH = CONSTANTS.APP_PATH; const SRC_FOLDER = CONSTANTS.SRC_FOLDER; @@ -21,12 +22,12 @@ config.plugins.push(new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"product config.plugins.push(new webpack.optimize.DedupePlugin()); config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true)); // Assign the module and chunk ids by occurrence count config.plugins.push(new webpack.optimize.UglifyJsPlugin({ - compressor: { screw_ie8: false, keep_fnames: true, warnings: true }, - mangle: { - except: ['$super', '$', 'exports', 'require'], - screw_ie8: false, - keep_fnames: true, - }, + compressor: { screw_ie8: false, keep_fnames: true, warnings: true }, + mangle: { + except: ['$super', '$', 'exports', 'require'], + screw_ie8: false, + keep_fnames: true, + }, })); // config.plugins.push(new CompressionPlugin({threshold: 10240})); config.plugins.push(new CopyWebpackPlugin(copyConfig)); @@ -34,7 +35,7 @@ config.devtool = 'cheap-module-source-map'; config.cache = false; config.debug = false; config.entry = `${APP_PATH}/index.js`; -config.output.path = outputPath;; +config.output.path = outputPath; module.exports = config; diff --git a/webpack/webpack.bundle.config.js b/webpack/webpack.bundle.config.js index ecf9609..06f5493 100644 --- a/webpack/webpack.bundle.config.js +++ b/webpack/webpack.bundle.config.js @@ -2,20 +2,21 @@ const config = require('./webpack.base.config'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CONSTANTS = require('./constants'); + const APP_PATH = CONSTANTS.APP_PATH; const APP_NAME = CONSTANTS.APP_NAME; const SRC_FOLDER = CONSTANTS.SRC_FOLDER; config.plugins.push(new HtmlWebpackPlugin({ - template: `${SRC_FOLDER}/index.html`, - inject: true, - filename: 'index.html', + template: `${SRC_FOLDER}/index.html`, + inject: true, + filename: 'index.html', })); -config.entry = `${APP_PATH}/index.js`; +config.entry = `${APP_PATH}/index.jsx`; config.output = { - filename: `${APP_NAME}.[name].[hash].js`, + filename: `${APP_NAME}.[name].[hash].js`, }; module.exports = config; diff --git a/webpack/webpack.dev.server.config.js b/webpack/webpack.dev.server.config.js index f94c6ae..b51f6cf 100644 --- a/webpack/webpack.dev.server.config.js +++ b/webpack/webpack.dev.server.config.js @@ -5,6 +5,7 @@ const path = require('path'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CONSTANTS = require('./constants'); + const APP_ROOT = CONSTANTS.APP_ROOT; const SRC_FOLDER = CONSTANTS.SRC_FOLDER; @@ -33,30 +34,30 @@ var devServerAPIUrl; var devServerRewrite; if (args.proxy) { - if (args.mockAPI) { - devServerAPIUrl = 'http://localhost:3030'; - devServerRewrite = function rewrite(req) { - req.url = req.url // eslint-disable-line no-param-reassign + if (args.mockAPI) { + devServerAPIUrl = 'http://localhost:3030'; + devServerRewrite = function rewrite(req) { + req.url = req.url // eslint-disable-line no-param-reassign .replace(/\/api\//, '/fake-api/') // Local mocks as API .split('?')[0]; // strip query string if exists - if (req.method === 'POST') req.method = 'GET'; // eslint-disable-line no-param-reassign - }; - } - if (args.prodAPI) devServerAPIUrl = 'http://api.débats.co'; + if (req.method === 'POST') req.method = 'GET'; // eslint-disable-line no-param-reassign + }; + } + if (args.prodAPI) devServerAPIUrl = 'http://api.débats.co'; } config.devServer = { - quiet: false, - stats: { colors: true }, - outputPath, - proxy: { - '/api/*': { - target: devServerAPIUrl, - rewrite: devServerRewrite, - changeOrigin: true, - secure: false, - }, + quiet: false, + stats: { colors: true }, + outputPath, + proxy: { + '/api/*': { + target: devServerAPIUrl, + rewrite: devServerRewrite, + changeOrigin: true, + secure: false, }, + }, }; module.exports = config;