From 54e645f2523810f5f0c00cb35bfd0619b69955ba Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sun, 9 Feb 2020 20:44:59 +0000 Subject: [PATCH] Simple form working end-to-end --- src/EAFunds/EAFunds_Form.bs.js | 47 +---------- src/EAFunds/EAFunds_Form.re | 45 +++++------ src/EAFunds/EAFunds_Form2.re | 102 ++++++++++++----------- src/EAFunds/EAFunds_Model.bs.js | 139 +++++++++++++++----------------- src/EAFunds/EAFunds_Model.re | 55 ++++++------- src/Index.bs.js | 4 +- src/Index.re | 2 +- src/{Model.re => Modell.re} | 0 src/Params.re | 17 ---- src/Prop.re | 92 ++++++++++++++++++--- 10 files changed, 245 insertions(+), 258 deletions(-) rename src/{Model.re => Modell.re} (100%) delete mode 100644 src/Params.re diff --git a/src/EAFunds/EAFunds_Form.bs.js b/src/EAFunds/EAFunds_Form.bs.js index 4800201f..ae1b9f17 100644 --- a/src/EAFunds/EAFunds_Form.bs.js +++ b/src/EAFunds/EAFunds_Form.bs.js @@ -1,46 +1 @@ -'use strict'; - -var $$Array = require("bs-platform/lib/js/array.js"); -var Curry = require("bs-platform/lib/js/curry.js"); -var React = require("react"); -var Belt_Option = require("bs-platform/lib/js/belt_Option.js"); -var Belt_MapString = require("bs-platform/lib/js/belt_MapString.js"); -var Model$ProbExample = require("../Model.bs.js"); -var EAFunds_Model$ProbExample = require("./EAFunds_Model.bs.js"); - -function handleChange(handleChange$1, $$event) { - return Curry._1(handleChange$1, $$event.target.value); -} - -var model = EAFunds_Model$ProbExample.Interface.model; - -var initialMap = Model$ProbExample.toMaps(model); - -function EAFunds_Form(Props) { - var match = React.useState((function () { - return Model$ProbExample.toMaps(model); - })); - var params = match[0]; - return $$Array.map((function (parameter) { - var __x = Belt_MapString.get(params[/* inputs */1], parameter[/* id */0]); - var value = Belt_Option.flatMap(__x, (function (param) { - return param[1]; - })); - return React.createElement(React.Fragment, undefined, parameter[/* name */1], parameter[/* id */0], React.createElement(Model$ProbExample.Input.Form.make, { - parameter: parameter, - value: value, - onChange: (function (r) { - console.log(r); - return /* () */0; - }) - })); - }), $$Array.of_list(model[/* inputs */3])); -} - -var make = EAFunds_Form; - -exports.handleChange = handleChange; -exports.model = model; -exports.initialMap = initialMap; -exports.make = make; -/* initialMap Not a pure module */ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/EAFunds/EAFunds_Form.re b/src/EAFunds/EAFunds_Form.re index 383b5477..f9a5b153 100644 --- a/src/EAFunds/EAFunds_Form.re +++ b/src/EAFunds/EAFunds_Form.re @@ -1,24 +1,21 @@ -let model = EAFunds_Model.Interface.model; - -let handleChange = (handleChange, event) => - handleChange(ReactEvent.Form.target(event)##value); - -let model = EAFunds_Model.Interface.model; -let initialMap = Model.toMaps(model); - -[@react.component] -let make = () => { - let (params, changeParams) = React.useState(() => Model.toMaps(model)); - model.inputs - |> Array.of_list - |> Array.map((parameter: Model.Input.parameter) => { - let value = - params.inputs->Model.MS.get(parameter.id) - |> Belt.Option.flatMap(_, ((_, b)) => b); - <> - {parameter.name |> ReasonReact.string} - {parameter.id |> ReasonReact.string} - Js.log(r)} /> - ; - }); -}; \ No newline at end of file +// let model = EAFunds_Model.Interface.model; + // let handleChange = (handleChange, event) => + // handleChange(ReactEvent.Form.target(event)##value); + // let model = EAFunds_Model.Interface.model; + // let initialMap = Model.toMaps(model); + // [@react.component] + // let make = () => { + // let (params, changeParams) = React.useState(() => Model.toMaps(model)); + // model.inputs + // |> Array.of_list + // |> Array.map((parameter: Model.Input.parameter) => { + // let value = + // params.inputs->Model.MS.get(parameter.id) + // |> Belt.Option.flatMap(_, ((_, b)) => b); + // <> + // {parameter.name |> ReasonReact.string} + // {parameter.id |> ReasonReact.string} + // Js.log(r)} /> + // ; + // }); + /* }*/ \ No newline at end of file diff --git a/src/EAFunds/EAFunds_Form2.re b/src/EAFunds/EAFunds_Form2.re index 30c3f9ec..2f767614 100644 --- a/src/EAFunds/EAFunds_Form2.re +++ b/src/EAFunds/EAFunds_Form2.re @@ -1,52 +1,50 @@ -open EAFunds_Data; - -let handleChange = (handleChange, event) => - handleChange(ReactEvent.Form.target(event)##value); - -[@react.component] -let make = () => { - let (year, setYear) = React.useState(() => 2021.); - <> -

{"EA Funds Forecasting Model 0.1" |> ReasonReact.string}

- Js.Float.toString} - onChange={handleChange(r => - switch (Js.Float.fromString(r)) { - | r when r >= 2020.0 && r <= 2050.0 => setYear(_ => r) - | _ => () - } - )} - /> - - - - - - - - - - {funds - |> Belt.Array.map(_, r => - - - - - - ) - |> ReasonReact.array} - -
{"Fund Name" |> ReasonReact.string} {"Donations" |> ReasonReact.string} {"Payouts" |> ReasonReact.string}
- {r.name |> ReasonReact.string} - - {EAFunds_Model.go(r.group, year, DONATIONS) - |> Model.InputTypes.to_string - |> ReasonReact.string} - - {EAFunds_Model.go(r.group, year, PAYOUTS) - |> Model.InputTypes.to_string - |> ReasonReact.string} -
- ; -}; \ No newline at end of file +// open EAFunds_Data; + // let handleChange = (handleChange, event) => + // handleChange(ReactEvent.Form.target(event)##value); + // [@react.component] + // let make = () => { + // let (year, setYear) = React.useState(() => 2021.); + // <> + //

