WIP ⚙️ implémentation du retour en arrière (brut visuellement)

Reste : corriger le fix dans reducers

Bonus : brouillons d'icônes
pull/6/head
Mael Thomas 2017-03-22 18:18:37 +01:00
parent d0da37db5c
commit 092947a145
8 changed files with 457 additions and 156 deletions

87
finsvg.svg Normal file
View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="finsvg.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="295.97165"
inkscape:cy="571.35343"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:0;fill-rule:nonzero;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4136"
width="557.06598"
height="344.28571"
x="90"
y="308.07648" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.3871851;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 155.20364,307.27204 352.90158,145.51919 578.15741,304.87571"
id="path4140"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:8.3871851;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path4148"
cx="352.90158"
cy="145.51918"
r="23.963387" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="162.85715"
y="569.50507"
id="text4150"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4152"
x="162.85715"
y="569.50507"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:250px;font-family:msbm10;-inkscape-font-specification:msbm10">FIN</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

203
icônes-CDD.svg Normal file
View File

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg4166"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="icônes-CDD.svg">
<defs
id="defs4168" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="222.37121"
inkscape:cy="329.39132"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata4171">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:10.3946209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4714"
width="575.48065"
height="176.74823"
x="21.464886"
y="86.84523" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 205.67544,154.64744 210.26673,0"
id="path4716"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 153.54319,183.32017 263.26786,0"
id="path4718"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:87.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="520.22858"
y="183.63103"
id="text4724"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4726"
x="520.22858"
y="183.63103"
style="font-size:50px">€</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="478.81232"
y="163.42796"
id="text4728"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4730"
x="478.81232"
y="163.42796" /></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 474.7717,244.24018 c 31.31473,-20.20306 59.599,-38.3858 53.53809,-17.1726 -6.06092,21.21321 35.35534,6.06092 35.35534,6.06092"
id="path4732"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 130.30968,528.09304 c 32.32488,-19.1929 61.6783,-24.56623 178.797,-28.28428 63.63961,-2.0203 88.38835,-12.6269 88.38835,-12.6269"
id="path4755"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<g
transform="matrix(1.7389448,0,0,1.7389448,237.04228,351.03091)"
id="g4">
<path
style="fill:#000000"
inkscape:connector-curvature="0"
d="m 74.97,45.051 c 3.928,0.775 6.896,2.735 7.001,4.52 C 83.465,33.237 72.374,18.072 55.869,14.811 39.362,11.55 23.337,21.357 18.508,37.032 c 0.775,-1.612 4.267,-2.294 8.193,-1.519 4.228,0.835 7.351,3.041 6.979,4.927 0.373,-1.886 4.364,-2.686 8.915,-1.787 4.552,0.9 7.939,3.157 7.567,5.043 0.373,-1.886 4.364,-2.685 8.914,-1.787 4.554,0.899 7.939,3.158 7.568,5.043 0.371,-1.885 4.099,-2.737 8.326,-1.901 z"
id="path6" />
<polygon
style="fill:#000000"
points="51.331,41.31 42.67,85.143 41.402,86.638 40.799,84.773 49.459,40.94 "
id="polygon8" />
</g>
<g
id="g4790"
transform="translate(-10,5)">
<path
inkscape:connector-curvature="0"
id="path4771"
d="m 222.23356,482.63617 108.08632,-8.08122 36.36549,-29.29443"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4773"
d="m 250,480.93363 -5.1978,19.39847"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4773-3"
d="m 296.73836,478.27687 4.38042,19.59923"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 5.4314649,517.38856 C 19.894644,500.38015 53.55256,494.39958 72.243237,494.78475 c 18.690678,0.38517 31.590923,16.1695 46.221523,16.86681 14.63061,0.69731 27.35758,-14.60867 39.46566,-14.03158 7.12056,0.33938 17.61353,4.41922 22.0853,6.84295 8.75475,4.74514 -12.68938,5.64463 -37.17939,18.28112 -13.21823,6.82042 -91.943091,84.09988 -91.943091,84.09988"
id="path4795"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssc" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="729.33014"
y="709.92047"
id="text5346"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5348"
x="729.33014"
y="709.92047">https://thenounproject.com/search/?q=job+search&amp;i=873829</tspan></text>
<path
inkscape:connector-curvature="0"
d="m 383.92066,784.656 -12.41,-12.41 c 13.289,-18.911 8.731,-45.014 -10.18,-58.303 -18.911,-13.289 -45.014,-8.731 -58.303,10.18 -13.289,18.911 -8.731,45.014 10.18,58.303 14.437,10.145 33.686,10.145 48.123,0 l 12.41,12.41 c 2.011,2.009 5.269,2.009 7.28,0 l 2.89,-2.89 c 2.016,-2.007 2.023,-5.267 0.017,-7.283 -0.003,-0.003 -0.005,-0.005 -0.007,-0.007 z m -69.11,-14 c -12.407,-12.407 -12.407,-32.523 0,-44.93 12.407,-12.407 32.523,-12.407 44.93,0 12.407,12.407 12.407,32.522 0,44.929 -12.416,12.386 -32.514,12.386 -44.93,10e-4 z"
id="path4" />
<path
inkscape:connector-curvature="0"
d="m 355.21066,737.696 -8.92,0 0,-2.51 c 0,-2.066 -1.674,-3.74 -3.74,-3.74 l 0,0 -10.12,0 c -2.066,0 -3.74,1.674 -3.74,3.74 l 0,0 0,2.51 -9.34,0 c -1.613,0 -2.92,1.307 -2.92,2.92 l 0,0 0,19.67 c 0,1.613 1.307,2.92 2.92,2.92 l 0,0 35.86,0 c 1.613,0 2.92,-1.307 2.92,-2.92 l 0,-19.67 c 0,-1.613 -1.307,-2.92 -2.92,-2.92 z m -23.1,-2.51 c 0,-0.166 0.134,-0.3 0.3,-0.3 l 10.14,0 c 0.166,0 0.3,0.134 0.3,0.3 l 0,2.51 -10.74,0 0,-2.51 z"
id="path6-6" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="753.57379"
y="172.51933"
id="text5358"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5360"
x="753.57379"
y="172.51933"
style="font-size:25px">+ FUSÉE ?</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="370.72598"
y="719.01184"
id="text5364"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5366"
x="370.72598"
y="719.01184"
style="font-size:62.5px">+</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="591.9494"
y="895.78857"
id="text4715"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4717"
x="591.9494"
y="895.78857">https://thenounproject.com/search/?q=lesson&amp;i=118285</tspan></text>
<path
inkscape:connector-curvature="0"
d="m 64.058704,916.78877 c -0.599,0 -1.087,-0.486 -1.087,-1.086 l 0,-19.682 c 0,-0.148 -0.121,-0.271 -0.271,-0.271 l -3.141,0 c -0.133,0 -0.246,0.096 -0.269,0.229 l -3.318,19.902 c -0.087,0.527 -0.538,0.908 -1.072,0.908 l -4.187,0 c -0.314,0 -0.613,-0.137 -0.82,-0.375 -0.207,-0.238 -0.3,-0.553 -0.256,-0.865 l 3.491,-24.449 0.003,-12.611 c 0,-0.149 -0.121,-0.272 -0.271,-0.272 l -0.788,0 c -0.15,0 -0.272,0.123 -0.272,0.272 l 0,9.164 c 0,0.598 -0.487,1.086 -1.087,1.086 l -4.186,0 c -0.6,0 -1.087,-0.488 -1.087,-1.086 l 0,-10.523 c 0,-4.467 3.633,-8.101 8.1,-8.101 l 6.332,0 c 0.15,0 0.272,-0.122 0.272,-0.272 l 0,-0.91 c 0,-0.133 -0.097,-0.246 -0.228,-0.268 -3.931,-0.646 -6.783,-4.004 -6.783,-7.982 0,-3.978 2.853,-7.336 6.783,-7.983 0.131,-0.021 0.228,-0.135 0.228,-0.268 l 0,-5.775 c 0,-0.599 0.487,-1.087 1.087,-1.087 l 53.864996,0 c 0.6,0 1.087,0.488 1.087,1.087 l 0,28.055 c 0,0.599 -0.487,1.087 -1.087,1.087 l -35.688996,0 c -0.045,0 -0.09,0.011 -0.129,0.033 l -2.398,1.3 c -0.158,0.086 -0.338,0.131 -0.518,0.131 l -6.758,0 c -0.15,0 -0.271,0.122 -0.271,0.272 l 0,39.254 c 0,0.6 -0.488,1.086 -1.088,1.086 l -4.187,0 z m 0,-23.213 c 0.6,0 1.087,0.488 1.087,1.088 l 0,19.68 c 0,0.15 0.122,0.271 0.272,0.271 l 1.469,0 c 0.15,0 0.272,-0.121 0.272,-0.271 l 0,-39.255 c 0,-0.599 0.487,-1.086 1.086,-1.086 l 7.772,0 c 0.045,0 0.089,-0.012 0.129,-0.033 l 5.469,-2.787 c 0.111,-0.06 0.166,-0.188 0.133,-0.311 l -1.07,-2.217 c -0.021,-0.08 -0.079,-0.146 -0.155,-0.179 -0.034,-0.015 -0.07,-0.021 -0.106,-0.021 -0.045,0 -0.089,0.011 -0.13,0.033 l -4.767,2.583 c -0.158,0.087 -0.337,0.132 -0.519,0.132 l -21.46,0 c -3.268,0 -5.926,2.659 -5.926,5.927 l 0,9.163 c 0,0.15 0.121,0.271 0.271,0.271 l 1.469,0 c 0.149,0 0.271,-0.121 0.271,-0.271 l 0,-9.163 c 0,-0.6 0.488,-1.087 1.087,-1.087 l 3.506,0 c 0.6,0 1.087,0.487 1.087,1.087 l 0,14.026 c 0,0.051 -0.003,0.104 -0.01,0.152 l -3.283,22.996 c -0.012,0.078 0.012,0.158 0.063,0.217 0.051,0.061 0.126,0.094 0.205,0.094 l 1.468,0 c 0.133,0 0.246,-0.096 0.269,-0.227 l 3.319,-19.904 c 0.088,-0.525 0.538,-0.908 1.072,-0.908 l 5.65,0 z m 31.653,-33.949 c -0.047,0 -0.094,0.013 -0.136,0.036 l -12.146,7.014 c -0.131,0.074 -0.175,0.241 -0.1,0.371 l 1.298,2.222 c 0.036,0.062 0.096,0.108 0.165,0.127 0.023,0.006 0.047,0.009 0.07,0.009 0.047,0 0.095,-0.012 0.137,-0.036 l 12.207,-6.881 c 0.13,-0.075 0.174,-0.241 0.1,-0.371 l -1.359,-2.354 c -0.036,-0.062 -0.096,-0.108 -0.165,-0.127 -0.024,-0.007 -0.047,-0.01 -0.071,-0.01 z m -34.478,-5.956 c -3.268,0 -5.926,2.658 -5.926,5.926 0,3.267 2.658,5.926 5.926,5.926 3.268,0 5.926,-2.659 5.926,-5.926 0,-3.268 -2.658,-5.926 -5.926,-5.926 z"
id="path4-3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -2,8 +2,8 @@
// The state keeps track of which of them have been submitted
// The user can also come back to one of his answers and edit it
export const STEP_ACTION = 'STEP_ACTION'
export function stepAction(name, newState) {
return {type: STEP_ACTION, name, newState}
export function stepAction(name, step) {
return {type: STEP_ACTION, name, step}
}
export const START_CONVERSATION = 'START_CONVERSATION'

View File

@ -14,7 +14,8 @@ let situationSelector = formValueSelector('conversation')
@connect(
state => ({
situation: variableName => situationSelector(state, variableName),
steps: state.submittedSteps.concat(state.steps),
foldedSteps: state.foldedSteps,
unfoldedSteps: state.unfoldedSteps,
themeColours: state.themeColours,
analysedSituation: state.analysedSituation,
}),
@ -28,12 +29,22 @@ export default class CDD extends Component {
this.props.startConversation()
}
render() {
let {steps, situation} = this.props
let {foldedSteps, unfoldedSteps, situation} = this.props
let conversation = steps.map(step => (
<step.component key={step.name} {...step} step={step} answer={situation(step.name)}/>
let conversation = foldedSteps.map(step => <step.component
key={step.name}
{...step}
step={step}
answer={situation(step.name)} />
).concat(unfoldedSteps.map(step => <step.component
key={step.name}
{...step}
step={step}
unfolded={true}
answer={situation(step.name)} />
))
return (
<div id="sim">
<PageTypeIcon type="simulation" />

View File

@ -19,7 +19,7 @@ export var FormDecorator = formType => RenderField =>
themeColours: state.themeColours
}),
dispatch => ({
stepAction: (name, newState) => dispatch(stepAction(name, newState)),
stepAction: (name, step) => dispatch(stepAction(name, step)),
setFormValue: (field, value) => dispatch(change('conversation', field, value)),
pointOutObjectives: objectives => dispatch({type: POINT_OUT_OBJECTIVES, objectives})
})
@ -33,11 +33,13 @@ export var FormDecorator = formType => RenderField =>
stepAction,
themeColours,
setFormValue,
pointOutObjectives
pointOutObjectives,
/* Une étape déjà répondue est marquée 'folded'. Dans ce dernier cas, un résumé
de la réponse est affiché */
unfolded
} = this.props,
{
name,
visible,
possibleChoice, // should be found in the question set theoritically, but it is used for a single choice question -> the question itself is dynamic and cannot be input as code,
// formerly in conversation-steps
valueType,
@ -48,20 +50,10 @@ export var FormDecorator = formType => RenderField =>
helpText,
suggestions,
subquestion,
objectives
objectives,
} = this.props.step
this.step = this.props.step
/* La saisie peut être cachée car ce n'est pas encore son tour,
ou parce qu'elle a déjà été remplie. Dans ce dernier cas, un résumé
de la réponse est affiché */
let stepState = this.step.state,
completed = stepState && stepState != 'editing',
unfolded = !completed
if (!visible) return null
/* Nos propriétés personnalisées à envoyer au RenderField.
Elles sont regroupées dans un objet précis pour pouvoir être enlevées des
props passées à ce dernier, car React 15.2 n'aime pas les attributes inconnus
@ -73,7 +65,7 @@ export var FormDecorator = formType => RenderField =>
optionsURL, /* Select component's data source */
possibleChoice, /* RhetoricalQuestion component's only choice :'-( */
//TODO hack, enables redux-form/CHANGE to update the form state before the traverse functions are run
submit: () => setTimeout(() => stepAction(name, 'filled'), 1),
submit: () => setTimeout(() => stepAction('fold', name), 1),
setFormValue: value => setFormValue(name, value),
valueType,
suggestions,
@ -85,7 +77,7 @@ export var FormDecorator = formType => RenderField =>
return (
<div
className={classNames({step: unfolded, fact: completed}, formType)}
className={classNames({step: unfolded}, formType)}
onMouseOver={() => pointOutObjectives(objectives)}
onMouseOut={() => pointOutObjectives([])}>
{this.state.helpVisible && this.renderHelpBox(helpText)}
@ -142,9 +134,8 @@ export var FormDecorator = formType => RenderField =>
<span>
<span className="title">{this.props.step.title}</span>
<span className="answer">{answer}
<span className="edit">
<span className="edit" onClick={() => stepAction('unfold', name)}>
<i
onClick={() => stepAction(name, 'editing')}
className="fa fa-pencil-square-o"
aria-hidden="true">
</i>

View File

@ -11,7 +11,6 @@ export let constructStepMeta = ({titre, question, subquestion, dottedName, name}
lightBackground={true}
/>,
title: titre || name,
dependencyOfVariables: ['chai pas'],
subquestion,
// Legacy properties :

View File

@ -128,7 +128,7 @@ let collectNodeMissingVariables = target => (root, source=root, results=[]) => {
}
export let collectMissingVariables = (groupMethod='groupByMissingVariable', analysedSituation) =>
export let collectMissingVariables = (groupMethod='groupByMissingVariable') => analysedSituation =>
R.pipe(
R.unless(R.is(Array), R.of),
R.chain( v =>

View File

@ -43,6 +43,143 @@ function pointedOutObjectives(state=[], {type, objectives}) {
}
}
let handleSteps = (state, action) => {
let returnObject = {
...state,
analysedSituation: analyse(state)
}
if (action.type == START_CONVERSATION) {
return {
...returnObject,
unfoldedSteps: buildNextSteps(returnObject.analysedSituation)
}
}
if (action.type == STEP_ACTION && action.name == 'fold') {
return {
...returnObject,
foldedSteps: [...state.foldedSteps, R.head(state.unfoldedSteps)],
unfoldedSteps: buildNextSteps(returnObject.analysedSituation)
}
}
if (action.type == STEP_ACTION && action.name == 'unfold') {
let stepFinder = R.propEq('name', action.step),
foldedSteps = R.pipe(
R.splitWhen(stepFinder),
R.head
)(state.foldedSteps)
console.log('foldedSteps', foldedSteps)
return {
...returnObject,
foldedSteps,
unfoldedSteps: [R.find(stepFinder)(state.foldedSteps)]
}
}
return state
}
let analyse = R.pipe(
situationGate,
// une liste des objectifs de la simulation (des 'rules' aussi nommées 'variables')
analyseSituation
)
let missingVariables
let buildNextSteps = R.pipe(
/*
on collecte les variables manquantes : celles qui sont nécessaires pour
remplir les objectifs de la simulation (calculer des cotisations) mais qui n'ont pas
encore été renseignées
TODO perf : peut-on le faire en même temps que l'on traverse l'AST ?
Oui sûrement, cette liste se complète en remontant l'arbre. En fait, on le fait déjà pour nodeValue,
et quand nodeValue vaut null, c'est qu'il y a des missingVariables ! Il suffit donc de remplacer les
null par un tableau, et d'ailleurs utiliser des fonction d'aide pour mutualiser ces tests.
missingVariables: {variable: [objectives]}
*/
R.path(['formule', 'explanation', 'explanation']),
analysedSituation => {
//TODO temporary fix
missingVariables = collectMissingVariables('groupByMissingVariable')(analysedSituation)
return missingVariables
},
R.keys,
/*
Certaines variables manquantes peuvent être factorisées dans des groupes.
Par exemple, au lieu de :
q1: "Pensez vous porlonger le CDD en CDI",
r1: Oui | Non
q2: "Pensez-vous qu'une rupture pour faute grave est susceptible d'arriver"
r2: Oui | Non
on préfère :
q: "Pensez-vous être confronté à l'un de ces événements ?"
r: Prolongation du CDD en CDI | Rupture pour faute grave
*/
R.groupBy(parentName),
// on va maintenant construire la liste des composants React qui afficheront les questions à l'utilisateur pour que l'on obtienne les variables manquantes
R.pipe(
R.mapObjIndexed((variables, group) =>
R.pipe(
findGroup,
R.cond([
// Pas de groupe trouvé : ce sont des variables individuelles
[R.isNil, () => variables.map(dottedName => {
let rule = findRuleByDottedName(dottedName)
return Object.assign(constructStepMeta(rule),
rule.format == 'nombre positif' ||
rule.format == 'période' ?
{
component: Input,
valueType: rule.format == 'nombre positif' ? euro : months,
attributes: {
inputMode: 'numeric',
placeholder: 'votre réponse'
},
suggestions: rule.suggestions
} : {
component: Question,
choices: [
{value: 'non', label: 'Non'},
{value: 'oui', label: 'Oui'}
]
},
{
objectives: missingVariables[dottedName]
}
)})],
[R.T, group => do {
let possibilities = group['une possibilité']
Object.assign(
constructStepMeta(group),
{
component: Question,
choices:
possibilities.concat(
group['langue au chat possible'] === 'oui' ?
[{value: '_', label: 'Aucun'}] : []
)
},
{
objectives: R.pipe(
R.chain(v => missingVariables[group.dottedName + ' . ' + v]),
R.uniq()
)(possibilities)
}
)}]
])
)(group)
),
R.values,
R.unnest
)
)
export default reduceReducers(
combineReducers({
// this is handled by redux-form, pas touche !
@ -50,9 +187,9 @@ export default reduceReducers(
/* Have forms been filled or ignored ?
false means the user is reconsidering its previous input */
steps: (steps=[]) => steps,
foldedSteps: (steps=[]) => steps,
unfoldedSteps: (steps=[]) => steps,
submittedSteps: (steps=[]) => steps,
analysedSituation: (state = []) => state,
@ -63,132 +200,5 @@ export default reduceReducers(
pointedOutObjectives
}),
// cross-cutting concerns because here `state` is the whole state tree
(state, action) => {
if (action.type == STEP_ACTION || action.type == START_CONVERSATION) {
// pour débugguer :
window.situationGate = situationGate(state)
let newlySubmittedSteps =
action.newState == 'filled'
? [{
...state.steps.find(s => s.name === action.name),
state: 'filled'
}]
: []
// on calcule la prochaine étape, à ajouter sur la pile
let
// une liste des objectifs de la simulation (des 'rules' aussi nommées 'variables')
analysedSituation = analyseSituation(
situationGate(state)
),
// y = console.log('analysedSituation',analysedSituation),
/*
on collecte les variables manquantes : celles qui sont nécessaires pour
remplir les objectifs de la simulation (calculer des cotisations) mais qui n'ont pas
encore été renseignées
TODO perf : peut-on le faire en même temps que l'on traverse l'AST ?
Oui sûrement, cette liste se complète en remontant l'arbre. En fait, on le fait déjà pour nodeValue,
et quand nodeValue vaut null, c'est qu'il y a des missingVariables ! Il suffit donc de remplacer les
null par un tableau, et d'ailleurs utiliser des fonction d'aide pour mutualiser ces tests.
missingVariables: {variable: [objectives]}
*/
missingVariables = collectMissingVariables('groupByMissingVariable', R.path(['formule', 'explanation', 'explanation'])(analysedSituation)),
// yy = console.log('missingVariables',missingVariables),
missingVariablesList = R.keys(missingVariables),
/*
Certaines variables manquantes peuvent être factorisées dans des groupes.
Par exemple, au lieu de :
q1: "Pensez vous porlonger le CDD en CDI",
r1: Oui | Non
q2: "Pensez-vous qu'une rupture pour faute grave est susceptible d'arriver"
r2: Oui | Non
on préfère :
q: "Pensez-vous être confronté à l'un de ces événements ?"
r: Prolongation du CDD en CDI | Rupture pour faute grave
*/
groups = R.groupBy(
parentName
)(missingVariablesList),
// on va maintenant construire la liste des composants React qui afficheront les questions à l'utilisateur pour que l'on obtienne les variables manquantes
steps = R.pipe(
R.mapObjIndexed((variables, group) =>
R.pipe(
findGroup,
R.cond([
// Pas de groupe trouvé : ce sont des variables individuelles
[R.isNil, () => variables.map(dottedName => {
let rule = findRuleByDottedName(dottedName)
return Object.assign(constructStepMeta(rule),
rule.format == 'nombre positif' ||
rule.format == 'période' ?
{
component: Input,
valueType: rule.format == 'nombre positif' ? euro : months,
attributes: {
inputMode: 'numeric',
placeholder: 'votre réponse'
},
suggestions: rule.suggestions
} : {
component: Question,
choices: [
{value: 'non', label: 'Non'},
{value: 'oui', label: 'Oui'}
]
},
{
objectives: missingVariables[dottedName]
}
)})],
[R.T, group => do {
let possibilities = group['une possibilité']
Object.assign(
constructStepMeta(group),
{
component: Question,
choices:
possibilities.concat(
group['langue au chat possible'] === 'oui' ?
[{value: '_', label: 'Aucun'}] : []
)
},
{
objectives: R.pipe(
R.chain(v => missingVariables[group.dottedName + ' . ' + v]),
R.uniq()
)(possibilities)
}
)}]
])
)(group)
),
R.values,
R.unnest
)(groups)
return {
...state,
steps,
submittedSteps: state.submittedSteps.concat(newlySubmittedSteps),
analysedSituation
}
} else {
return state
}
}
handleSteps
)