瀏覽代碼

add to cart links for products in home

bach 3 年之前
父節點
當前提交
352223500f
共有 25 個文件被更改,包括 512 次插入241 次删除
  1. 9 1
      config/sync/core.entity_view_display.commerce_product.materio_product_type.home_summary.yml
  2. 8 1
      config/sync/core.entity_view_display.commerce_product_variation.materio_product_variation_type.add_to_cart.yml
  3. 12 3
      config/sync/core.entity_view_display.node.frontpage.home_light.yml
  4. 5 3
      web/modules/custom/materio_home/src/Plugin/Field/FieldType/ComputedMaterialsReferences.php
  5. 4 0
      web/themes/custom/materiotheme/assets/dist/main.css
  6. 二進制
      web/themes/custom/materiotheme/assets/dist/main.css.gz
  7. 0 0
      web/themes/custom/materiotheme/assets/dist/main.js
  8. 二進制
      web/themes/custom/materiotheme/assets/dist/main.js.gz
  9. 0 0
      web/themes/custom/materiotheme/assets/dist/module-pricing.bundle.js
  10. 二進制
      web/themes/custom/materiotheme/assets/dist/module-pricing.bundle.js.gz
  11. 40 2
      web/themes/custom/materiotheme/assets/dist/module-pricing.css
  12. 二進制
      web/themes/custom/materiotheme/assets/dist/module-pricing.css.gz
  13. 1 1
      web/themes/custom/materiotheme/assets/dist/report.html
  14. 193 104
      web/themes/custom/materiotheme/assets/styles/main.scss
  15. 19 0
      web/themes/custom/materiotheme/materiotheme.theme
  16. 33 0
      web/themes/custom/materiotheme/templates/content/commerce-product--4--home-summary.html.twig
  17. 5 0
      web/themes/custom/materiotheme/templates/content/commerce-product--home-summary.html.twig
  18. 2 2
      web/themes/custom/materiotheme/templates/content/commerce-product-variation--materio-product-variation-type--summary.html.twig
  19. 21 109
      web/themes/custom/materiotheme/vuejs/components/Content/Product.vue
  20. 1 1
      web/themes/custom/materiotheme/vuejs/components/Form/LoginForm.vue
  21. 1 1
      web/themes/custom/materiotheme/vuejs/components/Form/RegisterForm.vue
  22. 16 11
      web/themes/custom/materiotheme/vuejs/components/Helper/LoginRegister.vue
  23. 1 1
      web/themes/custom/materiotheme/vuejs/components/Pages/Article.vue
  24. 3 1
      web/themes/custom/materiotheme/vuejs/components/Pages/Home.vue
  25. 138 0
      web/themes/custom/materiotheme/vuejs/components/productsMixins.js

+ 9 - 1
config/sync/core.entity_view_display.commerce_product.materio_product_type.home_summary.yml

@@ -29,6 +29,15 @@ content:
     settings:
       link_to_entity: false
     third_party_settings: {  }
+  variations:
+    type: entity_reference_entity_view
+    weight: 2
+    region: content
+    label: hidden
+    settings:
+      view_mode: add_to_cart
+      link: false
+    third_party_settings: {  }
 hidden:
   created: true
   field_price_description: true
@@ -36,4 +45,3 @@ hidden:
   search_api_excerpt: true
   stores: true
   uid: true
-  variations: true

+ 8 - 1
config/sync/core.entity_view_display.commerce_product_variation.materio_product_variation_type.add_to_cart.yml

@@ -13,6 +13,7 @@ dependencies:
     - field.field.commerce_product_variation.materio_product_variation_type.subscription_type
   module:
     - commerce_variation_cart_form
+    - text
 third_party_settings:
   commerce_variation_cart_form:
     combine: '1'
@@ -22,13 +23,19 @@ bundle: materio_product_variation_type
 mode: add_to_cart
 content:
   commerce_variation_cart_form:
+    weight: 1
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_description:
+    type: text_default
     weight: 0
     region: content
+    label: hidden
     settings: {  }
     third_party_settings: {  }
 hidden:
   billing_schedule: true
