Merge branch 'master' into feat/api/add_statement
This commit is contained in:
commit
65ecb15706
65 changed files with 916 additions and 906 deletions
45
.eslintrc
45
.eslintrc
|
|
@ -31,38 +31,53 @@
|
||||||
"jsx": true
|
"jsx": true
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
|
"document": false,
|
||||||
"window": false,
|
"window": false,
|
||||||
"global": false,
|
"global": false,
|
||||||
"require": false,
|
"require": false,
|
||||||
"expect": false,
|
"expect": false,
|
||||||
"should": false,
|
|
||||||
"chai": false,
|
|
||||||
"sinon": false,
|
|
||||||
"Power2": false,
|
|
||||||
"Sine": false,
|
|
||||||
"__DEVELOPMENT__": false
|
"__DEVELOPMENT__": false
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"max-len": [0],
|
"max-len": [0],
|
||||||
"new-cap": ["warn", {"capIsNewExceptions": [
|
"new-cap": ["warn", {"capIsNewExceptions": [
|
||||||
"Immutable",
|
"Moment"
|
||||||
"Map",
|
|
||||||
"List",
|
|
||||||
"Set",
|
|
||||||
"OrderedSet",
|
|
||||||
"Range",
|
|
||||||
"Moment",
|
|
||||||
"Linker",
|
|
||||||
]}],
|
]}],
|
||||||
"comma-dangle": ["warn", "always-multiline"], // disallow or enforce trailing commas
|
"comma-dangle": ["warn", "always-multiline"], // disallow or enforce trailing commas
|
||||||
"curly": ["warn", "multi-or-nest"], // specify curly brace conventions for all control statements
|
"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)
|
"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
|
"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
|
"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)
|
"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
|
// React
|
||||||
//"computed-property-spacing": ["warn", "never"], // disallow spaces inside computed properties
|
//"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"
|
||||||
|
]
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable import/imports-first */
|
||||||
import jquery from 'jquery';
|
import jquery from 'jquery';
|
||||||
global.$ = jquery;
|
global.$ = jquery;
|
||||||
global.jQuery = jquery;
|
global.jQuery = jquery;
|
||||||
|
|
|
||||||
16
package.json
16
package.json
|
|
@ -12,8 +12,8 @@
|
||||||
"copy-mocks": "node scripts/copy-mocks.js",
|
"copy-mocks": "node scripts/copy-mocks.js",
|
||||||
"renderer": "node ./renderer/renderer.js",
|
"renderer": "node ./renderer/renderer.js",
|
||||||
"clean": "./node_modules/.bin/rimraf ./build integration/main.css integration/static && echo --- Cleaned ---",
|
"clean": "./node_modules/.bin/rimraf ./build integration/main.css integration/static && echo --- Cleaned ---",
|
||||||
"lint": "eslint src",
|
"lint": "eslint --ext .js --ext .jsx src webpack stories",
|
||||||
"lint-fix": "eslint src --fix",
|
"lint-fix": "npm run lint -- --fix",
|
||||||
"test": "jest --coverage",
|
"test": "jest --coverage",
|
||||||
"test-watch": "jest --watch",
|
"test-watch": "jest --watch",
|
||||||
"e2e-test": "./node_modules/.bin/nightwatch",
|
"e2e-test": "./node_modules/.bin/nightwatch",
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
"@kadira/storybook-addon-knobs": "^1.4.1",
|
"@kadira/storybook-addon-knobs": "^1.4.1",
|
||||||
"babel-cli": "<6.3.0",
|
"babel-cli": "<6.3.0",
|
||||||
"babel-core": "<6.3.0",
|
"babel-core": "<6.3.0",
|
||||||
"babel-eslint": "^6.0.0",
|
"babel-eslint": "^7.1.0",
|
||||||
"babel-loader": "~6.2.1",
|
"babel-loader": "~6.2.1",
|
||||||
"babel-plugin-ramda": "^1.1.6",
|
"babel-plugin-ramda": "^1.1.6",
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||||
|
|
@ -89,11 +89,11 @@
|
||||||
"copy-webpack-plugin": "^2.1.3",
|
"copy-webpack-plugin": "^2.1.3",
|
||||||
"css-loader": "^0.23.0",
|
"css-loader": "^0.23.0",
|
||||||
"enzyme": "^2.3.0",
|
"enzyme": "^2.3.0",
|
||||||
"eslint": "^2.5.3",
|
"eslint": "^3.9.1",
|
||||||
"eslint-config-airbnb": "^6.2.0",
|
"eslint-config-airbnb": "^12.0.0",
|
||||||
"eslint-plugin-import": "^1.10.2",
|
"eslint-plugin-import": "^1.16.0",
|
||||||
"eslint-plugin-jsx-a11y": "^1.5.5",
|
"eslint-plugin-jsx-a11y": "^2.2.3",
|
||||||
"eslint-plugin-react": "^4.2.3",
|
"eslint-plugin-react": "^6.5.0",
|
||||||
"extract-text-webpack-plugin": "^0.9.1",
|
"extract-text-webpack-plugin": "^0.9.1",
|
||||||
"file-loader": "^0.8.4",
|
"file-loader": "^0.8.4",
|
||||||
"html-webpack-plugin": "^2.15.0",
|
"html-webpack-plugin": "^2.15.0",
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,28 @@
|
||||||
|
/* eslint-disable jsx-a11y/href-no-hash */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import paths from 'constants/paths';
|
import paths from 'constants/paths';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
const Footer = () => (
|
const Footer = () => (
|
||||||
<footer className="footer">
|
<footer className="footer">
|
||||||
<div className="col-md-1"></div>
|
<div className="col-md-1" />
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<small>
|
<small>
|
||||||
<a href="#">Crédits</a>
|
<a href="#">Crédits</a>
|
||||||
|
|
|
|
||||||
<a href="#">Mentions Légales</a>
|
<a href="#">Mentions Légales</a>
|
||||||
</small></div>
|
</small></div>
|
||||||
<div className="col-md-7">
|
<div className="col-md-7">
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><Link to={paths.about}>À propos</Link></li>
|
<li><Link to={paths.about}>À propos</Link></li>
|
||||||
<li><Link to={paths.contact}>Contact</Link></li>
|
<li><Link to={paths.contact}>Contact</Link></li>
|
||||||
<li><Link to={paths.external.twitter} target="_blank">Twitter</Link></li>
|
<li><Link to={paths.external.twitter} target="_blank">Twitter</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-1"></div>
|
<div className="col-md-1" />
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,25 @@
|
||||||
|
/* eslint-disable jsx-a11y/href-no-hash */
|
||||||
|
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import paths from 'constants/paths';
|
import paths from 'constants/paths';
|
||||||
|
|
||||||
const ConnectedUserMenu = ({ user, onLogOut }) => (
|
const ConnectedUserMenu = ({ user, onLogOut }) => (
|
||||||
<li className="dropdown">
|
<li className="dropdown">
|
||||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown">
|
<a href="#" className="dropdown-toggle" data-toggle="dropdown">
|
||||||
{user.name}
|
{user.name}
|
||||||
<b className="caret"></b>
|
<b className="caret" />
|
||||||
</a>
|
</a>
|
||||||
<ul className="dropdown-menu">
|
<ul className="dropdown-menu">
|
||||||
<li><Link to={paths.getFor.user(user)}>Profil</Link></li>
|
<li><Link to={paths.getFor.user(user)}>Profil</Link></li>
|
||||||
<li className="divider"></li>
|
<li className="divider" />
|
||||||
<li><a onClick={onLogOut}>Déconnexion</a></li>
|
<li><a href="#" onClick={onLogOut}>Déconnexion</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
ConnectedUserMenu.propTypes = {
|
ConnectedUserMenu.propTypes = {
|
||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
onLogOut: PropTypes.func.isRequired,
|
onLogOut: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ConnectedUserMenu;
|
export default ConnectedUserMenu;
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,19 @@ import cssModules from 'react-css-modules';
|
||||||
import { Navbar, Nav, NavItem } from 'react-bootstrap';
|
import { Navbar, Nav, NavItem } from 'react-bootstrap';
|
||||||
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
|
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
|
||||||
|
|
||||||
|
import paths from 'constants/paths';
|
||||||
|
|
||||||
import ConnectedUserMenu from './';
|
import ConnectedUserMenu from './';
|
||||||
|
|
||||||
import paths from 'constants/paths';
|
|
||||||
import logoImg from './images/logo_header.png';
|
import logoImg from './images/logo_header.png';
|
||||||
import styles from './Header.css';
|
import styles from './Header.css';
|
||||||
|
|
||||||
const renderUserMenu = (isConnected) => (
|
const renderUserMenu = isConnected => (
|
||||||
isConnected
|
isConnected
|
||||||
? <ConnectedUserMenu />
|
? <ConnectedUserMenu />
|
||||||
: [
|
: [
|
||||||
<li><a>Connexion</a></li>, /* modal ! */
|
<li><a>Connexion</a></li>, /* modal ! */
|
||||||
<li><a>Inscription</a></li>, /* modal ! */
|
<li><a>Inscription</a></li>, /* modal ! */
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ const Header = () => (
|
||||||
<Navbar.Brand>
|
<Navbar.Brand>
|
||||||
<IndexLinkContainer to="/" styleName="logo">
|
<IndexLinkContainer to="/" styleName="logo">
|
||||||
<NavItem>
|
<NavItem>
|
||||||
<img src={logoImg} />
|
<img alt="Brand Logo" src={logoImg} />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
</IndexLinkContainer>
|
</IndexLinkContainer>
|
||||||
</Navbar.Brand>
|
</Navbar.Brand>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
||||||
import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs';
|
import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs';
|
||||||
|
|
||||||
|
|
@ -10,9 +11,9 @@ const stories = storiesOf('Header', module);
|
||||||
stories.addDecorator(withKnobs);
|
stories.addDecorator(withKnobs);
|
||||||
|
|
||||||
stories.addWithInfo(
|
stories.addWithInfo(
|
||||||
'default header',
|
'default header',
|
||||||
'Description of the story',
|
'Description of the story',
|
||||||
() => (
|
() => (
|
||||||
<Header />
|
<Header />
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -5,18 +5,18 @@ import Footer from './Footer';
|
||||||
import GoogleAnalytics from './GoogleAnalytics';
|
import GoogleAnalytics from './GoogleAnalytics';
|
||||||
|
|
||||||
const Main = ({ children }) => (
|
const Main = ({ children }) => (
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
<Header />
|
<Header />
|
||||||
<FlashMessages />
|
<FlashMessages />
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
|
||||||
<Footer />
|
|
||||||
<GoogleAnalytics />
|
|
||||||
</div>
|
</div>
|
||||||
|
<Footer />
|
||||||
|
<GoogleAnalytics />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
Main.propTypes = {
|
Main.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Main;
|
export default Main;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
import { curry } from 'ramda';
|
import { curry } from 'ramda';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Config from 'Config';
|
import Config from 'Config';
|
||||||
|
|
@ -13,5 +15,4 @@ export const getStatements = () => get('statements');
|
||||||
export const getPublicFiguresAutocomplete = typed => get(`autocomplete/public_figure/${typed}`);
|
export const getPublicFiguresAutocomplete = typed => get(`autocomplete/public_figure/${typed}`);
|
||||||
export const getSubjectsAutocomplete = typed => get(`autocomplete/subject/${typed}`);
|
export const getSubjectsAutocomplete = typed => get(`autocomplete/subject/${typed}`);
|
||||||
export const getPositions = subjectId => get(`subjects/${subjectId}/positions`);
|
export const getPositions = subjectId => get(`subjects/${subjectId}/positions`);
|
||||||
|
|
||||||
export const postStatement = statement => post('statements', statement);
|
export const postStatement = statement => post('statements', statement);
|
||||||
|
|
|
||||||
|
|
@ -14,45 +14,45 @@ const getId = prop('id');
|
||||||
const getAttributesPair = objectWithAttributes => toPairs(objectWithAttributes.attributes);
|
const getAttributesPair = objectWithAttributes => toPairs(objectWithAttributes.attributes);
|
||||||
|
|
||||||
const mergeAttributes = entityWithAttributes => compose(
|
const mergeAttributes = entityWithAttributes => compose(
|
||||||
reduce(
|
reduce(
|
||||||
(entity, attributePair) => (assoc(attributePair[0], attributePair[1], entity)),
|
(entity, attributePair) => (assoc(attributePair[0], attributePair[1], entity)),
|
||||||
entityWithAttributes
|
entityWithAttributes
|
||||||
),
|
),
|
||||||
getAttributesPair,
|
getAttributesPair,
|
||||||
)(entityWithAttributes);
|
)(entityWithAttributes);
|
||||||
|
|
||||||
const overAttributes = over(lensProp('attributes'));
|
const overAttributes = over(lensProp('attributes'));
|
||||||
|
|
||||||
const toCamelCase = replace(
|
const toCamelCase = replace(
|
||||||
/-[a-z]/g,
|
/-[a-z]/g,
|
||||||
compose(replace('-', ''), toUpper)
|
compose(replace('-', ''), toUpper)
|
||||||
);
|
);
|
||||||
|
|
||||||
const toCamelCaseAttributes = overAttributes(pipe(
|
const toCamelCaseAttributes = overAttributes(pipe(
|
||||||
toPairs,
|
toPairs,
|
||||||
map(
|
map(
|
||||||
([k, v]) => ([toCamelCase(k), v])
|
([k, v]) => ([toCamelCase(k), v])
|
||||||
),
|
),
|
||||||
fromPairs,
|
fromPairs,
|
||||||
));
|
));
|
||||||
|
|
||||||
export const flattenAttributes = pipe(
|
export const flattenAttributes = pipe(
|
||||||
map(pipe(
|
map(pipe(
|
||||||
toCamelCaseAttributes,
|
toCamelCaseAttributes,
|
||||||
mergeAttributes,
|
mergeAttributes,
|
||||||
dissoc('attributes'),
|
dissoc('attributes'),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const index = pipe(
|
export const index = pipe(
|
||||||
when(isNotArray, of),
|
when(isNotArray, of),
|
||||||
flattenAttributes,
|
flattenAttributes,
|
||||||
map(indexBy(getId))
|
map(indexBy(getId))
|
||||||
);
|
);
|
||||||
|
|
||||||
export const indexAndGroup = pipe(
|
export const indexAndGroup = pipe(
|
||||||
when(isNotArray, of),
|
when(isNotArray, of),
|
||||||
flattenAttributes,
|
flattenAttributes,
|
||||||
groupBy(getType),
|
groupBy(getType),
|
||||||
map(indexBy(getId))
|
map(indexBy(getId))
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
require('bootstrap-loader');
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import 'bootstrap-loader';
|
||||||
|
|
||||||
const locale = 'fr';
|
const locale = 'fr';
|
||||||
moment.locale(locale);
|
moment.locale(locale);
|
||||||
|
|
@ -16,7 +16,8 @@ moment.locale(locale, {
|
||||||
|
|
||||||
// Install ImmutableDevTools
|
// Install ImmutableDevTools
|
||||||
if (process.env.NODE_ENV !== 'production') { // DEBUG/DEV MODE
|
if (process.env.NODE_ENV !== 'production') { // DEBUG/DEV MODE
|
||||||
const Immutable = require('immutable');
|
const Immutable = require('immutable');
|
||||||
const installDevTools = require('immutable-devtools').default;
|
const installDevTools = require('immutable-devtools').default;
|
||||||
installDevTools(Immutable);
|
|
||||||
|
installDevTools(Immutable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { PropTypes, Component } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { Button } from 'react-bootstrap';
|
import { Button } from 'react-bootstrap';
|
||||||
import AddStatementModal from 'components/AddStatementModal';
|
import AddStatementModal from 'components/AddStatementModal';
|
||||||
import connect from './connector';
|
import connect from './connector';
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import AddSubjectFrom from './AddSubjectForm';
|
||||||
|
|
||||||
const SubjectStep = ({ selected, onSelection }) => (
|
const SubjectStep = ({ selected, onSelection }) => (
|
||||||
<Well>
|
<Well>
|
||||||
|
<<<<<<< HEAD
|
||||||
<FormGroup controlId="subjectSelect" validationState={selected && !selected.customOption ? 'success' : undefined}>
|
<FormGroup controlId="subjectSelect" validationState={selected && !selected.customOption ? 'success' : undefined}>
|
||||||
<ControlLabel>Quel est le sujet qui fait débat ?</ControlLabel>
|
<ControlLabel>Quel est le sujet qui fait débat ?</ControlLabel>
|
||||||
{(!selected || !selected.customOption) &&
|
{(!selected || !selected.customOption) &&
|
||||||
|
|
@ -16,6 +17,11 @@ const SubjectStep = ({ selected, onSelection }) => (
|
||||||
onChange={onSelection}
|
onChange={onSelection}
|
||||||
onCancel={() => onSelection(null)}
|
onCancel={() => onSelection(null)}
|
||||||
/>}
|
/>}
|
||||||
|
=======
|
||||||
|
<FormGroup controlId="subjectSelect" validationState={!!selected ? 'success' : undefined}>
|
||||||
|
<ControlLabel>Quel est le sujet qui fait débat ?</ControlLabel>
|
||||||
|
<SubjectAutocompleteInput selected={selected} onSelection={onSelection} />
|
||||||
|
>>>>>>> master
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Well>
|
</Well>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@ import React, { PropTypes } from 'react';
|
||||||
import { propEq, prop, compose, find } from 'ramda';
|
import { propEq, prop, compose, find } from 'ramda';
|
||||||
import { Well } from 'react-bootstrap';
|
import { Well } from 'react-bootstrap';
|
||||||
|
|
||||||
|
const getPositionInSubject = (position, subject) => compose(
|
||||||
|
find(po => propEq('id', position, po)),
|
||||||
|
prop('positions'),
|
||||||
|
)(subject);
|
||||||
|
|
||||||
|
|
||||||
const SummaryStep = ({
|
const SummaryStep = ({
|
||||||
publicFigure, subject, position, date, evidenceUrl, evidenceFile, evidenceSource, quote, note, tags,
|
publicFigure, subject, position, date, evidenceUrl, evidenceFile, evidenceSource, quote, note, tags,
|
||||||
}) => (
|
}) => (
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
getAddStatementPublicFigure, getAddStatementSubject, getAddStatementPosition,
|
getAddStatementPublicFigure, getAddStatementSubject, getAddStatementPosition,
|
||||||
getAddStatementEvidenceUrl, getAddStatementEvidenceFile
|
getAddStatementEvidenceUrl, getAddStatementEvidenceFile,
|
||||||
} from 'store/selectors';
|
} from 'store/selectors';
|
||||||
import {
|
import {
|
||||||
onAddStatementPublicFigureSelection, onAddStatementSubjectSelection, onAddStatementPositionSelection,
|
onAddStatementPublicFigureSelection, onAddStatementSubjectSelection, onAddStatementPositionSelection,
|
||||||
|
|
@ -10,20 +10,20 @@ import {
|
||||||
} from 'store/actions';
|
} from 'store/actions';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
selectedPublicFigure: getAddStatementPublicFigure(state),
|
selectedPublicFigure: getAddStatementPublicFigure(state),
|
||||||
selectedSubject: getAddStatementSubject(state),
|
selectedSubject: getAddStatementSubject(state),
|
||||||
selectedPosition: getAddStatementPosition(state),
|
selectedPosition: getAddStatementPosition(state),
|
||||||
evidenceUrl: getAddStatementEvidenceUrl(state),
|
evidenceUrl: getAddStatementEvidenceUrl(state),
|
||||||
evidenceFile: getAddStatementEvidenceFile(state),
|
evidenceFile: getAddStatementEvidenceFile(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onPublicFigureSelection: publicFigureId => dispatch(onAddStatementPublicFigureSelection(publicFigureId)),
|
onPublicFigureSelection: publicFigureId => dispatch(onAddStatementPublicFigureSelection(publicFigureId)),
|
||||||
onSubjectSelection: publicFigureId => dispatch(onAddStatementSubjectSelection(publicFigureId)),
|
onSubjectSelection: publicFigureId => dispatch(onAddStatementSubjectSelection(publicFigureId)),
|
||||||
onPositionSelection: publicFigureId => dispatch(onAddStatementPositionSelection(publicFigureId)),
|
onPositionSelection: publicFigureId => dispatch(onAddStatementPositionSelection(publicFigureId)),
|
||||||
onUpdateEvidenceUrl: url => dispatch(onAddStatementUpdateEvidenceUrl(url)),
|
onUpdateEvidenceUrl: url => dispatch(onAddStatementUpdateEvidenceUrl(url)),
|
||||||
onUpdateEvidenceFile: file => dispatch(onAddStatementUpdateEvidenceFile(file)),
|
onUpdateEvidenceFile: file => dispatch(onAddStatementUpdateEvidenceFile(file)),
|
||||||
onValidate: () => dispatch(onAddStatementValidate()),
|
onValidate: () => dispatch(onAddStatementValidate()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps);
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
const getText = nb => {
|
const getText = (nb) => {
|
||||||
if (nb === 0)
|
if (nb === 0)
|
||||||
return "Aucun sujet actif";
|
return 'Aucun sujet actif';
|
||||||
else if (nb > 1)
|
else if (nb > 1)
|
||||||
return nb + "sujets actifs";
|
return `${nb}sujets actifs`;
|
||||||
|
|
||||||
return "1 sujet actif";
|
return '1 sujet actif';
|
||||||
};
|
};
|
||||||
|
|
||||||
const AssociatedSubjects = ({ publicFigure }) => (
|
const AssociatedSubjects = ({ publicFigure }) => (
|
||||||
<h6 style={{ color: "#f21e40 !important" }}>{getText(publicFigure.nbActiveSubjects)}</h6>
|
<h6 style={{ color: '#f21e40 !important' }}>{getText(publicFigure.nbActiveSubjects)}</h6>
|
||||||
);
|
);
|
||||||
|
|
||||||
AssociatedSubjects.propTypes = {
|
AssociatedSubjects.propTypes = {
|
||||||
publicFigure: PropTypes.object.isRequired
|
publicFigure: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AssociatedSubjects;
|
export default AssociatedSubjects;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
const Identity = ({ children }) => <div>{children}</div>;
|
const Identity = ({ children }) => <div>{children}</div>;
|
||||||
Identity.propTypes = {
|
Identity.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Identity;
|
export default Identity;
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
||||||
import Identity from './';
|
import Identity from './';
|
||||||
|
|
@ -6,28 +6,28 @@ import cssModules from 'react-css-modules';
|
||||||
import style from './Statement.css';
|
import style from './Statement.css';
|
||||||
|
|
||||||
const Statement = ({ statement }) => (
|
const Statement = ({ statement }) => (
|
||||||
<li id={`statement-${statement.id}`} styleName="wrapper" >
|
<li id={`statement-${statement.id}`} styleName="wrapper" >
|
||||||
<PublicFigureAvatar publicFigure={statement.publicFigure} />
|
<PublicFigureAvatar publicFigure={statement.publicFigure} />
|
||||||
<div styleName="public-figure-text">
|
<div styleName="public-figure-text">
|
||||||
<strong>
|
<strong>
|
||||||
<Link to={paths.getFor.publicFigure(statement.publicFigure)}>
|
<Link to={paths.getFor.publicFigure(statement.publicFigure)}>
|
||||||
{statement.publicFigure.name}
|
{statement.publicFigure.name}
|
||||||
</Link>
|
</Link>
|
||||||
</strong>
|
</strong>
|
||||||
s'est déclaré pour
|
s'est déclaré pour
|
||||||
"<strong>{statement.position.title}</strong>"
|
"<strong>{statement.position.title}</strong>"
|
||||||
dans le débat sur
|
dans le débat sur
|
||||||
<strong><Link to={paths.getFor.subject(statement.subject)}>
|
<strong><Link to={paths.getFor.subject(statement.subject)}>
|
||||||
{statement.subject.title}
|
{statement.subject.title}
|
||||||
</Link></strong>
|
</Link></strong>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
Statement.propTypes = {
|
Statement.propTypes = {
|
||||||
statement: PropTypes.shape({
|
statement: PropTypes.shape({
|
||||||
publicFigure: PropTypes.object,
|
publicFigure: PropTypes.object,
|
||||||
position: PropTypes.object,
|
position: PropTypes.object,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default cssModules(Statement, style);
|
export default cssModules(Statement, style);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import { getLatestStatements } from 'store/selectors';
|
||||||
import { onLastStatementsAccess } from 'store/actions/entities';
|
import { onLastStatementsAccess } from 'store/actions/entities';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
statements: getLatestStatements(state),
|
statements: getLatestStatements(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onAccess: () => dispatch(onLastStatementsAccess()),
|
onAccess: () => dispatch(onLastStatementsAccess()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps);
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
import React, { PropTypes, Component } from 'react';
|
import React, { PropTypes, Component } from 'react';
|
||||||
import CSSModules from 'react-css-modules';
|
import cssModules from 'react-css-modules';
|
||||||
import Statement from './Statement';
|
import Statement from './Statement';
|
||||||
import LastStatementsStyle from './LastStatements.css';
|
import LastStatementsStyle from './LastStatements.css';
|
||||||
import connect from './connector';
|
import connect from './connector';
|
||||||
|
|
||||||
class LastStatements extends Component {
|
class LastStatements extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
statements: PropTypes.arrayOf(PropTypes.object),
|
statements: PropTypes.arrayOf(PropTypes.object),
|
||||||
onAccess: PropTypes.func.isRequired,
|
onAccess: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.onAccess();
|
this.props.onAccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderStatements = () => this.props.statements.map(
|
renderStatements = () => this.props.statements.map(
|
||||||
(s, i) => <Statement key={i} statement={s} />
|
(s, i) => <Statement key={i} statement={s} />
|
||||||
);
|
);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.props.statements) return <span>loading last statements ...</span>;
|
if (!this.props.statements) return <span>loading last statements ...</span>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div styleName="wrapper">
|
<div styleName="wrapper">
|
||||||
<h2 styleName="title">Les dernières prises de positions</h2>
|
<h2 styleName="title">Les dernières prises de positions</h2>
|
||||||
<ul styleName="wrapper">
|
<ul styleName="wrapper">
|
||||||
{ this.renderStatements() };
|
{ this.renderStatements() };
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(CSSModules(LastStatements, LastStatementsStyle));
|
export default connect(cssModules(LastStatements, LastStatementsStyle));
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, {Component, PropTypes} from 'react';
|
||||||
import { head, of, compose, when, prop, not, isNil } from 'ramda';
|
import {head, of, compose, when, prop, not, isNil} from 'ramda';
|
||||||
import Typeahead from 'react-bootstrap-typeahead';
|
import Typeahead from 'react-bootstrap-typeahead';
|
||||||
import { getPublicFiguresAutocomplete } from 'api/debats';
|
import {getPublicFiguresAutocomplete} from 'api/debats';
|
||||||
import { flattenAttributes } from 'api/jsonApiParser';
|
import {flattenAttributes} from 'api/jsonApiParser';
|
||||||
import PublicFigureAvatar from 'components/PublicFigureAvatar';
|
import PublicFigureAvatar from 'components/PublicFigureAvatar';
|
||||||
import { makeCancelable } from 'helpers/promises';
|
import { makeCancelable } from 'helpers/promises';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@ import cssModules from 'react-css-modules';
|
||||||
import styles from './PublicFigureAvatar.css';
|
import styles from './PublicFigureAvatar.css';
|
||||||
|
|
||||||
const PublicFigureAvatar = ({ publicFigure }) => (
|
const PublicFigureAvatar = ({ publicFigure }) => (
|
||||||
<div
|
<div
|
||||||
styleName="wrapper"
|
styleName="wrapper"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: !!publicFigure.picture
|
backgroundImage: publicFigure.picture
|
||||||
? `url(${publicFigure.picture.url})`
|
? `url(${publicFigure.picture.url})`
|
||||||
: undefined,
|
: undefined,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
PublicFigureAvatar.propTypes = {
|
PublicFigureAvatar.propTypes = {
|
||||||
publicFigure: PropTypes.object.isRequired,
|
publicFigure: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default cssModules(PublicFigureAvatar, styles);
|
export default cssModules(PublicFigureAvatar, styles);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
import { storiesOf, action, linkTo } from '@kadira/storybook';
|
||||||
import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs';
|
import { withKnobs, text, boolean, number } from '@kadira/storybook-addon-knobs';
|
||||||
import withReadme from 'storybook-readme/with-readme';
|
import withReadme from 'storybook-readme/with-readme';
|
||||||
|
|
@ -12,15 +13,15 @@ const stories = storiesOf('PublicFigureAvatar', module);
|
||||||
stories.addDecorator(withKnobs);
|
stories.addDecorator(withKnobs);
|
||||||
|
|
||||||
stories.addWithInfo(
|
stories.addWithInfo(
|
||||||
'pony avatar',
|
'pony avatar',
|
||||||
'Description of the story',
|
'Description of the story',
|
||||||
withReadme(README,
|
withReadme(README,
|
||||||
() => (
|
() => (
|
||||||
<PublicFigureAvatar publicFigure={{ picture: { url: text('image url', 'http://tinyurl.com/jucz8b9') } }} />
|
<PublicFigureAvatar publicFigure={{ picture: { url: text('image url', 'http://tinyurl.com/jucz8b9') } }} />
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
stories.add('jake avatar', () => (
|
stories.add('jake avatar', () => (
|
||||||
<PublicFigureAvatar publicFigure={{ picture: { url: 'http://tinyurl.com/jb286jq' } }} />
|
<PublicFigureAvatar publicFigure={{ picture: { url: 'http://tinyurl.com/jb286jq' } }} />
|
||||||
));
|
));
|
||||||
|
|
@ -13,7 +13,6 @@ const parseSubjects = raw => pipe(
|
||||||
)
|
)
|
||||||
)(raw.data);
|
)(raw.data);
|
||||||
|
|
||||||
|
|
||||||
class SubjectAutocompleteInput extends Component {
|
class SubjectAutocompleteInput extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
@ -57,23 +56,41 @@ class SubjectAutocompleteInput extends Component {
|
||||||
|
|
||||||
onSelection = compose(this.props.onSelection, head);
|
onSelection = compose(this.props.onSelection, head);
|
||||||
|
|
||||||
render() {
|
loadSuggestions = (typed) => {
|
||||||
return (
|
if (this.props.selected) this.props.onSelection(null);
|
||||||
<Typeahead
|
if (typed.length) {
|
||||||
name="subject"
|
getSubjectsAutocomplete(typed)
|
||||||
options={this.state.suggestions}
|
.then((response) => {
|
||||||
selected={of(this.props.selected)}
|
this.setState({
|
||||||
emptyLabel="Aucun sujet correspondante"
|
suggestions: flattenAttributes(response.data.data),
|
||||||
labelKey="title"
|
});
|
||||||
minLength={3}
|
}); }
|
||||||
allowNew
|
};
|
||||||
newSelectionPrefix="Ajouter "
|
|
||||||
onChange={this.onSelection}
|
renderMenuItemChildren = (typeaheadProps, subject) => (
|
||||||
onInputChange={this.loadSuggestions}
|
<div>
|
||||||
renderMenuItemChildren={this.renderMenuItemChildren}
|
<p>{subject.title} </p>
|
||||||
/>
|
<small>{take(100)(subject.presentation)}</small>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Typeahead
|
||||||
|
name="subject"
|
||||||
|
options={this.state.suggestions}
|
||||||
|
selected={of(this.props.selected)}
|
||||||
|
emptyLabel="Aucun sujet correspondante"
|
||||||
|
labelKey="title"
|
||||||
|
minLength={3}
|
||||||
|
allowNew
|
||||||
|
newSelectionPrefix="Ajouter "
|
||||||
|
onChange={this.onSelection}
|
||||||
|
onInputChange={this.loadSuggestions}
|
||||||
|
renderMenuItemChildren={this.renderMenuItemChildren}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const Empty = () => <span />;
|
|
||||||
export default Empty;
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
export default {
|
export default {
|
||||||
root: '/',
|
root: '/',
|
||||||
subjects: '/s',
|
subjects: '/s',
|
||||||
publicFigures: '/p',
|
publicFigures: '/p',
|
||||||
getFor: {
|
getFor: {
|
||||||
subject: (s) => `/s/${s.slug}`,
|
subject: s => `/s/${s.slug}`,
|
||||||
publicFigure: (pf) => `/p/${pf.slug}`,
|
publicFigure: pf => `/p/${pf.slug}`,
|
||||||
},
|
},
|
||||||
manual: '/guide',
|
manual: '/guide',
|
||||||
about: '/about',
|
about: '/about',
|
||||||
contact: '/contact',
|
contact: '/contact',
|
||||||
external: {
|
external: {
|
||||||
twitter: 'https://twitter.com/debatsco',
|
twitter: 'https://twitter.com/debatsco',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { pipe, always } from 'ramda';
|
import { pipe } from 'ramda';
|
||||||
|
|
||||||
const print = message => x => {
|
const print = message => (x) => {
|
||||||
if (!!message) console.warn(message);
|
if (message) console.warn(message);
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
const printWithPrefix = (prefix) => (x) => {
|
const printWithPrefix = prefix => (x) => {
|
||||||
console.warn('-------------------------------');
|
console.warn('-------------------------------');
|
||||||
console.warn(`---- ${prefix}: `, x);
|
console.warn(`---- ${prefix}: `, x);
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
const printBefore = printWithPrefix('BEFORE');
|
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 withConsole = (f, message) => pipe(printBefore, print(message), f, printAfter);
|
||||||
|
|
||||||
export const log = x => { console.log(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 */
|
export const warn = (x) => { console.warn(x); return x; }; /* eslint no-console: 0 */
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { complement } from 'ramda';
|
import { complement } from 'ramda';
|
||||||
|
|
||||||
export const hasWindow = () => (typeof window !== 'undefined');
|
export const hasWindow = () => (typeof window !== 'undefined');
|
||||||
export const isClientSide = hasWindow;
|
export const isClientSide = hasWindow;
|
||||||
export const isServerSide = complement(hasWindow);
|
export const isServerSide = complement(hasWindow);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
import 'react-hot-loader/patch'; // https://github.com/gaearon/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915
|
import 'react-hot-loader/patch'; // https://github.com/gaearon/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915
|
||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
|
|
||||||
// First boot side effects
|
|
||||||
import './boot.js';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { AppContainer } from 'react-hot-loader';
|
import { AppContainer } from 'react-hot-loader';
|
||||||
|
|
@ -11,6 +8,10 @@ import { match } from 'react-router';
|
||||||
|
|
||||||
// Styles
|
// Styles
|
||||||
import 'styles/_main.css';
|
import 'styles/_main.css';
|
||||||
|
|
||||||
|
// First boot side effects
|
||||||
|
import './boot.js';
|
||||||
|
|
||||||
// Redux
|
// Redux
|
||||||
import { store, history } from './store'; // Redux store
|
import { store, history } from './store'; // Redux store
|
||||||
import Root from './root'; // App root (Router, Provider, Hot reload ...
|
import Root from './root'; // App root (Router, Provider, Hot reload ...
|
||||||
|
|
@ -18,31 +19,31 @@ import routes from './routes'; // React-router routes
|
||||||
|
|
||||||
// Init app function
|
// Init app function
|
||||||
const loadApplication = (DOMElementId) => {
|
const loadApplication = (DOMElementId) => {
|
||||||
const DOMElement = document.getElementById(DOMElementId);
|
const DOMElement = document.getElementById(DOMElementId);
|
||||||
|
|
||||||
match({ history, routes, location }, () => {
|
match({ history, routes }, () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AppContainer>
|
<AppContainer>
|
||||||
<Root store={store} history={history} />
|
<Root store={store} history={history} />
|
||||||
</AppContainer>,
|
</AppContainer>,
|
||||||
DOMElement
|
DOMElement
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
module.hot.accept('./root/index.jsx', () => {
|
module.hot.accept('./root/index.jsx', () => {
|
||||||
// If you use Webpack 2 in ES modules mode, you can
|
// If you use Webpack 2 in ES modules mode, you can
|
||||||
// use <App /> here rather than require() a <NextApp />.
|
// use <App /> here rather than require() a <NextApp />.
|
||||||
const NextApp = require('./root/index').default;
|
const NextApp = require('./root/index').default;
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AppContainer>
|
<AppContainer>
|
||||||
<NextApp store={store} history={history} />
|
<NextApp store={store} history={history} />
|
||||||
</AppContainer>,
|
</AppContainer>,
|
||||||
DOMElement
|
DOMElement
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { store, history };
|
export { store, history };
|
||||||
|
|
@ -3,31 +3,31 @@ import cssModules from 'react-css-modules';
|
||||||
import styles from './About.css';
|
import styles from './About.css';
|
||||||
|
|
||||||
const About = () => (
|
const About = () => (
|
||||||
<div>
|
<div>
|
||||||
<h1>Pourquoi Débats.co ?</h1>
|
<h1>Pourquoi Débats.co ?</h1>
|
||||||
<p>
|
<p>
|
||||||
<i>Débats</i> 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é.
|
<i>Débats</i> 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é.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
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.
|
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.
|
C’est ainsi que semblent se développer des idées confuses et des discussions stériles.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
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.
|
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.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
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.
|
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.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
L’ambition de <i>Débats</i> 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.
|
L’ambition de <i>Débats</i> 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.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Rédigé par des volontaires sur une plateforme en ligne, et fonctionnant sur le principe du wiki, <i>Débats</i> 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.
|
Rédigé par des volontaires sur une plateforme en ligne, et fonctionnant sur le principe du wiki, <i>Débats</i> 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.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
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 <i>Débats</i>.
|
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 <i>Débats</i>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default cssModules(About, styles);
|
export default cssModules(About, styles);
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@ const Contact = () => (
|
||||||
<ul className="list-inline banner-social-buttons">
|
<ul className="list-inline banner-social-buttons">
|
||||||
<li>
|
<li>
|
||||||
<a href="mailto:contact@debats.co" className="btn btn-default btn-lg">
|
<a href="mailto:contact@debats.co" className="btn btn-default btn-lg">
|
||||||
<i className="fa fa-envelope-o fa-fw"></i><span className="network-name"> Courriel</span>
|
<i className="fa fa-envelope-o fa-fw" /><span className="network-name"> Courriel</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://twitter.com/debatsco" className="btn btn-default btn-lg">
|
<a href="https://twitter.com/debatsco" className="btn btn-default btn-lg">
|
||||||
<i className="fa fa-twitter fa-fw"></i> <span className="network-name">Twitter</span>
|
<i className="fa fa-twitter fa-fw" /> <span className="network-name">Twitter</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ import cssModules from 'react-css-modules';
|
||||||
import styles from './Guide.css';
|
import styles from './Guide.css';
|
||||||
|
|
||||||
const Guide = () => (
|
const Guide = () => (
|
||||||
<div>
|
<div>
|
||||||
<div className="col-md-1"></div>
|
<div className="col-md-1" />
|
||||||
<div className="col-md-10">
|
<div className="col-md-10">
|
||||||
<h1>Mode d'emploi</h1>
|
<h1>Mode d'emploi</h1>
|
||||||
|
|
||||||
<h2>Panel de discussion</h2>
|
<h2>Panel de discussion</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
La confiance
|
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 :
|
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
|
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
|
Le contenu pré-existe autrepart sur la plateforme
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Comment éviter d’être signalé ?</h2>
|
<h2>Comment éviter d’être signalé ?</h2>
|
||||||
|
|
||||||
<div className="panel-group" id="accordion">
|
<div className="panel-group" id="accordion">
|
||||||
|
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">
|
<h2 className="panel-title">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse1">
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse1">
|
||||||
Débats.co, qu’est-ce que c’est ?</a>
|
Débats.co, qu’est-ce que c’est ?</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse1" className="panel-collapse collapse">
|
<div id="collapse1" className="panel-collapse collapse">
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<p>
|
<p>
|
||||||
Débats.co n’est pas un site de débats.
|
Débats.co n’est pas un site de débats.
|
||||||
<br />
|
<br />
|
||||||
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.
|
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.
|
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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">
|
<h2 className="panel-title">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse2">Comment fonctionne Débats.co ?</a>
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse2">Comment fonctionne Débats.co ?</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse2" className="panel-collapse collapse">
|
<div id="collapse2" className="panel-collapse collapse">
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<p>
|
<p>
|
||||||
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 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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
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 :
|
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 :
|
||||||
</p>
|
</p>
|
||||||
<ul id="reputation">
|
<ul id="reputation">
|
||||||
<li>Le sujet</li>
|
<li>Le sujet</li>
|
||||||
<li>La position</li>
|
<li>La position</li>
|
||||||
<li>La personnalité</li>
|
<li>La personnalité</li>
|
||||||
<li>La prise de position</li>
|
<li>La prise de position</li>
|
||||||
<li>L’argument</li>
|
<li>L’argument</li>
|
||||||
<li>La source</li>
|
<li>La source</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
Chaque <b>sujet</b> comporte au moins deux <b>positions</b>. Une <b>position</b> peut être "prise" par plusieurs <b>personnalités</b>. A chaque <b>prise de position</b> sont attachés une <b>personnalité</b> et un ensemble d’<b>arguments</b>. Pour que la <b>prise de position</b> puisse être recensée, elle doit être justifiée par au moins une <b>source</b>.
|
Chaque <b>sujet</b> comporte au moins deux <b>positions</b>. Une <b>position</b> peut être "prise" par plusieurs <b>personnalités</b>. A chaque <b>prise de position</b> sont attachés une <b>personnalité</b> et un ensemble d’<b>arguments</b>. Pour que la <b>prise de position</b> puisse être recensée, elle doit être justifiée par au moins une <b>source</b>.
|
||||||
<br />
|
<br />
|
||||||
En somme, pour qu’un <b>sujet</b> puisse être référencé, il est nécessaire d'y recenser au moins une <b>prise de position</b> par au moins une <b>personnalité</b> dans chacune des <b>positions</b>.
|
En somme, pour qu’un <b>sujet</b> puisse être référencé, il est nécessaire d'y recenser au moins une <b>prise de position</b> par au moins une <b>personnalité</b> dans chacune des <b>positions</b>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">
|
<h2 className="panel-title">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse5">
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse5">
|
||||||
Qu'est-ce qu'une source ?</a>
|
Qu'est-ce qu'une source ?</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse5" className="panel-collapse collapse">
|
<div id="collapse5" className="panel-collapse collapse">
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<p>
|
<p>
|
||||||
Une <b>source</b> 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.
|
Une <b>source</b> 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.
|
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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">
|
<h2 className="panel-title">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse3">Comment référencer et recenser un contenu de qualité ?</a>
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse3">Comment référencer et recenser un contenu de qualité ?</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse3" className="panel-collapse collapse">
|
<div id="collapse3" className="panel-collapse collapse">
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
Préexistence d'un contenu :
|
Préexistence d'un contenu :
|
||||||
</b>
|
</b>
|
||||||
<br />
|
<br />
|
||||||
Tout d'abord, le contributeur peut se demander si le contenu qu'il s'apprête à référencer existe déjà.
|
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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<b>
|
<b>
|
||||||
Notoriété et véracité :
|
Notoriété et véracité :
|
||||||
</b>
|
</b>
|
||||||
<br />
|
<br />
|
||||||
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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<b>Neutralité et cohérence du point de vue</b>
|
<b>Neutralité et cohérence du point de vue</b>
|
||||||
<br />
|
<br />
|
||||||
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é.
|
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é.
|
||||||
<br />
|
<br />
|
||||||
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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
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.
|
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.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">
|
<h2 className="panel-title">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse4">Comment avoir accès à toutes les fonctions de Débats.co ?</a>
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse4">Comment avoir accès à toutes les fonctions de Débats.co ?</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse4" className="panel-collapse collapse">
|
<div id="collapse4" className="panel-collapse collapse">
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<p>
|
<p>
|
||||||
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 :
|
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 :
|
||||||
</p>
|
</p>
|
||||||
<ul id="reputation">
|
<ul id="reputation">
|
||||||
<li><b>Le Métèque</b> : 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. </li>
|
<li><b>Le Métèque</b> : 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. </li>
|
||||||
<li><b>L'Eloquent</b> : 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.</li>
|
<li><b>L'Eloquent</b> : 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.</li>
|
||||||
<li><b>L'Idéaliste</b> : Son score est élevé, il peut instantanément supprimer la plupart des modifications faites par d'autres utilisateurs.</li>
|
<li><b>L'Idéaliste</b> : Son score est élevé, il peut instantanément supprimer la plupart des modifications faites par d'autres utilisateurs.</li>
|
||||||
<li><b>Le Sophiste</b> : 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. </li>
|
<li><b>Le Sophiste</b> : 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. </li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-1"></div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="col-md-1" />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default cssModules(Guide, styles);
|
export default cssModules(Guide, styles);
|
||||||
|
|
|
||||||
|
|
@ -6,40 +6,40 @@ import PublicFigureAvatar from 'components/PublicFigureAvatar';
|
||||||
|
|
||||||
const PublicFigureAvatarMapper = pf => <PublicFigureAvatar key={pf.id} publicFigure={pf} />;
|
const PublicFigureAvatarMapper = pf => <PublicFigureAvatar key={pf.id} publicFigure={pf} />;
|
||||||
const renderAssociatedPublicFigures = compose(
|
const renderAssociatedPublicFigures = compose(
|
||||||
map(PublicFigureAvatarMapper),
|
map(PublicFigureAvatarMapper),
|
||||||
take(5),
|
take(5),
|
||||||
prop('remarquablePublicFigures'),
|
prop('remarquablePublicFigures'),
|
||||||
);
|
);
|
||||||
|
|
||||||
const HomeSubject = ({ subject }) => (
|
const HomeSubject = ({ subject }) => (
|
||||||
<li>
|
<li>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: '50%', border: 'none', textTransform: 'uppercase' }}>
|
<td style={{ width: '50%', border: 'none', textTransform: 'uppercase' }}>
|
||||||
<h2 className="subjects-title">
|
<h2 className="subjects-title">
|
||||||
<Link to={paths.getFor.subject(subject)}>
|
<Link to={paths.getFor.subject(subject)}>
|
||||||
{subject.title}
|
{subject.title}
|
||||||
</Link>
|
</Link>
|
||||||
</h2>
|
</h2>
|
||||||
<h6 className="count">
|
<h6 className="count">
|
||||||
{`${subject.remarquablePublicFigures.length} personnalité(s)`}
|
{`${subject.remarquablePublicFigures.length} personnalité(s)`}
|
||||||
</h6>
|
</h6>
|
||||||
</td>
|
</td>
|
||||||
<td style={{ width: '50%', textAlign: 'center', verticalAlign: 'middle' }}>
|
<td style={{ width: '50%', textAlign: 'center', verticalAlign: 'middle' }}>
|
||||||
{renderAssociatedPublicFigures(subject)}
|
{renderAssociatedPublicFigures(subject)}
|
||||||
</td>
|
</td>
|
||||||
<td className="seemore">
|
<td className="seemore">
|
||||||
<div>
|
<div>
|
||||||
<Link to={paths.getFor.subject(subject)}>Voir plus de personnalités</Link>
|
<Link to={paths.getFor.subject(subject)}>Voir plus de personnalités</Link>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
HomeSubject.propTypes = {
|
HomeSubject.propTypes = {
|
||||||
subject: PropTypes.shape({
|
subject: PropTypes.shape({
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
remarquablePublicFigures: PropTypes.arrayOf(PropTypes.object).isRequired,
|
remarquablePublicFigures: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (HomeSubject);
|
export default (HomeSubject);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import { getHomeSubjectsWithRelations } from 'store/selectors';
|
||||||
import { onHottestSubjectsAccess } from 'store/actions/entities';
|
import { onHottestSubjectsAccess } from 'store/actions/entities';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
subjects: getHomeSubjectsWithRelations(state),
|
subjects: getHomeSubjectsWithRelations(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onAccess: () => dispatch(onHottestSubjectsAccess()),
|
onAccess: () => dispatch(onHottestSubjectsAccess()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps);
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,26 @@ import connector from './connectors';
|
||||||
|
|
||||||
class HomeSubjects extends Component {
|
class HomeSubjects extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
subjects: PropTypes.arrayOf(PropTypes.object).isRequired,
|
subjects: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onAccess: PropTypes.func.isRequired,
|
onAccess: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.onAccess();
|
this.props.onAccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.props.subjects) return <span>loading subjects ...</span>;
|
if (!this.props.subjects) return <span>loading subjects ...</span>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div> {/* TODO Bootstrap */}
|
<div> {/* TODO Bootstrap */}
|
||||||
{this.props.subjects.map(
|
{this.props.subjects.map(
|
||||||
s => <HomeSubject key={s.id} subject={s} />
|
s => <HomeSubject key={s.id} subject={s} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,40 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cssModules from 'react-css-modules';
|
import cssModules from 'react-css-modules';
|
||||||
import HomeSubjects from './HomeSubjects';
|
|
||||||
import LastStatements from 'components/LastStatements';
|
import LastStatements from 'components/LastStatements';
|
||||||
|
import HomeSubjects from './HomeSubjects';
|
||||||
import bgSrc from './images/intro-bg.jpg';
|
import bgSrc from './images/intro-bg.jpg';
|
||||||
import styles from './Home.css';
|
import styles from './Home.css';
|
||||||
import AddStatementButton from 'components/AddStatementButton';
|
import AddStatementButton from 'components/AddStatementButton';
|
||||||
|
|
||||||
const Home = () => (
|
const Home = () => (
|
||||||
<div className="container-fluid" styleName="container">
|
<div className="container-fluid" styleName="container">
|
||||||
<AddStatementButton />
|
<AddStatementButton />
|
||||||
<div className="row" styleName="background-title" style={{ backgroundImage: `url(${bgSrc})` }}>
|
<div className="row" styleName="background-title" style={{ backgroundImage: `url(${bgSrc})` }}>
|
||||||
<div styleName="title-mask">
|
<div styleName="title-mask">
|
||||||
<h5 >Bienvenue sur Débats.co</h5>
|
<h5 >Bienvenue sur Débats.co</h5>
|
||||||
<div styleName="introduction">
|
<div styleName="introduction">
|
||||||
<span>Débats est un projet francophone et participatif, ayant pour objectif </span>
|
<span>Débats est un projet francophone et participatif, ayant pour objectif </span>
|
||||||
<span>d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société.</span>
|
<span>d’offrir une synthèse ouverte, impartiale et vérifiable, des sujets clivants de notre société.</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-1"></div>
|
</div>
|
||||||
<div className="subjects-index col-md-7 subjects-home">
|
|
||||||
<h1>Sujets d'actualité</h1>
|
|
||||||
<table className="table">
|
|
||||||
<tbody>
|
|
||||||
<ul id="subject">
|
|
||||||
<HomeSubjects />
|
|
||||||
</ul>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div className="col-md-3 col-centered" style={{ textAlign: 'right' }} >
|
|
||||||
<LastStatements />
|
|
||||||
</div>
|
|
||||||
<div className="col-md-1"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="col-md-1"></div>
|
||||||
|
<div className="subjects-index col-md-7 subjects-home">
|
||||||
|
<h1>Sujets d'actualité</h1>
|
||||||
|
<table className="table">
|
||||||
|
<tbody>
|
||||||
|
<ul id="subject">
|
||||||
|
<HomeSubjects />
|
||||||
|
</ul>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-1" />
|
||||||
|
<div className="col-md-3 col-centered" style={{ textAlign: 'right' }}>
|
||||||
|
<LastStatements />
|
||||||
|
</div>
|
||||||
|
<div className="col-md-1" />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default cssModules(Home, styles);
|
export default cssModules(Home, styles);
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,47 @@
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import paths from '../../../constants/paths';
|
import cssModules from 'react-css-modules';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
|
import paths from 'constants/paths';
|
||||||
import PublicFigureAvatar from 'components/PublicFigureAvatar';
|
import PublicFigureAvatar from 'components/PublicFigureAvatar';
|
||||||
import AssociatedSubjects from 'components/AssociatedSubjects';
|
import AssociatedSubjects from 'components/AssociatedSubjects';
|
||||||
|
|
||||||
import PublicFigureStyle from './PublicFigure.css';
|
import PublicFigureStyle from './PublicFigure.css';
|
||||||
import cssModules from 'react-css-modules';
|
|
||||||
|
|
||||||
const PublicFigureInList = ({ publicFigure }) => (
|
const PublicFigureInList = ({ publicFigure }) => (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<ul id="subject">
|
<ul id="subject">
|
||||||
<li>
|
<li>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<PublicFigureAvatar publicFigure={publicFigure} />
|
<PublicFigureAvatar publicFigure={publicFigure} />
|
||||||
</td>
|
</td>
|
||||||
<td style= {{ width: '33%' }}>
|
<td style={{ width: '33%' }}>
|
||||||
|
|
||||||
<h2 className="figure-title" style={{ color: '#333333 !important' }}>
|
<h2 className="figure-title" style={{ color: '#333333 !important' }}>
|
||||||
<Link to={paths.getFor.subject(publicFigure)}>
|
<Link to={paths.getFor.subject(publicFigure)}>
|
||||||
{publicFigure.name}
|
{publicFigure.name}
|
||||||
</Link>
|
</Link>
|
||||||
</h2>
|
</h2>
|
||||||
<AssociatedSubjects publicFigure={publicFigure} />
|
<AssociatedSubjects publicFigure={publicFigure} />
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td styleName="presentationWrapper">
|
<td styleName="presentationWrapper">
|
||||||
<p className="figure-presentation-text" styleName="presentation">
|
<p className="figure-presentation-text" styleName="presentation">
|
||||||
{publicFigure.presentation}
|
{publicFigure.presentation}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
|
|
||||||
PublicFigureInList.propTypes = {
|
PublicFigureInList.propTypes = {
|
||||||
publicFigure: PropTypes.object.isRequired,
|
publicFigure: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default cssModules(PublicFigureInList, PublicFigureStyle);
|
export default cssModules(PublicFigureInList, PublicFigureStyle);
|
||||||
|
|
||||||
/*
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function() {
|
|
||||||
|
|
||||||
$(".figure-presentation-text").shorten();
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import { getPublicFiguresWithRelations } from 'store/selectors';
|
||||||
import { onPublicFiguresListAccess } from 'store/actions/entities';
|
import { onPublicFiguresListAccess } from 'store/actions/entities';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
publicFigures: getPublicFiguresWithRelations(state),
|
publicFigures: getPublicFiguresWithRelations(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onAccess: () => dispatch(onPublicFiguresListAccess()),
|
onAccess: () => dispatch(onPublicFiguresListAccess()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps);
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,38 @@
|
||||||
import React, { PropTypes, Component } from 'react';
|
import React, { PropTypes, Component } from 'react';
|
||||||
|
|
||||||
|
import LastStatements from 'components/LastStatements';
|
||||||
import PublicFigureInList from './PublicFigureInList';
|
import PublicFigureInList from './PublicFigureInList';
|
||||||
import connect from './connector';
|
import connect from './connector';
|
||||||
import LastStatements from 'components/LastStatements';
|
|
||||||
|
|
||||||
class PublicFigures extends Component {
|
class PublicFigures extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
publicFigures: PropTypes.arrayOf(PropTypes.object).isRequired,
|
publicFigures: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onAccess: PropTypes.func.isRequired,
|
onAccess: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.onAccess();
|
this.props.onAccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.props.publicFigures) return <span>loading public figures ...</span>;
|
if (!this.props.publicFigures) return <span>loading public figures ...</span>;
|
||||||
|
|
||||||
const renderChilds = () => this.props.publicFigures.map(
|
const renderChilds = () => this.props.publicFigures.map(
|
||||||
pf => <PublicFigureInList key={pf.id} publicFigure={pf} />
|
pf => <PublicFigureInList key={pf.id} publicFigure={pf} />
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="col-md-9">
|
<div className="col-md-9">
|
||||||
{renderChilds()}
|
{renderChilds()}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<LastStatements />
|
<LastStatements />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(PublicFigures);
|
export default connect(PublicFigures);
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ import { Router } from 'react-router';
|
||||||
import routes from '../routes';
|
import routes from '../routes';
|
||||||
|
|
||||||
const Root = ({ store, history }) => (
|
const Root = ({ store, history }) => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router history={history} routes={routes} />
|
<Router history={history} routes={routes} />
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
Root.propTypes = {
|
Root.propTypes = {
|
||||||
store: PropTypes.object.isRequired,
|
store: PropTypes.object.isRequired,
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Root;
|
export default Root;
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { Route, IndexRoute } from 'react-router';
|
|
||||||
|
|
||||||
// Main Page
|
|
||||||
import Main from 'Main/index';
|
|
||||||
export default (
|
|
||||||
<Route path="/" component={Main}>
|
|
||||||
<IndexRoute
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/Home').default);
|
|
||||||
}, 'home');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="contact"
|
|
||||||
name="contact"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/Contact').default);
|
|
||||||
}, 'contact');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="about"
|
|
||||||
name="about"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/About').default);
|
|
||||||
}, 'about');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="guide"
|
|
||||||
name="guide"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/Guide').default);
|
|
||||||
}, 'guide');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route path="s" name="subjects">
|
|
||||||
<IndexRoute
|
|
||||||
name="subjects.index"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/Subjects').default);
|
|
||||||
}, 'subjects.index');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
name="subjects.page"
|
|
||||||
path=":subjectSlug"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/Subject').default);
|
|
||||||
}, 'subjects.page');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
<Route path="p" name="publicFigures">
|
|
||||||
<IndexRoute
|
|
||||||
name="publicFigures.index"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/PublicFigures').default);
|
|
||||||
}, 'publicFigures.index');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
name="publicFigures.page"
|
|
||||||
path=":publicFigureSlug"
|
|
||||||
getComponent={(nextState, done) => {
|
|
||||||
require.ensure([], require => {
|
|
||||||
done(null, require('pages/publicFigure').default);
|
|
||||||
}, 'publicFigures.page');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
</Route>
|
|
||||||
);
|
|
||||||
82
src/routes/index.jsx
Normal file
82
src/routes/index.jsx
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Route, IndexRoute } from 'react-router';
|
||||||
|
|
||||||
|
// Main Page
|
||||||
|
import Main from 'Main/index';
|
||||||
|
|
||||||
|
export default (
|
||||||
|
<Route path="/" component={Main}>
|
||||||
|
<IndexRoute
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/Home').default);
|
||||||
|
}, 'home');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="contact"
|
||||||
|
name="contact"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/Contact').default);
|
||||||
|
}, 'contact');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="about"
|
||||||
|
name="about"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/About').default);
|
||||||
|
}, 'about');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="guide"
|
||||||
|
name="guide"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/Guide').default);
|
||||||
|
}, 'guide');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route path="s" name="subjects">
|
||||||
|
<IndexRoute
|
||||||
|
name="subjects.index"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/Subjects').default);
|
||||||
|
}, 'subjects.index');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
name="subjects.page"
|
||||||
|
path=":subjectSlug"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/Subject').default);
|
||||||
|
}, 'subjects.page');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
<Route path="p" name="publicFigures">
|
||||||
|
<IndexRoute
|
||||||
|
name="publicFigures.index"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/PublicFigures').default);
|
||||||
|
}, 'publicFigures.index');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
name="publicFigures.page"
|
||||||
|
path=":publicFigureSlug"
|
||||||
|
getComponent={(nextState, done) => {
|
||||||
|
require.ensure([], (require) => {
|
||||||
|
done(null, require('pages/publicFigure').default);
|
||||||
|
}, 'publicFigures.page');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
</Route>
|
||||||
|
);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import types from '../actions_types';
|
import types from '../actions_types';
|
||||||
|
|
||||||
export const onAddStatementValidate = (newStatement) => ({
|
export const onAddStatementValidate = newStatement => ({
|
||||||
type: types.ADD_STATEMENT_VALIDATE,
|
type: types.ADD_STATEMENT_VALIDATE,
|
||||||
payload: { ...newStatement },
|
payload: { ...newStatement },
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
import actionsTypes from '../actions_types';
|
import actionsTypes from '../actions_types';
|
||||||
|
|
||||||
export const onLastStatementsAccess = () => ({
|
export const onLastStatementsAccess = () => ({
|
||||||
type: actionsTypes.ENTITY_ACCESS,
|
type: actionsTypes.ENTITY_ACCESS,
|
||||||
accessType: 'list',
|
accessType: 'list',
|
||||||
entityType: 'statements',
|
entityType: 'statements',
|
||||||
listType: 'latest',
|
listType: 'latest',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const onHottestSubjectsAccess = () => ({
|
export const onHottestSubjectsAccess = () => ({
|
||||||
type: actionsTypes.ENTITY_ACCESS,
|
type: actionsTypes.ENTITY_ACCESS,
|
||||||
accessType: 'list',
|
accessType: 'list',
|
||||||
entityType: 'subjects',
|
entityType: 'subjects',
|
||||||
listType: 'hottest',
|
listType: 'hottest',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const onPublicFiguresListAccess = () => ({
|
export const onPublicFiguresListAccess = () => ({
|
||||||
type: actionsTypes.ENTITY_ACCESS,
|
type: actionsTypes.ENTITY_ACCESS,
|
||||||
accessType: 'list',
|
accessType: 'list',
|
||||||
entityType: 'publicFigures',
|
entityType: 'publicFigures',
|
||||||
listType: 'all',
|
listType: 'all',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
|
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
|
||||||
import createSagaMiddleware from 'redux-saga';
|
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 { map } from 'ramda';
|
||||||
import { isClientSide } from 'helpers/env';
|
import { isClientSide } from 'helpers/env';
|
||||||
import rootSaga from './sagas';
|
|
||||||
import { entitiesReducer, addStatementReducer } from './reducers';
|
|
||||||
|
|
||||||
import { useRouterHistory } from 'react-router';
|
import { useRouterHistory } from 'react-router';
|
||||||
import { syncHistoryWithStore } from 'react-router-redux';
|
|
||||||
import createHashHistory from 'history/lib/createHashHistory';
|
import createHashHistory from 'history/lib/createHashHistory';
|
||||||
import createMemoryHistory from 'history/lib/createMemoryHistory';
|
import createMemoryHistory from 'history/lib/createMemoryHistory';
|
||||||
|
|
||||||
|
import rootSaga from './sagas';
|
||||||
|
import { entitiesReducer } from './reducers';
|
||||||
|
|
||||||
// Build history
|
// Build history
|
||||||
const createHistory = isClientSide() ? createHashHistory : createMemoryHistory;
|
const createHistory = isClientSide() ? createHashHistory : createMemoryHistory;
|
||||||
// const browserHistory = useScroll(useRouterHistory(createHistory))();
|
// const browserHistory = useScroll(useRouterHistory(createHistory))();
|
||||||
|
|
@ -21,31 +20,30 @@ const initialState = isClientSide() ? window.__INITIAL_STATE__ : {};
|
||||||
|
|
||||||
// REDUCERS
|
// REDUCERS
|
||||||
const reducer = combineReducers({
|
const reducer = combineReducers({
|
||||||
routing: routerReducer,
|
routing: routerReducer,
|
||||||
entities: entitiesReducer,
|
entities: entitiesReducer,
|
||||||
addStatement: addStatementReducer,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// MIDDLEWARE
|
// MIDDLEWARE
|
||||||
const sagaMiddleware = createSagaMiddleware();
|
const sagaMiddleware = createSagaMiddleware();
|
||||||
const middlewares = [routerMiddleware(browserHistory), sagaMiddleware];
|
const middlewares = [routerMiddleware(browserHistory), sagaMiddleware];
|
||||||
if (isClientSide() && process.env.NODE_ENV !== 'production') {
|
if (isClientSide() && process.env.NODE_ENV !== 'production') {
|
||||||
middlewares.push(require('redux-logger')({
|
middlewares.push(require('redux-logger')({
|
||||||
stateTransformer: map(state => ((state && state.toJS) ? state.toJS() : state)),
|
stateTransformer: map(state => ((state && state.toJS) ? state.toJS() : state)),
|
||||||
timestamp: true,
|
timestamp: true,
|
||||||
duration: true,
|
duration: true,
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
predicate: (getState, action) => action.type !== 'APP_LOG',
|
predicate: (getState, action) => action.type !== 'APP_LOG',
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// STORE
|
// STORE
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
reducer,
|
reducer,
|
||||||
initialState,
|
initialState,
|
||||||
compose(
|
compose(
|
||||||
applyMiddleware(...middlewares),
|
applyMiddleware(...middlewares),
|
||||||
window.devToolsExtension ? window.devToolsExtension() : f => f,
|
window.devToolsExtension ? window.devToolsExtension() : f => f,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const history = syncHistoryWithStore(browserHistory, store);
|
const history = syncHistoryWithStore(browserHistory, store);
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import {
|
|
||||||
assoc, compose, not, allPass, prop, isNil, either, complement,
|
|
||||||
} from 'ramda';
|
|
||||||
import actionsTypes from '../actions_types';
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
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')),
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,35 +1,36 @@
|
||||||
import actionsType from '../actions_types';
|
|
||||||
import { map, compose, prop, merge, assoc, not, isNil, pipe, when } from 'ramda';
|
import { map, compose, prop, merge, assoc, not, isNil, pipe, when } from 'ramda';
|
||||||
const initialState = {};
|
|
||||||
import { indexAndGroup } from 'api/jsonApiParser';
|
import { indexAndGroup } from 'api/jsonApiParser';
|
||||||
|
import actionsType from '../actions_types';
|
||||||
|
|
||||||
|
const initialState = {};
|
||||||
|
|
||||||
const isNotNil = compose(not, isNil);
|
const isNotNil = compose(not, isNil);
|
||||||
|
|
||||||
export const indexAndGroupMainData = compose(
|
export const indexAndGroupMainData = compose(
|
||||||
indexAndGroup,
|
indexAndGroup,
|
||||||
map(assoc('fetched', true)),
|
map(assoc('fetched', true)),
|
||||||
prop('data')
|
prop('data')
|
||||||
);
|
);
|
||||||
|
|
||||||
const indexAndGroupIncludedData = pipe(
|
const indexAndGroupIncludedData = pipe(
|
||||||
prop('included'),
|
prop('included'),
|
||||||
when(
|
when(
|
||||||
isNotNil,
|
isNotNil,
|
||||||
compose(
|
compose(
|
||||||
indexAndGroup,
|
indexAndGroup,
|
||||||
map(assoc('fetched', true)),
|
map(assoc('fetched', true)),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const saveData = data => compose(
|
const saveData = data => compose(
|
||||||
merge(indexAndGroupIncludedData(data)),
|
merge(indexAndGroupIncludedData(data)),
|
||||||
indexAndGroupMainData,
|
indexAndGroupMainData,
|
||||||
)(data);
|
)(data);
|
||||||
|
|
||||||
export const entitiesReducer = (state = initialState, action) => {
|
export const entitiesReducer = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actionsType.ENTITY_READ: return merge(state, saveData(action.data));
|
case actionsType.ENTITY_READ: return merge(state, saveData(action.data));
|
||||||
default: return state;
|
default: return state;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
export * from './entities';
|
export * from './entities';
|
||||||
export * from './addStatement';
|
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,45 @@
|
||||||
import { identity } from 'ramda';
|
import { identity } from 'ramda';
|
||||||
import actionsTypes from '../actions_types';
|
|
||||||
import { takeEvery } from 'redux-saga';
|
import { takeEvery } from 'redux-saga';
|
||||||
import { call, put } from 'redux-saga/effects';
|
import { call, put } from 'redux-saga/effects';
|
||||||
import { getSubjects, getStatements, getPositions } from 'api/debats';
|
import { getSubjects, getStatements, getPositions } from 'api/debats';
|
||||||
|
|
||||||
|
import actionsTypes from '../actions_types';
|
||||||
|
|
||||||
const getApiCallFor = (entityType, entityRequest) => {
|
const getApiCallFor = (entityType, entityRequest) => {
|
||||||
switch (entityType) {
|
switch (entityType) {
|
||||||
case 'statements': return getStatements;
|
case 'statements': return getStatements;
|
||||||
case 'subjects':
|
case 'subjects':
|
||||||
switch (entityRequest) {
|
switch (entityRequest) {
|
||||||
case 'hottest': return getSubjects;
|
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;
|
default: return identity;
|
||||||
}
|
}
|
||||||
|
case 'publicFigures':
|
||||||
|
switch (entityRequest) {
|
||||||
|
case 'hottest': return getSubjects;
|
||||||
|
case 'all': return getSubjects;
|
||||||
|
default: return identity;
|
||||||
|
}
|
||||||
|
default: return identity;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function* fetchEntityIfNeeded(action) {
|
function* fetchEntityIfNeeded(action) {
|
||||||
// Test Do we have to call API
|
// Test Do we have to call API
|
||||||
|
|
||||||
const apiCall = getApiCallFor(action.entityType, (
|
const apiCall = getApiCallFor(action.entityType, (
|
||||||
action.accessType === 'list' ? action.listType : action.accessedId
|
action.accessType === 'list' ? action.listType : action.accessedId
|
||||||
));
|
));
|
||||||
|
|
||||||
// Call API
|
// Call API
|
||||||
const response = yield call(apiCall);
|
const response = yield call(apiCall);
|
||||||
|
|
||||||
// Error actions
|
// Error actions
|
||||||
|
|
||||||
// Success actions
|
// Success actions
|
||||||
yield put({ type: actionsTypes.ENTITY_READ, data: response.data });
|
yield put({ type: actionsTypes.ENTITY_READ, data: response.data });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* watchEntityAccess() {
|
export function* watchEntityAccess() {
|
||||||
yield* takeEvery(actionsTypes.ENTITY_ACCESS, fetchEntityIfNeeded);
|
yield* takeEvery(actionsTypes.ENTITY_ACCESS, fetchEntityIfNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ import { createSelector } from 'reselect';
|
||||||
import { prop, propEq, find, pipe, dissoc, when, not, isNil, compose } from 'ramda';
|
import { prop, propEq, find, pipe, dissoc, when, not, isNil, compose } from 'ramda';
|
||||||
import { getPublicFigures, getSubjects, getPositions, enrichWithRelationships } from './entities';
|
import { getPublicFigures, getSubjects, getPositions, enrichWithRelationships } from './entities';
|
||||||
|
|
||||||
import { withConsole } from 'helpers/debug';
|
|
||||||
|
|
||||||
const isNotNil = compose(not, isNil);
|
const isNotNil = compose(not, isNil);
|
||||||
|
|
||||||
const getAddState = state => state.addStatement;
|
const getAddState = state => state.addStatement;
|
||||||
|
|
@ -11,43 +9,43 @@ const getAddState = state => state.addStatement;
|
||||||
const injectPositions = enrichWithRelationships('positions', 'positions');
|
const injectPositions = enrichWithRelationships('positions', 'positions');
|
||||||
|
|
||||||
export const getAddStatementPublicFigure = createSelector(
|
export const getAddStatementPublicFigure = createSelector(
|
||||||
getAddState,
|
getAddState,
|
||||||
getPublicFigures,
|
getPublicFigures,
|
||||||
(addState, publicFigures) => find(
|
(addState, publicFigures) => find(
|
||||||
propEq('id', prop('publicFigureId')(addState))
|
propEq('id', prop('publicFigureId')(addState))
|
||||||
)(publicFigures)
|
)(publicFigures)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAddStatementSubject = createSelector(
|
export const getAddStatementSubject = createSelector(
|
||||||
getAddState,
|
getAddState,
|
||||||
getSubjects,
|
getSubjects,
|
||||||
getPositions,
|
getPositions,
|
||||||
(addState, allSubjects, allPositions) => pipe(
|
(addState, allSubjects, allPositions) => pipe(
|
||||||
find(propEq('id', prop('subjectId')(addState))),
|
find(propEq('id', prop('subjectId')(addState))),
|
||||||
when(
|
when(
|
||||||
isNotNil,
|
isNotNil,
|
||||||
pipe(
|
pipe(
|
||||||
injectPositions(allPositions),
|
injectPositions(allPositions),
|
||||||
dissoc('relationthips')
|
dissoc('relationthips')
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)(allSubjects)
|
)(allSubjects)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAddStatementPosition = createSelector(
|
export const getAddStatementPosition = createSelector(
|
||||||
getAddState,
|
getAddState,
|
||||||
getPositions,
|
getPositions,
|
||||||
(addState, publicFigures) => find(
|
(addState, publicFigures) => find(
|
||||||
propEq('id', prop('positionId')(addState))
|
propEq('id', prop('positionId')(addState))
|
||||||
)(publicFigures)
|
)(publicFigures)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAddStatementEvidenceUrl = createSelector(
|
export const getAddStatementEvidenceUrl = createSelector(
|
||||||
getAddState,
|
getAddState,
|
||||||
prop('evidenceUrl')
|
prop('evidenceUrl')
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAddStatementEvidenceFile = createSelector(
|
export const getAddStatementEvidenceFile = createSelector(
|
||||||
getAddState,
|
getAddState,
|
||||||
prop('evidenceFile')
|
prop('evidenceFile')
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { curry, assoc, compose, when, take, path, is, map, isNil, always, values, propEq, ifElse, pipe, find } from 'ramda';
|
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 getSubjects = state => values(state.entities.subjects);
|
||||||
export const getPositions = state => values(state.entities.positions);
|
export const getPositions = state => values(state.entities.positions);
|
||||||
export const getStatements = state => values(state.entities.statements);
|
export const getStatements = state => values(state.entities.statements);
|
||||||
export const getPublicFigures = state => values(state.entities['public-figures']);
|
export const getPublicFigures = state => values(state.entities['public-figures']);
|
||||||
|
|
||||||
import { withConsole, warn } from 'helpers/debug';
|
|
||||||
|
|
||||||
const getEntityByRef = curry(
|
const getEntityByRef = curry(
|
||||||
(sourceEntities, entityReference) => ifElse(
|
(sourceEntities, entityReference) => ifElse(
|
||||||
isNil,
|
isNil,
|
||||||
always(entityReference), // No source entities yet, return reference object
|
always(entityReference), // No source entities yet, return reference object
|
||||||
pipe(
|
pipe(
|
||||||
find(propEq('id', entityReference.id)),
|
find(propEq('id', entityReference.id)),
|
||||||
when(isNil, always(entityReference)), // Entity not fetched yet, return reference object
|
when(isNil, always(entityReference)), // Entity not fetched yet, return reference object
|
||||||
),
|
),
|
||||||
)(sourceEntities)
|
)(sourceEntities)
|
||||||
);
|
);
|
||||||
|
|
@ -23,14 +23,14 @@ const getEntityByRef = curry(
|
||||||
* const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure');
|
* const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure');
|
||||||
*/
|
*/
|
||||||
export const enrichWithRelationship = curry(
|
export const enrichWithRelationship = curry(
|
||||||
(propertyName, relationshipName, fromCollection, entity) => assoc(
|
(propertyName, relationshipName, fromCollection, entity) => assoc(
|
||||||
propertyName,
|
propertyName,
|
||||||
compose(
|
compose(
|
||||||
getEntityByRef(fromCollection),
|
getEntityByRef(fromCollection),
|
||||||
when(is(Array), take(1)),
|
when(is(Array), take(1)),
|
||||||
path(['relationships', relationshipName, 'data']),
|
path(['relationships', relationshipName, 'data']),
|
||||||
)(entity),
|
)(entity),
|
||||||
entity
|
entity
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -41,13 +41,13 @@ export const enrichWithRelationship = curry(
|
||||||
* = enrichWithRelationships('remarquablePublicFigures', 'remarquable-public-figures');
|
* = enrichWithRelationships('remarquablePublicFigures', 'remarquable-public-figures');
|
||||||
*/
|
*/
|
||||||
export const enrichWithRelationships = curry(
|
export const enrichWithRelationships = curry(
|
||||||
(propertyName, relationshipName, fromCollection, entity) => assoc(
|
(propertyName, relationshipName, fromCollection, entity) => assoc(
|
||||||
propertyName,
|
propertyName,
|
||||||
compose(
|
compose(
|
||||||
map(getEntityByRef(fromCollection)),
|
map(getEntityByRef(fromCollection)),
|
||||||
path(['relationships', relationshipName, 'data'])
|
path(['relationships', relationshipName, 'data'])
|
||||||
)(entity),
|
)(entity),
|
||||||
entity
|
entity
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
/* eslint-disable import/export */ // since positions.js is an empty file
|
||||||
export * from './positions';
|
export * from './positions';
|
||||||
|
|
||||||
export * from './publicFigures';
|
export * from './publicFigures';
|
||||||
export * from './statements';
|
export * from './statements';
|
||||||
export * from './subjects';
|
export * from './subjects';
|
||||||
|
|
|
||||||
|
|
@ -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 { whenNotNil } from 'helpers/ramda-ext';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { enrichWithRelationships, getSubjects, getPublicFigures } from './entities';
|
import { enrichWithRelationships, getSubjects, getPublicFigures } from './entities';
|
||||||
|
|
@ -6,14 +8,14 @@ import { enrichWithRelationships, getSubjects, getPublicFigures } from './entiti
|
||||||
const injectSubjects = enrichWithRelationships('subjects', 'subjects');
|
const injectSubjects = enrichWithRelationships('subjects', 'subjects');
|
||||||
|
|
||||||
export const getPublicFiguresWithRelations = createSelector(
|
export const getPublicFiguresWithRelations = createSelector(
|
||||||
getPublicFigures,
|
getPublicFigures,
|
||||||
getSubjects,
|
getSubjects,
|
||||||
(publicFigures, allSubjects) => whenNotNil(
|
(publicFigures, allSubjects) => whenNotNil(
|
||||||
compose(
|
compose(
|
||||||
values,
|
values,
|
||||||
map(pipe(
|
map(pipe(
|
||||||
// injectSubjects(allSubjects),
|
// injectSubjects(allSubjects),
|
||||||
dissoc('relationthips'),
|
dissoc('relationthips'),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
)(publicFigures)
|
)(publicFigures)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { values, pipe, map, compose, dissoc } from 'ramda';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { whenNotNil } from 'helpers/ramda-ext';
|
import { whenNotNil } from 'helpers/ramda-ext';
|
||||||
import {
|
import {
|
||||||
enrichWithRelationship, getPublicFigures, getPositions, getSubjects, getStatements
|
enrichWithRelationship, getPublicFigures, getPositions, getSubjects, getStatements,
|
||||||
} from './entities';
|
} from './entities';
|
||||||
|
|
||||||
const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure');
|
const injectPublicFigure = enrichWithRelationship('publicFigure', 'public-figure');
|
||||||
|
|
@ -10,18 +10,18 @@ const injectPosition = enrichWithRelationship('position', 'position');
|
||||||
const injectSubject = enrichWithRelationship('subject', 'subject');
|
const injectSubject = enrichWithRelationship('subject', 'subject');
|
||||||
|
|
||||||
export const getLatestStatements = createSelector(
|
export const getLatestStatements = createSelector(
|
||||||
getStatements,
|
getStatements,
|
||||||
getPublicFigures,
|
getPublicFigures,
|
||||||
getPositions,
|
getPositions,
|
||||||
getSubjects,
|
getSubjects,
|
||||||
(allStatements, allPublicFigures, allPositions, allSubjects) => whenNotNil(
|
(allStatements, allPublicFigures, allPositions, allSubjects) => whenNotNil(
|
||||||
compose(
|
compose(
|
||||||
values,
|
values,
|
||||||
map(pipe(
|
map(pipe(
|
||||||
injectPublicFigure(allPublicFigures),
|
injectPublicFigure(allPublicFigures),
|
||||||
injectSubject(allSubjects),
|
injectSubject(allSubjects),
|
||||||
injectPosition(allPositions),
|
injectPosition(allPositions),
|
||||||
dissoc('relationthips'),
|
dissoc('relationthips'),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
)(allStatements)
|
)(allStatements)
|
||||||
|
|
|
||||||
|
|
@ -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 { createSelector } from 'reselect';
|
||||||
import { whenNotNil } from 'helpers/ramda-ext';
|
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));
|
export const getHomeSubjects = state => values(getSubjects(state));
|
||||||
|
|
||||||
|
|
@ -13,29 +12,29 @@ const injectRemarquablePublicFigures
|
||||||
const injectPositions = enrichWithRelationships('positions', 'positions');
|
const injectPositions = enrichWithRelationships('positions', 'positions');
|
||||||
|
|
||||||
export const getHomeSubjectsWithRelations = createSelector(
|
export const getHomeSubjectsWithRelations = createSelector(
|
||||||
getHomeSubjects,
|
getHomeSubjects,
|
||||||
getPublicFigures,
|
getPublicFigures,
|
||||||
getPositions,
|
getPositions,
|
||||||
(homeSubjects, allPublicFigures, allPositions) => whenNotNil(
|
(homeSubjects, allPublicFigures, allPositions) => whenNotNil(
|
||||||
compose(
|
compose(
|
||||||
values,
|
values,
|
||||||
map(pipe(
|
map(pipe(
|
||||||
injectRemarquablePublicFigures(allPublicFigures),
|
injectRemarquablePublicFigures(allPublicFigures),
|
||||||
injectPositions(allPositions),
|
injectPositions(allPositions),
|
||||||
dissoc('relationships'),
|
dissoc('relationships'),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
)(homeSubjects)
|
)(homeSubjects)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getSubject = (state, props) => createSelector(
|
export const getSubject = (state, props) => createSelector(
|
||||||
getSubjects,
|
getSubjects,
|
||||||
getPositions,
|
getPositions,
|
||||||
getPublicFigures,
|
getPublicFigures,
|
||||||
(allSubjects, allPositions, allPublicFigures) => pipe(
|
(allSubjects, allPositions, allPublicFigures) => pipe(
|
||||||
find(propEq('id', props.subjectId)),
|
find(propEq('id', props.subjectId)),
|
||||||
injectRemarquablePublicFigures(allPublicFigures),
|
injectRemarquablePublicFigures(allPublicFigures),
|
||||||
injectPositions(allPositions),
|
injectPositions(allPositions),
|
||||||
dissoc('relationthips'),
|
dissoc('relationthips'),
|
||||||
)(allSubjects)
|
)(allSubjects)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
import { urlRegex } from './generic';
|
import { urlRegex } from './generic';
|
||||||
|
|
||||||
export const isValidEvidenceUrl = (tested) => urlRegex.test(tested);
|
export const isValidEvidenceUrl = tested => urlRegex.test(tested);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ const SRC_FOLDER = 'src';
|
||||||
const APP_ROOT = path.normalize(path.join(__dirname, '..'));
|
const APP_ROOT = path.normalize(path.join(__dirname, '..'));
|
||||||
|
|
||||||
const constants = Object.freeze({
|
const constants = Object.freeze({
|
||||||
APP_NAME: 'debats',
|
APP_NAME: 'debats',
|
||||||
APP_ROOT,
|
APP_ROOT,
|
||||||
APP_PATH: path.join(APP_ROOT, SRC_FOLDER),
|
APP_PATH: path.join(APP_ROOT, SRC_FOLDER),
|
||||||
STATIC_PATH: path.join(APP_ROOT, SRC_FOLDER, 'static'),
|
STATIC_PATH: path.join(APP_ROOT, SRC_FOLDER, 'static'),
|
||||||
SRC_FOLDER,
|
SRC_FOLDER,
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = constants;
|
module.exports = constants;
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,55 @@
|
||||||
const CONSTANTS = require('../webpack/constants');
|
const CONSTANTS = require('../webpack/constants');
|
||||||
|
|
||||||
const APP_PATH = CONSTANTS.APP_PATH;
|
const APP_PATH = CONSTANTS.APP_PATH;
|
||||||
|
|
||||||
const loaders = [
|
const loaders = [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.jsx?$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /src.+\.css$/,
|
test: /src.+\.css$/,
|
||||||
loader: 'style-loader'
|
loader: 'style-loader'
|
||||||
+ '!css-loader'
|
+ '!css-loader'
|
||||||
+ '?modules&localIdentName=[name]__[local]___[hash:base64:5]'
|
+ '?modules&localIdentName=[name]__[local]___[hash:base64:5]'
|
||||||
+ '&importLoaders=1'
|
+ '&importLoaders=1'
|
||||||
+ '!postcss-loader',
|
+ '!postcss-loader',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /node_modules.*\.css$/,
|
test: /node_modules.*\.css$/,
|
||||||
loader: 'style-loader'
|
loader: 'style-loader'
|
||||||
+ '!css-loader'
|
+ '!css-loader'
|
||||||
+ '!postcss-loader',
|
+ '!postcss-loader',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg|gif|jpeg|jpg)$/,
|
test: /\.(png|svg|gif|jpeg|jpg)$/,
|
||||||
include: APP_PATH,
|
include: APP_PATH,
|
||||||
loader: 'file?name=images/[name].[ext]',
|
loader: 'file?name=images/[name].[ext]',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(eot|woff|ttf)$/,
|
test: /\.(eot|woff|ttf)$/,
|
||||||
include: APP_PATH,
|
include: APP_PATH,
|
||||||
loader: 'file-loader?name=fonts/[name].[ext]',
|
loader: 'file-loader?name=fonts/[name].[ext]',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(svg|woff2?)$/,
|
test: /\.(svg|woff2?)$/,
|
||||||
exclude: APP_PATH,
|
exclude: APP_PATH,
|
||||||
loader: 'url?limit=10000',
|
loader: 'url?limit=10000',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(ttf|eot)$/,
|
test: /\.(ttf|eot)$/,
|
||||||
exclude: APP_PATH,
|
exclude: APP_PATH,
|
||||||
loader: 'file',
|
loader: 'file',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
loader: 'json',
|
loader: 'json',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.md$/,
|
test: /\.md$/,
|
||||||
loader: 'raw',
|
loader: 'raw',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = loaders;
|
module.exports = loaders;
|
||||||
|
|
|
||||||
|
|
@ -12,35 +12,36 @@ const postcssHide = require('postcss-hide');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const makeMap = aPath => {
|
const makeMap = (aPath) => {
|
||||||
try {
|
try {
|
||||||
return webpackPostcssTools.makeVarMap(aPath);
|
return webpackPostcssTools.makeVarMap(aPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// console.log(`${aPath} not found.`);
|
// console.log(`${aPath} not found.`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const map = makeMap('./src/styles/_constants.css');
|
const map = makeMap('./src/styles/_constants.css');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
module.exports = webpack => [
|
module.exports = webpack => [
|
||||||
postcssMixins({
|
postcssMixins({
|
||||||
mixinsDir: path.join(CONSTANTS.APP_PATH, 'style', 'mixins'),
|
mixinsDir: path.join(CONSTANTS.APP_PATH, 'style', 'mixins'),
|
||||||
}),
|
}),
|
||||||
atImport(),
|
atImport(),
|
||||||
postcssShortPosition(),
|
postcssShortPosition(),
|
||||||
postcssAssets(),
|
postcssAssets(),
|
||||||
postcssColorFunction(),
|
postcssColorFunction(),
|
||||||
postcssNext({
|
postcssNext({
|
||||||
features: {
|
features: {
|
||||||
customProperties: {
|
customProperties: {
|
||||||
variables: map.vars,
|
variables: map.vars,
|
||||||
warnings: false,
|
warnings: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
lost(),
|
lost(),
|
||||||
postcssInlineSVG(),
|
postcssInlineSVG(),
|
||||||
postcssHide(),
|
postcssHide(),
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const APP_ROOT = CONSTANTS.APP_ROOT;
|
const APP_ROOT = CONSTANTS.APP_ROOT;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
alias: {
|
alias: {
|
||||||
react: path.resolve(APP_ROOT, 'node_modules/react'),
|
react: path.resolve(APP_ROOT, 'node_modules/react'),
|
||||||
},
|
},
|
||||||
modulesDirectories: ['src', 'web_modules', 'node_modules'],
|
modulesDirectories: ['src', 'web_modules', 'node_modules'],
|
||||||
extensions: ['', '.js', '.jsx'],
|
extensions: ['', '.js', '.jsx'],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const path = require('path');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const APP_ROOT = CONSTANTS.APP_ROOT;
|
const APP_ROOT = CONSTANTS.APP_ROOT;
|
||||||
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const path = require('path');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const APP_ROOT = CONSTANTS.APP_ROOT;
|
const APP_ROOT = CONSTANTS.APP_ROOT;
|
||||||
const APP_PATH = CONSTANTS.APP_PATH;
|
const APP_PATH = CONSTANTS.APP_PATH;
|
||||||
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
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.DedupePlugin());
|
||||||
config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true)); // Assign the module and chunk ids by occurrence count
|
config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true)); // Assign the module and chunk ids by occurrence count
|
||||||
config.plugins.push(new webpack.optimize.UglifyJsPlugin({
|
config.plugins.push(new webpack.optimize.UglifyJsPlugin({
|
||||||
compressor: { screw_ie8: false, keep_fnames: true, warnings: true },
|
compressor: { screw_ie8: false, keep_fnames: true, warnings: true },
|
||||||
mangle: {
|
mangle: {
|
||||||
except: ['$super', '$', 'exports', 'require'],
|
except: ['$super', '$', 'exports', 'require'],
|
||||||
screw_ie8: false,
|
screw_ie8: false,
|
||||||
keep_fnames: true,
|
keep_fnames: true,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
// config.plugins.push(new CompressionPlugin({threshold: 10240}));
|
// config.plugins.push(new CompressionPlugin({threshold: 10240}));
|
||||||
config.plugins.push(new CopyWebpackPlugin(copyConfig));
|
config.plugins.push(new CopyWebpackPlugin(copyConfig));
|
||||||
|
|
@ -34,7 +35,7 @@ config.devtool = 'cheap-module-source-map';
|
||||||
config.cache = false;
|
config.cache = false;
|
||||||
config.debug = false;
|
config.debug = false;
|
||||||
config.entry = `${APP_PATH}/index.js`;
|
config.entry = `${APP_PATH}/index.js`;
|
||||||
config.output.path = outputPath;;
|
config.output.path = outputPath;
|
||||||
|
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,21 @@ const config = require('./webpack.base.config');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const APP_PATH = CONSTANTS.APP_PATH;
|
const APP_PATH = CONSTANTS.APP_PATH;
|
||||||
const APP_NAME = CONSTANTS.APP_NAME;
|
const APP_NAME = CONSTANTS.APP_NAME;
|
||||||
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
||||||
|
|
||||||
|
|
||||||
config.plugins.push(new HtmlWebpackPlugin({
|
config.plugins.push(new HtmlWebpackPlugin({
|
||||||
template: `${SRC_FOLDER}/index.html`,
|
template: `${SRC_FOLDER}/index.html`,
|
||||||
inject: true,
|
inject: true,
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
config.entry = `${APP_PATH}/index.js`;
|
config.entry = `${APP_PATH}/index.jsx`;
|
||||||
config.output = {
|
config.output = {
|
||||||
filename: `${APP_NAME}.[name].[hash].js`,
|
filename: `${APP_NAME}.[name].[hash].js`,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const path = require('path');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
const CONSTANTS = require('./constants');
|
const CONSTANTS = require('./constants');
|
||||||
|
|
||||||
const APP_ROOT = CONSTANTS.APP_ROOT;
|
const APP_ROOT = CONSTANTS.APP_ROOT;
|
||||||
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
const SRC_FOLDER = CONSTANTS.SRC_FOLDER;
|
||||||
|
|
||||||
|
|
@ -33,30 +34,30 @@ var devServerAPIUrl;
|
||||||
var devServerRewrite;
|
var devServerRewrite;
|
||||||
|
|
||||||
if (args.proxy) {
|
if (args.proxy) {
|
||||||
if (args.mockAPI) {
|
if (args.mockAPI) {
|
||||||
devServerAPIUrl = 'http://localhost:3030';
|
devServerAPIUrl = 'http://localhost:3030';
|
||||||
devServerRewrite = function rewrite(req) {
|
devServerRewrite = function rewrite(req) {
|
||||||
req.url = req.url // eslint-disable-line no-param-reassign
|
req.url = req.url // eslint-disable-line no-param-reassign
|
||||||
.replace(/\/api\//, '/fake-api/') // Local mocks as API
|
.replace(/\/api\//, '/fake-api/') // Local mocks as API
|
||||||
.split('?')[0]; // strip query string if exists
|
.split('?')[0]; // strip query string if exists
|
||||||
if (req.method === 'POST') req.method = 'GET'; // eslint-disable-line no-param-reassign
|
if (req.method === 'POST') req.method = 'GET'; // eslint-disable-line no-param-reassign
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (args.prodAPI) devServerAPIUrl = 'http://api.débats.co';
|
if (args.prodAPI) devServerAPIUrl = 'http://api.débats.co';
|
||||||
}
|
}
|
||||||
|
|
||||||
config.devServer = {
|
config.devServer = {
|
||||||
quiet: false,
|
quiet: false,
|
||||||
stats: { colors: true },
|
stats: { colors: true },
|
||||||
outputPath,
|
outputPath,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api/*': {
|
'/api/*': {
|
||||||
target: devServerAPIUrl,
|
target: devServerAPIUrl,
|
||||||
rewrite: devServerRewrite,
|
rewrite: devServerRewrite,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue