code from amapei
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package react;
|
||||
|
||||
import api.react.ReactMacro.jsx;
|
||||
import js.html.InputElement;
|
||||
import Common;
|
||||
|
||||
typedef ComposerAppState = {
|
||||
products:Array<{id:Int,name:String,qt:Float,unit:UnitType}>
|
||||
}
|
||||
|
||||
typedef ComposerAppRefs = {
|
||||
pi:ProductInput,
|
||||
productContainer:js.html.DivElement,
|
||||
qt:InputElement,
|
||||
unit:js.html.SelectElement,
|
||||
}
|
||||
|
||||
/**
|
||||
* Composite product composer
|
||||
*
|
||||
*/
|
||||
class ComposerApp extends ReactComponentOfStateAndRefs<ComposerAppState, ComposerAppRefs>
|
||||
{
|
||||
/*var products:Array<{id:Int,name:String,?qt:Float,?unit:UnitType}>;
|
||||
|
||||
|
||||
public function new(props:Dynamic)
|
||||
{
|
||||
|
||||
super(props);
|
||||
products = [{id:1,name:"pipo"},{id:2,name:"Loclac"}];
|
||||
}
|
||||
|
||||
override public function render(){
|
||||
return jsx('
|
||||
<div className="ComposerApp" style={{margin:"10px"}} >
|
||||
|
||||
<div className="form-inline">
|
||||
|
||||
<ProductInput ref="pi"/>
|
||||
|
||||
<input ref="qt" onChange="$onChange" className="form-control" type="text" name="qt" placeholder="Quantité" />
|
||||
|
||||
<select ref="unit" className="form-control" name="unit">
|
||||
${getUnits()}
|
||||
</select>
|
||||
|
||||
<a className="btn btn-primary" onClick=$addItem>
|
||||
<span className="glyphicon glyphicon-plus"></span> Ajouter
|
||||
</a>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div className="container" ref="productContainer">
|
||||
${createChildren()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
');
|
||||
|
||||
}
|
||||
|
||||
function onChange(){
|
||||
|
||||
}
|
||||
|
||||
function getUnits(){
|
||||
var out = [];
|
||||
for ( c in Unit.createAll()){
|
||||
|
||||
out.push(jsx( '<option value="{c.getIndex()}"> {Std.string(c)} </option>'));
|
||||
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function createChildren()
|
||||
{
|
||||
|
||||
|
||||
return [for (p in products) jsx('<ProductComp key={p.id} name={p.name} qt={p.qt} unit={p.unit}/>')];
|
||||
}
|
||||
|
||||
function addItem(){
|
||||
var text :String = refs.pi.refs.input.value;
|
||||
if (text.length > 0)
|
||||
{
|
||||
trace("add " + text);
|
||||
trace("qt " + this.refs.qt.value);
|
||||
trace("unit " + this.refs.unit.selectedIndex);
|
||||
|
||||
var qt = Std.parseFloat(this.refs.qt.value);
|
||||
var unit = UnitType.createByIndex(this.refs.unit.selectedIndex);
|
||||
var id = Std.random(999);
|
||||
products.push( {id:id, name:text,qt:qt,unit:unit});
|
||||
|
||||
setState({products:[{id:id,name:text, qt:qt, unit:unit}]});
|
||||
//this.forceUpdate();
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package react.product;
|
||||
import react.ReactComponent;
|
||||
import react.ReactMacro.jsx;
|
||||
import Common;
|
||||
|
||||
/**
|
||||
* A Product
|
||||
* @author fbarbut
|
||||
*/
|
||||
class Product extends react.ReactComponentOfProps<{productInfo:ProductInfo}>
|
||||
{
|
||||
|
||||
public function new(props)
|
||||
{
|
||||
super(props);
|
||||
}
|
||||
|
||||
override public function render(){
|
||||
var p :ProductInfo = props.productInfo;
|
||||
|
||||
//convert int to enum
|
||||
//p.unitType = Type.createEnumIndex(Common.Unit,cast p.unit);
|
||||
|
||||
//var unit = ;
|
||||
var imgStyle = {width:'64px',height:'64px','backgroundImage':'url("${p.image}")'};
|
||||
var divStyle = p.active ? {} : {opacity: 0.4};
|
||||
|
||||
return jsx('<div className="product row" style=$divStyle>
|
||||
<div className="col-md-4">
|
||||
<div src="${p.image}" className="productImg" style=$imgStyle/>
|
||||
</div>
|
||||
<div className="col-md-8">
|
||||
<strong>${p.name}</strong> ${p.qt} ${Formatting.unit(p.unitType)}<br/>
|
||||
${p.price} €
|
||||
</div>
|
||||
</div>');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package react.product;
|
||||
import react.ReactDOM;
|
||||
import react.ReactComponent;
|
||||
import react.ReactMacro.jsx;
|
||||
import Common;
|
||||
import react.Typeahead;
|
||||
|
||||
typedef ProductInputProps = {
|
||||
formName:String,
|
||||
txpProductId:Int,
|
||||
productName:String,
|
||||
}
|
||||
typedef ProductInputState = {
|
||||
txpProductId:Int,
|
||||
productName:String,
|
||||
categoryId:Int,
|
||||
breadcrumb:String,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Product Text Input with autocompletion
|
||||
*
|
||||
* @author fbarbut
|
||||
*/
|
||||
class ProductInput extends react.ReactComponentOfPropsAndState<ProductInputProps,ProductInputState>
|
||||
{
|
||||
|
||||
public static var DICO : TxpDictionnary = null;
|
||||
var options : Array<{id:Int,label:String}>;
|
||||
|
||||
public function new(props:ProductInputProps)
|
||||
{
|
||||
super(props);
|
||||
options = [];
|
||||
this.state = {
|
||||
txpProductId : props.txpProductId,
|
||||
productName : props.productName,
|
||||
categoryId : 0,
|
||||
breadcrumb : ""
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
override public function render(){
|
||||
var inputName :String = props.formName+"_name";
|
||||
var txpProductInputName :String = props.formName+"_txpProductId";
|
||||
|
||||
return jsx('
|
||||
<div className="row">
|
||||
|
||||
<div className="col-md-8">
|
||||
<AsyncTypeahead
|
||||
placeholder="Saisissez un nom de produit"
|
||||
options=$options
|
||||
onSearch=$onSearch
|
||||
minLength={3}
|
||||
style={{width:"350px"}}
|
||||
onChange=$onChange
|
||||
onInputChange=$onInputChange
|
||||
selected={["${state.productName}"]}
|
||||
isLoading=$true
|
||||
/>
|
||||
<div className = "txpProduct" > ${state.breadcrumb}</div>
|
||||
|
||||
<input className="txpProduct" type="hidden" name="$txpProductInputName" value="${state.txpProductId}" />
|
||||
<input className="txpProduct" type="hidden" name="$inputName" value="${state.productName}" />
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
<img ref="image" className="img-thumbnail" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when typing is stopped
|
||||
* @param o
|
||||
*/
|
||||
function onSearch(o){
|
||||
//trace("on search : "+o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each time a single letter change in the input
|
||||
* @param input
|
||||
*/
|
||||
function onInputChange(input:String){
|
||||
trace('on input change $input');
|
||||
this.setState({productName:input});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an item is selected in suggestions
|
||||
*/
|
||||
function onChange(selection:Array<{label:String,id:Int}>){
|
||||
|
||||
if (selection == null || selection.length == 0) return;
|
||||
|
||||
trace("on change "+selection[0]);
|
||||
|
||||
var product = Lambda.find(DICO.products, function(x) return x.id == selection[0].id);
|
||||
setTaxo(product);
|
||||
this.setState({productName:selection[0].label});
|
||||
}
|
||||
|
||||
/**
|
||||
* init typeahead auto-completion features when component is mounted
|
||||
*/
|
||||
override function componentDidMount(){
|
||||
|
||||
//get dictionnary
|
||||
if (DICO == null){
|
||||
|
||||
var r = new haxe.Http("/product/getTaxo");
|
||||
r.onData = function(data){
|
||||
//load dico
|
||||
DICO = haxe.Unserializer.run(data);
|
||||
|
||||
for ( p in DICO.products){
|
||||
options.push({label:p.name,id:p.id});
|
||||
}
|
||||
|
||||
//default values of input
|
||||
if (props.txpProductId != null){
|
||||
var txp = Lambda.find(DICO.products, function(x) return x.id == props.txpProductId);
|
||||
setTaxo(txp);
|
||||
}
|
||||
};
|
||||
r.request();
|
||||
}
|
||||
}
|
||||
|
||||
function setTaxo(txp:{id:Int, name:String, category:Int, subCategory:Int}){
|
||||
|
||||
if (txp == null) return;
|
||||
|
||||
//trace(txp);
|
||||
|
||||
this.setState({
|
||||
categoryId:txp.category,
|
||||
txpProductId:txp.id,
|
||||
breadcrumb:getBreadcrumb(txp)/*,
|
||||
productName:product.name //do not override product name ! */
|
||||
});
|
||||
|
||||
this.refs.image.src="/img/taxo/cat"+txp.category+".png";
|
||||
}
|
||||
|
||||
/**
|
||||
* generate string like "fruits & vegetables / vegetables / carrots"
|
||||
* @param name
|
||||
*/
|
||||
function getBreadcrumb(product){
|
||||
//cat
|
||||
var str = DICO.categories.get(product.category).name;
|
||||
if (product.subCategory != null){
|
||||
str += " / " + DICO.subCategories.get(product.subCategory).name;
|
||||
}
|
||||
str += " / " + product.name;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package react.product;
|
||||
import react.ReactDOM;
|
||||
import react.ReactComponent;
|
||||
import react.ReactMacro.jsx;
|
||||
import Common;
|
||||
import utils.HttpUtil;
|
||||
|
||||
/**
|
||||
* A Product selector
|
||||
* @author fbarbut
|
||||
*/
|
||||
class ProductSelect extends react.ReactComponentOfPropsAndState<{onSelect:ProductInfo->Void,products:Array<ProductInfo>},{selected:Int}>
|
||||
{
|
||||
|
||||
public function new(props)
|
||||
{
|
||||
super(props);
|
||||
state = { selected : null };
|
||||
}
|
||||
|
||||
override public function render(){
|
||||
|
||||
var products = props.products.map(function(info){
|
||||
//var selector = info.id==state.selected ? jsx(''):jsx('<div className="clickable"><$Product productInfo=$info /></div>');
|
||||
return jsx('<div key=${info.id} className="col-md-6" onClick=${onClick.bind(info.id)}>
|
||||
<div className="clickable"><$Product productInfo=$info /></div>
|
||||
</div>');
|
||||
});
|
||||
|
||||
return jsx('<div className="productSelect">${products}</div>');
|
||||
}
|
||||
|
||||
function onClick(i:Int){
|
||||
this.setState(cast {selected:i});
|
||||
if(props.onSelect!=null){
|
||||
var p = Lambda.find(props.products,function(x) return x.id==i);
|
||||
props.onSelect(p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user