@mframework/layer-commerce 0.0.5 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/app/components/catalog/product/ProductAccordion/ProductAccordion.vue +41 -0
  2. package/app/components/catalog/product/ProductAccordion/__tests__/ProductAccordion.spec.ts +15 -0
  3. package/app/components/catalog/product/ProductAccordion/types.ts +5 -0
  4. package/app/components/catalog/product/ProductProperties/ProductProperties.vue +52 -0
  5. package/app/components/catalog/product/ProductProperties/__tests__/ProductProperties.spec.ts +15 -0
  6. package/app/components/catalog/product/ProductProperties/types.ts +5 -0
  7. package/app/components/catalog/product/ProductSlider/ProductSlider.vue +28 -0
  8. package/app/components/catalog/product/ProductSlider/__tests__/ProductSlider.spec.ts +14 -0
  9. package/app/components/catalog/product/ProductSlider/types.ts +7 -0
  10. package/app/components/catalog/product/RecommendedProducts/RecommendedProducts.vue +12 -0
  11. package/app/components/catalog/product/RecommendedProducts/types.ts +5 -0
  12. package/app/components/catalog/product/RenderContentProductSlider/RenderContentProductSlider.vue +11 -0
  13. package/app/components/catalog/product/add-attribute.vue +54 -0
  14. package/app/components/catalog/product/add-product-type.vue +54 -0
  15. package/app/components/catalog/product/add-product.vue +53 -0
  16. package/app/components/catalog/product/add-showcase.vue +52 -0
  17. package/app/components/catalog/product/add-station.vue +54 -0
  18. package/app/components/catalog/product/bestsellers.vue +69 -0
  19. package/app/components/catalog/product/bidding.vue +93 -0
  20. package/app/components/catalog/product/colorOptions.vue +58 -0
  21. package/app/components/catalog/product/deals.vue +61 -0
  22. package/app/components/catalog/product/exclusives.vue +58 -0
  23. package/app/components/catalog/product/featuredproducts.vue +69 -0
  24. package/app/components/catalog/product/giftCard.vue +63 -0
  25. package/app/components/catalog/product/latestproducts.vue +58 -0
  26. package/app/components/catalog/product/productCard.vue +71 -0
  27. package/app/components/catalog/product/productCompare.vue +60 -0
  28. package/app/components/catalog/product/productCompareTable.vue +441 -0
  29. package/app/components/catalog/product/productDetails.vue +120 -0
  30. package/app/components/catalog/product/productFaqs.vue +17 -0
  31. package/app/components/catalog/product/productGallery.vue +16 -0
  32. package/app/components/catalog/product/productQty.vue +54 -0
  33. package/app/components/catalog/product/productReviews.vue +56 -0
  34. package/app/components/catalog/product/productSpecs.vue +116 -0
  35. package/app/components/catalog/product/radiostation.vue +36 -0
  36. package/app/components/catalog/product/recentlyviewed.vue +43 -0
  37. package/app/components/catalog/product/relatedbrands.vue +54 -0
  38. package/app/components/catalog/product/relatedproducts.vue +58 -0
  39. package/app/components/catalog/product/relatedstations.vue +40 -0
  40. package/app/components/catalog/product/shippingOptions.vue +41 -0
  41. package/app/components/catalog/product/sizeOptions.vue +47 -0
  42. package/app/components/catalog/product/update-attribute-set.vue +209 -0
  43. package/app/components/catalog/product/update-attribute.vue +118 -0
  44. package/app/components/catalog/product/update-product.vue +372 -0
  45. package/app/components/catalog/product/update-showcase.vue +153 -0
  46. package/app/components/catalog/shops/relatedstores.vue +52 -0
  47. package/app/components/catalog/shops/restaurant.vue +66 -0
  48. package/app/components/catalog/shops/stores.vue +44 -0
  49. package/app/components/catalog/vendor/README.md +3 -0
  50. package/app/components/catalog/vendor/blocks/biggestcustomers.vue +33 -0
  51. package/app/components/catalog/vendor/blocks/lowestselling.vue +33 -0
  52. package/app/components/catalog/vendor/blocks/topcategories.vue +33 -0
  53. package/app/components/catalog/vendor/blocks/topproducts.vue +27 -0
  54. package/app/components/catalog/vendor/pages/attributes.vue +43 -0
  55. package/app/components/catalog/vendor/pages/commissions.vue +43 -0
  56. package/app/components/catalog/vendor/pages/crm.vue +67 -0
  57. package/app/components/catalog/vendor/pages/dashboard.vue +46 -0
  58. package/app/components/catalog/vendor/pages/emails.vue +43 -0
  59. package/app/components/catalog/vendor/pages/enquiries.vue +43 -0
  60. package/app/components/catalog/vendor/pages/invoices.vue +43 -0
  61. package/app/components/catalog/vendor/pages/orders.vue +68 -0
  62. package/app/components/catalog/vendor/pages/products.vue +55 -0
  63. package/app/components/catalog/vendor/pages/reviews.vue +48 -0
  64. package/app/components/catalog/vendor/pages/shipments.vue +43 -0
  65. package/app/components/catalog/vendor/pages/stores.vue +43 -0
  66. package/app/components/content/blocks/breadcrumbs.vue +0 -0
  67. package/app/components/content/blocks/currencySwitcher.vue +0 -0
  68. package/app/components/content/blocks/languageSwitcher.vue +0 -0
  69. package/app/components/content/blocks/videoproduct.vue +9 -0
  70. package/app/components/content/pages/checkout.vue +118 -0
  71. package/app/components/content/pages/meeoviGlobal.vue +68 -0
  72. package/app/components/content/pages/pickup-locations.vue +238 -0
  73. package/app/components/content/pages/showcases.vue +90 -0
  74. package/app/components/content/pages/success.vue +60 -0
  75. package/app/components/marketing/add-brand.vue +54 -0
  76. package/app/components/marketing/add-incentive.vue +54 -0
  77. package/app/components/marketing/promotions/giftcards.vue +127 -0
  78. package/app/components/marketing/promotions/subscriptions.vue +134 -0
  79. package/app/components/marketing/update-incentive.vue +326 -0
  80. package/app/components/menus/lowernav.vue +78 -0
  81. package/app/components/partials/LocaleSelector.vue +24 -0
  82. package/app/components/partials/ShoppingCart.vue +128 -0
  83. package/app/components/partials/StripePayment.vue +149 -0
  84. package/app/components/partials/addToCartBtn.vue +40 -0
  85. package/app/components/partials/cartItem.vue +124 -0
  86. package/app/components/partials/checkoutButton.vue +44 -0
  87. package/app/components/partials/compareBtn.vue +68 -0
  88. package/app/components/partials/ratings.vue +13 -0
  89. package/app/components/partials/store/CurrencySelector.vue +133 -0
  90. package/app/components/partials/store/StoreSwitcher.vue +13 -0
  91. package/app/components/related/brandCard.vue +41 -0
  92. package/app/components/related/incentiveCard.vue +44 -0
  93. package/app/components/related/invoiceCard.vue +43 -0
  94. package/app/components/related/orderCard.vue +43 -0
  95. package/app/components/related/relatedproducts.vue +17 -0
  96. package/app/components/sales/CartPageContent/CartPageContent.vue +43 -0
  97. package/app/components/sales/CheckoutAddress/CheckoutAddress.vue +50 -0
  98. package/app/components/sales/CheckoutAddress/__tests__/CheckoutAddress.spec.ts +16 -0
  99. package/app/components/sales/CheckoutAddress/types.ts +16 -0
  100. package/app/components/sales/CheckoutPayment/CheckoutPayment.vue +65 -0
  101. package/app/components/sales/CheckoutPayment/__tests__/CheckoutPayment.spec.ts +14 -0
  102. package/app/components/sales/CheckoutPayment/types.ts +12 -0
  103. package/app/components/sales/OrderSummary/OrderSummary.vue +57 -0
  104. package/app/components/sales/OrderSummary/__tests__/ContactInformation.spec.ts +52 -0
  105. package/app/components/sales/OrderSummary/types.ts +5 -0
  106. package/app/components/sales/incentives.vue +247 -0
  107. package/app/components/sales/invoices.vue +107 -0
  108. package/app/components/sales/orders.vue +378 -0
  109. package/app/components/sales/shipments.vue +65 -0
  110. package/app/components/sales/transactions.vue +109 -0
  111. package/app/components/shop/add-shop.vue +54 -0
  112. package/app/components/shop/cart/cartItem.vue +182 -0
  113. package/app/components/shop/cart/checkout.vue +415 -0
  114. package/app/components/shop/checkout/StripeCardElement.vue +206 -0
  115. package/app/components/shop/checkout/StripeCheckout.vue +49 -0
  116. package/app/components/shop/checkout/addressBilling.vue +263 -0
  117. package/app/components/shop/checkout/addressShipping.vue +175 -0
  118. package/app/components/shop/checkout/cart/ProductItem.vue +56 -0
  119. package/app/components/shop/checkout/cart/PromotionItem.vue +53 -0
  120. package/app/composables/useCustomer/__tests__/useCustomer.spec.ts +1 -1
  121. package/app/composables/useProductReviews/__tests__/useProductReviews.spec.ts +1 -1
  122. package/app/stores/cart.ts +1 -1
  123. package/app/types/Direction.type.ts +1 -1
  124. package/app/types/Global.type.ts +6 -6
  125. package/app/types/Layout.type.ts +1 -1
  126. package/app/types/index.ts +1 -1
  127. package/app/{normalizers → types/normalizers}/Cart.query.ts +1 -1
  128. package/app/{normalizers → types/normalizers}/Cart.type.ts +2 -2
  129. package/app/{normalizers → types/normalizers}/Checkout.query.ts +2 -2
  130. package/app/{normalizers → types/normalizers}/Config.query.ts +1 -1
  131. package/app/{normalizers → types/normalizers}/Config.type.ts +1 -1
  132. package/app/{normalizers → types/normalizers}/ContactForm.query.ts +2 -2
  133. package/app/{normalizers → types/normalizers}/CreditMemo.type.ts +1 -1
  134. package/app/{normalizers → types/normalizers}/GiftCard.type.ts +1 -1
  135. package/app/{normalizers → types/normalizers}/Invoice.type.ts +1 -1
  136. package/app/{normalizers → types/normalizers}/MyAccount.query.ts +1 -1
  137. package/app/{normalizers → types/normalizers}/MyAccount.type.ts +1 -1
  138. package/app/{normalizers → types/normalizers}/NewsletterSubscription.query.ts +1 -1
  139. package/app/{normalizers → types/normalizers}/Order.query.ts +1 -1
  140. package/app/{normalizers → types/normalizers}/Order.type.ts +2 -2
  141. package/app/{normalizers → types/normalizers}/Payment.type.ts +1 -1
  142. package/app/{normalizers → types/normalizers}/ProductCompare.query.ts +1 -1
  143. package/app/{normalizers → types/normalizers}/ProductCompare.type.ts +1 -1
  144. package/app/{normalizers → types/normalizers}/ProductList.query.ts +2 -2
  145. package/app/{normalizers → types/normalizers}/ProductList.type.ts +2 -2
  146. package/app/{normalizers → types/normalizers}/Return.type.ts +1 -1
  147. package/app/{normalizers → types/normalizers}/Review.query.ts +1 -1
  148. package/app/{normalizers → types/normalizers}/Review.type.ts +1 -1
  149. package/app/{normalizers → types/normalizers}/StoreInPickUp.query.ts +1 -1
  150. package/app/{normalizers → types/normalizers}/Subscription.type.ts +1 -1
  151. package/app/{normalizers → types/normalizers}/Transaction.type.ts +1 -1
  152. package/app/{normalizers → types/normalizers}/UrlRewrites.query.ts +1 -1
  153. package/app/{normalizers → types/normalizers}/UrlRewrites.type.ts +1 -1
  154. package/app/{normalizers → types/normalizers}/Wishlist.query.ts +4 -4
  155. package/app/{normalizers → types/normalizers}/Wishlist.type.ts +1 -1
  156. package/app/utils/Address/Address.type.ts +1 -1
  157. package/app/utils/Address/index.ts +5 -5
  158. package/app/utils/Cart/Cart.ts +1 -1
  159. package/app/utils/Currency/Currency.ts +1 -1
  160. package/app/utils/History/History.type.ts +1 -1
  161. package/app/utils/Menu/Menu.ts +1 -1
  162. package/app/utils/Menu/Menu.type.ts +2 -2
  163. package/app/utils/Orders/Orders.ts +1 -1
  164. package/app/utils/Preload/CategoryPreload.ts +2 -2
  165. package/app/utils/Preload/ProductPreload.ts +1 -1
  166. package/app/utils/Preload/index.ts +1 -1
  167. package/app/utils/Price/Price.ts +1 -1
  168. package/app/utils/Product/Extract.ts +1 -1
  169. package/app/utils/Product/Product.ts +1 -1
  170. package/app/utils/Product/Product.type.ts +1 -1
  171. package/app/utils/Product/Transform.ts +1 -1
  172. package/app/utils/Wishlist/Wishlist.ts +1 -1
  173. package/app/utils/client.ts +20 -20
  174. package/package.json +1 -3
  175. package/tsconfig.json +2 -2
  176. package/app/cart/useCart.ts +0 -1
  177. /package/app/{components → composables}/ChevronIcon/ChevronIcon.config.ts +0 -0
  178. /package/app/{components → composables}/DateSelect/DateSelect.config.ts +0 -0
  179. /package/app/{components → composables}/Field/Field.config.ts +0 -0
  180. /package/app/{components → composables}/FieldDate/FieldDate.config.ts +0 -0
  181. /package/app/{components → composables}/Form/Form.type.ts +0 -0
  182. /package/app/{components → composables}/Product/Product.config.ts +0 -0
  183. /package/app/{components → composables}/Product/Stock.config.ts +0 -0
  184. /package/app/{components → composables}/ProductCustomizableOption/ProductCustomizableOption.config.ts +0 -0
  185. /package/app/{components → composables}/ProductGallery/ProductGallery.config.ts +0 -0
  186. /package/app/{components → composables}/ProductReviews/ProductReviews.config.ts +0 -0
  187. /package/app/{normalizers → types/normalizers}/Category.query.ts +0 -0
  188. /package/app/{normalizers → types/normalizers}/Category.type.ts +0 -0
  189. /package/app/{normalizers → types/normalizers}/CheckEmail.query.ts +0 -0
  190. /package/app/{normalizers → types/normalizers}/Checkout.type.ts +0 -0
  191. /package/app/{normalizers → types/normalizers}/CmsBlock.query.ts +0 -0
  192. /package/app/{normalizers → types/normalizers}/CmsBlock.type.ts +0 -0
  193. /package/app/{normalizers → types/normalizers}/CmsPage.query.ts +0 -0
  194. /package/app/{normalizers → types/normalizers}/CmsPage.type.ts +0 -0
  195. /package/app/{normalizers → types/normalizers}/Menu.query.ts +0 -0
  196. /package/app/{normalizers → types/normalizers}/Menu.type.ts +0 -0
  197. /package/app/{normalizers → types/normalizers}/ProductAlerts.query.ts +0 -0
  198. /package/app/{normalizers → types/normalizers}/Region.query.ts +0 -0
  199. /package/app/{normalizers → types/normalizers}/Region.type.ts +0 -0
  200. /package/app/{normalizers → types/normalizers}/Slider.query.ts +0 -0
  201. /package/app/{normalizers → types/normalizers}/Slider.type.ts +0 -0
  202. /package/app/{normalizers → types/normalizers}/StoreInPickUp.type.ts +0 -0
  203. /package/app/{routes → types/routes}/CategoryPage/CategoryPage.config.ts +0 -0
  204. /package/app/{routes → types/routes}/CategoryPage/CategoryPage.type.ts +0 -0
  205. /package/app/{routes → types/routes}/Checkout/Checkout.config.ts +0 -0
  206. /package/app/{routes → types/routes}/Checkout/Checkout.type.ts +0 -0
  207. /package/app/{routes → types/routes}/MyAccount/MyAccount.config.ts +0 -0
  208. /package/app/{routes → types/routes}/SearchPage/SearchPage.config.ts +0 -0
  209. /package/app/{routes → types/routes}/UrlRewrites/UrlRewrites.config.ts +0 -0
