From 47694d286ef822195c09859987db2c97329a2ddd Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 20 Mar 2019 16:29:33 +0300 Subject: [PATCH] Revrite types de champ editor using React --- .../new_design/procedure_champs_editor.scss | 72 ++---- .../components/TypesDeChampEditor/Flash.js | 35 +++ .../TypesDeChampEditor/OperationsQueue.js | 52 ++++ .../components/DescriptionInput.js | 29 +++ .../components/LibelleInput.js | 28 +++ .../components/MandatoryInput.js | 28 +++ .../components/MoveButton.js | 22 ++ .../components/TypeDeChamp.js | 227 ++++++++++++++++++ .../components/TypeDeChampCarteOption.js | 25 ++ .../components/TypeDeChampCarteOptions.js | 21 ++ .../components/TypeDeChampDropDownOptions.js | 31 +++ .../TypeDeChampPieceJustificative.js | 81 +++++++ .../TypeDeChampRepetitionOptions.js | 63 +++++ .../components/TypeDeChampTypesSelect.js | 29 +++ .../components/TypeDeChamps.js | 72 ++++++ .../components/TypesDeChampEditor/index.js | 63 +++++ .../TypesDeChampEditor/operations.js | 51 ++++ .../TypesDeChampEditor/typeDeChampsReducer.js | 184 ++++++++++++++ .../components/TypesDeChampEditor/utils.js | 14 ++ app/javascript/shared/utils.js | 4 + package.json | 1 + yarn.lock | 57 +++++ 22 files changed, 1141 insertions(+), 48 deletions(-) create mode 100644 app/javascript/components/TypesDeChampEditor/Flash.js create mode 100644 app/javascript/components/TypesDeChampEditor/OperationsQueue.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/DescriptionInput.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/LibelleInput.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/MandatoryInput.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/MoveButton.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampCarteOption.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampCarteOptions.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampDropDownOptions.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampPieceJustificative.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampRepetitionOptions.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChampTypesSelect.js create mode 100644 app/javascript/components/TypesDeChampEditor/components/TypeDeChamps.js create mode 100644 app/javascript/components/TypesDeChampEditor/index.js create mode 100644 app/javascript/components/TypesDeChampEditor/operations.js create mode 100644 app/javascript/components/TypesDeChampEditor/typeDeChampsReducer.js create mode 100644 app/javascript/components/TypesDeChampEditor/utils.js diff --git a/app/assets/stylesheets/new_design/procedure_champs_editor.scss b/app/assets/stylesheets/new_design/procedure_champs_editor.scss index 591eb48df..917b2d561 100644 --- a/app/assets/stylesheets/new_design/procedure_champs_editor.scss +++ b/app/assets/stylesheets/new_design/procedure_champs_editor.scss @@ -1,15 +1,8 @@ @import "colors"; @import "constants"; -#champs-editor { - .spinner { - margin-right: auto; - margin-left: auto; - margin-top: 80px; - } -} - -.draggable-item { +.type-de-champ { + background-color: $white; border: 1px solid $border-grey; border-radius: 5px; margin-bottom: 10px; @@ -18,24 +11,11 @@ .handle { cursor: ns-resize; margin-right: 10px; - margin-top: 8px; } - .error-message { - text-align: center; - flex-grow: 1; - font-size: 14px; - color: $light-grey; - display: flex; - align-items: center; - flex-direction: column; - justify-content: space-around; - - .content { - background-color: $medium-red; - border-radius: 8px; - padding: 4px 10px; - } + .move { + margin-right: 10px; + margin-bottom: 5px; } &.type-header-section { @@ -46,12 +26,6 @@ } } - &:not(.type-header-section) { - input.error { - border: 1px solid $medium-red; - } - } - .flex { &.section { padding: 10px 10px 0 10px; @@ -67,7 +41,7 @@ } &.shift-left { - margin-left: 35px; + margin-left: 55px; } &.head { @@ -112,21 +86,23 @@ } } -.footer { - margin-bottom: 70px; -} +.champs-editor { + .footer { + margin-bottom: 40px; + } -.buttons { - display: flex; - justify-content: space-between; - margin: 0px; - position: fixed; - bottom: 0px; - background-color: $white; - max-width: $page-width; - width: 100%; - border: 1px solid $border-grey; - padding: 10px; - border-top-left-radius: 5px; - border-top-right-radius: 5px; + .buttons { + display: flex; + justify-content: space-between; + margin: 0px; + position: fixed; + bottom: 0px; + background-color: $white; + max-width: $page-width; + width: 100%; + border: 1px solid $border-grey; + padding: 10px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + } } diff --git a/app/javascript/components/TypesDeChampEditor/Flash.js b/app/javascript/components/TypesDeChampEditor/Flash.js new file mode 100644 index 000000000..945c6efd8 --- /dev/null +++ b/app/javascript/components/TypesDeChampEditor/Flash.js @@ -0,0 +1,35 @@ +export default class Flash { + constructor(isAnnotation) { + this.element = document.querySelector('#flash_messages'); + this.isAnnotation = isAnnotation; + } + success() { + if (this.isAnnotation) { + this.add('Annotations privées enregistrées.'); + } else { + this.add('Formulaire enregistré.'); + } + } + error(message) { + this.add(message, true); + } + clear() { + this.element.innerHTML = ''; + } + add(message, isError) { + const html = `
+
+ ${message} +
+
`; + + this.element.innerHTML = html; + + clearTimeout(this.timeout); + this.timeout = setTimeout(() => { + this.clear(); + }, 4000); + } +} diff --git a/app/javascript/components/TypesDeChampEditor/OperationsQueue.js b/app/javascript/components/TypesDeChampEditor/OperationsQueue.js new file mode 100644 index 000000000..f849e64bc --- /dev/null +++ b/app/javascript/components/TypesDeChampEditor/OperationsQueue.js @@ -0,0 +1,52 @@ +import { to, getJSON } from '@utils'; + +export default class OperationsQueue { + constructor(baseUrl) { + this.queue = []; + this.isRunning = false; + this.baseUrl = baseUrl; + } + + async run() { + if (this.queue.length > 0) { + this.isRunning = true; + const operation = this.queue.shift(); + await this.exec(operation); + this.run(); + } else { + this.isRunning = false; + } + } + + enqueue(operation) { + return new Promise((resolve, reject) => { + this.queue.push({ ...operation, resolve, reject }); + if (!this.isRunning) { + this.run(); + } + }); + } + + async exec(operation) { + const { path, method, payload, resolve, reject } = operation; + const url = `${this.baseUrl}${path}`; + const [data, xhr] = await to(getJSON(url, payload, method)); + + if (xhr) { + handleError(xhr, reject); + } else { + resolve(data); + } + } +} + +function handleError(xhr, reject) { + try { + const { + errors: [message] + } = JSON.parse(xhr.responseText); + reject(message); + } catch (e) { + reject(xhr.responseText); + } +} diff --git a/app/javascript/components/TypesDeChampEditor/components/DescriptionInput.js b/app/javascript/components/TypesDeChampEditor/components/DescriptionInput.js new file mode 100644 index 000000000..2d17f752c --- /dev/null +++ b/app/javascript/components/TypesDeChampEditor/components/DescriptionInput.js @@ -0,0 +1,29 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +function DescriptionInput({ isVisible, handler }) { + if (isVisible) { + return ( +
+ +