-  field_description: true
   field_multiple: true
   langcode: true
   license_expiration: true

+ 12 - 3
config/sync/core.entity_view_display.node.frontpage.home_light.yml

@@ -57,7 +57,7 @@ third_party_settings:
         speed: fast
         id: ''
         classes: home-database
-      label: database
+      label: 'base de données'
       region: content
     group_showrooms:
       children:
@@ -101,6 +101,7 @@ third_party_settings:
       children:
         - field_pricing_pitch
         - field_pricing
+        - computed_products_reference
       parent_name: ''
       weight: 4
       format_type: html_element
@@ -114,7 +115,7 @@ third_party_settings:
         id: ''
         classes: home-pricing
         element: section
-      label: pricing
+      label: tarifs
       region: content
     group_db_col_left:
       children:
@@ -229,6 +230,15 @@ targetEntityType: node
 bundle: frontpage
 mode: home_light
 content:
+  computed_products_reference:
+    type: entity_reference_entity_view
+    weight: 6
+    region: content
+    label: hidden
+    settings:
+      view_mode: home_summary
+      link: false
+    third_party_settings: {  }
   field_a_database:
     weight: 6
     label: above
@@ -350,7 +360,6 @@ content:
 hidden:
   computed_articles_reference: true
   computed_materials_reference: true
-  computed_products_reference: true
   computed_showrooms_reference: true
   langcode: true
   links: true

+ 5 - 3
web/modules/custom/materio_home/src/Plugin/Field/FieldType/ComputedMaterialsReferences.php

@@ -45,9 +45,11 @@ class ComputedMaterialsReferences extends EntityReferenceFieldItemList
         ->sort('created', 'DESC')
         ->range(0,200);
     $results = $query->execute();
-    $nids = array_rand($results, 70);
-    foreach ($nids as $key => $nid) {
-      $this->list[$key] = $this->createItem($key, $nid);
+    if ($results) {
+      $nids = array_rand($results, 70);
+      foreach ($nids as $key => $nid) {
+        $this->list[$key] = $this->createItem($key, $nid);
+      }
     }
   }
 

文件差異過大導致無法顯示
+ 4 - 0
web/themes/custom/materiotheme/assets/dist/main.css


二進制
web/themes/custom/materiotheme/assets/dist/main.css.gz


文件差異過大導致無法顯示
+ 0 - 0
web/themes/custom/materiotheme/assets/dist/main.js


二進制
web/themes/custom/materiotheme/assets/dist/main.js.gz


文件差異過大導致無法顯示
+ 0 - 0
web/themes/custom/materiotheme/assets/dist/module-pricing.bundle.js


二進制
web/themes/custom/materiotheme/assets/dist/module-pricing.bundle.js.gz


文件差異過大導致無法顯示
+ 40 - 2
web/themes/custom/materiotheme/assets/dist/module-pricing.css


二進制
web/themes/custom/materiotheme/assets/dist/module-pricing.css.gz


文件差異過大導致無法顯示
+ 1 - 1
web/themes/custom/materiotheme/assets/dist/report.html


+ 193 - 104
web/themes/custom/materiotheme/assets/styles/main.scss

