@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,134 @@
1
+ <template>
2
+ <div>
3
+ <v-row>
4
+ <v-col cols="12">
5
+ <v-toolbar title="Your Subscriptions" subtitle=""></v-toolbar>
6
+ <v-row class="accountRow">
7
+ <v-col cols="3" v-for="(subscriptions, index) in mySubscriptions" :key="index">
8
+ <v-card class="mx-auto" max-width="400">
9
+ <img loading="lazy" class="align-end text-white" height="200"
10
+ :src="subscriptions?.image?.filename_disk" :alt="subscriptions?.name" cover />
11
+ <v-card-title>{{subscriptions?.name}}</v-card-title>
12
+ <v-card-subtitle class="pt-4">
13
+ Status: {{ subscriptions?.status }}
14
+ </v-card-subtitle>
15
+
16
+ <v-card-text>
17
+ <div>Start Date: {{ subscriptions?.start_date }}</div>
18
+
19
+ <div>End Date: {{ subscriptions?.end_date }}</div>
20
+ </v-card-text>
21
+
22
+ <v-card-actions>
23
+ <v-btn color="red" :href="`/commerce/subscriptions/${subscriptions?.id}`">
24
+ Manage subscription
25
+ </v-btn>
26
+ </v-card-actions>
27
+ </v-card>
28
+ </v-col>
29
+ </v-row>
30
+ </v-col>
31
+
32
+ <v-col cols="12">
33
+ <v-toolbar title="Available Subscriptions" subtitle=""></v-toolbar>
34
+ <v-row class="accountRow">
35
+ <v-col cols="3" v-for="(subscriptions, index) in subscriptions" :key="index">
36
+ <v-card class="mx-auto" max-width="400">
37
+ <NuxtImg loading="lazy" class="align-end text-white" height="200"
38
+ :src="subscriptions?.image?.filename_disk" :alt="subscriptions?.name" cover />
39
+ <v-card-title>{{subscriptions?.name}}</v-card-title>
40
+
41
+ <v-card-subtitle class="pt-4">
42
+ Status: {{ subscriptions?.status }}
43
+ </v-card-subtitle>
44
+
45
+ <v-card-text>
46
+ <div>Start Date: {{ subscriptions?.start_date }}</div>
47
+
48
+ <div>End Date: {{ subscriptions?.end_date }}</div>
49
+ </v-card-text>
50
+
51
+ <v-card-actions>
52
+ <v-btn color="red">
53
+ Add to Cart
54
+ </v-btn>
55
+ </v-card-actions>
56
+ </v-card>
57
+ </v-col>
58
+ </v-row>
59
+ </v-col>
60
+ </v-row>
61
+ </div>
62
+ </template>
63
+
64
+ <script setup>
65
+ import productCard from '~/components/related/post.vue'
66
+ import { computed, unref } from 'vue'
67
+ // BetterAuth `useAuth()` fallback
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const auth: any = (globalThis as any).$useAuth ?? (typeof useAuth !== 'undefined' ? useAuth() : null)
70
+ const user = computed(() => {
71
+ if (!auth) return null
72
+ if (auth.user) return unref(auth.user) || null
73
+ if (auth.session) return unref(auth.session)?.user || null
74
+ return null
75
+ })
76
+
77
+ const {
78
+ $directus,
79
+ $readItem,
80
+ $readItems
81
+ } = useNuxtApp()
82
+ const tab = ref(null);
83
+
84
+ const {
85
+ data: incentiveBar
86
+ } = await useAsyncData('incentiveBar', async () => {
87
+ const resp = await $directus.request($readItem('navigation', '118', {
88
+ fields: ['*', {
89
+ '*': ['*']
90
+ }]
91
+ }))
92
+ return resp?.data ?? resp ?? null
93
+ })
94
+
95
+ const {
96
+ data: incentivePage
97
+ } = await useAsyncData('incentivePage', () => {
98
+ return $directus.request($readItem('pages', '86', {
99
+ fields: ['*', {
100
+ '*': ['*']
101
+ }]
102
+ }))
103
+ })
104
+
105
+ const {
106
+ data: subscriptions
107
+ } = await useAsyncData('subscriptions', async () => {
108
+ const resp = await $directus.request($readItems('products', {
109
+ fields: ['*', {
110
+ '*': ['*']
111
+ }],
112
+ filter: {
113
+ user_id: {
114
+ _eq: user?.id
115
+ },
116
+ type: {
117
+ name: {
118
+ _eq: 'Subscription'
119
+ }
120
+ }
121
+ }
122
+ }))
123
+ return resp?.data ?? resp ?? []
124
+ })
125
+
126
+
127
+ useHead({
128
+ title: 'Subscriptions',
129
+ })
130
+
131
+ definePageMeta({
132
+ middleware: ['authenticated'],
133
+ })
134
+ </script>
@@ -0,0 +1,326 @@
1
+ <!-- modify-rewards.vue -->
2
+ <template>
3
+ <div class="rewards-dashboard">
4
+ <v-row>
5
+ <!-- Header -->
6
+ <v-col cols="12">
7
+ <v-toolbar color="primary">
8
+ <v-toolbar-title>Modify Rewards</v-toolbar-title>
9
+ </v-toolbar>
10
+ </v-col>
11
+
12
+ <!-- Current Balance Card -->
13
+ <v-col cols="12" md="6">
14
+ <v-card class="mb-4">
15
+ <v-card-title>Current Balance</v-card-title>
16
+ <v-card-text>
17
+ <div class="text-h4 text-primary">
18
+ {{ currentBalance }} Points
19
+ </div>
20
+ </v-card-text>
21
+ </v-card>
22
+ </v-col>
23
+
24
+ <!-- Active Rewards Card -->
25
+ <v-col cols="12" md="6">
26
+ <v-card class="mb-4">
27
+ <v-card-title>Active Cart Rewards</v-card-title>
28
+ <v-card-text>
29
+ <v-list v-if="activeRewards.length">
30
+ <v-list-item v-for="reward in activeRewards" :key="reward.cartId">
31
+ <v-list-item-content>
32
+ <v-list-item-title>Cart ID: {{ reward.cartId }}</v-list-item-title>
33
+ <v-list-item-subtitle>Points: {{ reward.points }}</v-list-item-subtitle>
34
+ </v-list-item-content>
35
+ <v-list-item-action>
36
+ <v-btn color="error" small @click="removeReward(reward.cartId)"
37
+ :loading="removingReward === reward.cartId">
38
+ Remove
39
+ </v-btn>
40
+ </v-list-item-action>
41
+ </v-list-item>
42
+ </v-list>
43
+ <v-alert v-else type="info" text="No active rewards"></v-alert>
44
+ </v-card-text>
45
+ </v-card>
46
+ </v-col>
47
+
48
+ <!-- Modify Rewards Form -->
49
+ <v-col cols="12">
50
+ <v-card>
51
+ <v-card-title>Modify Rewards</v-card-title>
52
+ <v-card-text>
53
+ <v-form ref="form" v-model="valid" @submit.prevent="handleModify">
54
+ <v-row>
55
+ <v-col cols="12" md="6">
56
+ <v-select v-model="formData.cartId" :items="activeRewards" item-text="cartId"
57
+ item-value="cartId" label="Select Cart" required
58
+ :rules="[v => !!v || 'Cart is required']"></v-select>
59
+ </v-col>
60
+
61
+ <v-col cols="12" md="6">
62
+ <v-text-field v-model="formData.points" label="New Points Amount" type="number"
63
+ required :rules="[
64
+ v => !!v || 'Points are required',
65
+ v => v >= 0 || 'Points must be non-negative'
66
+ ]"></v-text-field>
67
+ </v-col>
68
+
69
+ <v-col cols="12">
70
+ <v-textarea v-model="formData.reason" label="Modification Reason" rows="3" required
71
+ :rules="[v => !!v || 'Reason is required']"></v-textarea>
72
+ </v-col>
73
+ </v-row>
74
+
75
+ <!-- Action Buttons -->
76
+ <v-row>
77
+ <v-col cols="12" class="text-right">
78
+ <v-btn color="error" class="mr-4" @click="resetForm">
79
+ Reset
80
+ </v-btn>
81
+ <v-btn color="primary" type="submit" :loading="loading" :disabled="!valid">
82
+ Update Rewards
83
+ </v-btn>
84
+ </v-col>
85
+ </v-row>
86
+ </v-form>
87
+ </v-card-text>
88
+ </v-card>
89
+ </v-col>
90
+
91
+ <!-- Modification History -->
92
+ <v-col cols="12">
93
+ <v-card>
94
+ <v-card-title>Modification History</v-card-title>
95
+ <v-card-text>
96
+ <v-data-table :headers="historyHeaders" :items="modificationHistory" :loading="loadingHistory"
97
+ class="elevation-1">
98
+ <template v-slot:item.points_change="{ item }">
99
+ <span :class="item.points_change > 0 ? 'success--text' : 'error--text'">
100
+ {{ item.points_change > 0 ? '+' : '' }}{{ item.points_change }}
101
+ </span>
102
+ </template>
103
+ <template v-slot:item.modified_at="{ item }">
104
+ {{ formatDate(item.modified_at) }}
105
+ </template>
106
+ </v-data-table>
107
+ </v-card-text>
108
+ </v-card>
109
+ </v-col>
110
+ </v-row>
111
+
112
+ <!-- Snackbar for notifications -->
113
+ <v-snackbar v-model="snackbar.show" :color="snackbar.color">
114
+ {{ snackbar.message }}
115
+ <template v-slot:action="{ attrs }">
116
+ <v-btn text v-bind="attrs" @click="snackbar.show = false">
117
+ Close
118
+ </v-btn>
119
+ </template>
120
+ </v-snackbar>
121
+ </div>
122
+ </template>
123
+
124
+ <script setup>
125
+ import {
126
+ ref,
127
+ onMounted
128
+ } from 'vue';
129
+ import {
130
+ getRewardBalance,
131
+ useRewardPoints,
132
+ removeRewardPoints,
133
+ getRewardHistory
134
+ } from '#commerce/app/composables/commerce/marketing/useReward';
135
+
136
+ // State
137
+ const currentBalance = ref(0);
138
+ const activeRewards = ref([]);
139
+ const modificationHistory = ref([]);
140
+ const loading = ref(false);
141
+ const loadingHistory = ref(false);
142
+ const removingReward = ref(null);
143
+ const valid = ref(false);
144
+ const form = ref(null);
145
+
146
+ const formData = ref({
147
+ cartId: '',
148
+ points: '',
149
+ reason: ''
150
+ });
151
+
152
+ const snackbar = ref({
153
+ show: false,
154
+ message: '',
155
+ color: 'success'
156
+ });
157
+
158
+ // Table headers for history
159
+ const historyHeaders = [{
160
+ text: 'Date',
161
+ value: 'modified_at'
162
+ },
163
+ {
164
+ text: 'Cart ID',
165
+ value: 'cart_id'
166
+ },
167
+ {
168
+ text: 'Points Change',
169
+ value: 'points_change'
170
+ },
171
+ {
172
+ text: 'Reason',
173
+ value: 'reason'
174
+ },
175
+ {
176
+ text: 'Modified By',
177
+ value: 'modified_by'
178
+ }
179
+ ];
180
+
181
+ // Methods
182
+ const loadInitialData = async () => {
183
+ try {
184
+ // Load balance
185
+ const balance = await getRewardBalance();
186
+ currentBalance.value = balance;
187
+
188
+ // Load active rewards
189
+ await loadActiveRewards();
190
+
191
+ // Load modification history
192
+ await loadHistory();
193
+ } catch (error) {
194
+ showError('Error loading initial data');
195
+ console.error('Error loading initial data:', error);
196
+ }
197
+ };
198
+
199
+ const loadActiveRewards = async () => {
200
+ // Implementation depends on your API structure
201
+ // This is a placeholder
202
+ activeRewards.value = [];
203
+ };
204
+
205
+ const loadHistory = async () => {
206
+ loadingHistory.value = true;
207
+ try {
208
+ const history = await getRewardHistory({
209
+ pageSize: 10,
210
+ currentPage: 1,
211
+ filters: [{
212
+ field: 'type',
213
+ value: 'modification',
214
+ conditionType: 'eq'
215
+ }]
216
+ });
217
+ modificationHistory.value = history.items || [];
218
+ } catch (error) {
219
+ showError('Error loading modification history');
220
+ console.error('Error loading history:', error);
221
+ } finally {
222
+ loadingHistory.value = false;
223
+ }
224
+ };
225
+
226
+ const handleModify = async () => {
227
+ if (!valid.value) return;
228
+
229
+ loading.value = true;
230
+ try {
231
+ // Remove existing rewards
232
+ await removeRewardPoints(formData.value.cartId);
233
+
234
+ // Add new rewards if points > 0
235
+ if (formData.value.points > 0) {
236
+ await useRewardPoints(formData.value.cartId);
237
+ }
238
+
239
+ // Refresh data
240
+ await loadInitialData();
241
+
242
+ showSuccess('Rewards modified successfully');
243
+ resetForm();
244
+ } catch (error) {
245
+ showError('Error modifying rewards');
246
+ console.error('Error modifying rewards:', error);
247
+ } finally {
248
+ loading.value = false;
249
+ }
250
+ };
251
+
252
+ const removeReward = async (cartId) => {
253
+ removingReward.value = cartId;
254
+ try {
255
+ await removeRewardPoints(cartId);
256
+ await loadInitialData();
257
+ showSuccess('Rewards removed successfully');
258
+ } catch (error) {
259
+ showError('Error removing rewards');
260
+ console.error('Error removing rewards:', error);
261
+ } finally {
262
+ removingReward.value = null;
263
+ }
264
+ };
265
+
266
+ const resetForm = () => {
267
+ if (form.value) {
268
+ form.value.reset();
269
+ }
270
+ formData.value = {
271
+ cartId: '',
272
+ points: '',
273
+ reason: ''
274
+ };
275
+ };
276
+
277
+ const showSuccess = (message) => {
278
+ snackbar.value = {
279
+ show: true,
280
+ message,
281
+ color: 'success'
282
+ };
283
+ };
284
+
285
+ const showError = (message) => {
286
+ snackbar.value = {
287
+ show: true,
288
+ message,
289
+ color: 'error'
290
+ };
291
+ };
292
+
293
+ const formatDate = (date) => {
294
+ return new Date(date).toLocaleDateString('en-US', {
295
+ year: 'numeric',
296
+ month: 'short',
297
+ day: 'numeric',
298
+ hour: '2-digit',
299
+ minute: '2-digit'
300
+ });
301
+ };
302
+
303
+ // Lifecycle
304
+ onMounted(() => {
305
+ loadInitialData();
306
+ });
307
+
308
+ // Meta
309
+ definePageMeta({
310
+ layout: 'dashboard'
311
+ });
312
+
313
+ useHead({
314
+ title: 'Modify Rewards',
315
+ });
316
+ </script>
317
+
318
+ <style scoped>
319
+ .rewards-dashboard {
320
+ padding: 20px;
321
+ }
322
+
323
+ .v-data-table {
324
+ background: transparent !important;
325
+ }
326
+ </style>
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <div>
3
+ <v-card variant="text" class="lowerBar">
4
+ <v-tabs v-model="tab" :bg-color="lowerbar?.color" :color="lowerbar?.colortext" align-tabs="center">
5
+ <v-tab>
6
+ <NuxtLink style="color: black;" to="/">{{ lowerbar?.name }}</NuxtLink>
7
+ </v-tab>
8
+ <div v-for="(menu, index) in lowerbar?.menus" :key="index">
9
+ <v-tab :value="menu?.value">
10
+ <v-btn variant="text" :style="`color: ${lowerbar?.colortext} !important`"
11
+ :href="menu?.slug">{{ menu?.name }}</v-btn>
12
+ </v-tab>
13
+ </div>
14
+
15
+ <v-btn variant="text" prepend-icon="fas fa-plus" class="lowerBarBtn">
16
+ Add
17
+
18
+ <v-menu activator="parent">
19
+ <v-list lines="two">
20
+ <v-list-item>
21
+ <!--<addList />-->
22
+ </v-list-item>
23
+
24
+ <v-list-item>
25
+ <!--<addBookmark />-->
26
+ </v-list-item>
27
+ </v-list>
28
+ </v-menu>
29
+ </v-btn>
30
+ </v-tabs>
31
+ </v-card>
32
+
33
+ <!--<v-tabs-window v-model="tab">
34
+ <v-tabs-window-item :value="lowerbar?.menus?.[0]?.value">
35
+ <myLists />
36
+ </v-tabs-window-item>
37
+ <v-tabs-window-item :value="lowerbar?.menus?.[1]?.value">
38
+ <bookmarks />
39
+ </v-tabs-window-item>
40
+ <v-tabs-window-item :value="lowerbar?.menus?.[2]?.value">
41
+ <starredLists />
42
+ </v-tabs-window-item>
43
+ <v-tabs-window-item :value="lowerbar?.menus?.[3]?.value">
44
+ <archivedLists />
45
+ </v-tabs-window-item>
46
+ </v-tabs-window>-->
47
+ </div>
48
+ </template>
49
+
50
+ <script setup>
51
+ import {
52
+ ref
53
+ } from 'vue'
54
+ //import addList from '~/components/related/add-list.vue'
55
+ //import addBookmark from '~/components/related/add-bookmark.vue'
56
+ //import myLists from '~/components/features/lists.vue'
57
+ //import bookmarks from '~/components/features/bookmarks.vue'
58
+ //import starredLists from '~/components/features/starred.vue'
59
+ //import archivedLists from '~/components/features/archived.vue'
60
+
61
+ const tab = ref(null);
62
+
63
+ const {
64
+ $directus,
65
+ $readItem
66
+ } = useNuxtApp()
67
+ const route = useRoute()
68
+
69
+ const {
70
+ data: lowerbar
71
+ } = await useAsyncData('lowerbar', () => {
72
+ return $directus.request($readItem('navigation', '46', {
73
+ fields: ['*', {
74
+ '*': ['*']
75
+ }]
76
+ }))
77
+ })
78
+ </script>
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <select aria-label="Select language"
3
+ class="mt-1 block w-full p-2.5 border border-secondary-300 text-secondary-900 text-sm rounded-md shadow-sm focus:ring-brand-light focus:border-light"
4
+ @change="onChangeHandler">
5
+ <option v-for="locale in availableLocales" :key="locale" :value="locale"
6
+ :selected="currentLocale === locale" :label="locale">
7
+ {{ locale }}
8
+ </option>
9
+ </select>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { useI18n } from 'vue-i18n';
14
+ import { ref, computed } from 'vue';
15
+
16
+ const { locale, availableLocales, t } = useI18n();
17
+ const currentLocale = computed(() => locale.value);
18
+
19
+ const onChangeHandler = (event: Event) => {
20
+ const lang = (event.target as HTMLSelectElement).value;
21
+ locale.value = lang as typeof locale.value;
22
+ window.location.reload();
23
+ };
24
+ </script>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <v-sheet class="pa-4" elevation="2">
3
+ <div class="flex items-center justify-between mb-4">
4
+ <h3 class="text-lg font-semibold">Your Cart ({{ cartStore.itemCount }})</h3>
5
+ <v-btn color="primary" variant="tonal" @click="proceedToCheckout" :disabled="cartStore.isEmpty || cartStore.loading">
6
+ Proceed to Checkout
7
+ </v-btn>
8
+ </div>
9
+
10
+ <v-divider />
11
+
12
+ <div v-if="cartStore.loading" class="py-6 text-center">Loading cart…</div>
13
+
14
+ <div v-else>
15
+ <v-list two-line>
16
+ <v-list-item v-for="item in cartItems" :key="item.id" class="py-4">
17
+ <PartialsCartItem :item="item" @cart-changed="initialize" />
18
+ </v-list-item>
19
+ </v-list>
20
+
21
+ <v-divider class="my-4" />
22
+
23
+ <div class="flex flex-col gap-2">
24
+ <div class="flex justify-between">
25
+ <span>Subtotal</span>
26
+ <span>{{ formatPrice(cartStore.subtotal) }}</span>
27
+ </div>
28
+ <div class="flex justify-between">
29
+ <span>Tax</span>
30
+ <span>{{ formatPrice(cartStore.taxAmount) }}</span>
31
+ </div>
32
+ <div class="flex justify-between font-semibold text-lg">
33
+ <span>Total</span>
34
+ <span>{{ formatPrice(cartStore.total) }}</span>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div v-if="cartStore.error" class="mt-4 text-sm text-error">{{ cartStore.error }}</div>
40
+ </v-sheet>
41
+ </template>
42
+
43
+ <script setup>
44
+ import { ref, watch, computed, onMounted } from 'vue'
45
+ import { useCartStore } from '~/stores/cart'
46
+ import { useRouter } from 'vue-router'
47
+
48
+ const cartStore = useCartStore()
49
+ const router = useRouter()
50
+
51
+ const placeholder = '/_assets/placeholder.png'
52
+
53
+ const quantities = ref({})
54
+
55
+ const cartItems = computed(() => (cartStore.cart?.items || []))
56
+
57
+ const initialize = async () => {
58
+ await cartStore.initializeCart()
59
+ // initialize local quantity map
60
+ cartItems.value.forEach((it) => {
61
+ quantities.value[it.id] = it.quantity
62
+ })
63
+ }
64
+
65
+ onMounted(() => {
66
+ initialize()
67
+ })
68
+
69
+ watch(cartItems, (newItems) => {
70
+ // keep local quantities in sync when items change
71
+ newItems.forEach((it) => {
72
+ if (!quantities.value[it.id]) quantities.value[it.id] = it.quantity
73
+ })
74
+ })
75
+
76
+ const getImageUrl = (item) => {
77
+ const file = item.product?.images?.[0]
78
+ const config = useRuntimeConfig()
79
+ if (file && file.id) return `${config.public.directus.url}/assets/${file.id}`
80
+ return placeholder
81
+ }
82
+
83
+ const formatPrice = (value) => {
84
+ const amount = typeof value === 'number' ? value : Number(value || 0)
85
+ return new Intl.NumberFormat(undefined, { style: 'currency', currency: cartStore.cart?.currency || 'USD' }).format(amount)
86
+ }
87
+
88
+ const removeItem = async (item) => {
89
+ await cartStore.removeProductFromCart(item.id)
90
+ }
91
+
92
+ const updateQty = async (itemId, qty) => {
93
+ qty = Number(qty)
94
+ if (isNaN(qty) || qty < 1) return
95
+ await cartStore.updateProductQuantity(itemId, qty)
96
+ }
97
+
98
+ const onQtyChange = async (item) => {
99
+ const newQty = quantities.value[item.id]
100
+ await updateQty(item.id, newQty)
101
+ }
102
+
103
+ const increaseQty = async (item) => {
104
+ quantities.value[item.id] = (quantities.value[item.id] || item.quantity) + 1
105
+ await updateQty(item.id, quantities.value[item.id])
106
+ }
107
+
108
+ const decreaseQty = async (item) => {
109
+ const newVal = (quantities.value[item.id] || item.quantity) - 1
110
+ if (newVal <= 0) {
111
+ // remove item
112
+ await removeItem(item)
113
+ return
114
+ }
115
+ quantities.value[item.id] = newVal
116
+ await updateQty(item.id, newVal)
117
+ }
118
+
119
+ const proceedToCheckout = () => {
120
+ // navigate to a checkout route; adjust if project uses a different path
121
+ router.push('/checkout')
122
+ }
123
+ </script>
124
+
125
+ <style scoped>
126
+ .v-list-item { align-items: flex-start; }
127
+ .w-24 { width: 6rem; }
128
+ </style>