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.

229 lines
6.0 KiB

  1. package react.store;
  2. import react.ReactComponent;
  3. import react.ReactMacro.jsx;
  4. import haxe.Json;
  5. using Lambda;
  6. import Common;
  7. import utils.CartUtils;
  8. import utils.HttpUtil;
  9. typedef StoreProps = {
  10. var place:Int;
  11. var date:String;
  12. };
  13. typedef StoreState = {
  14. var place:PlaceInfos;
  15. var orderByEndDates:Array<OrderByEndDate>;
  16. var categories:Array<CategoryInfo>;
  17. var productsBySubcategoryIdMap:Map<Int, Array<ProductInfo>>;
  18. var order:OrderSimple;
  19. var filters:Array<String>;
  20. };
  21. class Store extends react.ReactComponentOfPropsAndState<StoreProps, StoreState>
  22. {
  23. static inline var CATEGORY_URL = '/api/shop/categories';
  24. static inline var PRODUCT_URL = '/api/shop/products';
  25. static inline var INIT_URL = '/api/shop/init';
  26. static inline var VIEW_URL = '/place/view';
  27. public function new() {
  28. super();
  29. state = {
  30. place: null,
  31. orderByEndDates: [],
  32. categories: [],
  33. filters: [],
  34. productsBySubcategoryIdMap: new Map(),
  35. order: {
  36. products: [],
  37. total: 0
  38. }
  39. };
  40. }
  41. override function componentDidMount() {
  42. var categoriesRequest = HttpUtil.fetch(CATEGORY_URL, GET, {date: props.date, place: props.place}, JSON);
  43. var initRequest = HttpUtil.fetch(INIT_URL, GET, {date: props.date, place: props.place}, JSON);
  44. initRequest.then(function(infos:Dynamic) {
  45. setState({
  46. place: infos.place,
  47. orderByEndDates: infos.orderEndDates
  48. });
  49. })
  50. .catchError(function(error) {
  51. trace("ERROR", error);
  52. });
  53. categoriesRequest.then(function(categories:Dynamic) {
  54. var categories:Array<CategoryInfo> = categories.categories;
  55. var subCategories = [];
  56. for (category in categories) {
  57. subCategories = subCategories.concat(category.subcategories);
  58. }
  59. setState({
  60. categories: categories,
  61. filters: categories.map(function(category) {
  62. return category.name;
  63. })
  64. });
  65. subCategories.map(function(category:CategoryInfo) {
  66. return HttpUtil.fetch(PRODUCT_URL, GET, {date: props.date, place: props.place, subcategory: category.id}, JSON)
  67. .then(function(result) {
  68. var productsBySubcategoryIdMapCopy = [
  69. for (key in state.productsBySubcategoryIdMap.keys())
  70. key => state.productsBySubcategoryIdMap.get(key)
  71. ];
  72. productsBySubcategoryIdMapCopy.set(category.id, result.products);
  73. setState({
  74. productsBySubcategoryIdMap: productsBySubcategoryIdMapCopy
  75. });
  76. });
  77. });
  78. })
  79. .catchError(function(error) {
  80. trace("ERROR", error);
  81. });
  82. }
  83. function toggleFilter(category:String) {
  84. var filters = state.filters.copy();
  85. if (state.filters.find(function(categoryInFilter) {
  86. return category == categoryInFilter;
  87. }) != null)
  88. filters.remove(category);
  89. else
  90. filters.push(category);
  91. if (filters.length == 0)
  92. filters = state.categories.map(function(category) {
  93. return category.name;
  94. });
  95. setState({
  96. filters: filters
  97. });
  98. }
  99. function addToCart(productToAdd:ProductInfo, quantity:Int):Void {
  100. setState({
  101. order: CartUtils.addToCart(state.order, productToAdd, quantity)
  102. });
  103. }
  104. function removeFromCart(productToRemove:ProductInfo, ?quantity:Int):Void {
  105. setState({
  106. order: CartUtils.removeFromCart(state.order, productToRemove, quantity)
  107. });
  108. }
  109. function submitOrder(order:OrderSimple) {
  110. var orderInSession = {
  111. total: order.total,
  112. products: order.products.map(function(p:ProductWithQuantity){
  113. return {
  114. productId: p.product.id,
  115. quantity: p.quantity
  116. };
  117. })
  118. }
  119. trace('Order', orderInSession);
  120. }
  121. override public function render(){
  122. return jsx('
  123. <div className="shop">
  124. ${renderHeader()}
  125. <ProductList
  126. categories=${state.categories}
  127. productsBySubcategoryIdMap=${state.productsBySubcategoryIdMap}
  128. filters=${state.filters}
  129. addToCart=$addToCart
  130. />
  131. <Filters
  132. categories=${state.categories}
  133. filters=${state.filters}
  134. toggleFilter=$toggleFilter
  135. />
  136. <Cart
  137. order=${state.order}
  138. addToCart=$addToCart
  139. removeFromCart=$removeFromCart
  140. submitOrder=$submitOrder
  141. />
  142. </div>
  143. ');
  144. }
  145. function renderHeader() {
  146. if (state.orderByEndDates == null || state.orderByEndDates.length == 0)
  147. return null;
  148. var endDates;
  149. if (state.orderByEndDates.length == 1) {
  150. var orderEndDate = state.orderByEndDates[0].date;
  151. endDates = [jsx('<div key=$orderEndDate>La commande fermera le $orderEndDate</div>')];
  152. }
  153. else {
  154. endDates = state.orderByEndDates.map(function(order) {
  155. if (order.contracts.length == 1)
  156. return jsx('
  157. <div key=${order.date}>
  158. La commande ${order.contracts[0]} fermera le: ${order.date}
  159. </div>
  160. ');
  161. return jsx('
  162. <div key=${order.date}>
  163. Les autres commandes fermeront: ${order.date}
  164. </div>
  165. ');
  166. });
  167. }
  168. var viewUrl = '$VIEW_URL/${props.place}';
  169. var addressBlock = Lambda.array([
  170. state.place.address1,
  171. state.place.address2,
  172. [state.place.zipCode, state.place.city].join(" "),
  173. ].mapi(function(index, element) {
  174. if (element == null)
  175. return null;
  176. return jsx('<div className="address" key=$index>$element</div>');
  177. }));
  178. return jsx('
  179. <div className="shop-header">
  180. <div>
  181. <div className="shop-distribution">
  182. Distribution le ${props.date}
  183. </div>
  184. <div className="shop-order-ends">
  185. $endDates
  186. </div>
  187. </div>
  188. <div className="shop-place">
  189. <span className="info">
  190. <span className="glyphicon glyphicon-map-marker"></span>
  191. <a href=$viewUrl>${state.place.name}</a>
  192. </span>
  193. <div>
  194. $addressBlock
  195. </div>
  196. </div>
  197. </div>
  198. ');
  199. }
  200. }