You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.7 KiB

  1. package react;
  2. import react.ReactComponent;
  3. import react.ReactMacro.jsx;
  4. import Common;
  5. // I need to store also the "input" because of https://stackoverflow.com/questions/29140354/how-to-handle-decimal-values-in-reacts-onchange-event-for-input
  6. typedef VATBoxState = {ht:Float, ttc:Float, vat:Float, htInput:String, ttcInput:String,lastEdited:String};
  7. /**
  8. * A box to manage prices with and without VAT
  9. * @author fbarbut
  10. */
  11. class VATBox extends react.ReactComponentOfPropsAndState<{ttc:Float,currency:String,vatRates:String,vat:Float,formName:String},VATBoxState>
  12. {
  13. public function new(props)
  14. {
  15. super(props);
  16. //trace(props);
  17. this.state = {
  18. ht : round(props.ttc/(1+props.vat/100)),
  19. htInput : Std.string(round(props.ttc/(1+props.vat/100))),
  20. ttc : round(props.ttc),
  21. ttcInput : Std.string(round(props.ttc)),
  22. vat:props.vat,
  23. lastEdited:null
  24. };
  25. }
  26. override public function render(){
  27. var rates :Array<Float>= props.vatRates.split("|").map(Std.parseFloat);
  28. var options = [for (r in rates) jsx('<option key="$r" value="$r">$r %</option>') ];
  29. var priceInputName = props.formName+"_price";
  30. var vatInputName = props.formName+"_vat";
  31. return jsx('<div>
  32. <div className="row">
  33. <div className="col-md-4 text-center"> Hors taxe </div>
  34. <div className="col-md-4 text-center"> Taux de TVA </div>
  35. <div className="col-md-4 text-center"> TTC </div>
  36. </div>
  37. <div className="row">
  38. <div className="col-md-4">
  39. <div className="input-group">
  40. <input type="text" name="htInput" value="${state.htInput}" className="form-control" onChange={onChange}/>
  41. <div className="input-group-addon">${props.currency}</div>
  42. </div>
  43. </div>
  44. <div className="col-md-4">
  45. <select name="vat" className="form-control" onChange={onChange} defaultValue=${state.vat}>
  46. ${options}
  47. </select>
  48. </div>
  49. <div className="col-md-4">
  50. <div className="input-group">
  51. <input type="text" name="ttcInput" value="${state.ttcInput}" className="form-control" onChange={onChange}/>
  52. <div className="input-group-addon">${props.currency}</div>
  53. </div>
  54. </div>
  55. </div>
  56. <input type="hidden" name="$priceInputName" value="${state.ttc}" />
  57. <input type="hidden" name="$vatInputName" value="${state.vat}" />
  58. </div>
  59. ');
  60. }
  61. /**
  62. * Recompute prices
  63. */
  64. function onChange(e:js.html.Event){
  65. e.preventDefault();
  66. var name :String = untyped e.target.name;
  67. var input : String = Std.string(untyped e.target.value);
  68. if (input == null || input == "") input = "0";
  69. input = StringTools.replace(input, ",", ".");
  70. var value : Float = Std.parseFloat(input);
  71. if (value == null) value = 0;
  72. var rate = 1 + (state.vat / 100);
  73. //trace('name:$name - raw:' + untyped e.target.value+' - input:$input - value:$value ');
  74. switch(name){
  75. case "htInput":
  76. this.setState(cast {ht:value , htInput:input , ttc: round(value * rate), ttcInput:round(value * rate) , lastEdited:"htInput"});
  77. case "ttcInput":
  78. this.setState(cast {ht: round(value / rate), htInput : round(value/rate), ttcInput:input , ttc:value , lastEdited:"ttcInput"});
  79. case "vat":
  80. rate = 1 + (value / 100);
  81. if (state.lastEdited == "htInput"){
  82. //compute ttc from ht
  83. this.setState(cast { vat:value, ht:state.ht, htInput:state.ht, ttc:round(state.ht * rate) , ttcInput:round(state.ht * rate)} );
  84. }else{
  85. //compute ht from ttc
  86. this.setState(cast { vat:value, ht: round( state.ttc/rate ), htInput: round( state.ttc/rate ), ttc:state.ttc , ttcInput:state.ttc} );
  87. }
  88. default:
  89. }
  90. }
  91. inline function round(f:Float):Float{
  92. return Math.round(f * 100) / 100;
  93. }
  94. }