@@ -0,0 +1,149 @@
1
+ <!-- components/StripePayment.vue -->
2
+ <template>
3
+ <div class="stripe-payment-container">
4
+ <div v-if="error" class="error-message">
5
+ {{ error }}
6
+ </div>
7
+
8
+ <div v-if="stripe && clientSecret" class="payment-form">
9
+ <form @submit.prevent="handleSubmit">
10
+ <div ref="paymentElement"></div>
11
+
12
+ <button type="submit" class="payment-button" :disabled="!stripe || loading">
13
+ <span v-if="loading">Processing...</span>
14
+ <span v-else>Pay Now</span>
15
+ </button>
16
+ </form>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import {
23
+ ref,
24
+ onMounted
25
+ } from 'vue'
26
+ import type {
27
+ Stripe,
28
+ StripeElements
29
+ } from '@stripe/stripe-js'
30
+ import {
31
+ loadStripe
32
+ } from '@stripe/stripe-js'
33
+
34
+ const props = defineProps < {
35
+ orderCode: string,
36
+ clientSecret: string
37
+ } > ()
38
+
39
+ const stripe = ref < Stripe | null > (null)
40
+ const elements = ref < StripeElements | null > (null)
41
+ const error = ref < string | null > (null)
42
+ const loading = ref(false)
43
+ const paymentElement = ref < HTMLDivElement | null > (null)
44
+ const clientSecret = ref < string > (props.clientSecret)
45
+
46
+ onMounted(async () => {
47
+ try {
48
+ stripe.value = await loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY)
49
+ if (stripe.value && clientSecret.value) {
50
+ elements.value = stripe.value.elements({
51
+ clientSecret: clientSecret.value,
52
+ appearance: {
53
+ theme: 'stripe',
54
+ variables: {
55
+ colorPrimary: '#0570de',
56
+ colorBackground: '#ffffff',
57
+ colorText: '#30313d'
58
+ }
59
+ }
60
+ })
61
+
62
+ // Create and mount payment element
63
+ if (elements.value && paymentElement.value) {
64
+ const element = elements.value.create('payment')
65
+ element.mount(paymentElement.value as HTMLDivElement)
66
+ }
67
+ }
68
+ } catch (err) {
69
+ error.value = 'Failed to initialize Stripe'
70
+ console.error('Stripe initialization error:', err)
71
+ }
72
+ })
73
+
74
+ const handleSubmit = async () => {
75
+ if (!stripe.value || !elements.value) {
76
+ return
77
+ }
78
+
79
+ try {
80
+ loading.value = true
81
+ error.value = null
82
+
83
+ const {
84
+ error: stripeError
85
+ } = await stripe.value.confirmPayment({
86
+ elements: elements.value,
87
+ confirmParams: {
88
+ return_url: `${window.location.origin}/checkout/confirmation/${props.orderCode}`,
89
+ },
90
+ })
91
+
92
+ if (stripeError) {
93
+ error.value = stripeError.message || 'Payment failed'
94
+ }
95
+ } catch (err) {
96
+ error.value = 'An unexpected error occurred'
97
+ console.error('Payment error:', err)
98
+ } finally {
99
+ loading.value = false
100
+ }
101
+ }
102
+ </script>
103
+
104
+ <style scoped>
105
+ .stripe-payment-container {
106
+ max-width: 500px;
107
+ margin: 0 auto;
108
+ padding: 20px;
109
+ }
110
+
111
+ .error-message {
112
+ color: #df1b41;
113
+ background-color: #fff0f0;
114
+ padding: 12px;
115
+ border-radius: 4px;
116
+ margin-bottom: 16px;
117
+ }
118
+
119
+ .payment-form {
120
+ background: #ffffff;
121
+ padding: 20px;
122
+ border-radius: 4px;
123
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
124
+ }
125
+
126
+ .payment-button {
127
+ background: #5469d4;
128
+ color: #ffffff;
129
+ border: none;
130
+ border-radius: 4px;
131
+ padding: 12px 16px;
132
+ font-size: 16px;
133
+ font-weight: 600;
134
+ cursor: pointer;
135
+ display: block;
136
+ width: 100%;
137
+ margin-top: 24px;
138
+ transition: all 0.2s ease;
139
+ }
140
+
141
+ .payment-button:disabled {
142
+ opacity: 0.5;
143
+ cursor: not-allowed;
144
+ }
145
+
146
+ .payment-button:hover:not(:disabled) {
147
+ filter: brightness(1.1);
148
+ }
149
+ </style>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div class="flex flex-col gap-2">
3
+ <v-btn size="lg" class="w-full xs:ml-4" :disabled="loading || hasItemInCart" @click="addToCart">
4
+ <template #prefix>
5
+ <SfIconShoppingCart size="sm" />
6
+ </template>
7
+ Add to Cart
8
+ </v-btn>
9
+ <compareBtn />
10
+ </div>
11
+ </template>
12
+
13
+ <script setup>
14
+ import { SfIconShoppingCart } from "@storefront-ui/vue";
15
+ import compareBtn from './compareBtn.vue';
16
+ import { useCartStore } from '~/stores/cart'
17
+
18
+ const props = defineProps({
19
+ product: {
20
+ type: Object,
21
+ required: true
22
+ }
23
+ });
24
+
25
+ const cart = useCartStore()
26
+
27
+ const addToCart = async (product) => {
28
+ try {
29
+ await cart.addItem({
30
+ sku: product.sku,
31
+ name: product.name,
32
+ price: product.price,
33
+ qty: 1
34
+ })
35
+ } catch (error) {
36
+ // Handle error (show notification, etc.)
37
+ console.error('Failed to add item to cart:', error)
38
+ }
39
+ }
40
+ </script>
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <div class="flex items-center py-4 border-b border-gray-200">
3
+ <div class="shrink-0 w-24 h-24">
4
+ <productCard :product="productForCard" />
5
+ </div>
6
+ <div class="ml-4 flex-1">
7
+ <h3 class="text-lg font-medium text-gray-900">{{ item.productVariant?.name }}</h3>
8
+ <p class="mt-1 text-sm text-gray-500">SKU: {{ item.productVariant?.sku }}</p>
9
+ <div class="mt-2 flex items-center">
10
+ <div class="flex items-center border border-gray-300 rounded">
11
+ <button
12
+ class="px-2 py-1 text-gray-600 hover:bg-gray-100"
13
+ @click="updateQuantity(item.id, item.quantity - 1)"
14
+ :disabled="item.quantity <= 1"
15
+ >
16
+ -
17
+ </button>
18
+ <span class="px-4 py-1">{{ item.quantity }}</span>
19
+ <button
20
+ class="px-2 py-1 text-gray-600 hover:bg-gray-100"
21
+ @click="updateQuantity(item.id, item.quantity + 1)"
22
+ >
23
+ +
24
+ </button>
25
+ </div>
26
+ <button
27
+ class="ml-4 text-sm text-red-600 hover:text-red-800"
28
+ @click="removeItem(item.id)"
29
+ >
30
+ Remove
31
+ </button>
32
+ </div>
33
+ </div>
34
+ <div class="ml-4 text-right">
35
+ <p class="text-lg font-medium text-gray-900">
36
+ {{ formatPrice(item.unitPriceWithTax || productForCardPrice) }}
37
+ </p>
38
+ <p v-if="item.listPriceWithTax && item.listPriceWithTax !== item.unitPriceWithTax" class="mt-1 text-sm text-gray-500 line-through">
39
+ {{ formatPrice(item.listPriceWithTax) }}
40
+ </p>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ import productCard from '../catalog/product/productCard.vue';
47
+ import { computed } from 'vue';
48
+
49
+ const props = defineProps<{ item: Record<string, any> }>();
50
+ const emit = defineEmits(['cart-changed'])
51
+ const nuxtApp = useNuxtApp()
52
+
53
+ // Prepare a product object compatible with productCard.vue
54
+ const productForCard = computed(() => {
55
+ const pv = props.item?.productVariant || {};
56
+ return {
57
+ id: pv?.product?.id || pv?.id || props.item?.id,
58
+ name: pv?.name || pv?.product?.name,
59
+ image: pv?.featuredAsset ? { filename_disk: pv.featuredAsset?.id } : (pv?.product?.image || {}),
60
+ brands: pv?.product?.brands || [],
61
+ currency: pv?.product?.currency || [],
62
+ price: (props.item?.unitPriceWithTax && props.item.unitPriceWithTax / 100) || pv?.price || 0,
63
+ rating: pv?.product?.rating || 0,
64
+ };
65
+ });
66
+
67
+ const productForCardPrice = computed(() => productForCard.value?.price || 0);
68
+
69
+ async function removeItem(orderLineId: string) {
70
+ try {
71
+ // Try to delete using Directus client
72
+ try {
73
+ if (nuxtApp.$directus && nuxtApp.$directus.items) {
74
+ await nuxtApp.$directus.items('order_lines').delete(orderLineId);
75
+ } else if (nuxtApp.$deleteItem) {
76
+ await nuxtApp.$deleteItem('order_lines', orderLineId);
77
+ }
78
+ } catch (e) {
79
+ console.warn('Directus delete failed, falling back to plugin helper or ignoring', e);
80
+ }
81
+
82
+ emit('cart-changed');
83
+ } catch (error) {
84
+ console.error('Failed to remove item:', error);
85
+ }
86
+ }
87
+
88
+ async function updateQuantity(orderLineId: string, newQuantity: number) {
89
+ if (newQuantity < 1) return;
90
+ try {
91
+ // Try to update via Directus SDK
92
+ try {
93
+ if (nuxtApp.$directus && nuxtApp.$directus.items) {
94
+ await nuxtApp.$directus.items('order_lines').update(orderLineId, { quantity: newQuantity });
95
+ } else if (nuxtApp.$createItem) {
96
+ // Fallback: read existing, delete and recreate with new quantity
97
+ const existing = await nuxtApp.$readItem('order_lines', orderLineId).catch(() => null);
98
+ if (existing) {
99
+ await nuxtApp.$deleteItem('order_lines', orderLineId).catch(() => null);
100
+ const payload = { ...existing, quantity: newQuantity };
101
+ delete payload.id;
102
+ await nuxtApp.$createItem('order_lines', payload).catch(() => null);
103
+ }
104
+ }
105
+ } catch (e) {
106
+ console.warn('Directus update fallback failed', e);
107
+ }
108
+
109
+ emit('cart-changed');
110
+ } catch (error) {
111
+ console.error('Failed to update quantity:', error);
112
+ }
113
+ }
114
+
115
+ function formatPrice(price: number) {
116
+ const p = price ?? 0;
117
+ // If price seems to be in cents (large integer), convert
118
+ const normalized = p > 1000 ? p / 100 : p;
119
+ return new Intl.NumberFormat('en-US', {
120
+ style: 'currency',
121
+ currency: 'USD'
122
+ }).format(normalized);
123
+ }
124
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <div>
3
+ <v-btn color="primary" @click="redirectToCheckout">
4
+ Proceed to Payment
5
+ </v-btn>
6
+ </div>
7
+ </template>
8
+
9
+ <script setup>
10
+ import getActiveOrderQuery from '#graphql/app/commerce/queries/activeOrder.gql';
11
+
12
+ const nuxtApp = useNuxtApp();
13
+
14
+ const redirectToCheckout = async () => {
15
+ try {
16
+ // Fetch the active order to get the order code or id
17
+ const orderRes = await nuxtApp.$graphql.request(getActiveOrderQuery);
18
+ const order = orderRes?.activeOrder;
19
+ if (!order) return;
20
+
21
+ // Attempt to create a checkout session in Directus
22
+ try {
23
+ const payload = {
24
+ orderCode: order.code,
25
+ items: (order.lines || []).map((l) => ({ sku: l?.productVariant?.sku, quantity: l.quantity }))
26
+ };
27
+ const created = await nuxtApp.$createItem('checkout_sessions', payload);
28
+ // support common response shapes
29
+ const redirectUrl = created?.redirect_url || created?.data?.redirect_url || created?.url || created?.data?.url;
30
+ if (redirectUrl) {
31
+ window.location.href = redirectUrl;
32
+ return;
33
+ }
34
+ } catch (e) {
35
+ console.warn('Directus checkout session creation failed, falling back:', e);
36
+ }
37
+
38
+ // Fallback: redirect to local confirmation route
39
+ window.location.href = `/checkout/confirmation/${order.code}`;
40
+ } catch (error) {
41
+ console.error('Checkout redirect failed:', error);
42
+ }
43
+ };
44
+ </script>
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <SfButton size="sm" variant="tertiary" @click="handleCompare" :disabled="isInCompare">
3
+ <template #prefix>
4
+ <SfIconCompareArrows size="sm" />
5
+ </template>
6
+ {{ buttonText }}
7
+ </SfButton>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { computed } from 'vue';
12
+ import { useCompareStore } from '../../stores/compare';
13
+ import { useNuxtApp } from '#imports';
14
+ import type { Product } from '../../types/product';
15
+
16
+ // Define props
17
+ const props = defineProps<{ product: Product }>();
18
+
19
+ const compareStore = useCompareStore();
20
+ const { $directus } = useNuxtApp() as any;
21
+
22
+ // Check if the product is already in compare list
23
+ const isInCompare = computed(() => {
24
+ return compareStore.getComparedProducts.some((product: { sku: string; }) => product.sku === props.product?.sku) || compareStore.getComparedProductSkus.includes(props.product?.sku);
25
+ });
26
+
27
+ // Dynamically update button text
28
+ const buttonText = computed(() => (isInCompare.value ? 'In Compare List' : 'Add to Compare'));
29
+
30
+ // Handle Add/Remove from Compare list using Directus where possible
31
+ const handleCompare = async () => {
32
+ try {
33
+ if (!props.product || !props.product.sku) {
34
+ throw new Error('Product data is required');
35
+ }
36
+
37
+ const sku = props.product.sku;
38
+
39
+ if (isInCompare.value) {
40
+ // Remove from Directus compare_items collection if exists
41
+ try {
42
+ const itemsRes = await $directus.$readItems('compare_items', { filter: { sku: { _eq: sku } } });
43
+ const items = itemsRes?.data || itemsRes || [];
44
+ for (const it of items) {
45
+ const id = it.id || it._id || it.ID;
46
+ if (id) await $directus.$deleteItem('compare_items', id);
47
+ }
48
+ } catch (e) {
49
+ // ignore Directus errors, still update local store
50
+ console.warn('Directus remove compare item failed:', e);
51
+ }
52
+
53
+ compareStore.removeComparedProduct(sku);
54
+ } else {
55
+ // Add to Directus compare_items collection
56
+ try {
57
+ await $directus.$createItem('compare_items', { sku });
58
+ } catch (e) {
59
+ console.warn('Directus create compare item failed:', e);
60
+ }
61
+
62
+ compareStore.addComparedProductSku(sku);
63
+ }
64
+ } catch (error) {
65
+ console.error('Error handling compare:', error);
66
+ }
67
+ };
68
+ </script>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <v-rating size="lg" :half-increment="true" :model-value="(rating?.rating)" :max="5" />
3
+ </template>
4
+
5
+ <script setup>
6
+
7
+ const props = defineProps({
8
+ rating: {
9
+ type: Number,
10
+ default: 5
11
+ },
12
+ });
13
+ </script>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <div class="currency-selector">
3
+ <select v-model="selectedCurrency" @change="handleCurrencyChange" class="currency-select">
4
+ <option v-for="currency in availableCurrencies" :key="currency.code" :value="currency.code">
5
+ {{ currency.symbol }} {{ currency.code }}
6
+ </option>
7
+ </select>
8
+ </div>
9
+ </template>
10
+
11
+ <script setup>
12
+ import {
13
+ ref,
14
+ onMounted,
15
+ watch
16
+ } from 'vue'
17
+ import {
18
+ useCurrencyStore
19
+ } from '~/stores/currency'
20
+ import {
21
+ useQuery,
22
+ useMutation
23
+ } from '@vue/apollo-composable'
24
+ import {
25
+ CURRENCY_QUERY
26
+ } from '#graphql/commerce/queries/currency.gql'
27
+ import {
28
+ UPDATE_USER_CURRENCY
29
+ } from '#graphql/commerce/mutations/updateUserCurrency.gql'
30
+ import {
31
+ getCurrencySymbol
32
+ } from '~/utils/currency'
33
+ import {
34
+ useCurrency
35
+ } from '~/app/composables/useCurrency'
36
+
37
+ const store = useCurrencyStore()
38
+ const selectedCurrency = ref('')
39
+ const availableCurrencies = ref([])
40
+
41
+ const {
42
+ currentCurrency,
43
+ setCurrency
44
+ } = useCurrency()
45
+
46
+ // Fetch currency data from Magento
47
+ const {
48
+ result: currencyResult
49
+ } = useQuery(CURRENCY_QUERY)
50
+
51
+ // Mutation for updating user currency preference
52
+ const {
53
+ mutate: updateUserCurrency
54
+ } = useMutation(UPDATE_USER_CURRENCY)
55
+
56
+ // Watch for currency data changes
57
+ watch(currencyResult, (newResult) => {
58
+ if (newResult?.currency) {
59
+ const {
60
+ available_currency_codes,
61
+ exchange_rates,
62
+ default_display_currency_code
63
+ } = newResult.currency
64
+
65
+ // Map available currencies with their symbols
66
+ availableCurrencies.value = available_currency_codes.map(code => ({
67
+ code,
68
+ symbol: getCurrencySymbol(code),
69
+ rate: exchange_rates.find(rate => rate.currency_to === code)?.rate || 1
70
+ }))
71
+
72
+ // Set initial currency from user preference or default
73
+ const userCurrency = store.getCurrentCurrency
74
+ selectedCurrency.value = userCurrency || default_display_currency_code
75
+
76
+ // Update exchange rates in store
77
+ const ratesObj = {}
78
+ exchange_rates.forEach(({
79
+ currency_to,
80
+ rate
81
+ }) => {
82
+ ratesObj[currency_to] = rate
83
+ })
84
+ store.setExchangeRates(ratesObj)
85
+ }
86
+ })
87
+
88
+ // Handle currency change
89
+ const handleCurrencyChange = async () => {
90
+ await setCurrency(selectedCurrency.value)
91
+
92
+ // If user is logged in, save preference
93
+ if (store.user) {
94
+ try {
95
+ await updateUserCurrency({
96
+ variables: {
97
+ currency: selectedCurrency.value
98
+ }
99
+ })
100
+ } catch (error) {
101
+ console.error('Failed to update user currency preference:', error)
102
+ }
103
+ }
104
+ }
105
+
106
+ onMounted(() => {
107
+ // Initialize with store currency if available
108
+ if (currentCurrency.value) {
109
+ selectedCurrency.value = currentCurrency.value
110
+ }
111
+ })
112
+ </script>
113
+
114
+ <style scoped>
115
+ .currency-selector {
116
+ display: inline-block;
117
+ margin: 0 10px;
118
+ }
119
+
120
+ .currency-select {
121
+ padding: 5px 10px;
122
+ border: 1px solid #ddd;
123
+ border-radius: 4px;
124
+ background-color: white;
125
+ cursor: pointer;
126
+ font-size: 14px;
127
+ }
128
+
129
+ .currency-select:focus {
130
+ outline: none;
131
+ border-color: #007bff;
132
+ }
133
+ </style>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div class="container">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+
9
+ </script>
10
+
11
+ <style>
12
+
13
+ </style>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <div>
3
+ <section data-bs-version="5.1" data-sortbtn="btn-primary">
4
+ <div class="container">
5
+ <div class="row main justify-content-center">
6
+ <div class="col-lg-12 p-4">
7
+ <div class="image-element card-wrapper">
8
+ <NuxtImg class="brandLogo" :src="`${$directus.url}assets/${brand.image?.filename_disk}`" :alt="brand.name" />
9
+ <!--<div class="mbr-overlay card-overlay"></div>-->
10
+ <div class="wrapper">
11
+ <h5 class="card-title mbr-fonts-style align-left display-2">
12
+ {{ brand.name }}</h5>
13
+ <div class="collapsed-content">
14
+ <div class="mbr-section-btn"><a class="btn btn-md btn-info display-4"
15
+ :href="`/commerce/brand/${brand.id}`">View Brand</a></div>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </section>
23
+ </div>
24
+ </template>
25
+
26
+ <script setup>
27
+ import {
28
+ ref,
29
+ onMounted
30
+ } from 'vue'
31
+
32
+ const props = defineProps({
33
+ brand: {
34
+ type: Object,
35
+ required: true,
36
+ },
37
+ });
38
+ const {
39
+ brand
40
+ } = props;
41
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <div>
3
+ <!--<profilebar />-->
4
+ <section data-bs-version="5.1" class="firmm4_features1 features1 cid-uhBuptnWmV" id="features1-9v"
5
+ data-sortbtn="btn-primary">
6
+ <div class="container-fluid">
7
+ <div class="row">
8
+ <div class="col-12 title_block">
9
+ <h3 class="mbr-section-title mbr-fonts-style align-center mb-0 display-2">
10
+ <strong>Incentive: {{ incentive?.id }}</strong></h3>
11
+ </div>
12
+ </div>
13
+ <div class="row justify-content-center">
14
+ <div class="card col-12">
15
+ <div class="card_wrapper">
16
+ <div class="card-box">
17
+ <div class="icon_block">
18
+ <div class="iconfont-wrapper">
19
+ <span class="mbr-iconfont mobi-mbri-cart-full mobi-mbri"></span>
20
+ </div>
21
+ </div>
22
+ <p class="card-text mbr-fonts-style display-4">Incentive: {{ incentive?.id }}</p>
23
+ <p class="card-text mbr-fonts-style display-4">Incentive Date: {{ new Date(incentive?.date_created).toLocaleDateString() }}</p>
24
+ <p class="card-text mbr-fonts-style display-4">Bill to Name: {{ incentive?.user_id?.first_name }} {{ incentive?.user_id?.last_name }}</p>
25
+ <p class="card-text mbr-fonts-style display-4">Status: {{ incentive?.status }}</p>
26
+ <p class="card-text mbr-fonts-style display-4">Type: {{ incentive?.incentive_type }}</p>
27
+ <p class="btn_link mbr-fonts-style display-4"><NuxtLink :to="`/incentive/${incentive?.id}`" class="text-secondary">View<span class="mobi-mbri mobi-mbri-right mbr-iconfont"></span></NuxtLink></p>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </section>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup>
38
+ const props = defineProps({
39
+ incentive: {
40
+ type: Object,
41
+ required: true,
42
+ },
43
+ });
44
+ </script>