@mframework/layer-commerce 0.0.7 → 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.
- package/app/components/catalog/product/ProductAccordion/ProductAccordion.vue +41 -0
- package/app/components/catalog/product/ProductAccordion/__tests__/ProductAccordion.spec.ts +15 -0
- package/app/components/catalog/product/ProductAccordion/types.ts +5 -0
- package/app/components/catalog/product/ProductProperties/ProductProperties.vue +52 -0
- package/app/components/catalog/product/ProductProperties/__tests__/ProductProperties.spec.ts +15 -0
- package/app/components/catalog/product/ProductProperties/types.ts +5 -0
- package/app/components/catalog/product/ProductSlider/ProductSlider.vue +28 -0
- package/app/components/catalog/product/ProductSlider/__tests__/ProductSlider.spec.ts +14 -0
- package/app/components/catalog/product/ProductSlider/types.ts +7 -0
- package/app/components/catalog/product/RecommendedProducts/RecommendedProducts.vue +12 -0
- package/app/components/catalog/product/RecommendedProducts/types.ts +5 -0
- package/app/components/catalog/product/RenderContentProductSlider/RenderContentProductSlider.vue +11 -0
- package/app/components/catalog/product/add-attribute.vue +54 -0
- package/app/components/catalog/product/add-product-type.vue +54 -0
- package/app/components/catalog/product/add-product.vue +53 -0
- package/app/components/catalog/product/add-showcase.vue +52 -0
- package/app/components/catalog/product/add-station.vue +54 -0
- package/app/components/catalog/product/bestsellers.vue +69 -0
- package/app/components/catalog/product/bidding.vue +93 -0
- package/app/components/catalog/product/colorOptions.vue +58 -0
- package/app/components/catalog/product/deals.vue +61 -0
- package/app/components/catalog/product/exclusives.vue +58 -0
- package/app/components/catalog/product/featuredproducts.vue +69 -0
- package/app/components/catalog/product/giftCard.vue +63 -0
- package/app/components/catalog/product/latestproducts.vue +58 -0
- package/app/components/catalog/product/productCard.vue +71 -0
- package/app/components/catalog/product/productCompare.vue +60 -0
- package/app/components/catalog/product/productCompareTable.vue +441 -0
- package/app/components/catalog/product/productDetails.vue +120 -0
- package/app/components/catalog/product/productFaqs.vue +17 -0
- package/app/components/catalog/product/productGallery.vue +16 -0
- package/app/components/catalog/product/productQty.vue +54 -0
- package/app/components/catalog/product/productReviews.vue +56 -0
- package/app/components/catalog/product/productSpecs.vue +116 -0
- package/app/components/catalog/product/radiostation.vue +36 -0
- package/app/components/catalog/product/recentlyviewed.vue +43 -0
- package/app/components/catalog/product/relatedbrands.vue +54 -0
- package/app/components/catalog/product/relatedproducts.vue +58 -0
- package/app/components/catalog/product/relatedstations.vue +40 -0
- package/app/components/catalog/product/shippingOptions.vue +41 -0
- package/app/components/catalog/product/sizeOptions.vue +47 -0
- package/app/components/catalog/product/update-attribute-set.vue +209 -0
- package/app/components/catalog/product/update-attribute.vue +118 -0
- package/app/components/catalog/product/update-product.vue +372 -0
- package/app/components/catalog/product/update-showcase.vue +153 -0
- package/app/components/catalog/shops/relatedstores.vue +52 -0
- package/app/components/catalog/shops/restaurant.vue +66 -0
- package/app/components/catalog/shops/stores.vue +44 -0
- package/app/components/catalog/vendor/README.md +3 -0
- package/app/components/catalog/vendor/blocks/biggestcustomers.vue +33 -0
- package/app/components/catalog/vendor/blocks/lowestselling.vue +33 -0
- package/app/components/catalog/vendor/blocks/topcategories.vue +33 -0
- package/app/components/catalog/vendor/blocks/topproducts.vue +27 -0
- package/app/components/catalog/vendor/pages/attributes.vue +43 -0
- package/app/components/catalog/vendor/pages/commissions.vue +43 -0
- package/app/components/catalog/vendor/pages/crm.vue +67 -0
- package/app/components/catalog/vendor/pages/dashboard.vue +46 -0
- package/app/components/catalog/vendor/pages/emails.vue +43 -0
- package/app/components/catalog/vendor/pages/enquiries.vue +43 -0
- package/app/components/catalog/vendor/pages/invoices.vue +43 -0
- package/app/components/catalog/vendor/pages/orders.vue +68 -0
- package/app/components/catalog/vendor/pages/products.vue +55 -0
- package/app/components/catalog/vendor/pages/reviews.vue +48 -0
- package/app/components/catalog/vendor/pages/shipments.vue +43 -0
- package/app/components/catalog/vendor/pages/stores.vue +43 -0
- package/app/components/content/blocks/breadcrumbs.vue +0 -0
- package/app/components/content/blocks/currencySwitcher.vue +0 -0
- package/app/components/content/blocks/languageSwitcher.vue +0 -0
- package/app/components/content/blocks/videoproduct.vue +9 -0
- package/app/components/content/pages/checkout.vue +118 -0
- package/app/components/content/pages/meeoviGlobal.vue +68 -0
- package/app/components/content/pages/pickup-locations.vue +238 -0
- package/app/components/content/pages/showcases.vue +90 -0
- package/app/components/content/pages/success.vue +60 -0
- package/app/components/marketing/add-brand.vue +54 -0
- package/app/components/marketing/add-incentive.vue +54 -0
- package/app/components/marketing/promotions/giftcards.vue +127 -0
- package/app/components/marketing/promotions/subscriptions.vue +134 -0
- package/app/components/marketing/update-incentive.vue +326 -0
- package/app/components/menus/lowernav.vue +78 -0
- package/app/components/partials/LocaleSelector.vue +24 -0
- package/app/components/partials/ShoppingCart.vue +128 -0
- package/app/components/partials/StripePayment.vue +149 -0
- package/app/components/partials/addToCartBtn.vue +40 -0
- package/app/components/partials/cartItem.vue +124 -0
- package/app/components/partials/checkoutButton.vue +44 -0
- package/app/components/partials/compareBtn.vue +68 -0
- package/app/components/partials/ratings.vue +13 -0
- package/app/components/partials/store/CurrencySelector.vue +133 -0
- package/app/components/partials/store/StoreSwitcher.vue +13 -0
- package/app/components/related/brandCard.vue +41 -0
- package/app/components/related/incentiveCard.vue +44 -0
- package/app/components/related/invoiceCard.vue +43 -0
- package/app/components/related/orderCard.vue +43 -0
- package/app/components/related/relatedproducts.vue +17 -0
- package/app/components/sales/CartPageContent/CartPageContent.vue +43 -0
- package/app/components/sales/CheckoutAddress/CheckoutAddress.vue +50 -0
- package/app/components/sales/CheckoutAddress/__tests__/CheckoutAddress.spec.ts +16 -0
- package/app/components/sales/CheckoutAddress/types.ts +16 -0
- package/app/components/sales/CheckoutPayment/CheckoutPayment.vue +65 -0
- package/app/components/sales/CheckoutPayment/__tests__/CheckoutPayment.spec.ts +14 -0
- package/app/components/sales/CheckoutPayment/types.ts +12 -0
- package/app/components/sales/OrderSummary/OrderSummary.vue +57 -0
- package/app/components/sales/OrderSummary/__tests__/ContactInformation.spec.ts +52 -0
- package/app/components/sales/OrderSummary/types.ts +5 -0
- package/app/components/sales/incentives.vue +247 -0
- package/app/components/sales/invoices.vue +107 -0
- package/app/components/sales/orders.vue +378 -0
- package/app/components/sales/shipments.vue +65 -0
- package/app/components/sales/transactions.vue +109 -0
- package/app/components/shop/add-shop.vue +54 -0
- package/app/components/shop/cart/cartItem.vue +182 -0
- package/app/components/shop/cart/checkout.vue +415 -0
- package/app/components/shop/checkout/StripeCardElement.vue +206 -0
- package/app/components/shop/checkout/StripeCheckout.vue +49 -0
- package/app/components/shop/checkout/addressBilling.vue +263 -0
- package/app/components/shop/checkout/addressShipping.vue +175 -0
- package/app/components/shop/checkout/cart/ProductItem.vue +56 -0
- package/app/components/shop/checkout/cart/PromotionItem.vue +53 -0
- package/app/stores/cart.ts +1 -1
- package/app/types/Direction.type.ts +1 -1
- package/app/types/Global.type.ts +6 -6
- package/app/types/Layout.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/Cart.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Cart.type.ts +2 -2
- package/app/{normalizers → types/normalizers}/Checkout.query.ts +2 -2
- package/app/{normalizers → types/normalizers}/Config.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Config.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/ContactForm.query.ts +2 -2
- package/app/{normalizers → types/normalizers}/CreditMemo.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/GiftCard.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/Invoice.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/MyAccount.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/MyAccount.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/NewsletterSubscription.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Order.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Order.type.ts +2 -2
- package/app/{normalizers → types/normalizers}/Payment.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/ProductCompare.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/ProductCompare.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/ProductList.query.ts +2 -2
- package/app/{normalizers → types/normalizers}/ProductList.type.ts +2 -2
- package/app/{normalizers → types/normalizers}/Return.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/Review.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Review.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/StoreInPickUp.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/Subscription.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/Transaction.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/UrlRewrites.query.ts +1 -1
- package/app/{normalizers → types/normalizers}/UrlRewrites.type.ts +1 -1
- package/app/{normalizers → types/normalizers}/Wishlist.query.ts +4 -4
- package/app/{normalizers → types/normalizers}/Wishlist.type.ts +1 -1
- package/app/utils/Address/Address.type.ts +1 -1
- package/app/utils/Address/index.ts +5 -5
- package/app/utils/Cart/Cart.ts +1 -1
- package/app/utils/Currency/Currency.ts +1 -1
- package/app/utils/History/History.type.ts +1 -1
- package/app/utils/Menu/Menu.ts +1 -1
- package/app/utils/Menu/Menu.type.ts +2 -2
- package/app/utils/Orders/Orders.ts +1 -1
- package/app/utils/Preload/CategoryPreload.ts +2 -2
- package/app/utils/Preload/ProductPreload.ts +1 -1
- package/app/utils/Preload/index.ts +1 -1
- package/app/utils/Price/Price.ts +1 -1
- package/app/utils/Product/Extract.ts +1 -1
- package/app/utils/Product/Product.ts +1 -1
- package/app/utils/Product/Product.type.ts +1 -1
- package/app/utils/Product/Transform.ts +1 -1
- package/app/utils/Wishlist/Wishlist.ts +1 -1
- package/app/utils/client.ts +19 -19
- package/package.json +1 -2
- package/tsconfig.json +2 -2
- package/app/cart/useCart.ts +0 -1
- /package/app/{components → composables}/ChevronIcon/ChevronIcon.config.ts +0 -0
- /package/app/{components → composables}/DateSelect/DateSelect.config.ts +0 -0
- /package/app/{components → composables}/Field/Field.config.ts +0 -0
- /package/app/{components → composables}/FieldDate/FieldDate.config.ts +0 -0
- /package/app/{components → composables}/Form/Form.type.ts +0 -0
- /package/app/{components → composables}/Product/Product.config.ts +0 -0
- /package/app/{components → composables}/Product/Stock.config.ts +0 -0
- /package/app/{components → composables}/ProductCustomizableOption/ProductCustomizableOption.config.ts +0 -0
- /package/app/{components → composables}/ProductGallery/ProductGallery.config.ts +0 -0
- /package/app/{components → composables}/ProductReviews/ProductReviews.config.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Category.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Category.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/CheckEmail.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Checkout.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/CmsBlock.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/CmsBlock.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/CmsPage.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/CmsPage.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Menu.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Menu.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/ProductAlerts.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Region.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Region.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Slider.query.ts +0 -0
- /package/app/{normalizers → types/normalizers}/Slider.type.ts +0 -0
- /package/app/{normalizers → types/normalizers}/StoreInPickUp.type.ts +0 -0
- /package/app/{routes → types/routes}/CategoryPage/CategoryPage.config.ts +0 -0
- /package/app/{routes → types/routes}/CategoryPage/CategoryPage.type.ts +0 -0
- /package/app/{routes → types/routes}/Checkout/Checkout.config.ts +0 -0
- /package/app/{routes → types/routes}/Checkout/Checkout.type.ts +0 -0
- /package/app/{routes → types/routes}/MyAccount/MyAccount.config.ts +0 -0
- /package/app/{routes → types/routes}/SearchPage/SearchPage.config.ts +0 -0
- /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>
|