Commit b280df50 authored by Florian Pagnoux's avatar Florian Pagnoux
Browse files

Adapt to Wordpress & add breadcrum

parents 3f26fc41 72091dfd
PRODUCTION=true
BASENAME=outils/baremes-ipp
.next
node_modules
out
.env
import {formatNumber, formatDate} from '../../services/formatter'
it('formatNumber should format numbers in a French style', () => {
expect(formatNumber(3000)).toEqual('3\xa0000')
});
it('formatNumber should format currencies in a French style', () => {
expect(formatNumber(3000, {style: 'currency', currency: 'EUR'})).toEqual('3\xa0000,00\xa0€')
});
it('formatNumber should format anciens francs', () => {
expect(formatNumber(3000, {style: 'currency', currency: 'AFRF'})).toEqual('3\xa0000,00\xa0AF')
});
it('formatDate should format dates in a French style', () => {
expect(formatDate('2019-02-01')).toEqual('01/02/2019')
});
import stylesheet from '../styles/style.css'
const isProd = process.env.PRODUCTION;
if (! isProd) {
require('../styles/style.css')
}
const Layout = ({children, fullWidth}) => (
const StagingLayout = ({children, fullWidth}) => (
<div>
<style dangerouslySetInnerHTML={{ __html: stylesheet }} />
<header id="main-header" className="main-header" role="banner">
<div className="inner">
<h1>
......@@ -55,4 +57,8 @@ const Layout = ({children, fullWidth}) => (
</div>
)
const ProdLayout = ({children}) => (<div>{ children }</div>)
const Layout = isProd ? ProdLayout : StagingLayout
export default Layout
......@@ -5,24 +5,21 @@ import size from 'lodash.size'
import isString from 'lodash.isstring'
import sortBy from 'lodash.sortby'
import flow from 'lodash.flow'
import { FormattedDate, IntlProvider, addLocaleData, FormattedNumber} from 'react-intl'
import fr from 'react-intl/locale-data/fr'
import extractData from '../services/dataPreprocesser'
import {formatNumber, formatDate} from '../services/formatter'
import Table from '../components/Table'
addLocaleData(fr)
function cellFormatter({value, metadata}) {
if ((! value && ! value !== 0) || ! metadata || ! metadata.unit) {
return value
}
if (metadata.unit == '/1') {
return <FormattedNumber value={value} style="percent" maximumFractionDigits={3}/>
return formatNumber(value, { style: 'percent', maximumFractionDigits: 3 })
}
if (metadata.unit.startsWith('currency')) {
const currency = metadata.unit.split('-')[1]
return <FormattedNumber value={value} style="currency" maximumFractionDigits={3} currency={currency}/>
return formatNumber(value, { style: 'currency', currency, maximumFractionDigits: 3 })
}
return value
}
......@@ -102,19 +99,17 @@ const ParameterTable = ({parameter}) => {
Header: 'Date d’effet',
accessor: item => item.date,
id: 'date',
Cell: props => <FormattedDate value={props.value} timeZone="UTC"/> // Input is considered to be in UTC, so dates should be formatted for the same timezone.
Cell: props => formatDate(props.value)
}
const columns = [dateColumn, buildColumn(parameter)]
return (
<IntlProvider locale="fr">
<div>
<Table
columns={columns}
data={data}
/>
<p className="table-doc">{parameter.documentation}</p>
</div>
</IntlProvider>
<div>
<Table
columns={columns}
data={data}
/>
<p className="table-doc">{parameter.documentation}</p>
</div>
)
}
......
export const basename = process.env.BASENAME || ''
export const isProd = process.env.PRODUCTION
......@@ -25,5 +25,5 @@ module.exports = withCSS({
)
})
},
assetPrefix: (localEnv && localEnv.BASENAME) || ""
assetPrefix: (localEnv && localEnv.BASENAME) || "."
})
......@@ -9,6 +9,7 @@
"bluebird": "^3.5.1",
"dotenv": "^6.1.0",
"express": "^4.16.3",
"intl": "^1.2.5",
"isomorphic-unfetch": "^2.0.0",
"js-yaml-loader": "^0.1.0",
"lodash.filter": "^4.6.0",
......@@ -35,8 +36,7 @@
"lodash.union": "^4.6.0",
"next": "^6.0.3",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-intl": "^2.4.0"
"react-dom": "^16.4.1"
},
"devDependencies": {
"babel-core": "7.0.0-bridge.0",
......
import Document, { Head, Main, NextScript } from 'next/document'
import {basename, isProd} from '../config'
const basename = process.env.BASENAME || ''
export default class MyDocument extends Document {
class StagingDocument extends Document {
render() {
return (
<html>
......@@ -18,3 +17,13 @@ export default class MyDocument extends Document {
)
}
}
class ProdDocument extends Document {
render() {
return <Main />
}
}
const MyDocument = isProd ? ProdDocument : StagingDocument
export default MyDocument
import Layout from '../components/Layout'
import { withRouter } from 'next/router'
import map from 'lodash.map'
import isArray from 'lodash.isarray'
......@@ -6,6 +5,9 @@ import includes from 'lodash.includes'
import flow from 'lodash.flow';
import sortBy from 'lodash.sortby';
import Layout from '../components/Layout'
import {basename, isProd} from '../config'
function renderSubParams(item, key, path) {
const shouldSort = ! isArray(item.subparams) // A specific order has been explicitly defined in the conf
const subParams = flow([
......@@ -35,22 +37,33 @@ function renderItem(item, key, path) {
}
}
function renderSectionContent(subParams, path) {
return (
<div>
<h4>Sommaire</h4>
<ol>
{map(subParams, subParam => renderItem(subParam, subParam.name, `${basename}${path}`))}
</ol>
</div>)
}
const Section = (props) => {
const section = props.router.query
const path = props.router.asPath.endsWith('/') ? props.router.asPath : props.router.asPath + '/'
const basename = process.env.BASENAME || ''
const subParams = flow([
x => map(x, (subParam, name) => Object.assign({}, subParam, {name})),
x => sortBy(x, subParam => section?.metadata?.order.indexOf(subParam.name))
])(section.subparams)
if (isProd) {
return renderSectionContent(subParams, path)
}
return <Layout>
<h1 className="box"><span>{section.title}</span></h1>
<div className="entry-content text">
<h4>Sommaire</h4>
<ol>
{map(subParams, subParam => renderItem(subParam, subParam.name, `${basename}${path}`))}
</ol>
{renderSectionContent(subParams, path)}
</div>
</Layout>
}
......
......@@ -2,10 +2,25 @@ import {withRouter} from 'next/router'
import ParameterTable from "../components/ParameterTable"
import Layout from '../components/Layout'
import {basename} from '../config'
const BreadCrum = ({links}) => (
<p><a href={basename + '/'}>Barèmes IPP</a>{links.map(({path, title}, index) => {
if (! title) {
return
}
if (! path) {
return <span key={index}> >> {title}</span>
}
return <span key={index}> >> <a href={`${basename}/${path}`}>{title}</a></span>
})}</p>
)
const TablePage = (props) => {
const parameter = props.router.query
const {parameter, parents} = props.router.query
return <Layout fullWidth={ true }>
<BreadCrum links={parents}/>
<h1 className="box"><span>{parameter.description}</span></h1>
<ParameterTable parameter={parameter}/>
</Layout>
}
......
......@@ -4,6 +4,9 @@ const fs = require('fs')
const yaml = require('js-yaml');
const map = require('lodash.map')
const flatten = require('lodash.flatten')
const fromPairs = require('lodash.frompairs')
const get = require('lodash.get')
const resolver = require('./resolver')
......@@ -12,32 +15,51 @@ async function loadSectionFile(file) {
const textContent = fs.readFileSync(`./tables/${file}`, 'utf8')
const yamlContent = yaml.safeLoad(textContent)
const resolvedDesc = await resolver.resolveSection(yamlContent)
return extractRoutes(resolvedDesc, `/${fileName}`)
return [fileName, resolvedDesc]
}
async function loadRoutes() {
async function loadParametersTree() {
const sectionsFiles = fs.readdirSync('./tables')
const routes = await Promise.all(sectionsFiles.map(loadSectionFile))
const resolvedFiles = await Promise.all(sectionsFiles.map(loadSectionFile))
return fromPairs(resolvedFiles)
}
async function loadRoutes() {
const parametersTree = await loadParametersTree()
const routes = map(parametersTree, extractRoutes)
return flatten(routes)
}
function extractRoutes(desc, path) {
function addLeadingSlash(string) {
return string.startsWith('/') ? string : `/${string}`
}
function extractRoutes(desc, path, parametersTree, parents = []) {
const isPage = ! parents.length
if (desc.table) {
return [{
route: path,
route: addLeadingSlash(path),
page: '/table',
query: desc.table,
query: {parameter: desc.table, parents}
}]
}
if (desc.subparams) {
const sectionRoute = {
route: path,
route: addLeadingSlash(path),
page: '/section',
query: desc
}
return [sectionRoute].concat(flatten(map(desc.subparams, (child, key) => {
return extractRoutes(child, `${path}/${key}`)
})))
const subRoutes = flatten(map(desc.subparams, (child, key) => {
return extractRoutes(
child,
`${path}/${key}`,
parametersTree,
parents.concat(
[{path: isPage && path, title: desc.title || desc.description}]
)
)
}))
return isPage ? [sectionRoute].concat(subRoutes) : subRoutes
}
}
......
......@@ -60,7 +60,7 @@ async function fetchParam(key, previousTries = 0) {
const response = await fetch(`http://localhost:2000/parameter/${key}`)
return await response.json()
} catch (error) { // Try again, to deal with Mac race-conditions
if (previousTries <= 2) {
if (previousTries <= 5) {
return fetchParam(key, previousTries = previousTries + 1)
} else {
throw error
......
// Polyfill to be able to use french locale
import IntlPolyfill from 'intl'
import 'intl/locale-data/jsonp/fr.js';
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
export function formatNumber(value, options) {
if (options && options.currency == 'AFRF') {
return formatAFRF(value, options)
}
return (new Intl.NumberFormat('fr', options)).format(value)
}
export function formatDate(value) {
return new Intl.DateTimeFormat('fr', {timeZone: 'UTC'}).format(new Date(value))
}
function formatAFRF(value, options) {
const {currency, ...otherOptions} = options
return formatNumber(value, {currency: 'FRF', ...otherOptions}).replace('F', 'AF')
}
......@@ -3022,27 +3022,15 @@ interpret@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
intl-format-cache@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316"
intl-messageformat-parser@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075"
intl-messageformat@^2.0.0, intl-messageformat@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc"
dependencies:
intl-messageformat-parser "1.4.0"
intl-locales-supported@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/intl-locales-supported/-/intl-locales-supported-1.0.0.tgz#9a9d94dbf104a87818881952dcb782053f0aeefa"
intl-relativeformat@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-2.1.0.tgz#010f1105802251f40ac47d0e3e1a201348a255df"
dependencies:
intl-messageformat "^2.0.0"
intl@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
invariant@^2.1.1, invariant@^2.2.0, invariant@^2.2.2:
invariant@^2.2.0, invariant@^2.2.2:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
dependencies:
......@@ -5321,15 +5309,6 @@ react-dom@^16.4.1:
object-assign "^4.1.1"
prop-types "^15.6.0"
react-intl@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15"
dependencies:
intl-format-cache "^2.0.5"
intl-messageformat "^2.1.0"
intl-relativeformat "^2.0.0"
invariant "^2.1.1"
react-is@^16.4.1:
version "16.4.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment