Fix HomeSubjects, connect PublicFigures page and fix Bootstrap

This commit is contained in:
Jalil Arfaoui 2018-09-29 11:38:12 +02:00
parent aba0bf0915
commit b4fc35a88c
27 changed files with 148 additions and 134 deletions

View file

@ -1,4 +1,4 @@
{
"presets": ["es2015", "react", "stage-0"],
"plugins": ["transform-decorators-legacy", "react-hot-loader/babel", "ramda"]
"plugins": ["transform-decorators-legacy", "react-hot-loader/babel", "ramda", "jsx-control-statements"]
}

View file

@ -4,6 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/flow-typed" />
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />

View file

@ -1,8 +0,0 @@
{
"api": {
"debats": {
"endpointHost": "http://localhost:3000",
"endpointPath": "/"
}
}
}

View file

@ -1,11 +1,25 @@
{
"name": "debats-front",
"version": "0.0.1",
"description": "Front for Débats.co website",
"author": "Jalil Arfaoui",
"description": "Front-end for Débats.co",
"main": "src/index.jsx",
"repository": "https://framagit.org/debats/debats-front",
"author": "Jalil Arfaoui <jalil@arfaoui.net>",
"license": "MIT",
"standard": {
"parser": "babel-eslint",
"plugins": [
"flowtype"
],
"globals": [
"__RAVEN__",
"__PRODUCTION__",
"API_URL"
]
},
"scripts": {
"dev-mock": "./node_modules/.bin/webpack-dev-server --config webpack/webpack.dev.server.config.js --inline --proxy --mockAPI --port 80 --host 0.0.0.0 --progress --colors --hot --content-base build/dev",
"dev-local": "./node_modules/.bin/webpack-dev-server --config webpack/webpack.dev.server.config.js --inline --proxy --localAPI --port 80 --host 0.0.0.0 --progress --colors --hot --content-base build/dev",
"dev-mock": "./node_modules/.bin/webpack-dev-server --config webpack/webpack.dev.server.config.js --inline --proxy --mockAPI --port 1984 --host 0.0.0.0 --progress --colors --hot --content-base build/dev",
"dev-local": "./node_modules/.bin/webpack-dev-server --config webpack/webpack.dev.server.config.js --inline --proxy --localAPI --port 1984 --host 0.0.0.0 --progress --colors --hot --content-base build/dev",
"build-dev": "./node_modules/.bin/webpack --config webpack/webpack.build.dev.config.js --progress --colors",
"build-prod": "./node_modules/.bin/webpack --config webpack/webpack.config.js --production --progress --colors",
"build-stats": "./node_modules/.bin/webpack --config webpack/webpack.config.js --production --json > stats.json",
@ -83,6 +97,7 @@
"babel-core": "<6.3.0",
"babel-eslint": "^8.2.5",
"babel-loader": "~6.2.1",
"babel-plugin-jsx-control-statements": "^3.2.8",
"babel-plugin-ramda": "^1.1.6",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-es2015-modules-umd": "^6.8.0",

View file

@ -3,12 +3,9 @@ import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { curry } from 'ramda';
import axios from 'axios';
import Config from 'Config';
const endpoint = Config.api.debats.endpointHost + Config.api.debats.endpointPath;
const get = url => axios.get(`${endpoint}${url}`);
const post = (url, data) => axios.post(`${endpoint}${url}`, data);
const get = url => axios.get(`${API_URL}/${url}`);
const post = (url, data) => axios.post(`${API_URL}/${url}`, data);
export const getSubjects = () => get('subjects');
export const getStatements = () => get('statements');
@ -19,6 +16,6 @@ export const getPositions = subjectId => get(`subjects/${subjectId}/positions`);
export const postStatement = statement => post('statements', statement);
export const apolloClient = new ApolloClient({
link: new HttpLink({ uri: 'http://localhost:4000' }),
link: new HttpLink({ uri: API_URL }),
cache: new InMemoryCache()
})

View file

@ -1,5 +1,4 @@
import moment from 'moment';
import 'bootstrap-loader';
const locale = 'fr';
moment.locale(locale);

View file

@ -3,7 +3,7 @@ import { cond, always, T, test } from 'ramda';
import { isNotEmpty } from 'helpers/ramda-ext';
import DateField from './DateField';
import { Well } from 'react-bootstrap';
import { isValidEvidenceUrl } from 'validations/statements';
import { isValidEvidenceUrl } from 'domain/statements';
import Dropzone from 'react-dropzone';
import FieldGroup from 'components/FieldGroup';

View file

@ -11,7 +11,7 @@ import PositionStep from './PositionStep';
import StatementStep from './StatementStep';
import SummaryStep from './SummaryStep';
import { QUOTE_MIN_CHARS } from 'constants/limits';
import { isValidEvidenceUrl } from 'validations/statements';
import { isValidEvidenceUrl } from 'domain/statements';
const steps = {
PUBLIC_FIGURE: 1,

View file

@ -1,3 +1,3 @@
import { urlRegex } from './generic';
import { urlRegex } from 'validations/generic'
export const isValidEvidenceUrl = tested => urlRegex.test(tested);
export const isValidEvidenceUrl = tested => urlRegex.test(tested)

View file

@ -1,5 +0,0 @@
import { complement } from 'ramda';
export const hasWindow = () => (typeof window !== 'undefined');
export const isClientSide = hasWindow;
export const isServerSide = complement(hasWindow);

View file

@ -6,8 +6,12 @@
<title>Débats.co</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<script type="application/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<script>
var API_URL = 'http://localhost:4000'
</script>
<div id="react-content" />
<!-- Google Tag Manager -->
<!-- <noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-N4M2L9"

View file

@ -1,13 +0,0 @@
import { connect } from 'react-redux';
import { getHomeSubjectsWithRelations } from 'store/selectors';
import { onHottestSubjectsAccess } from 'store/actions/entities';
const mapStateToProps = state => ({
subjects: getHomeSubjectsWithRelations(state),
});
const mapDispatchToProps = dispatch => ({
onAccess: () => dispatch(onHottestSubjectsAccess()),
});
export default connect(mapStateToProps, mapDispatchToProps);

View file

@ -1,24 +1,18 @@
import React, { PropTypes, Component } from 'react'
import React from 'react'
import HomeSubject from './HomeSubject'
import withGraphQL from './withGraphQL'
class HomeSubjects extends Component {
static propTypes = {
lastSubjects: PropTypes.arrayOf(PropTypes.object).isRequired
}
render () {
console.log('props', this.props)
if (!this.props.lastSubjects) return <span>loading subjects ...</span>
return (
<div> {/* TODO Bootstrap */}
{this.props.lastSubjects.map(
s => <HomeSubject key={s.id} subject={s} />
)}
export default withGraphQL(
({ lastSubjects }) => <Choose>
<When condition={lastSubjects}>
<div>
<For each='subject' of={lastSubjects}>
<HomeSubject key={subject.id} subject={subject} />
</For>
</div>
)
}
}
export default withGraphQL(HomeSubjects)
</When>
<Otherwise>
<span>loading subjects ...</span>
</Otherwise>
</Choose>
)

View file

@ -6,15 +6,16 @@ const query = gql`
subjects (last: 20) {
id
title
slug
publicFigures {
id
name
name,
slug
}
}
}
`
const options = {
props: ({ data }) => ({ lastSubjects: data.subjects })
}

View file

@ -1 +1,30 @@
export const PublicFigurePage = () => null;
import React from 'react'
import { Query } from 'react-apollo'
import query from './query'
export default ({ routeParams: { slug } }) => <Query variables={{ slug }} query={query}>
{({ loading, error, data }) => <div className='row' style={{ marginTop: '20px' }}>
<div className='col-md-1' />
<div className='col-md-1'>
<div className='publicfigurehead'>
<div
style={{
background: "url('https://debats.s3.amazonaws.com/uploads/public_figure/picture/1/Fran_ois-Hollande.jpg') 50% 50% no-repeat",
backgroundSize: 'cover',
backgroundPosition: 'center center'
}}
className='publicfigurethumb' />
</div>
</div>
<div class='col-md-3'>
<div class='publicfiguredescription'>
<h1 id='PublicFigureTitle'>
{data && data.publicFigure ? data.publicFigure.name : '...'}
</h1>
<p className='figure-presentation-text'>
{data && data.publicFigure ? data.publicFigure.presentation : '...'}
</p>
</div>
</div>
</div>}
</Query>

View file

@ -0,0 +1,12 @@
import gql from 'graphql-tag'
export default gql`
query($slug: String!) {
publicFigure (slug: $slug) {
id
name
slug
presentation
}
}
`

View file

@ -1,13 +0,0 @@
import { connect } from 'react-redux';
import { getPublicFiguresWithRelations } from 'store/selectors';
import { onPublicFiguresListAccess } from 'store/actions/entities';
const mapStateToProps = state => ({
publicFigures: getPublicFiguresWithRelations(state),
});
const mapDispatchToProps = dispatch => ({
onAccess: () => dispatch(onPublicFiguresListAccess()),
});
export default connect(mapStateToProps, mapDispatchToProps);

View file

@ -1,38 +1,24 @@
import React, { PropTypes, Component } from 'react';
import React from 'react'
import LastStatements from 'components/LastStatements'
import PublicFigureInList from './PublicFigureInList'
import withGraphQL from './withGraphQL'
import LastStatements from 'components/LastStatements';
import PublicFigureInList from './PublicFigureInList';
import connect from './connector';
class PublicFigures extends Component {
static propTypes = {
publicFigures: PropTypes.arrayOf(PropTypes.object).isRequired,
onAccess: PropTypes.func.isRequired,
}
componentWillMount() {
this.props.onAccess();
}
render() {
if (!this.props.publicFigures) return <span>loading public figures ...</span>;
const renderChilds = () => this.props.publicFigures.map(
pf => <PublicFigureInList key={pf.id} publicFigure={pf} />
);
return (
<div>
<div className="col-md-9">
{renderChilds()}
</div>
<div className="col-md-3">
<LastStatements />
</div>
</div>
);
}
}
export default connect(PublicFigures);
export default withGraphQL(
({ publicFigures }) => <div>
<div className="col-md-9">
<Choose>
<When condition={publicFigures}>
<For each='publicFigure' of={publicFigures}>
<PublicFigureInList key={publicFigure.id} publicFigure={publicFigure} />
</For>
</When>
<Otherwise>
<span>loading public figures ...</span>
</Otherwise>
</Choose>
</div>
<div className="col-md-3">
<LastStatements />
</div>
</div>
)

View file

@ -0,0 +1,18 @@
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'
const query = gql`
query {
publicFigures (last: 20) {
id
name
slug
}
}
`
const options = {
props: ({ data }) => ({ publicFigures: data.publicFigures })
}
export default graphql(query, options)

View file

@ -70,10 +70,10 @@ export default (
/>
<Route
name="publicFigures.page"
path=":publicFigureSlug"
path=":slug"
getComponent={(nextState, done) => {
require.ensure([], (require) => {
done(null, require('pages/publicFigure').default);
done(null, require('pages/PublicFigure').default);
}, 'publicFigures.page');
}}
/>

View file

@ -1,7 +1,6 @@
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import { routerReducer, routerMiddleware, syncHistoryWithStore } from 'react-router-redux'
import { map } from 'ramda'
import { isClientSide } from 'helpers/env'
import { useRouterHistory } from 'react-router'
import createHashHistory from 'history/lib/createHashHistory'
import createMemoryHistory from 'history/lib/createMemoryHistory'
@ -9,13 +8,10 @@ import createMemoryHistory from 'history/lib/createMemoryHistory'
import { entitiesReducer } from './reducers'
// Build history
const createHistory = isClientSide() ? createHashHistory : createMemoryHistory
const createHistory = createHashHistory
// const browserHistory = useScroll(useRouterHistory(createHistory))();
const browserHistory = useRouterHistory(createHistory)()
// INITIAL STATE
const initialState = isClientSide() ? window.__INITIAL_STATE__ : {}
// REDUCERS
const reducer = combineReducers({
routing: routerReducer,
@ -24,7 +20,7 @@ const reducer = combineReducers({
// MIDDLEWARE
const middlewares = [routerMiddleware(browserHistory)]
if (isClientSide() && process.env.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
middlewares.push(require('redux-logger')({
stateTransformer: map(state => ((state && state.toJS) ? state.toJS() : state)),
timestamp: true,
@ -37,7 +33,7 @@ if (isClientSide() && process.env.NODE_ENV !== 'production') {
// STORE
const store = createStore(
reducer,
initialState,
{},
compose(
applyMiddleware(...middlewares),
window.devToolsExtension ? window.devToolsExtension() : f => f

View file

@ -1 +1 @@
export const urlRegex = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
export const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/

View file

@ -1 +0,0 @@
module.exports = '';

View file

@ -1,4 +0,0 @@
// Return a Proxy to emulate css modules (if you are using them)
var idObj = require('identity-obj-proxy');
module.exports = idObj;

View file

@ -28,7 +28,7 @@ const loaders = [
loader: 'file?name=images/[name].[ext]',
},
{
test: /\.(eot|woff|ttf)$/,
test: /\.(eot|woff|woff2|ttf)$/,
include: APP_PATH,
loader: 'file-loader?name=fonts/[name].[ext]',
},

View file

@ -14,7 +14,6 @@ module.exports = {
plugins,
module: { loaders },
externals: {
Config: JSON.stringify(require('../config/dev.config.json')),
TweenLite: 'TweenLite',
},
node: {

View file

@ -800,7 +800,7 @@ babel-core@<6.3.0:
slash "^1.0.0"
source-map "^0.5.0"
babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.2.4, babel-core@^6.24.1, babel-core@^6.26.0:
babel-core@^6.0.0, babel-core@^6.1.2, babel-core@^6.11.4, babel-core@^6.2.4, babel-core@^6.24.1, babel-core@^6.26.0:
version "6.26.3"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
dependencies:
@ -1025,6 +1025,13 @@ babel-plugin-jest-hoist@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-16.0.0.tgz#b58ca3f770982a7e7c25b5614b2e57e9dafc6e76"
babel-plugin-jsx-control-statements@^3.2.8:
version "3.2.8"
resolved "https://registry.yarnpkg.com/babel-plugin-jsx-control-statements/-/babel-plugin-jsx-control-statements-3.2.8.tgz#6d2c265d51e82518b03cbbec3a57bd37ef955c7e"
dependencies:
babel-core "^6.1.2"
babel-plugin-syntax-jsx "^6.1.18"
babel-plugin-ramda@^1.1.6:
version "1.6.1"
resolved "https://registry.yarnpkg.com/babel-plugin-ramda/-/babel-plugin-ramda-1.6.1.tgz#600efdcc2fe85620a6619cbccbd491f8699272e8"
@ -1084,7 +1091,7 @@ babel-plugin-syntax-function-bind@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46"
babel-plugin-syntax-jsx@^6.2.4, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
babel-plugin-syntax-jsx@^6.1.18, babel-plugin-syntax-jsx@^6.2.4, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"