{"EA Funds Forecasting Model 0.1" |> ReasonReact.string}

+ // Js.Float.toString} + // onChange={handleChange(r => + // switch (Js.Float.fromString(r)) { + // | r when r >= 2020.0 && r <= 2050.0 => setYear(_ => r) + // | _ => () + // } + // )} + // /> + // + // + // + // + // + // + // + // + // + // {funds + // |> Belt.Array.map(_, r => + // + // + // + // + // + // ) + // |> ReasonReact.array} + // + //
{"Fund Name" |> ReasonReact.string} {"Donations" |> ReasonReact.string} {"Payouts" |> ReasonReact.string}
+ // {r.name |> ReasonReact.string} + // + // {EAFunds_Model.go(r.group, year, DONATIONS) + // |> Model.InputTypes.to_string + // |> ReasonReact.string} + // + // {EAFunds_Model.go(r.group, year, PAYOUTS) + // |> Model.InputTypes.to_string + // |> ReasonReact.string} + //
+ // ; + /* }*/ \ No newline at end of file diff --git a/src/EAFunds/EAFunds_Model.bs.js b/src/EAFunds/EAFunds_Model.bs.js index 3dd010eb..4cecfecf 100644 --- a/src/EAFunds/EAFunds_Model.bs.js +++ b/src/EAFunds/EAFunds_Model.bs.js @@ -1,8 +1,10 @@ 'use strict'; var Block = require("bs-platform/lib/js/block.js"); +var Curry = require("bs-platform/lib/js/curry.js"); +var React = require("react"); var Math$ProbExample = require("../Math.bs.js"); -var Model$ProbExample = require("../Model.bs.js"); +var Prop$ProbExample = require("../Prop.bs.js"); function yearDiff(year) { return year - 2020.0; @@ -66,46 +68,38 @@ var PayoutsIfAround = { }; function go(group, year, output) { - return /* FloatCdf */Block.__(3, [calculateDifference(currentValue(group, output), year, /* record */[ + return /* FloatCdf */Block.__(2, [calculateDifference(currentValue(group, output), year, /* record */[ /* meanDiff */1.1, /* stdDiff */1.1 ])]); } -var model_002 = /* assumptions : :: */[ - Model$ProbExample.Input.make("Yearly Growth Rate", /* FloatPoint */0, undefined, /* () */0), - /* :: */[ - Model$ProbExample.Input.currentYear, - /* [] */0 - ] -]; - -var model_003 = /* inputs : :: */[ - Model$ProbExample.Input.make("Fund", /* SingleChoice */Block.__(1, [/* record */[ +var model_002 = /* inputTypes : array */[ + Prop$ProbExample.TypeWithMetadata.make("Fund", /* SelectSingle */Block.__(0, [/* record */[ /* options : :: */[ - /* tuple */[ - "Animal Welfare Fund", - "animal" + /* record */[ + /* id */"animal", + /* name */"Animal Welfare Fund" ], /* :: */[ - /* tuple */[ - "Global Health Fund", - "globalHealth" + /* record */[ + /* id */"globalHealth", + /* name */"Global Health Fund" ], /* :: */[ - /* tuple */[ - "Long Term Future Fund", - "longTerm" + /* record */[ + /* id */"longTerm", + /* name */"Long Term Future Fund" ], /* :: */[ - /* tuple */[ - "Meta Fund", - "meta" + /* record */[ + /* id */"longterm", + /* name */"Meta Fund" ], /* :: */[ - /* tuple */[ - "All", - "all" + /* record */[ + /* id */"all", + /* name */"All" ], /* [] */0 ] @@ -114,32 +108,21 @@ var model_003 = /* inputs : :: */[ ] ], /* default */"total" - ]]), undefined, /* () */0), - /* :: */[ - Model$ProbExample.Input.make("Year", /* Year */Block.__(0, [/* record */[ - /* default */2030.0, - /* min */2020.0, - /* max */2050.0 - ]]), undefined, /* () */0), - /* [] */0 - ] + ]]), undefined, undefined, undefined, /* () */0), + Prop$ProbExample.TypeWithMetadata.make("Year", /* Year */Block.__(2, [/* record */[ + /* default */2030.0, + /* min */2020.0, + /* max */2050.0 + ]]), undefined, undefined, undefined, /* () */0) ]; -var model_004 = /* outputs : :: */[ - Model$ProbExample.Output.make("Payments", /* FloatCdf */2, undefined, /* () */0), - /* :: */[ - Model$ProbExample.Output.make("Payouts", /* FloatCdf */2, undefined, /* () */0), - /* [] */0 - ] -]; +var model_003 = /* outputTypes : array */[]; var model = /* record */[ /* name */"Calculate the payments and payouts of EA Funds based on existing data.", /* author */"George Harrison", model_002, - model_003, - model_004, - /* outputConfig : Single */0 + model_003 ]; function convertChoice(s) { @@ -158,48 +141,54 @@ function convertChoice(s) { } function run(p) { - var match = p[/* assumptions */0]; - var match$1 = p[/* inputs */1]; - if (match) { - var match$2 = match[0]; - if (match$2 !== undefined) { - var match$3 = match$2; - if (match$3.tag) { - return ; - } else { - var match$4 = match[1]; - if (match$4) { - var match$5 = match$4[0]; - if (match$5 !== undefined && !(match$5.tag || match$4[1] || !match$1)) { - var match$6 = match$1[0]; - if (match$6 !== undefined) { - var match$7 = match$6; - if (match$7.tag === /* SingleChoice */1 && !match$1[1]) { - return go(convertChoice(match$7[0]), match$3[0], /* DONATIONS */0); - } else { - return ; - } - } else { - return ; + var partial_arg = p[/* inputValues */1]; + var partial_arg$1 = Prop$ProbExample.ValueMap.get; + var get = function (param) { + return partial_arg$1(partial_arg, param); + }; + var match = Curry._1(get, "Fund"); + var match$1 = Curry._1(get, "Year"); + if (match !== undefined) { + var match$2 = match; + switch (match$2.tag | 0) { + case /* SelectSingle */0 : + if (match$1 !== undefined) { + var match$3 = match$1; + switch (match$3.tag | 0) { + case /* FloatPoint */1 : + return go(convertChoice(match$2[0]), match$3[0], /* DONATIONS */0); + case /* SelectSingle */0 : + case /* FloatCdf */2 : + return ; + } } else { return ; } - } else { + case /* FloatPoint */1 : + case /* FloatCdf */2 : return ; - } - } - } else { - return ; + } } } +function EAFunds_Model$Interface$Form(Props) { + return React.createElement(Prop$ProbExample.ModelForm.make, { + combo: Prop$ProbExample.Combo.fromModel(model) + }); +} + +var Form = { + make: EAFunds_Model$Interface$Form +}; + var Interface = { model: model, convertChoice: convertChoice, - run: run + run: run, + Form: Form }; exports.PayoutsIfAround = PayoutsIfAround; diff --git a/src/EAFunds/EAFunds_Model.re b/src/EAFunds/EAFunds_Model.re index 02e20b2d..0babcba0 100644 --- a/src/EAFunds/EAFunds_Model.re +++ b/src/EAFunds/EAFunds_Model.re @@ -44,7 +44,7 @@ module PayoutsIfAround = { let go = (group: group, year: float, output: output) => { PayoutsIfAround.( - Model.InputTypes.FloatCdf( + Prop.Value.FloatCdf( calculateDifference( currentValue(group, output), year, @@ -55,34 +55,30 @@ let go = (group: group, year: float, output: output) => { }; module Interface = { - open Model; + open Prop; - let model = { + let model: Model.t = { name: "Calculate the payments and payouts of EA Funds based on existing data.", author: "George Harrison", - assumptions: [ - Input.make(~name="Yearly Growth Rate", ~parameterType=FloatPoint, ()), - Input.currentYear, - ], - inputs: [ - Input.make( + inputTypes: [| + TypeWithMetadata.make( ~name="Fund", - ~parameterType= - SingleChoice({ + ~type_= + SelectSingle({ default: Some("total"), options: [ - ("Animal Welfare Fund", "animal"), - ("Global Health Fund", "globalHealth"), - ("Long Term Future Fund", "longTerm"), - ("Meta Fund", "meta"), - ("All", "all"), + {name: "Animal Welfare Fund", id: "animal"}, + {name: "Global Health Fund", id: "globalHealth"}, + {name: "Long Term Future Fund", id: "longTerm"}, + {name: "Meta Fund", id: "longterm"}, + {name: "All", id: "all"}, ], }), (), ), - Input.make( + TypeWithMetadata.make( ~name="Year", - ~parameterType= + ~type_= Year({ default: Some(2030.0), min: Some(2020.0), @@ -90,12 +86,8 @@ module Interface = { }), (), ), - ], - outputs: [ - Output.make(~name="Payments", ~parameterType=FloatCdf, ()), - Output.make(~name="Payouts", ~parameterType=FloatCdf, ()), - ], - outputConfig: Single, + |], + outputTypes: [||], }; let convertChoice = (s: string) => @@ -107,14 +99,17 @@ module Interface = { | _ => All }; - let run = (p: Model.modelParams) => { - switch (p.assumptions, p.inputs) { - | ( - [Some(Year(intendedYear)), Some(Year(currentYear))], - [Some(SingleChoice(fund))], - ) => + let run = (p: Combo.t) => { + let get = Prop.ValueMap.get(p.inputValues); + switch (get("Fund"), get("Year")) { + | (Some(SelectSingle(fund)), Some(FloatPoint(intendedYear))) => Some(go(convertChoice(fund), intendedYear, DONATIONS)) | _ => None }; }; + + module Form = { + [@react.component] + let make = () => ; + }; }; \ No newline at end of file diff --git a/src/Index.bs.js b/src/Index.bs.js index fc86cbd4..f65028d8 100644 --- a/src/Index.bs.js +++ b/src/Index.bs.js @@ -2,10 +2,10 @@ var React = require("react"); var ReactDOMRe = require("reason-react/src/ReactDOMRe.js"); -var EAFunds_Form2$ProbExample = require("./EAFunds/EAFunds_Form2.bs.js"); +var EAFunds_Model$ProbExample = require("./EAFunds/EAFunds_Model.bs.js"); ((import('./styles/index.css'))); -ReactDOMRe.renderToElementWithId(React.createElement(EAFunds_Form2$ProbExample.make, { }), "app"); +ReactDOMRe.renderToElementWithId(React.createElement(EAFunds_Model$ProbExample.Interface.Form.make, { }), "app"); /* Not a pure module */ diff --git a/src/Index.re b/src/Index.re index ce2edeb4..9f620a7e 100644 --- a/src/Index.re +++ b/src/Index.re @@ -1,2 +1,2 @@ [%bs.raw {|import('./styles/index.css')|}]; -ReactDOMRe.renderToElementWithId(, "app"); \ No newline at end of file +ReactDOMRe.renderToElementWithId(, "app"); \ No newline at end of file diff --git a/src/Model.re b/src/Modell.re similarity index 100% rename from src/Model.re rename to src/Modell.re diff --git a/src/Params.re b/src/Params.re deleted file mode 100644 index bc0b1473..00000000 --- a/src/Params.re +++ /dev/null @@ -1,17 +0,0 @@ -type yearAsFloat = { - min: option(float), - max: option(float), -}; - -type namedValue('a) = { - name: string, - value: 'a, -}; - -type choice('a) = list(namedValue('a)); - -type output = - | A - | B; - -let nOutput: choice(output) = [{name: "sdfsdf", value: A}]; \ No newline at end of file diff --git a/src/Prop.re b/src/Prop.re index 86ea3b30..833bb480 100644 --- a/src/Prop.re +++ b/src/Prop.re @@ -51,12 +51,12 @@ module Type = { module ValueMap = { module MS = Belt.Map.String; type t = MS.t(Value.t); - let get = MS.get; + let get = (t: t, s) => MS.get(t, s); let keys = MS.keysToArray; let map = MS.map; let fromArray = (r): t => MS.fromArray(r); let values = (t: t) => t |> MS.valuesToArray; - let update = MS.update; + let update = (t, k, v) => MS.update(t, k, _ => v); let toArray = MS.toArray; let fromOptionalMap = (t: MS.t(option(Value.t))): t => MS.keep(t, (_, d) => E.O.isSome(d)) @@ -121,7 +121,7 @@ module Model = { }; module Combo = { - type combo = { + type t = { model: Model.t, inputValues: ValueMap.t, outputValues: ValueMap.t, @@ -135,20 +135,90 @@ module Combo = { ) |> ValueMap.fromOptionalArray; - let isValid = (t: combo) => + let isValid = t => t.model |> Model.InputTypes.keys |> E.A.fmap(ValueMap.get(t.inputValues)) |> Belt.Array.some(_, E.O.isNone); - let update = - ( - t: combo, - key: string, - onUpdate: option(Value.t) => option(Value.t), - ) => + let update = (t, key: string, onUpdate: option(Value.t)) => ValueMap.update(t.inputValues, key, onUpdate); }; - let run = (t: combo, f): ValueMap.t => f(t.inputValues); + let updateInputValue = (t, k, u) => { + ...t, + inputValues: InputValues.update(t, k, u), + }; + + let inputTypeValuePairs = (t: t) => + t.model.inputTypes + |> E.A.fmap((i: TypeWithMetadata.t) => + (i, ValueMap.get(t.inputValues, i.id)) + ); + + let fromModel = (t: Model.t) => { + model: t, + inputValues: InputValues.defaults(t), + outputValues: InputValues.defaults(t), + }; + + let run = (t: t, f): ValueMap.t => f(t.inputValues); +}; + +module ValueForm = { + let handleChange = (handleChange, event) => + handleChange(ReactEvent.Form.target(event)##value); + type onChange = option(Value.t) => unit; + + [@react.component] + let make = + ( + ~type_: TypeWithMetadata.t, + ~value: option(Value.t), + ~onChange: onChange, + ) => { + switch (type_.type_, value) { + | (Year(_), Some(FloatPoint(r))) => + Js.Float.toString} + onChange={handleChange(r => + switch (Js.Float.fromString(r)) { + | r => onChange(Some(Value.FloatPoint(r))) + } + )} + /> + | (FloatPoint(_), Some(FloatPoint(r))) => + Js.Float.toString} /> + | (Year(_), _) + | (FloatPoint(_), _) => + | (SelectSingle(_), _) => +
{"Single Choice" |> ReasonReact.string}
+ }; + }; +}; + +module ModelForm = { + let handleChange = (handleChange, event) => + handleChange(ReactEvent.Form.target(event)##value); + + [@react.component] + let make = (~combo: Combo.t) => { + let (combo, setCombo) = React.useState(() => combo); +
+ {Combo.inputTypeValuePairs(combo) + |> E.A.fmap(((type_, value)) => + + setCombo(_ => + Combo.updateInputValue(combo, type_.id, newValue) + ) + } + /> + ) + |> ReasonReact.array} +
; + }; }; \ No newline at end of file