From 406202ddc4b0abea53d4608adbd293eb690d0efa Mon Sep 17 00:00:00 2001 From: Teddy Cornaut Date: Fri, 28 Aug 2020 16:00:36 +0200 Subject: [PATCH 1/6] =?UTF-8?q?Permettre=20de=20g=C3=A9rer=20les=20options?= =?UTF-8?q?=20propos=C3=A9es=20dans=20un=20DAD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package-lock.json | 2 +- .../DecisionSupportFilePage.tsx | 6 + .../OptionsSection.tsx | 145 +++++++++++++++++- client/src/util/uuid.ts | 53 +++++++ package-lock.json | 27 ++++ 5 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 client/src/util/uuid.ts create mode 100644 package-lock.json diff --git a/client/package-lock.json b/client/package-lock.json index 8552a0f..ad051a6 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,5 +1,5 @@ { - "name": "dadd-", + "name": "daddy", "version": "0.0.0", "lockfileVersion": 1, "requires": true, diff --git a/client/src/components/DecisionSupportFilePage/DecisionSupportFilePage.tsx b/client/src/components/DecisionSupportFilePage/DecisionSupportFilePage.tsx index 3af2a01..84da55f 100644 --- a/client/src/components/DecisionSupportFilePage/DecisionSupportFilePage.tsx +++ b/client/src/components/DecisionSupportFilePage/DecisionSupportFilePage.tsx @@ -8,6 +8,7 @@ import { useParams, useHistory } from 'react-router'; import { useDecisionSupportFiles } from '../../gql/queries/dsf'; import { useCreateDecisionSupportFileMutation, useUpdateDecisionSupportFileMutation } from '../../gql/mutations/dsf'; import { useDebounce } from '../../hooks/useDebounce'; +import { OptionsSection } from './OptionsSection'; export interface DecisionSupportFilePageProps { @@ -143,6 +144,11 @@ export const DecisionSupportFilePage: FunctionComponent : null } + { + state.selectedTabIndex === 1 ? + : + null + }
diff --git a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx index bd537cd..80bd5ed 100644 --- a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx +++ b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx @@ -1,16 +1,147 @@ -import React, { FunctionComponent, useState } from 'react'; -import { DecisionSupportFile } from '../../types/decision'; +import React, { FunctionComponent, useState, useEffect, ChangeEvent, MouseEvent } from 'react'; +import { DecisionSupportFileUpdaterProps } from './DecisionSupportFileUpdaterProps'; +import { base58UUID } from "../../util/uuid"; -export interface OptionsSectionProps { - dsf: DecisionSupportFile, -}; +export interface OptionsSectionProps extends DecisionSupportFileUpdaterProps {}; + +const OptionsSectionName = 'options'; + +export const OptionsSection: FunctionComponent = ({ dsf, updateDSF }) => { + interface OptionsSectionState { + changed: boolean + section: OptionsSection + } + + interface OptionsSection { + options: Option[] + } + + interface Option { + id: string + label: string + pros: string + cons: string + } + + const [ state, setState ] = useState({ + changed: false, + section: { + options: [], + } + }); + + useEffect(() => { + if (!state.changed) return; + updateDSF({ ...dsf, sections: { ...dsf.sections, [OptionsSectionName]: { ...state.section }} }) + setState(state => ({ ...state, changed: false })); + }, [state.changed]); + + useEffect(() => { + if (!dsf.sections[OptionsSectionName]) return; + setState(state => ({ ...state, changed: false, section: {...state.section, ...dsf.sections[OptionsSectionName] }})); + }, [dsf.sections[OptionsSectionName]]); + + function newOption(label: string, pros: string, cons: string): Option { + return { + id: base58UUID(), + label, + pros, + cons + }; + } + + const onAddOptionClick = (evt: MouseEvent) => { + const option = newOption("Décision", "", ""); + setState(state => ({ ...state, changed: true, section: { ...state.section, options: [ ...state.section.options, option ] }})); + }; + + const onOptionChange = (id: string, attrName: string, evt: ChangeEvent) => { + const target = evt.currentTarget; + const value = target.hasOwnProperty('checked') ? target.checked : target.value; + var options = state.section.options; + options[id][attrName] = value; + setState(state => ({ ...state, changed: true, section: { ...state.section, options: options }})); + }; -export const OptionsSection: FunctionComponent = ({ dsf }) => { return (

Explorer les options

- +
+ + + + + + + + + + + { + state.section.options.map((o, index) => { + return ( + + + + + + + ) + }) + } + { + state.section.options.length === 0 ? + + + + : + null + } + + + + + + + +
DécisionPoursContres
+ + + + + + + +
Aucune option pour l'instant.
+ +
+
); diff --git a/client/src/util/uuid.ts b/client/src/util/uuid.ts new file mode 100644 index 0000000..9cf8c09 --- /dev/null +++ b/client/src/util/uuid.ts @@ -0,0 +1,53 @@ +import bs58 from 'bs58'; + +const hex: string[] = []; + +for (var i = 0; i < 256; i++) { + hex[i] = (i < 16 ? '0' : '') + (i).toString(16); +} + +export function uuidV4(): string { + const r = crypto.getRandomValues(new Uint8Array(16)); + + r[6] = r[6] & 0x0f | 0x40; + r[8] = r[8] & 0x3f | 0x80; + + return ( + hex[r[0]] + + hex[r[1]] + + hex[r[2]] + + hex[r[3]] + + "-" + + hex[r[4]] + + hex[r[5]] + + "-" + + hex[r[6]] + + hex[r[7]] + + "-" + + hex[r[8]] + + hex[r[9]] + + "-" + + hex[r[10]] + + hex[r[11]] + + hex[r[12]] + + hex[r[13]] + + hex[r[14]] + + hex[r[15]] + ); +} + +export function toUTF8Bytes(str: string): number[] { + var utf8 = unescape(encodeURIComponent(str)); + + var arr: number[] = []; + for (var i = 0; i < utf8.length; i++) { + arr.push(utf8.charCodeAt(i)); + } + + return arr +} + +export function base58UUID(): string { + const uuid = uuidV4(); + return bs58.encode(toUTF8Bytes(uuid)); +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3a41205 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } +} From 2d66888ed35d2ebadc71b378e72cc6f087d71501 Mon Sep 17 00:00:00 2001 From: Teddy Cornaut Date: Mon, 31 Aug 2020 12:55:33 +0200 Subject: [PATCH 2/6] Modification des options OK --- .../DecisionSupportFilePage/OptionsSection.tsx | 10 ++++++---- client/src/gql/queries/dsf.tsx | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx index 80bd5ed..766eb0f 100644 --- a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx +++ b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx @@ -51,16 +51,18 @@ export const OptionsSection: FunctionComponent = ({ dsf, up } const onAddOptionClick = (evt: MouseEvent) => { - const option = newOption("Décision", "", ""); - setState(state => ({ ...state, changed: true, section: { ...state.section, options: [ ...state.section.options, option ] }})); + var options = JSON.parse(JSON.stringify(state.section.options)) + var option = newOption("Décision", "", ""); + options.push(option); + setState(state => ({ ...state, changed: true, section: { ...state.section, options }})); }; const onOptionChange = (id: string, attrName: string, evt: ChangeEvent) => { const target = evt.currentTarget; const value = target.hasOwnProperty('checked') ? target.checked : target.value; - var options = state.section.options; + var options = JSON.parse(JSON.stringify(state.section.options)) options[id][attrName] = value; - setState(state => ({ ...state, changed: true, section: { ...state.section, options: options }})); + setState(state => ({ ...state, changed: true, section: { ...state.section, options }})); }; return ( diff --git a/client/src/gql/queries/dsf.tsx b/client/src/gql/queries/dsf.tsx index 2155aa6..e41b5fc 100644 --- a/client/src/gql/queries/dsf.tsx +++ b/client/src/gql/queries/dsf.tsx @@ -7,7 +7,7 @@ export const QUERY_DECISION_SUPPORT_FILES = gql` decisionSupportFiles(filter: $filter) { id, title, - sections + sections, createdAt, closedAt, votedAt, @@ -18,7 +18,7 @@ export const QUERY_DECISION_SUPPORT_FILES = gql` members { id } - } + }, } } `; From 089d91a84c4f4f52a0960b2e00f5c2606a5badc2 Mon Sep 17 00:00:00 2001 From: Teddy Cornaut Date: Mon, 31 Aug 2020 13:18:39 +0200 Subject: [PATCH 3/6] Suppression des options OK + CSS --- .../OptionsSection.tsx | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx index 766eb0f..a87e4a7 100644 --- a/client/src/components/DecisionSupportFilePage/OptionsSection.tsx +++ b/client/src/components/DecisionSupportFilePage/OptionsSection.tsx @@ -65,6 +65,14 @@ export const OptionsSection: FunctionComponent = ({ dsf, up setState(state => ({ ...state, changed: true, section: { ...state.section, options }})); }; + const onRemoveOptionClick = (id: string, evt: MouseEvent) => { + if(confirm('Voulez-vous supprimer cette option ?')){ + var options = JSON.parse(JSON.stringify(state.section.options)) + options.splice(id, 1); + setState(state => ({ ...state, changed: true, section: { ...state.section, options }})); + } + }; + return (

Explorer les options

@@ -86,7 +94,7 @@ export const OptionsSection: FunctionComponent = ({ dsf, up @@ -100,7 +108,7 @@ export const OptionsSection: FunctionComponent = ({ dsf, up - -