@@ -1239,37 +1239,22 @@ article.node--type-frontpage{
         .field--name-computed-products-reference{
           display: flex;
           flex-flow: row nowrap;
-					@include col-mediaquery-max(3){
+					@include col-mediaquery-max(5){
 						flex-flow: column;
 						justify-content: flex-start;
 					}
           >.field__item{
-            flex:0 0 50%;
+            flex:0 0 33%;
             text-align: center;
             padding: 2em 0;
-            a.btn{
-              @include btn;
-              background-color: #fff;
-            }
-            &:nth-child(1){
-              background-color: $color-base;
-              a.btn{
-                color: $color-base;
-              }
-            }
-            &:nth-child(2){
-              background-color: $color-webshowroom;
-              a.btn{
-                color: $color-webshowroom;
-              }
-            }
-            color: #fff;
+						color: #fff;
             position: relative;
-            height:18em;
+            height:23em;
             >article{
               position: absolute;
               top:50%; left:50%;
               transform: translate(-50%, -50%);
+							width:80%;
             }
             .field--name-title{
               @extend %front-col-field__label;
@@ -1286,8 +1271,77 @@ article.node--type-frontpage{
                 margin: 0;
               }
             }
+						.field--name-variations{
+							.field__item{
+								>div{
+									display: flex;
+									flex-direction: row;
+									justify-content: center;
+									align-items: baseline;
+									.form-actions,p{
+										margin:0;
+									}
+									.field--name-field-description{
+										margin-right: 0.5em;
+										p{
+											font-size: 1.512em;
+											font-weight: 800;
+											color: #fff;
+											white-space: nowrap;
+											text-align: right;
+										}
+									}
+									input.button--add-to-cart{
+										@include btn;
+									}
+								}
+							}
+						}
+            a.btn{
+              @include btn;
+              background-color: #fff;
+            }
+            &:nth-child(1){
+              background-color: $color-base;
+              a.btn{
+                color: $color-base;
+              }
+							.field--name-variations{
+								.field__item{
+									>div{
+										input.button--add-to-cart{
+			                color: $color-base;
+										}
+									}
+								}
+							}
+            }
+            &:nth-child(2){
+              background-color: $color-webshowroom;
+              a.btn{
+                color: $color-webshowroom;
+              }
+							.field--name-variations{
+								.field__item{
+									>div{
+										input.button--add-to-cart{
+			                color: $color-webshowroom;
+										}
+									}
+								}
+							}
+            }
+            &:nth-child(3){
+              background-color: $color-showrooms;
+              a.btn{
+                color: $color-showrooms;
+              }
+							>article{
+								max-width: 345px;
+							}
+            }
 
-						@include col-mediaquery-max(3){
+						@include col-mediaquery-max(5){
 							flex: 0 0 auto;
 							padding:0;
 							// height: auto;
@@ -2176,7 +2230,7 @@ article.card{
 
   article.product,
   .views-row{
-    flex:0 0 50%;
+    flex:0 0 33%;
     text-align: center;
     padding: 2em 0;
     >header{
@@ -2233,6 +2287,12 @@ article.card{
       aside .variation button{
         color: $color-webshowroom;
       }
+    }
+		&:nth-child(3){
+      background-color: $color-showrooms;
+      aside .variation button{
+        color: $color-showrooms;
+      }
     }
   }
 	@include col-mediaquery-max(3){
@@ -2247,99 +2307,128 @@ article.card{
 .modal{
   position: relative;
 }
-#pricing-modal-login-register{
-  position: relative;
-  width: 100%;
-  text-align: left;
-  h2{
-    margin: 0.4em 0 1.1em;
-    padding-right: 4em;
-    font-size: 1.2em;
-    font-weight: 300;
-  }
+// #pricing-modal-login-register{
+//   position: relative;
+//   width: 100%;
+//   text-align: left;
+//
+// .vm--modale-loginregister{
+// }
   #login-register{
-    width: 100%;
-    display: flex;
-    flex-flow: row nowrap;
-    >section{
-      flex:0 0 250px;
-      form{
-        .form-item, .form-actions {
-          margin: 0.5em 0;
-          max-width: none;
-        }
-        .form-type-email,
-        .form-type-password,
-        .form-actions{
-          display:block;
-        }
-        input[type="email"],
-        input[type="password"]{
-          max-width: 11em;
-        }
-        &#user-login-form #edit-pass--description,
-        #edit-pass-pass1--description{
-          display: block;
-          max-width: 16em;
-          font-size: 0.693em;
-        }
-
-        span.login-message,
-        span.register-message{
-          color: red;
-          font-size: 0.693em;
-          line-height: 1.2;
-          display: block;
-          padding: 0.8em 0 0 0;
-        }
-        span.login-message[v-if="loginMessage"],
-        span.register-message[v-if="registerMessage"]{
-          display: none;
-        }
-      }
-		}
-    section.login{
-      form{
-        >div{
-          // display: block;
-        }
-      }
-    }
-    section.register{
-
-    }
-  }
-	@include col-mediaquery-max(3){
-		height:100%;
-		overflow-y: auto;
-		#login-register{
-			flex-flow: column;
+		padding: 1em;
+		box-sizing: content-box;
+		width: 100%;
+		h2{
+	    margin: 0.4em 0 1.1em;
+	    padding-right: 4em;
+	    font-size: 1.2em;
+	    font-weight: 300;
+	  }
+		>div.wrapper{
+	    display: flex;
+	    flex-flow: row nowrap;
 			>section{
-				flex:0 0 auto;
-				form{
-					input[type="email"],
+	      flex:0 0 50%;
+	      form{
+	        .form-item, .form-actions {
+	          margin: 0.5em 0;
+	          max-width: none;
+	        }
+	        .form-type-email,
+	        .form-type-password,
+	        .form-actions{
+	          display:block;
+	        }
+	        input[type="email"],
 	        input[type="password"]{
-						max-width: 90%;
-						width: 90%;
+	          max-width: 11em;
 	        }
 	        &#user-login-form #edit-pass--description,
 	        #edit-pass-pass1--description{
-	          max-width: 90%;
-						width: 90%;
+	          display: block;
+	          max-width: 16em;
+	          font-size: 0.693em;
 	        }
-				}
-				&.login{
-					padding-bottom: 0.5em;
+
+	        span.login-message,
+	        span.register-message{
+	          color: red;
+	          font-size: 0.693em;
+	          line-height: 1.2;
+	          display: block;
+	          padding: 0.8em 0 0 0;
+	        }
+	        span.login-message[v-if="loginMessage"],
+	        span.register-message[v-if="registerMessage"]{
+	          display: none;
+	        }
+	      }
+			}
+	    section.login{
+	      form{
+	        >div{
+	          // display: block;
+	        }
+	      }
+	    }
+	    section.register{
+
+	    }
+			@include col-mediaquery-max(3){
+				flex-flow: column;
+				>section{
+					flex:0 0 auto;
+					form{
+						input[type="email"],
+		        input[type="password"]{
+							max-width: 90%;
+							width: 90%;
+		        }
+		        &#user-login-form #edit-pass--description,
+		        #edit-pass-pass1--description{
+		          max-width: 90%;
+							width: 90%;
+		        }
+					}
+					&.login{
+						padding-bottom: 0.5em;
+					}
 				}
 			}
 		}
+
 	}
-	@include col-mediaquery-max(4, landscape){
-		h2{
-	    margin: 0 0 0.5em;
-		}
-	}
-}
+// 	@include col-mediaquery-max(3){
+// 		height:100%;
+// 		overflow-y: auto;
+// 		#login-register{
+// 			flex-flow: column;
+// 			>section{
+// 				flex:0 0 auto;
+// 				form{
+// 					input[type="email"],
+// 	        input[type="password"]{
+// 						max-width: 90%;
+// 						width: 90%;
+// 	        }
+// 	        &#user-login-form #edit-pass--description,
+// 	        #edit-pass-pass1--description{
+// 	          max-width: 90%;
+// 						width: 90%;
+// 	        }
+// 				}
+// 				&.login{
+// 					padding-bottom: 0.5em;
+// 				}
+// 			}
+// 		}
+// 	}
+// 	@include col-mediaquery-max(4, landscape){
+// 		h2{
+// 	    margin: 0 0 0.5em;
+// 		}
+// 	}
+// }
 #pricing{
 	@include col-mediaquery-max(3){
 		.overlay > .modal{

+ 19 - 0
web/themes/custom/materiotheme/materiotheme.theme

@@ -182,6 +182,25 @@ function materiotheme_preprocess_page(&$vars){
   // kint($vars['attributes']);
 // }
 
+
+/**
+ * Implements hook_form_alter
+ */
+function materiotheme_form_alter(&$form, FormStateInterface $form_state, $form_id) {
+  // commerce_order_item_variation_cart_form_form_commerce_product_variation_3
+  preg_match('/commerce_order_item_variation_cart_form_form_commerce_product_variation_(\d+)/', $form_id, $matches);
+  if ($matches && isset($matches[1]) && $variation_id = $matches[1]) {
+  // if (isset($form['#entity_type']) && $form['#entity_type'] == "commerce_order_item") {
+    // $product = $form_state->storage['product'];
+    // $storage = &$form_state->getStorage();
+    // $product = $storage['product'];
+    // $variations = $product->fields['variations'];
+    $form['actions']['submit']['#attributes'] += array(
+      "@click.prevent.stop" => "checkaddtocart(\$event, $variation_id)"
+    );
+  }
+}
+
 /**
  * Implements hook_form_alter
  */

+ 33 - 0
web/themes/custom/materiotheme/templates/content/commerce-product--4--home-summary.html.twig

@@ -0,0 +1,33 @@
+{#
+/**
+ * @file
+ *
+ * Default product template.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the wrapper.
+ * - product: The rendered product fields.
+ *   Use 'product' to print them all, or print a subset such as
+ *   'product.title'. Use the following code to exclude the
+ *   printing of a given field:
+ *   @code
+ *   {{ product|without('title') }}
+ *   @endcode
+ * - product_entity: The product entity.
+ * - product_url: The product URL.
+ *
+ * @ingroup themeable
+ */
+#}
+{#
+<article{{ attributes }}>
+{{- product -}}
+</article>
+#}
+
+<article{{ attributes }}>
+  {{- product|without('variation_attributes') -}}
+  <a href="mailto:info@materio.com?subject=Multi-Joueurs" class="btn">
+    {% trans %}Demander un devis{% endtrans %}
+  </a>
+</article>

+ 5 - 0
web/themes/custom/materiotheme/templates/content/commerce-product--home-summary.html.twig

@@ -19,9 +19,14 @@
  * @ingroup themeable
  */
 #}
+{#
 <article{{ attributes }}>
   {{- product|without('variation_attributes') -}}
   <a href="/{{ language }}/pricing" @click.prevent="onClickLink" class="btn">
     {% trans %}View Option Details{% endtrans %}
   </a>
 </article>
+#}
+<article{{ attributes }}>
+  {{- product -}}
+</article>

+ 2 - 2
web/themes/custom/materiotheme/templates/content/commerce-product-variation--materio-product-variation-type--summary.html.twig

@@ -21,7 +21,7 @@
 #}
 <div{{ attributes }}>
   {{- product_variation -}}
-  <a href="/pricing" @click.prevent="onClickLink" class="btn">
+  <!-- <a href="/pricing" @click.prevent="onClickLink" class="btn">
     {% trans %}View Option Details{% endtrans %}
-  </a>
+  </a> -->
 </div>

+ 21 - 109
web/themes/custom/materiotheme/vuejs/components/Content/Product.vue

@@ -25,7 +25,7 @@
 
     </aside>
 
-    <Modal
+    <!-- <Modal
       v-if="showLoginModal"
       @close="closeModal"
       :styles="{width:'500px', height:'350px'}"
@@ -38,132 +38,44 @@
           @onRegistered="onRegistered"
         />
       </section>
-    </Modal>
+    </Modal> -->
 
   </article>
 </template>
 
 <script>
 
-import { REST } from 'vuejs/api/rest-axios'
+// import { REST } from 'vuejs/api/rest-axios'
 import router from 'vuejs/route'
-import { mapState, mapActions } from 'vuex'
-import Modal from 'vuejs/components/Helper/Modal'
-import LoginRegister from 'vuejs/components/Helper/LoginRegister'
+// import { mapState, mapActions } from 'vuex'
+import productsMixins from 'vuejs/components/productsMixins'
+// import Modal from 'vuejs/components/Helper/Modal'
+// import LoginRegister from 'vuejs/components/Helper/LoginRegister'
 
-let basePath = drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix;
+// let basePath = drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix;
 
 export default {
   name: "Product",
   router,
   props: ['product'],
+  mixins: [productsMixins],
   data(){
     return {
       quantity: 1,
-      showLoginModal:false
+      // showLoginModal:false
     }
-  },
-  computed: {
-    ...mapState({
-      isloggedin: state => state.User.isloggedin,
-      isAdherent: state => state.User.isAdherent,
-      csrftoken: state => state.User.csrftoken
-    })
-  },
-  methods:{
-    // ...mapActions({
-    //   userLogin: 'User/userLogin'
-    // }),
-    closeModal () {
-      this.showLoginModal = false;
-    },
-    checkaddtocart(e, variation_id) {
-      console.log('checkaddtocart')
-
-      if (!this.isloggedin) {
-        // show popup for login or register
-        // login or register event will be catched by onLogedin or onRegistered
-        this.showLoginModal = variation_id
-      } else {
-        // if already logedin directly goes to cart operations
-        this.addtocart(variation_id)
-      }
-    },
-    // event bubbled from modal login form
-    onLogedIn (variation_id) {
-      console.log('Product: onLogedIn. variation_id', variation_id)
-      this.addtocart(variation_id)
-    },
-    // event bubbled from modal register form
-    onRegistered (variation_id) {
-      console.log('Product: onRegistered. variation_id', variation_id)
-      this.addtocart(variation_id)
-    },
-    getCarts () {
-      // this is bugging on stage
-      return REST.get(`/cart?_format=json`, {}, {'X-CSRF-Token':this.csrftoken})
-        // .then(({ data }) => {
-        //   console.log('current user carts: data', data)
-        // })
-        .catch((error) => {
-            console.warn('Issue with get cart', error)
-            Promise.reject(error)
-        })
-    },
-    deleteCart (order_id) {
-      console.log('deleting cart ', order_id)
-      return REST.delete(`/cart/${order_id}/items?_format=json`)
-        .then(({ data }) => {
-          console.log(`product cart ${order_id} deleted: data`, data)
-        })
-        .catch((error) => {
-            console.warn(`Issue with cart ${order_id} deleting`, error)
-            Promise.reject(error)
-        })
-    },
-    clearCarts (data) {
-      let promises = [];
-      // clear each cart as a promise
-      for (let i = 0; i < data.length; i++) {
-        promises.push(this.deleteCart(data[i].order_id))
-      }
-      // return all the promises as one
-      return Promise.all(promises)
-    },
-    addtocart (variation_id) {
-      console.log('addtocart')
-      this.getCarts()
-        .then(({data}) => {
-          console.log('current user carts: data', data)
-          this.clearCarts(data)
-            .then(() => {
-              console.log('all carts cleared')
-              // fill the cart with new product
-              REST.post(`/cart/add?_format=json`, [{
-                "purchased_entity_type": "commerce_product_variation",
-                "purchased_entity_id": variation_id,
-                "quantity": this.quantity
-              }])
-                .then(({ data }) => {
-                  console.log('product added to cart: data', data)
-                  this.closeModal()
-                  // redirect to /cart
-                  // window.location.href = "/cart"
-                  // TODO: redirect to checkout instead of cart
-                  window.location.href = `/checkout/${data[0].order_id}/order_information`
-                })
-                .catch((error) => {
-                    console.warn('Issue with product add to cart', error)
-                    Promise.reject(error)
-                })
-            })
-        })
-    }
-  },
-  components: {
-    Modal,
-    LoginRegister
   }
+  // ,
+  // methods:{
+  //   // ...mapActions({
+  //   //   userLogin: 'User/userLogin'
+  //   // })
+  // }
+  // ,
+  // components: {
+  //   Modal,
+  //   LoginRegister
+  // }
 }
 </script>
 

+ 1 - 1
web/themes/custom/materiotheme/vuejs/components/Form/LoginForm.vue

@@ -25,7 +25,7 @@ export default {
       // vuejs attributes a inserted by form alter in same module
       MA.get(`/materio_user/login_form`)
         .then(({data}) => {
-          console.log('getLoginForm data', data)
+          // console.log('getLoginForm data', data)
           this.form = Vue.compile(data.rendered)
           this.$options.staticRenderFns = [];
           this._staticTrees = [];

+ 1 - 1
web/themes/custom/materiotheme/vuejs/components/Form/RegisterForm.vue

@@ -38,7 +38,7 @@ export default {
       // vuejs attributes a inserted by form alter in same module
       MA.get(`/materio_user/register_form`)
         .then(({data}) => {
-          console.log("getRegisterForm data", data)
+          // console.log("getRegisterForm data", data)
           this.form = Vue.compile(data.rendered)
           this.$options.staticRenderFns = [];
           this._staticTrees = [];

+ 16 - 11
web/themes/custom/materiotheme/vuejs/components/Helper/LoginRegister.vue

@@ -1,13 +1,16 @@
 <template>
   <div id="login-register">
-    <section class="login">
-      <h3>{{ $t("default.Login") }} </h3>
-      <LoginForm @onLogedIn="onLogedIn" />
-    </section>
-    <section class="register">
-      <h3>{{ $t("default.Register a new account") }}</h3>
-      <RegisterForm @onRegistered="onRegistered" />
-    </section>
+    <h2>{{ $t("materio.Please login or create a new account") }}</h2>
+    <div class="wrapper">
+      <section class="login">
+        <h3>{{ $t("default.Login") }} </h3>
+        <LoginForm @onLogedIn="onLogedIn" />
+      </section>
+      <section class="register">
+        <h3>{{ $t("default.Register a new account") }}</h3>
+        <RegisterForm @onRegistered="onRegistered" />
+      </section>
+    </div>
   </div>
 </template>
 
@@ -24,17 +27,19 @@ export default {
     password:null,
     registerEmail:null
   }),
-  props:['callbackargs'],
+  props:['callbackargs', 'onLogedInBack', 'onRegisteredBack'],
   methods: {
     ...mapActions({
       userLogin: 'User/userLogin',
       userRegister: 'User/userRegister'
     }),
     onLogedIn () {
-      this.$emit('onLogedIn', this.callbackargs)
+      // this.$emit('onLogedIn', this.callbackargs)
+      this.onLogedInBack(this.callbackargs)
     },
     onRegistered () {
-      this.$emit('onRegistered', this.callbackargs)
+      // this.$emit('onRegistered', this.callbackargs)
+      this.onRegisteredBack(this.callbackargs)
     }
   },
   components: {

+ 1 - 1
web/themes/custom/materiotheme/vuejs/components/Pages/Article.vue

@@ -80,7 +80,7 @@
           ></div>
         </div>
         <aside class="linked-materials">
-          <h3 class="field__label">{{$t("materio.Linked Materials")}}</h3>
+          <h3 class="field__label">{{ $t('materio.Linked Materials') }}</h3>
           <div class="cards-list">
             <ul class="">
               <li v-for="node in article.linked_materials" v-bind:key="node.id">

+ 3 - 1
web/themes/custom/materiotheme/vuejs/components/Pages/Home.vue

@@ -1,9 +1,11 @@
 <script>
 
 import Vue from 'vue'
+import productsMixins from 'vuejs/components/productsMixins'
 
 export default {
   props: ['html', 'full'], // get the html from parent with props
+  mixins: [productsMixins],
   data() {
     return {
       template: null, // compiled template from html used in render
@@ -151,7 +153,7 @@ export default {
   },
   watch: {
     html: function(val) {
-      console.log('html prop changed', val)
+      // console.log('html prop changed', val)
       this.compileTemplate()
     }
   }

+ 138 - 0
web/themes/custom/materiotheme/vuejs/components/productsMixins.js

@@ -0,0 +1,138 @@
+// https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5
+
+import { REST } from 'vuejs/api/rest-axios'
+import Modal from 'vuejs/components/Helper/Modal'
+import LoginRegister from 'vuejs/components/Helper/LoginRegister'
+import { mapState } from 'vuex'
+
+export default {
+  components: {
+    Modal,
+    LoginRegister
+  },
+  computed: {
+    ...mapState({
+      isloggedin: state => state.User.isloggedin,
+      isAdherent: state => state.User.isAdherent,
+      csrftoken: state => state.User.csrftoken
+    })
+  },
+  methods: {
+    closeModal () {
+      this.showLoginModal = false
+    },
+    checkaddtocart (e, variation_id) {
+      console.log('checkaddtocart', e, variation_id, this.isloggedin)
+
+      if (!this.isloggedin) {
+        // show popup for login or register
+        // login or register event will be catched by onLogedin or onRegistered
+        // this.showLoginModal = variation_id
+        this.showLoginModal(variation_id)
+      } else {
+        // if already logedin directly goes to cart operations
+        this.addtocart(variation_id)
+      }
+    },
+    showLoginModal (variation_id) {
+      this.$modal.show(
+        LoginRegister,
+        // props
+        {
+          // item: this.item,
+          callbackargs: { variation_id: variation_id },
+          // close: (variation_id) => { this.closeModal(variation_id) },
+          onLogedInBack: (cba) => { this.onLogedIn(cba.variation_id) },
+          onRegisteredBack: (cba) => { this.onRegistered(cba.variation_id) }
+          // // not really an event
+          // // more a callback function passed as prop to the component
+          // addNoteId: (id) => {
+          //   // no needs to refresh the entire item via searchresults
+          //   // plus if we are in article, there is not searchresults
+          //   // this.refreshItem({id: this.item.id})
+          //   // instead create the note id directly
+          //   this.item.note = { id: id }
+          // }
+        },
+        // settings
+        {
+          // name: `modal-${this.item.id}`,
+          draggable: false,
+          classes: 'vm--modale-loginregister',
+          width: '500px',
+          height: '350px'
+        }
+      )
+    },
+    // event bubbled from modal login form
+    onLogedIn (variation_id) {
+      console.log('Product: onLogedIn. variation_id', variation_id)
+      this.addtocart(variation_id)
+    },
+    // event bubbled from modal register form
+    onRegistered (variation_id) {
+      console.log('Product: onRegistered. variation_id', variation_id)
+      this.addtocart(variation_id)
+    },
+    getCarts () {
+      // this is bugging on stage
+      return REST.get('/cart?_format=json', {}, { 'X-CSRF-Token': this.csrftoken })
+        // .then(({ data }) => {
+        //   console.log('current user carts: data', data)
+        // })
+        .catch((error) => {
+          console.warn('Issue with get cart', error)
+          Promise.reject(error)
+        })
+    },
+    deleteCart (order_id) {
+      console.log('deleting cart ', order_id)
+      return REST.delete(`/cart/${order_id}/items?_format=json`)
+        .then(({ data }) => {
+          console.log(`product cart ${order_id} deleted: data`, data)
+        })
+        .catch((error) => {
+          console.warn(`Issue with cart ${order_id} deleting`, error)
+          Promise.reject(error)
+        })
+    },
+    clearCarts (data) {
+      const promises = []
+      // clear each cart as a promise
+      for (let i = 0; i < data.length; i++) {
+        promises.push(this.deleteCart(data[i].order_id))
+      }
+      // return all the promises as one
+      return Promise.all(promises)
+    },
+    addtocart (variation_id) {
+      console.log('addtocart')
+      this.getCarts()
+        .then(({ data }) => {
+          console.log('current user carts: data', data)
+          this.clearCarts(data)
+            .then(() => {
+              console.log('all carts cleared')
+              // fill the cart with new product
+              REST.post('/cart/add?_format=json', [{
+                purchased_entity_type: 'commerce_product_variation',
+                purchased_entity_id: variation_id,
+                quantity: this.quantity
+              }])
+                .then(({ data }) => {
+                  console.log('product added to cart: data', data)
+                  this.closeModal()
+                  // redirect to /cart
+                  // window.location.href = "/cart"
+                  // TODO: redirect to checkout instead of cart
+                  window.location.href = `/checkout/${data[0].order_id}/order_information`
+                })
+                .catch((error) => {
+                  console.warn('Issue with product add to cart', error)
+                  Promise.reject(error)
+                })
+            })
+        })
+    }
+  }
+}

部分文件因文件數量過多而無法顯示