@meeovi/layer-commerce 1.0.2 → 1.0.4
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/types.ts +3 -3
- package/app/components/catalog/product/ProductProperties/types.ts +3 -3
- package/app/components/catalog/product/ProductSlider/types.ts +5 -5
- package/app/components/catalog/product/RecommendedProducts/types.ts +3 -3
- package/app/components/catalog/product/bestsellers.vue +8 -20
- package/app/components/catalog/product/deals.vue +7 -22
- package/app/components/catalog/product/exclusives.vue +8 -10
- package/app/components/catalog/product/featuredproducts.vue +8 -20
- package/app/components/catalog/product/latestproducts.vue +8 -20
- package/app/components/catalog/product/productCard.vue +55 -21
- package/app/components/catalog/product/productDetails.vue +20 -14
- package/app/components/catalog/product/relatedproducts.vue +5 -20
- package/app/components/catalog/product/sizeOptions.vue +3 -8
- package/app/components/catalog/shops/relatedstores.vue +6 -21
- package/app/components/categories/chart/[id].vue +200 -0
- package/app/components/categories/chart/add-chart.vue +142 -0
- package/app/components/categories/chart/chart.vue +82 -0
- package/app/components/categories/chart/monthlyChart.vue +46 -0
- package/app/components/categories/chart/weeklyChart.vue +46 -0
- package/app/components/categories/chart/yearlyChart.vue +46 -0
- package/app/components/categories/charts.vue +118 -0
- package/app/components/categories/deals.vue +101 -0
- package/app/components/categories/eats.vue +49 -0
- package/app/components/categories/restaurants.vue +26 -0
- package/app/components/categories/station/[id].vue +72 -0
- package/app/components/categories/stations.vue +124 -0
- package/app/components/categories/time/time.vue +63 -0
- package/app/components/categories/travel.vue +75 -0
- package/app/components/categories/weather/weather.vue +44 -0
- package/app/components/content/pages/showcases.vue +1 -1
- package/app/components/marketing/promotions/giftcards.vue +20 -45
- package/app/components/marketing/promotions/subscriptions.vue +8 -21
- package/app/components/placeholders/Comments.vue +15 -0
- package/app/components/placeholders/CreateListBtn.vue +7 -0
- package/app/components/placeholders/Event.vue +9 -0
- package/app/components/placeholders/ListShowcases.vue +9 -0
- package/app/components/placeholders/Short.vue +9 -0
- package/app/components/placeholders/Space.vue +9 -0
- package/app/components/placeholders/Tag.vue +7 -0
- package/app/components/sales/CheckoutAddress/types.ts +12 -11
- package/app/components/sales/OrderSummary/types.ts +3 -3
- package/app/components/sales/incentives.vue +13 -37
- package/app/composables/cart/registry.ts +7 -0
- package/app/composables/index.ts +1 -0
- package/app/composables/products/registry.ts +7 -0
- package/app/composables/registry.ts +21 -0
- package/app/composables/useCatalog.ts +64 -0
- package/app/composables/useContent.ts +57 -0
- package/app/composables/useProducts/types.ts +15 -10
- package/app/pages/brand/[...slug].vue +1 -1
- package/app/pages/departments/[...slug].vue +385 -0
- package/app/pages/departments/category/[...slug].vue +135 -0
- package/app/pages/product/[...id].vue +3 -3
- package/app/pages/shop/[...slug].vue +12 -18
- package/app/pages/shops.vue +18 -25
- package/global.d.ts +14 -0
- package/package.json +4 -2
- package/tsconfig.json +10 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { HTMLAttributes } from 'vue'
|
|
2
|
-
import type {
|
|
1
|
+
import type { HTMLAttributes } from 'vue'
|
|
2
|
+
import type { Product } from '../../../composables/_types'
|
|
3
3
|
|
|
4
4
|
export type ProductSliderProps = {
|
|
5
|
-
items?:
|
|
6
|
-
wrapperClass?: HTMLAttributes['class']
|
|
7
|
-
}
|
|
5
|
+
items?: Product[]
|
|
6
|
+
wrapperClass?: HTMLAttributes['class']
|
|
7
|
+
}
|
|
@@ -31,39 +31,27 @@
|
|
|
31
31
|
import productCard from './productCard.vue'
|
|
32
32
|
|
|
33
33
|
const model = ref(null);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
$readItems
|
|
37
|
-
} = useNuxtApp()
|
|
34
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
35
|
+
const catalog = useCatalogFallback()
|
|
38
36
|
|
|
39
37
|
const {
|
|
40
38
|
data: bestsellers
|
|
41
|
-
} = await useAsyncData('bestsellers', () => {
|
|
42
|
-
return
|
|
43
|
-
fields: ['*',
|
|
44
|
-
'products.products_id.*',
|
|
45
|
-
'products.products_id.image.*',
|
|
46
|
-
'currency.currency_id.*',
|
|
47
|
-
'brands.brands_id.*',
|
|
48
|
-
'image.*',
|
|
49
|
-
],
|
|
39
|
+
} = await useAsyncData('bestsellers', async () => {
|
|
40
|
+
return await catalog.listProducts({
|
|
41
|
+
fields: ['*', 'products.products_id.*', 'products.products_id.image.*', 'currency.currency_id.*', 'brands.brands_id.*', 'image.*'],
|
|
50
42
|
limit: 10,
|
|
51
43
|
filter: {
|
|
52
44
|
lists: {
|
|
53
45
|
lists_id: {
|
|
54
46
|
lists_types: {
|
|
55
47
|
lists_types_id: {
|
|
56
|
-
name: {
|
|
57
|
-
_eq: "Best Sellers"
|
|
58
|
-
}
|
|
48
|
+
name: { _eq: 'Best Sellers' }
|
|
59
49
|
}
|
|
60
50
|
}
|
|
61
51
|
}
|
|
62
52
|
},
|
|
63
|
-
status: {
|
|
64
|
-
_eq: "published"
|
|
65
|
-
}
|
|
53
|
+
status: { _eq: 'published' }
|
|
66
54
|
}
|
|
67
|
-
})
|
|
55
|
+
})
|
|
68
56
|
})
|
|
69
57
|
</script>
|
|
@@ -29,33 +29,18 @@
|
|
|
29
29
|
|
|
30
30
|
<script setup>
|
|
31
31
|
import productCard from './productCard.vue'
|
|
32
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
32
33
|
|
|
33
34
|
const model = ref(null)
|
|
34
|
-
const
|
|
35
|
-
$directus,
|
|
36
|
-
$readItems
|
|
37
|
-
} = useNuxtApp()
|
|
35
|
+
const catalog = useCatalogFallback()
|
|
38
36
|
|
|
39
37
|
const {
|
|
40
38
|
data: deals
|
|
41
|
-
} = await useAsyncData('deals', () => {
|
|
42
|
-
return
|
|
43
|
-
fields: ['*',
|
|
44
|
-
'products.products_id.*',
|
|
45
|
-
'products.products_id.image.*',
|
|
46
|
-
'currency.currency_id.*',
|
|
47
|
-
'brands.brands_id.*',
|
|
48
|
-
'image.*',
|
|
49
|
-
],
|
|
39
|
+
} = await useAsyncData('deals', async () => {
|
|
40
|
+
return await catalog.listProducts({
|
|
41
|
+
fields: ['*', 'products.products_id.*', 'products.products_id.image.*', 'currency.currency_id.*', 'brands.brands_id.*', 'image.*'],
|
|
50
42
|
limit: 10,
|
|
51
|
-
filter: {
|
|
52
|
-
|
|
53
|
-
_lte: "20.00"
|
|
54
|
-
},
|
|
55
|
-
status: {
|
|
56
|
-
_eq: "published"
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}))
|
|
43
|
+
filter: { price: { _lte: '20.00' }, status: { _eq: 'published' } }
|
|
44
|
+
})
|
|
60
45
|
})
|
|
61
46
|
</script>
|
|
@@ -31,21 +31,19 @@
|
|
|
31
31
|
import productCard from './productCard.vue'
|
|
32
32
|
|
|
33
33
|
const model = ref(null);
|
|
34
|
-
const { $
|
|
34
|
+
const { $commerce } = useNuxtApp()
|
|
35
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
36
|
+
const catalog = useCatalogFallback()
|
|
35
37
|
|
|
36
38
|
const { data: exclusives } = await useAsyncData('exclusives', async () => {
|
|
37
|
-
|
|
39
|
+
// ask the adapter for products first; composable will fallback to Directus
|
|
40
|
+
const refs = await catalog.listProducts({
|
|
38
41
|
fields: ['id', 'sku'],
|
|
39
42
|
limit: 10,
|
|
40
|
-
filter: {
|
|
41
|
-
|
|
42
|
-
departments: {
|
|
43
|
-
departments_id: { name: { _eq: 'Exclusives' } }
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}))
|
|
43
|
+
filter: { status: { _eq: 'published' }, departments: { departments_id: { name: { _eq: 'Exclusives' } } } }
|
|
44
|
+
})
|
|
47
45
|
|
|
48
|
-
const products = await Promise.all(refs.map(async (r) => {
|
|
46
|
+
const products = await Promise.all(refs.map(async (r: any) => {
|
|
49
47
|
try {
|
|
50
48
|
return await $commerce.getProduct(String(r.sku || r.id))
|
|
51
49
|
} catch (e) {
|
|
@@ -31,39 +31,27 @@
|
|
|
31
31
|
import productCard from './productCard.vue'
|
|
32
32
|
|
|
33
33
|
const model = ref(null);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
$readItems
|
|
37
|
-
} = useNuxtApp()
|
|
34
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
35
|
+
const catalog = useCatalogFallback()
|
|
38
36
|
|
|
39
37
|
const {
|
|
40
38
|
data: featured
|
|
41
|
-
} = await useAsyncData('featured', () => {
|
|
42
|
-
return
|
|
43
|
-
fields: ['*',
|
|
44
|
-
'products.products_id.*',
|
|
45
|
-
'products.products_id.image.*',
|
|
46
|
-
'currency.currency_id.*',
|
|
47
|
-
'brands.brands_id.*',
|
|
48
|
-
'image.*',
|
|
49
|
-
],
|
|
39
|
+
} = await useAsyncData('featured', async () => {
|
|
40
|
+
return await catalog.listProducts({
|
|
41
|
+
fields: ['*', 'products.products_id.*', 'products.products_id.image.*', 'currency.currency_id.*', 'brands.brands_id.*', 'image.*'],
|
|
50
42
|
limit: 10,
|
|
51
43
|
filter: {
|
|
52
44
|
lists: {
|
|
53
45
|
lists_id: {
|
|
54
46
|
lists_types: {
|
|
55
47
|
lists_types_id: {
|
|
56
|
-
name: {
|
|
57
|
-
_eq: "Featured"
|
|
58
|
-
}
|
|
48
|
+
name: { _eq: 'Featured' }
|
|
59
49
|
}
|
|
60
50
|
}
|
|
61
51
|
}
|
|
62
52
|
},
|
|
63
|
-
status: {
|
|
64
|
-
_eq: "published"
|
|
65
|
-
}
|
|
53
|
+
status: { _eq: 'published' }
|
|
66
54
|
}
|
|
67
|
-
})
|
|
55
|
+
})
|
|
68
56
|
})
|
|
69
57
|
</script>
|
|
@@ -30,29 +30,17 @@
|
|
|
30
30
|
import productCard from './productCard.vue'
|
|
31
31
|
|
|
32
32
|
const model = ref(null);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
$readItems
|
|
36
|
-
} = useNuxtApp()
|
|
33
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
34
|
+
const catalog = useCatalogFallback()
|
|
37
35
|
|
|
38
36
|
const {
|
|
39
37
|
data: latest
|
|
40
|
-
} = await useAsyncData('latest', () => {
|
|
41
|
-
return
|
|
42
|
-
fields: ['*',
|
|
43
|
-
|
|
44
|
-
'products.products_id.image.*',
|
|
45
|
-
'currency.currency_id.*',
|
|
46
|
-
'brands.brands_id.*',
|
|
47
|
-
'image.*',
|
|
48
|
-
],
|
|
49
|
-
filter: {
|
|
50
|
-
status: {
|
|
51
|
-
_eq: 'published'
|
|
52
|
-
}
|
|
53
|
-
},
|
|
38
|
+
} = await useAsyncData('latest', async () => {
|
|
39
|
+
return await catalog.listProducts({
|
|
40
|
+
fields: ['*', 'products.products_id.*', 'products.products_id.image.*', 'currency.currency_id.*', 'brands.brands_id.*', 'image.*'],
|
|
41
|
+
filter: { status: { _eq: 'published' } },
|
|
54
42
|
sort: '-products_id.date_created',
|
|
55
|
-
limit: 10
|
|
56
|
-
})
|
|
43
|
+
limit: 10
|
|
44
|
+
})
|
|
57
45
|
})
|
|
58
46
|
</script>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<div class="border border-neutral-200 rounded-md hover:shadow-lg max-w-[300px]">
|
|
4
|
-
<div class="relative" v-if="
|
|
5
|
-
<NuxtLink :to="`/product/${
|
|
6
|
-
<img
|
|
4
|
+
<div class="relative" v-if="displayProduct?.image?.length > 0">
|
|
5
|
+
<NuxtLink :to="`/product/${displayProduct?.id}`" class="block">
|
|
6
|
+
<img v-if="$directus && displayProduct?.image?.filename_disk"
|
|
7
|
+
:src="`${$directus.url}assets/${displayProduct?.image?.filename_disk}`" :alt="displayProduct?.name"
|
|
8
|
+
class="block object-cover h-auto rounded-md aspect-square" width="300" height="300" />
|
|
9
|
+
<img v-else-if="displayProduct?.imageUrl" :src="displayProduct?.imageUrl" :alt="displayProduct?.name"
|
|
7
10
|
class="block object-cover h-auto rounded-md aspect-square" width="300" height="300" />
|
|
8
11
|
</NuxtLink>
|
|
9
12
|
<v-btn variant="flat" size="sm" square
|
|
@@ -14,8 +17,8 @@
|
|
|
14
17
|
</div>
|
|
15
18
|
|
|
16
19
|
<div class="relative" v-else>
|
|
17
|
-
<NuxtLink :to="`/product/${
|
|
18
|
-
<img src="~/assets/images/mbr-1920x1893.png" :alt="
|
|
20
|
+
<NuxtLink :to="`/product/${displayProduct?.id}`" class="block">
|
|
21
|
+
<img src="~/assets/images/mbr-1920x1893.png" :alt="displayProduct?.name"
|
|
19
22
|
class="block object-cover h-auto rounded-md aspect-square" width="300" height="300" />
|
|
20
23
|
</NuxtLink>
|
|
21
24
|
<v-btn variant="flat" size="sm" square
|
|
@@ -25,26 +28,26 @@
|
|
|
25
28
|
</v-btn>
|
|
26
29
|
</div>
|
|
27
30
|
<div class="p-4 border-t border-neutral-200" style="background-color: white !important;">
|
|
28
|
-
<NuxtLink :to="`/product/${
|
|
31
|
+
<NuxtLink :to="`/product/${displayProduct?.id}`" variant="secondary" class="no-underline"> {{ displayProduct?.name }}
|
|
29
32
|
</NuxtLink>
|
|
30
33
|
<div class="flex items-center pt-1">
|
|
31
|
-
<v-rating size="xs" active-color="warning" :model-value="
|
|
34
|
+
<v-rating size="xs" active-color="warning" :model-value="displayProduct?.rating" :max="5" />
|
|
32
35
|
|
|
33
|
-
<NuxtLink :to="`/product/${
|
|
34
|
-
<v-chip size="xs">{{
|
|
36
|
+
<NuxtLink :to="`/product/${displayProduct?.id}`" variant="secondary" class="pl-1 no-underline">
|
|
37
|
+
<v-chip size="xs">{{ displayProduct?.rating }}</v-chip>
|
|
35
38
|
</NuxtLink>
|
|
36
39
|
</div>
|
|
37
40
|
<p class="block py-2 font-normal leading-5 typography-text-sm text-neutral-700"
|
|
38
|
-
v-if="
|
|
41
|
+
v-if="displayProduct?.brands && displayProduct?.brands.length > 0">
|
|
39
42
|
By:
|
|
40
43
|
<div style="display: inline-block;" v-for="brands in product?.brands" :key="brands">
|
|
41
44
|
<NuxtLink :to="`/brand/${brands?.brands_id?.slug}`">{{ brands?.brands_id?.name }}</NuxtLink></div>
|
|
42
45
|
</p>
|
|
43
46
|
<span class="block pb-2 font-bold typography-text-lg">
|
|
44
|
-
<div style="display: inline-block;" v-for="currency in
|
|
47
|
+
<div style="display: inline-block;" v-for="currency in displayProduct?.currency || []" :key="currency">
|
|
45
48
|
{{ currency?.currency_id?.symbol }}
|
|
46
49
|
</div>
|
|
47
|
-
{{
|
|
50
|
+
{{ displayProduct?.price }}
|
|
48
51
|
</span>
|
|
49
52
|
<!--<v-btn size="sm">
|
|
50
53
|
<template #prefix>
|
|
@@ -58,14 +61,45 @@
|
|
|
58
61
|
</template>
|
|
59
62
|
|
|
60
63
|
<script setup>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
import { ref, onMounted, watch, computed } from 'vue'
|
|
65
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
66
|
+
|
|
67
|
+
const props = defineProps({
|
|
68
|
+
product: {
|
|
69
|
+
type: [Object, String],
|
|
70
|
+
required: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const productData = ref<any>(null)
|
|
75
|
+
const catalog = useCatalogFallback()
|
|
76
|
+
|
|
77
|
+
const displayProduct = computed(() => productData.value || props.product)
|
|
78
|
+
|
|
79
|
+
const resolveId = (p: any) => {
|
|
80
|
+
if (!p) return null
|
|
81
|
+
if (typeof p === 'string') return p
|
|
82
|
+
// directus nested shape product?.products_id or products_id?.id
|
|
83
|
+
return p.id || p.products_id?.id || p.products_id || null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function load() {
|
|
87
|
+
const id = resolveId(props.product)
|
|
88
|
+
if (!id) return
|
|
89
|
+
// prefer adapter if available
|
|
90
|
+
if (catalog.adapter) {
|
|
91
|
+
// adapter may expose getProductById or getProductBySlug
|
|
92
|
+
try {
|
|
93
|
+
const p = await catalog.getProductById(id)
|
|
94
|
+
productData.value = p || (await catalog.getProductBySlug(id))
|
|
95
|
+
} catch (e) {
|
|
96
|
+
productData.value = await catalog.getProductBySlug(id)
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
productData.value = await catalog.getProductById(id)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
64
102
|
|
|
65
|
-
|
|
66
|
-
product
|
|
67
|
-
type: Object,
|
|
68
|
-
required: true,
|
|
69
|
-
},
|
|
70
|
-
});
|
|
103
|
+
onMounted(load)
|
|
104
|
+
watch(() => props.product, load)
|
|
71
105
|
</script>
|
|
@@ -3,24 +3,27 @@
|
|
|
3
3
|
<div class="container-fluid">
|
|
4
4
|
<div class="row">
|
|
5
5
|
<div class="col-12 col-md-6">
|
|
6
|
-
<div v-if="
|
|
7
|
-
<img
|
|
6
|
+
<div v-if="displayProduct?.image?.filename_disk || displayProduct?.imageUrl">
|
|
7
|
+
<img v-if="$directus && displayProduct?.image?.filename_disk"
|
|
8
|
+
:src="`${$directus.url}assets/${displayProduct.image.filename_disk}`" :alt="displayProduct.name"
|
|
9
|
+
class="w-full rounded-md" />
|
|
10
|
+
<img v-else-if="displayProduct?.imageUrl" :src="displayProduct?.imageUrl" :alt="displayProduct?.name"
|
|
8
11
|
class="w-full rounded-md" />
|
|
9
12
|
</div>
|
|
10
13
|
</div>
|
|
11
14
|
<div class="col-12 col-md-6">
|
|
12
15
|
<div class="right">
|
|
13
|
-
<h1 class="mb-1 font-bold typography-headline-4"><strong>{{
|
|
16
|
+
<h1 class="mb-1 font-bold typography-headline-4"><strong>{{ displayProduct?.name }}</strong></h1>
|
|
14
17
|
<div class="price-line">
|
|
15
|
-
|
|
16
|
-
{{
|
|
18
|
+
<span class="block pb-2 font-bold typography-text-lg">
|
|
19
|
+
{{ displayProduct?.price }}
|
|
17
20
|
</span>
|
|
18
21
|
</div>
|
|
19
22
|
<p class="productRatings">
|
|
20
|
-
|
|
23
|
+
<v-rating size="lg" :half-increment="true" :value="displayProduct?.ratings?.length || 0"
|
|
21
24
|
:max="5" />
|
|
22
25
|
<NuxtLink to="#" variant="secondary" class="ratingReviews ml-2 text-xs text-neutral-500">
|
|
23
|
-
{{
|
|
26
|
+
{{ displayProduct?.comments?.comments_id?.length || 0 }} reviews
|
|
24
27
|
</NuxtLink>
|
|
25
28
|
</p>
|
|
26
29
|
<div class="py-4 mb-4 border-gray-200 border-y">
|
|
@@ -39,8 +42,8 @@
|
|
|
39
42
|
<SfIconAdd />
|
|
40
43
|
</v-btn>
|
|
41
44
|
</div>
|
|
42
|
-
|
|
43
|
-
<strong class="text-neutral-900">{{
|
|
45
|
+
<p class="self-center mt-1 mb-4 text-xs text-neutral-500 xs:mb-0">
|
|
46
|
+
<strong class="text-neutral-900">{{ displayProduct?.stock }}</strong> in stock
|
|
44
47
|
</p>
|
|
45
48
|
</div>
|
|
46
49
|
<div class="col col-6">
|
|
@@ -50,10 +53,10 @@
|
|
|
50
53
|
</div>
|
|
51
54
|
<div class="mbr-section-btn row align-items-stretch justify-content-center">
|
|
52
55
|
<div class="col col-6">
|
|
53
|
-
|
|
56
|
+
<createListBtn :lists="displayProduct?.id" />
|
|
54
57
|
</div>
|
|
55
58
|
</div>
|
|
56
|
-
<div class="price-line1" v-for="tag in
|
|
59
|
+
<div class="price-line1" v-for="tag in displayProduct?.tags || []" :key="tag.id">
|
|
57
60
|
<p class="desc mbr-fonts-style display-7"><strong>Tags:</strong> <tagCard :tag="tag?.tag_id" /> </p>
|
|
58
61
|
</div>
|
|
59
62
|
</div>
|
|
@@ -65,7 +68,8 @@
|
|
|
65
68
|
|
|
66
69
|
<script setup lang="ts">
|
|
67
70
|
import {
|
|
68
|
-
ref
|
|
71
|
+
ref,
|
|
72
|
+
computed
|
|
69
73
|
} from 'vue';
|
|
70
74
|
import {
|
|
71
75
|
SfIconAdd,
|
|
@@ -77,9 +81,9 @@
|
|
|
77
81
|
import {
|
|
78
82
|
useCounter
|
|
79
83
|
} from '@vueuse/core';
|
|
80
|
-
import tagCard from '
|
|
84
|
+
import tagCard from '@/components/placeholders/Tag.vue';
|
|
81
85
|
import addToCartBtn from '../../partials/addToCartBtn.vue';
|
|
82
|
-
import createListBtn from '
|
|
86
|
+
import createListBtn from '@/components/placeholders/CreateListBtn.vue';
|
|
83
87
|
|
|
84
88
|
const {
|
|
85
89
|
$directus,
|
|
@@ -110,6 +114,8 @@
|
|
|
110
114
|
},
|
|
111
115
|
});
|
|
112
116
|
|
|
117
|
+
const displayProduct = computed(() => props.product)
|
|
118
|
+
|
|
113
119
|
const formatPrice = (amount: number) => {
|
|
114
120
|
if (!amount) return '$0.00';
|
|
115
121
|
return new Intl.NumberFormat('en-US', {
|
|
@@ -29,30 +29,15 @@
|
|
|
29
29
|
|
|
30
30
|
<script setup>
|
|
31
31
|
import productCard from './productCard.vue'
|
|
32
|
+
import { useCatalogFallback } from '../../../composables/useCatalog'
|
|
32
33
|
|
|
33
34
|
const model = ref(null)
|
|
34
|
-
const
|
|
35
|
-
$directus,
|
|
36
|
-
$readItems
|
|
37
|
-
} = useNuxtApp()
|
|
35
|
+
const catalog = useCatalogFallback()
|
|
38
36
|
|
|
39
37
|
const {
|
|
40
38
|
data: related
|
|
41
|
-
} = await useAsyncData('related', () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'products.products_id.*',
|
|
45
|
-
'products.products_id.image.*',
|
|
46
|
-
'currency.currency_id.*',
|
|
47
|
-
'brands.brands_id.*',
|
|
48
|
-
'image.*',
|
|
49
|
-
],
|
|
50
|
-
limit: 10,
|
|
51
|
-
filter: {
|
|
52
|
-
status: {
|
|
53
|
-
_eq: "published"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}))
|
|
39
|
+
} = await useAsyncData('related', async () => {
|
|
40
|
+
// delegate to adapter when available, otherwise fallback to Directus via composable
|
|
41
|
+
return await catalog.listProducts({ limit: 10, filter: { status: { _eq: 'published' } } })
|
|
57
42
|
})
|
|
58
43
|
</script>
|
|
@@ -17,17 +17,12 @@ const sizes = ref([])
|
|
|
17
17
|
const selectedSize = ref(null)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
const { $directus, $readItems } = nuxtApp
|
|
20
|
+
const catalog = useCatalogFallback()
|
|
22
21
|
|
|
23
22
|
const loadSizes = async () => {
|
|
24
23
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
attribute_code: { _eq: 'size' }
|
|
28
|
-
},
|
|
29
|
-
sort: ['id']
|
|
30
|
-
}))
|
|
24
|
+
// adapter may expose attributes; composable falls back to Directus
|
|
25
|
+
const res = await catalog.listAttributes({ filter: { attribute_code: { _eq: 'size' } }, sort: ['id'] })
|
|
31
26
|
|
|
32
27
|
const attr = (res && res[0]) || null
|
|
33
28
|
const opts = attr?.options || []
|
|
@@ -24,29 +24,14 @@
|
|
|
24
24
|
</template>
|
|
25
25
|
|
|
26
26
|
<script setup>
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} from 'vue'
|
|
31
|
-
import store from '~/components/catalog/product/stores.vue'
|
|
27
|
+
import { ref } from 'vue'
|
|
28
|
+
import store from './stores.vue'
|
|
29
|
+
import { useContentFallback } from '../../../composables/useContent'
|
|
32
30
|
|
|
33
31
|
const model = ref(null)
|
|
34
|
-
const
|
|
35
|
-
$directus,
|
|
36
|
-
$readItems,
|
|
37
|
-
} = useNuxtApp()
|
|
32
|
+
const content = useContentFallback()
|
|
38
33
|
|
|
39
|
-
const {
|
|
40
|
-
|
|
41
|
-
} = useSupabaseAuth()
|
|
42
|
-
|
|
43
|
-
const {
|
|
44
|
-
data: shops
|
|
45
|
-
} = await useAsyncData('shops', () => {
|
|
46
|
-
return $directus.request($readItems('shops', {
|
|
47
|
-
fields: ['*', {
|
|
48
|
-
'*': ['*']
|
|
49
|
-
}]
|
|
50
|
-
}))
|
|
34
|
+
const { data: shops } = await useAsyncData('shops', () => {
|
|
35
|
+
return content.listShops({ fields: ['*', { '*': ['*'] }] })
|
|
51
36
|
})
|
|
52
37
|
</script>
|