@meeovi/layer-commerce 1.0.13 → 1.1.0
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/cart/useCart.ts +1 -0
- package/app/composables/domain/product.ts +2 -0
- package/app/composables/featured-products.ts +20 -0
- package/app/composables/orders.ts +69 -0
- package/app/composables/products.ts +30 -0
- package/app/composables/useAuth.ts +43 -0
- package/app/composables/useCache.ts +38 -0
- package/app/composables/useInventory.ts +21 -0
- package/app/composables/useLoading.ts +21 -0
- package/app/composables/useNotification.ts +21 -0
- package/app/composables/useTax.ts +17 -0
- package/app/modules/vue-head/composables/useHead.ts +21 -2
- package/app/pages/departments/[...slug].vue +1 -3
- package/app/pages/departments/category/[...slug].vue +1 -1
- package/app/services/magento.ts +49 -0
- package/app/{composables/stores → stores}/cartStore.ts +16 -0
- package/app/{composables/stores → stores}/products.ts +4 -0
- package/app/types/checkout.d.ts +6 -0
- package/app/types/checkout.ts +6 -0
- package/app/types/imports.d.ts +28 -0
- package/app/{composables/types → types}/index.ts +6 -0
- package/app/types/nuxt-imports.d.ts +5 -0
- package/app/types/product-state.ts +8 -0
- package/app/types/product.d.ts +5 -0
- package/app/types/product.ts +22 -0
- package/app/types/review-state.ts +7 -0
- package/app/types/review.d.ts +1 -0
- package/app/types/review.ts +2 -0
- package/app/types/storeInPickUp.d.ts +1 -0
- package/app/types/storeInPickUp.ts +2 -0
- package/app/types/storePickup-state.ts +5 -0
- package/app/types/vue-globals.d.ts +9 -0
- package/app/types/wishlist-state.ts +5 -0
- package/app/types/wishlist.d.ts +1 -0
- package/app/types/wishlist.ts +2 -0
- package/app/utils/errorHandler.ts +16 -0
- package/graphql/queries-mutations_subscriptions/types/ProductCompare.type.ts +20 -0
- package/package.json +4 -5
- package/tsconfig.json +5 -0
- package/app/composables/types/product.ts +0 -14
- package/app/composables/useContent/index.ts +0 -1
- package/app/composables/useContent/types.ts +0 -44
- package/app/composables/useContent/useContent.ts +0 -45
- package/app/composables/utils/index.js +0 -0
- package/app/types/shims-imports.d.ts +0 -13
- package/global.d.ts +0 -149
- package/index.js +0 -3
- /package/app/{composables/stores → stores}/cart.ts +0 -0
- /package/app/{composables/stores → stores}/checkout.ts +0 -0
- /package/app/{composables/stores → stores}/compare.ts +0 -0
- /package/app/{composables/stores → stores}/currency.js +0 -0
- /package/app/{composables/stores → stores}/digital-products.js +0 -0
- /package/app/{composables/stores → stores}/index.js +0 -0
- /package/app/{composables/stores → stores}/orders.ts +0 -0
- /package/app/{composables/stores → stores}/product.ts +0 -0
- /package/app/{composables/stores → stores}/productList.ts +0 -0
- /package/app/{composables/stores → stores}/productListInfo.ts +0 -0
- /package/app/{composables/stores → stores}/recentlyViewedProducts.ts +0 -0
- /package/app/{composables/stores → stores}/review.ts +0 -0
- /package/app/{composables/stores → stores}/storeInPickUp.ts +0 -0
- /package/app/{composables/stores → stores}/user.ts +0 -0
- /package/app/{composables/stores → stores}/wishlist.ts +0 -0
- /package/app/{composables/types → types}/Order.type.ts +0 -0
- /package/app/{composables/utils → utils}/countryList.ts +0 -0
- /package/app/{composables/utils → utils}/currency.js +0 -0
- /package/app/{composables/utils → utils}/glossary.ts +0 -0
- /package/app/{composables/utils → utils}/importExport.ts +0 -0
- /package/app/{composables/utils → utils}/print.ts +0 -0
- /package/app/{composables/utils → utils}/shopThemes.ts +0 -0
- /package/app/{composables/utils → utils}/statistics.ts +0 -0
- /package/app/{composables/utils → utils}/stock.ts +0 -0
- /package/app/{composables/utils → utils}/stripe.ts +0 -0
- /package/app/{composables/utils → utils}/taxation.ts +0 -0
- /package/app/{composables/utils → utils}/tellFriends.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../composables/cart/useCart'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useProducts } from './useProducts/useProducts'
|
|
2
|
+
|
|
3
|
+
export function useFeaturedProducts() {
|
|
4
|
+
const { fetchProducts } = useProducts()
|
|
5
|
+
return {
|
|
6
|
+
async getFeaturedProducts(options: any = {}) {
|
|
7
|
+
const items = await fetchProducts()
|
|
8
|
+
// If fetchProducts returns a ref/computed, attempt to unwrap
|
|
9
|
+
// and filter by a common `featured` flag if present
|
|
10
|
+
try {
|
|
11
|
+
const list = (items as any)?.value ?? items
|
|
12
|
+
return (Array.isArray(list) ? list.filter((p: any) => p.featured || p.is_featured || p.isFeatured) : []) as any[]
|
|
13
|
+
} catch (e) {
|
|
14
|
+
return []
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default useFeaturedProducts
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getCommerceClient } from '../utils/client'
|
|
2
|
+
|
|
3
|
+
function clientOrNull() {
|
|
4
|
+
try {
|
|
5
|
+
return getCommerceClient()
|
|
6
|
+
} catch (e) {
|
|
7
|
+
return null
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useOrders() {
|
|
12
|
+
const client = clientOrNull()
|
|
13
|
+
return {
|
|
14
|
+
async getOrders(filters: any = {}) {
|
|
15
|
+
if (client && typeof client.listOrders === 'function') return client.listOrders(filters)
|
|
16
|
+
return []
|
|
17
|
+
},
|
|
18
|
+
async getOrderById(id: string) {
|
|
19
|
+
if (client && typeof client.getOrder === 'function') return client.getOrder(id)
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useReturns() {
|
|
26
|
+
const client = clientOrNull()
|
|
27
|
+
return {
|
|
28
|
+
async getReturns(opts: any = {}) {
|
|
29
|
+
if (client && typeof client.listReturns === 'function') return client.listReturns(opts)
|
|
30
|
+
return []
|
|
31
|
+
},
|
|
32
|
+
async createReturn(data: any) {
|
|
33
|
+
if (client && typeof client.createReturn === 'function') return client.createReturn(data)
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function useTransactions() {
|
|
40
|
+
const client = clientOrNull()
|
|
41
|
+
return {
|
|
42
|
+
async getTransactions(opts: any = {}) {
|
|
43
|
+
if (client && typeof client.listTransactions === 'function') return client.listTransactions(opts)
|
|
44
|
+
return []
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function useInvoices() {
|
|
50
|
+
const client = clientOrNull()
|
|
51
|
+
return {
|
|
52
|
+
async getInvoices(opts: any = {}) {
|
|
53
|
+
if (client && typeof client.listInvoices === 'function') return client.listInvoices(opts)
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function useCreditMemos() {
|
|
60
|
+
const client = clientOrNull()
|
|
61
|
+
return {
|
|
62
|
+
async getCreditMemos(opts: any = {}) {
|
|
63
|
+
if (client && typeof client.listCreditMemos === 'function') return client.listCreditMemos(opts)
|
|
64
|
+
return []
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default useOrders
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useProducts as _useProducts } from './useProducts/useProducts'
|
|
2
|
+
|
|
3
|
+
export function useProducts() {
|
|
4
|
+
const core = _useProducts()
|
|
5
|
+
return {
|
|
6
|
+
// map older names used in stores to the implementation
|
|
7
|
+
getProducts: async (opts?: any) => {
|
|
8
|
+
const res = await core.fetchProducts()
|
|
9
|
+
const maybe = (res as any)?.value ?? res
|
|
10
|
+
return maybe || []
|
|
11
|
+
},
|
|
12
|
+
getProductById: async (id: string) => {
|
|
13
|
+
const res = await core.fetchProducts()
|
|
14
|
+
const maybe = (res as any)?.value ?? res
|
|
15
|
+
return (Array.isArray(maybe) ? maybe.find((p: any) => p.id === id || p.sku === id) || null : null)
|
|
16
|
+
},
|
|
17
|
+
getProductsByCategory: async (categoryId: string, opts?: any) => {
|
|
18
|
+
const res = await core.fetchProducts()
|
|
19
|
+
const maybe = (res as any)?.value ?? res
|
|
20
|
+
return Array.isArray(maybe) ? maybe.filter((p: any) => p.category_id === categoryId || p.category === categoryId) : []
|
|
21
|
+
},
|
|
22
|
+
searchProducts: async (query: string, opts?: any) => {
|
|
23
|
+
const res = await core.fetchProducts()
|
|
24
|
+
const maybe = (res as any)?.value ?? res
|
|
25
|
+
return Array.isArray(maybe) ? maybe.filter((p: any) => (p.name || p.title || '').toLowerCase().includes((query || '').toLowerCase())) : []
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default useProducts
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
export function useAuth() {
|
|
4
|
+
const token = ref<string | null>(process.env.MAGENTO_TOKEN || null)
|
|
5
|
+
const refreshInProgress = ref(false)
|
|
6
|
+
|
|
7
|
+
function isTokenExpired() {
|
|
8
|
+
// Best-effort check: token may be JWT
|
|
9
|
+
if (!token.value) return true
|
|
10
|
+
try {
|
|
11
|
+
const parts = token.value.split('.')
|
|
12
|
+
if (parts.length !== 3) return false
|
|
13
|
+
const payload = JSON.parse(atob(parts[1]))
|
|
14
|
+
const exp = payload.exp as number | undefined
|
|
15
|
+
if (!exp) return false
|
|
16
|
+
return Date.now() / 1000 > exp - 30
|
|
17
|
+
} catch {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function refreshAccessToken() {
|
|
23
|
+
if (refreshInProgress.value) return
|
|
24
|
+
refreshInProgress.value = true
|
|
25
|
+
try {
|
|
26
|
+
const resp = await fetch(`${process.env.MAGENTO_API_URL}/auth/refresh`, { method: 'POST', credentials: 'include' })
|
|
27
|
+
if (resp.ok) {
|
|
28
|
+
const data = await resp.json()
|
|
29
|
+
token.value = data.token || token.value
|
|
30
|
+
}
|
|
31
|
+
} finally {
|
|
32
|
+
refreshInProgress.value = false
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function logout() {
|
|
37
|
+
token.value = null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { token, isTokenExpired, refreshAccessToken, logout }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default useAuth
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function useCache() {
|
|
2
|
+
const store = new Map<string, any>()
|
|
3
|
+
|
|
4
|
+
function setCacheItem(key: string, value: any) {
|
|
5
|
+
try {
|
|
6
|
+
store.set(key, value)
|
|
7
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
8
|
+
localStorage.setItem(key, JSON.stringify(value))
|
|
9
|
+
}
|
|
10
|
+
} catch (e) {
|
|
11
|
+
// ignore storage failures
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getCacheItem<T = any>(key: string): T | null {
|
|
16
|
+
if (store.has(key)) return store.get(key)
|
|
17
|
+
try {
|
|
18
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
19
|
+
const raw = localStorage.getItem(key)
|
|
20
|
+
if (raw) {
|
|
21
|
+
const parsed = JSON.parse(raw)
|
|
22
|
+
store.set(key, parsed)
|
|
23
|
+
return parsed as T
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch {}
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function removeCacheItem(key: string) {
|
|
31
|
+
store.delete(key)
|
|
32
|
+
try { if (typeof window !== 'undefined' && window.localStorage) localStorage.removeItem(key) } catch {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { setCacheItem, getCacheItem, removeCacheItem }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default useCache
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function useInventory() {
|
|
2
|
+
async function checkInventory(sku: string, qty: number) {
|
|
3
|
+
try {
|
|
4
|
+
const url = `${process.env.MAGENTO_API_URL}/inventory/${encodeURIComponent(sku)}`
|
|
5
|
+
const res = await fetch(url)
|
|
6
|
+
if (!res.ok) return false
|
|
7
|
+
const data = await res.json()
|
|
8
|
+
// Expecting an object { available: number }
|
|
9
|
+
const available = (data?.available ?? data?.qty ?? 0) as number
|
|
10
|
+
return available >= qty
|
|
11
|
+
} catch (e) {
|
|
12
|
+
// If inventory service is unavailable, fail-safe to false
|
|
13
|
+
console.error('Inventory check failed', e)
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { checkInventory }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default useInventory
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
export function useLoading() {
|
|
4
|
+
const active = ref<Record<string, boolean>>({})
|
|
5
|
+
|
|
6
|
+
function startLoading(key = 'default') {
|
|
7
|
+
active.value[key] = true
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function stopLoading(key = 'default') {
|
|
11
|
+
delete active.value[key]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isLoading(key = 'default') {
|
|
15
|
+
return Boolean(active.value[key])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { startLoading, stopLoading, isLoading, active }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default useLoading
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
export type NotificationPayload = { type: 'success'|'error'|'info'|'warning'; message: string }
|
|
4
|
+
|
|
5
|
+
const notifications = ref<NotificationPayload[]>([])
|
|
6
|
+
|
|
7
|
+
export function useNotification() {
|
|
8
|
+
function show(payload: NotificationPayload) {
|
|
9
|
+
notifications.value.push(payload)
|
|
10
|
+
// For production-grade UX integrate with a toast library here.
|
|
11
|
+
// Using console as fallback to keep runtime deterministic.
|
|
12
|
+
if (payload.type === 'error') console.error(payload.message)
|
|
13
|
+
else console.log(payload.type.toUpperCase(), payload.message)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function clear() { notifications.value = [] }
|
|
17
|
+
|
|
18
|
+
return { notifications, show, clear }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default useNotification
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function useTax() {
|
|
2
|
+
async function calculateTax(quoteId: string) {
|
|
3
|
+
try {
|
|
4
|
+
const url = `${process.env.MAGENTO_API_URL}/tax/calculate?quoteId=${encodeURIComponent(quoteId)}`
|
|
5
|
+
const res = await fetch(url)
|
|
6
|
+
if (!res.ok) throw new Error('Tax calculation failed')
|
|
7
|
+
return res.json()
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.error('Tax calculation error', e)
|
|
10
|
+
throw e
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return { calculateTax }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default useTax
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
export default function useHead(
|
|
2
|
-
|
|
1
|
+
export default function useHead(meta: { title?: string; description?: string; titleTemplate?: (titleChunk: any) => string } = {}) {
|
|
2
|
+
if (typeof document !== 'undefined') {
|
|
3
|
+
if (meta.title) {
|
|
4
|
+
const resolvedTitle = typeof meta.title === 'function' ? (meta.title as any)() : meta.title
|
|
5
|
+
document.title = resolvedTitle
|
|
6
|
+
}
|
|
7
|
+
if (meta.description) {
|
|
8
|
+
let desc = document.querySelector('meta[name="description"]')
|
|
9
|
+
if (!desc) {
|
|
10
|
+
desc = document.createElement('meta')
|
|
11
|
+
desc.setAttribute('name', 'description')
|
|
12
|
+
document.head.appendChild(desc)
|
|
13
|
+
}
|
|
14
|
+
desc.setAttribute('content', meta.description)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
set(metaUpdate: { title?: string; description?: string; titleTemplate?: (titleChunk: any) => string }) {
|
|
19
|
+
return useHead(metaUpdate)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
3
22
|
}
|
|
@@ -232,9 +232,7 @@
|
|
|
232
232
|
</template>
|
|
233
233
|
|
|
234
234
|
<script setup>
|
|
235
|
-
|
|
236
|
-
import spaces from '#social/app/components/related/space.vue'
|
|
237
|
-
import productCard from '#commerce/app/components/catalog/product/productCard.vue'
|
|
235
|
+
import productCard from '#commerce/app/components/catalog/product/productCard.vue'
|
|
238
236
|
import travel from '@/components/categories/travel.vue'
|
|
239
237
|
import deals from '@/components/categories/deals.vue'
|
|
240
238
|
import timeComponent from '@/components/categories/time/time.vue'
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
import stations from '~/components/categories/stations.vue'
|
|
78
78
|
import eats from '~/components/categories/eats.vue'
|
|
79
79
|
import restaurants from '~/components/categories/restaurants.vue'
|
|
80
|
-
import productCard from '
|
|
80
|
+
import productCard from '~/components/catalog/product/productCard.vue'
|
|
81
81
|
|
|
82
82
|
const route = useRoute()
|
|
83
83
|
const {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class MagentoService {
|
|
2
|
+
baseUrl: string
|
|
3
|
+
constructor(baseUrl?: string) {
|
|
4
|
+
this.baseUrl = baseUrl || (process.env.MAGENTO_API_URL as string) || ''
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
private headers(token?: string) {
|
|
8
|
+
const h: Record<string,string> = { 'Content-Type': 'application/json' }
|
|
9
|
+
if (token) h['Authorization'] = `Bearer ${token}`
|
|
10
|
+
return h
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async fetchJSON(path: string, opts: RequestInit = {}, token?: string) {
|
|
14
|
+
const url = path.startsWith('http') ? path : `${this.baseUrl.replace(/\/$/, '')}/${path.replace(/^\//, '')}`
|
|
15
|
+
const res = await fetch(url, { ...opts, headers: { ...(opts.headers as any || {}), ...this.headers(token) } })
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
const text = await res.text().catch(()=>'')
|
|
18
|
+
const err = new Error(`Magento API error ${res.status}: ${text}`)
|
|
19
|
+
throw err
|
|
20
|
+
}
|
|
21
|
+
return res.json()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async getProduct(sku: string) {
|
|
25
|
+
return this.fetchJSON(`/products/${encodeURIComponent(sku)}`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async createGuestCart() {
|
|
29
|
+
return this.fetchJSON('/guest-carts', { method: 'POST' })
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async createCustomerCart(token: string) {
|
|
33
|
+
return this.fetchJSON('/carts/mine', { method: 'POST' }, token)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async addItemToCart(token: string, item: any) {
|
|
37
|
+
return this.fetchJSON('/carts/mine/items', { method: 'POST', body: JSON.stringify({ cartItem: item }) }, token)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getCartTotals(token: string) {
|
|
41
|
+
return this.fetchJSON('/carts/mine/totals', {}, token)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async clearCart(token: string) {
|
|
45
|
+
return this.fetchJSON('/carts/mine/clear', { method: 'POST' }, token)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default MagentoService
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
// stores/cartStore.ts
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { MagentoService } from '~/services/magento'
|
|
4
|
+
import { useAuth } from '~/composables/useAuth'
|
|
5
|
+
import { useInventory } from '~/composables/useInventory'
|
|
6
|
+
import { useTax } from '~/composables/useTax'
|
|
7
|
+
import { useLoading } from '~/composables/useLoading'
|
|
8
|
+
import { useNotification } from '~/composables/useNotification'
|
|
9
|
+
import { useCache } from '~/composables/useCache'
|
|
10
|
+
import { errorHandler } from '~/utils/errorHandler'
|
|
11
|
+
|
|
12
|
+
class CartError extends Error {
|
|
13
|
+
code: string
|
|
14
|
+
constructor(message: string, code: string) {
|
|
15
|
+
super(message)
|
|
16
|
+
this.code = code
|
|
17
|
+
this.name = 'CartError'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
4
20
|
|
|
5
21
|
interface MagentoProduct {
|
|
6
22
|
sku: string
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// stores/products.ts - Pinia store for product management
|
|
2
2
|
import type { Product } from '~/app/types'
|
|
3
|
+
import { defineStore } from 'pinia'
|
|
4
|
+
import { ref, computed, readonly } from 'vue'
|
|
5
|
+
import { useProducts } from '~/app/composables/products'
|
|
6
|
+
import { useFeaturedProducts } from '~/app/composables/featured-products'
|
|
3
7
|
|
|
4
8
|
export const useProductsStore = defineStore('products', () => {
|
|
5
9
|
const products = ref<Product[]>([])
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
declare module '#imports' {
|
|
2
|
+
export function useRuntimeConfig(): any
|
|
3
|
+
export function useNuxtApp(): any
|
|
4
|
+
export function useAppConfig(): any
|
|
5
|
+
export function useOrders(): any
|
|
6
|
+
export function useReturns(): any
|
|
7
|
+
export function useTransactions(): any
|
|
8
|
+
export function useInvoices(): any
|
|
9
|
+
export function useCreditMemos(): any
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module 'nuxt/app' {
|
|
13
|
+
export function useAppConfig(): any
|
|
14
|
+
export function useAsyncData<T = any>(keyOrHandler: string | null | (() => Promise<T> | T), handler?: (...args: any[]) => Promise<T> | T): Promise<{ data: { value: T }, error: { value: any } }>
|
|
15
|
+
export function useState<T = any>(key: string, init?: T | (() => T)): { value: T }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Provide globals for files that call Nuxt auto-imports without module import
|
|
19
|
+
declare function useNuxtApp(): any
|
|
20
|
+
declare function useRuntimeConfig(): any
|
|
21
|
+
declare function useAppConfig(): any
|
|
22
|
+
|
|
23
|
+
// Order-related auto-imports used without explicit imports in stores
|
|
24
|
+
declare function useOrders(): any
|
|
25
|
+
declare function useReturns(): any
|
|
26
|
+
declare function useTransactions(): any
|
|
27
|
+
declare function useInvoices(): any
|
|
28
|
+
declare function useCreditMemos(): any
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export * from '~/types/checkout'
|
|
2
|
+
export * from '~/types/product'
|
|
3
|
+
export * from '~/types/review'
|
|
4
|
+
export * from '~/types/storeInPickUp'
|
|
5
|
+
export * from '~/types/wishlist'
|
|
1
6
|
// types/index.ts - Main type definitions for commerce layer
|
|
2
7
|
|
|
3
8
|
// Re-export Order types
|
|
@@ -33,6 +38,7 @@ export interface Product {
|
|
|
33
38
|
price?: number;
|
|
34
39
|
regularPrice?: number;
|
|
35
40
|
salePrice?: number;
|
|
41
|
+
sale_price?: number;
|
|
36
42
|
attributes?: Array<{ name: string; value: string }>;
|
|
37
43
|
variations?: ProductVariant[];
|
|
38
44
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export interface Price { amount: number; currency: string }
|
|
2
|
+
|
|
3
|
+
export interface ProductVariant { id: string; sku: string; price: Price; attributes?: Record<string, any> }
|
|
4
|
+
|
|
5
|
+
export interface Product { id: string; sku: string; name: string; variants?: ProductVariant[]; price?: Price }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Price {
|
|
2
|
+
value: number
|
|
3
|
+
currency: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface ProductVariant {
|
|
7
|
+
id: string
|
|
8
|
+
sku?: string
|
|
9
|
+
price?: Price
|
|
10
|
+
attributes?: Record<string, any>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface SimpleProduct {
|
|
14
|
+
id: string
|
|
15
|
+
title?: string
|
|
16
|
+
description?: string
|
|
17
|
+
images?: string[]
|
|
18
|
+
price?: Price
|
|
19
|
+
variants?: ProductVariant[]
|
|
20
|
+
}
|
|
21
|
+
export * from './index'
|
|
22
|
+
export type { ProductState } from './product-state'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface Review { id: string; productId: string; rating: number; comment?: string; author?: string }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface StoreInPickUp { id: string; name: string; address: string; phone?: string }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Minimal ambient declarations for Vue/Pinia globals used in the commerce layer
|
|
2
|
+
declare function ref<T = any>(value?: T): any
|
|
3
|
+
declare function computed<T = any>(fn: () => T): any
|
|
4
|
+
declare function readonly<T = any>(v: T): T
|
|
5
|
+
declare function reactive<T = any>(v: T): T
|
|
6
|
+
declare function watchEffect(fn: () => void): void
|
|
7
|
+
|
|
8
|
+
// Pinia-ish defineStore (layers may call defineStore during build time)
|
|
9
|
+
declare function defineStore(id: string, setup: any): any
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface WishlistItem { id: string; productSku: string; addedAt: string }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const errorHandler = {
|
|
2
|
+
handle(err: unknown) {
|
|
3
|
+
// Structured handling: log and optionally rethrow
|
|
4
|
+
try {
|
|
5
|
+
if (err instanceof Error) {
|
|
6
|
+
console.error(`[Commerce][Error] ${err.name}: ${err.message}`)
|
|
7
|
+
} else {
|
|
8
|
+
console.error('[Commerce][Error]', err)
|
|
9
|
+
}
|
|
10
|
+
} catch (e) {
|
|
11
|
+
console.error('Error while handling error', e)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default errorHandler
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ComparableAttribute { key: string; value: string }
|
|
2
|
+
|
|
3
|
+
export interface ComparableItem { id: string; sku?: string; name?: string }
|
|
4
|
+
|
|
5
|
+
export interface ComparableProduct {
|
|
6
|
+
id: string
|
|
7
|
+
sku?: string
|
|
8
|
+
name?: string
|
|
9
|
+
attributes?: ComparableAttribute[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CompareList {
|
|
13
|
+
attributes?: ComparableAttribute[]
|
|
14
|
+
products?: ComparableProduct[]
|
|
15
|
+
items?: ComparableItem[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type ProductCompare = ComparableProduct
|
|
19
|
+
|
|
20
|
+
export default ProductCompare
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meeovi/layer-commerce",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Commerce Layer for the Alternate Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"commerce",
|
|
@@ -24,14 +24,13 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@better-auth/stripe": "^1.4.15",
|
|
26
26
|
"@meeovi/adapter-magento": "^1.0.2",
|
|
27
|
-
"@meeovi/api": "^1.0.1",
|
|
28
|
-
"@meeovi/core": "^1.0.1",
|
|
29
27
|
"@meeovi/layer-social": "^1.0.4",
|
|
30
28
|
"@meeovi/sdk": "^1.0.2",
|
|
31
|
-
"@meeovi/
|
|
29
|
+
"@meeovi/core": "^1.0.4",
|
|
32
30
|
"@polar-sh/better-auth": "^1.6.4",
|
|
33
31
|
"@polar-sh/sdk": "^0.42.2",
|
|
34
|
-
"@storefront-ui/nuxt": "^3.1.1"
|
|
32
|
+
"@storefront-ui/nuxt": "^3.1.1",
|
|
33
|
+
"lodash-es": "^4.17.23"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
37
36
|
"@biomejs/biome": "^2.3.11",
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface Product {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
price: number;
|
|
5
|
-
image?: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
sku: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface ProductState {
|
|
11
|
-
products: Product[];
|
|
12
|
-
selectedProduct?: Product | null;
|
|
13
|
-
isLoading: boolean;
|
|
14
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './useContent';
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { Ref } from 'vue';
|
|
2
|
-
import type { Maybe } from '../_types';
|
|
3
|
-
import type { HeadingProps } from '~/components/Heading/types';
|
|
4
|
-
import type { ProductSliderProps } from '~/components/ProductSlider/types';
|
|
5
|
-
import type { CategoryCardProps } from '~/components/ui/CategoryCard/types';
|
|
6
|
-
import type { DisplayProps } from '~/components/ui/Display/types';
|
|
7
|
-
import type { HeroProps } from '~/components/ui/Hero/types';
|
|
8
|
-
|
|
9
|
-
type EntryFields<TFields> = Array<{
|
|
10
|
-
fields: TFields;
|
|
11
|
-
}>;
|
|
12
|
-
|
|
13
|
-
type WithComponentField<TProps, TComponent> = TProps & {
|
|
14
|
-
component: TComponent;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type DynamicContentFields =
|
|
18
|
-
| WithComponentField<HeroProps, 'Hero'>
|
|
19
|
-
| WithComponentField<CategoryCardProps, 'Card'>
|
|
20
|
-
| WithComponentField<HeadingProps, 'Heading'>
|
|
21
|
-
| WithComponentField<DisplayProps, 'Display'>
|
|
22
|
-
| WithComponentField<ProductSliderProps, 'ProductSlider'>;
|
|
23
|
-
|
|
24
|
-
export interface ContentDynamicPage {
|
|
25
|
-
component: 'Page';
|
|
26
|
-
content: EntryFields<DynamicContentFields>;
|
|
27
|
-
name: string;
|
|
28
|
-
url: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface UseContentState {
|
|
32
|
-
data: Maybe<EntryFields<ContentDynamicPage>>;
|
|
33
|
-
loading: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type GetContent = () => Promise<Ref<Maybe<EntryFields<ContentDynamicPage>>>>;
|
|
37
|
-
|
|
38
|
-
export interface UseContent {
|
|
39
|
-
data: Readonly<Ref<UseContentState['data']>>;
|
|
40
|
-
loading: Readonly<Ref<boolean>>;
|
|
41
|
-
getContent: GetContent;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export type UseContentReturn = (url: string) => UseContent;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { toRefs } from '@vueuse/shared';
|
|
2
|
-
import type { UseContentReturn, UseContentState, GetContent } from './types';
|
|
3
|
-
import { getCommerceClient } from '../../utils/client';
|
|
4
|
-
import { useAsyncData, useState } from 'nuxt/app';
|
|
5
|
-
import { useHandleError } from '../useHandleError';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @description Composable for managing content from CMS.
|
|
9
|
-
* @param url Parameter of the content to fetch.
|
|
10
|
-
* @returns {@link UseContent}
|
|
11
|
-
* @example
|
|
12
|
-
* const { data, loading, getContent } = useContent<ContentFieldsType>('url');
|
|
13
|
-
*/
|
|
14
|
-
export const useContent: UseContentReturn = (url) => {
|
|
15
|
-
const state = useState<UseContentState>(`content-${url}`, () => ({
|
|
16
|
-
data: null,
|
|
17
|
-
loading: false,
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @description Function for fetching the content.
|
|
22
|
-
* @example
|
|
23
|
-
* getContent();
|
|
24
|
-
*/
|
|
25
|
-
const getContent: GetContent = async () => {
|
|
26
|
-
state.value.loading = true;
|
|
27
|
-
try {
|
|
28
|
-
const client = getCommerceClient();
|
|
29
|
-
const result = await useAsyncData(() => client.listProducts?.());
|
|
30
|
-
const { data, error } = result as unknown as { data: Awaited<ReturnType<GetContent>>; error: any };
|
|
31
|
-
useHandleError(error?.value ?? error);
|
|
32
|
-
state.value.data = data.value;
|
|
33
|
-
return data;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
throw new Error(error as string);
|
|
36
|
-
} finally {
|
|
37
|
-
state.value.loading = false;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
getContent,
|
|
43
|
-
...toRefs(state.value),
|
|
44
|
-
};
|
|
45
|
-
};
|
|
File without changes
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
declare module '#imports' {
|
|
2
|
-
export function useRuntimeConfig(): any;
|
|
3
|
-
export function useState<T = any>(key: string, init?: T): any;
|
|
4
|
-
export function useFetch(...args: any[]): any;
|
|
5
|
-
export function defineNuxtPlugin(fn: any): any;
|
|
6
|
-
export const navigateTo: any;
|
|
7
|
-
export const useRouter: any;
|
|
8
|
-
export const useNuxtApp: any;
|
|
9
|
-
export const useRequestEvent: any;
|
|
10
|
-
export const useCookie: any;
|
|
11
|
-
export const useHeaders: any;
|
|
12
|
-
export const useQuery: any;
|
|
13
|
-
}
|
package/global.d.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
declare module '#imports' {
|
|
2
|
-
// Minimal shims for Nuxt auto-imports used in script-setup
|
|
3
|
-
export const useHead: any
|
|
4
|
-
export const useNuxtApp: any
|
|
5
|
-
export const useAsyncData: any
|
|
6
|
-
export const useState: any
|
|
7
|
-
export const useFetch: any
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
declare module '*.vue' {
|
|
11
|
-
import { DefineComponent } from 'vue'
|
|
12
|
-
const component: DefineComponent<{}, {}, any>
|
|
13
|
-
export default component
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Broad runtime shims to help isolated tsc runs in this monorepo
|
|
17
|
-
declare module 'pinia' {
|
|
18
|
-
export function defineStore(id: any, setup?: any): any
|
|
19
|
-
export function createPinia(): any
|
|
20
|
-
const pinia: any
|
|
21
|
-
export default pinia
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
declare module 'lodash-es' {
|
|
25
|
-
const _default: any
|
|
26
|
-
export default _default
|
|
27
|
-
export const groupBy: any
|
|
28
|
-
export const uniqBy: any
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
declare module '~/*'
|
|
32
|
-
declare module '@/*'
|
|
33
|
-
|
|
34
|
-
declare const defineStore: any
|
|
35
|
-
declare function ref<T = any>(v?: T): any
|
|
36
|
-
declare function computed<T = any>(fn: any): any
|
|
37
|
-
declare function readonly<T = any>(v: T): T
|
|
38
|
-
declare const reactive: any
|
|
39
|
-
declare const watch: any
|
|
40
|
-
declare const onMounted: any
|
|
41
|
-
declare const onBeforeMount: any
|
|
42
|
-
declare const onUnmounted: any
|
|
43
|
-
|
|
44
|
-
// Nuxt auto-imports (already partially declared under #imports)
|
|
45
|
-
declare const useNuxtApp: any
|
|
46
|
-
declare const useHead: any
|
|
47
|
-
declare const useAsyncData: any
|
|
48
|
-
declare const useState: any
|
|
49
|
-
declare const useFetch: any
|
|
50
|
-
|
|
51
|
-
// Test globals (vitest/jest)
|
|
52
|
-
declare function describe(...args: any[]): any
|
|
53
|
-
declare function it(...args: any[]): any
|
|
54
|
-
declare function beforeEach(...args: any[]): any
|
|
55
|
-
declare function afterEach(...args: any[]): any
|
|
56
|
-
declare const expect: any
|
|
57
|
-
declare const vi: any
|
|
58
|
-
|
|
59
|
-
// Common composable globals used across the layer (fallbacks for isolated tsc)
|
|
60
|
-
declare const useAuth: any
|
|
61
|
-
declare const useLoading: any
|
|
62
|
-
declare const useInventory: any
|
|
63
|
-
declare const useCache: any
|
|
64
|
-
declare const useNotification: any
|
|
65
|
-
declare const useOrders: any
|
|
66
|
-
declare const useReturns: any
|
|
67
|
-
declare const useTransactions: any
|
|
68
|
-
declare const useInvoices: any
|
|
69
|
-
declare const useCreditMemos: any
|
|
70
|
-
declare const useProducts: any
|
|
71
|
-
declare const useFeaturedProducts: any
|
|
72
|
-
declare const useTax: any
|
|
73
|
-
|
|
74
|
-
// Common error / service placeholders
|
|
75
|
-
declare const errorHandler: any
|
|
76
|
-
declare const CartError: any
|
|
77
|
-
type MagentoService = any
|
|
78
|
-
|
|
79
|
-
// Domain types used in many composables
|
|
80
|
-
type Price = any
|
|
81
|
-
type ProductVariant = any
|
|
82
|
-
type Order = any
|
|
83
|
-
type Return = any
|
|
84
|
-
type Transaction = any
|
|
85
|
-
type Invoice = any
|
|
86
|
-
type CreditMemo = any
|
|
87
|
-
type OrderFilters = any
|
|
88
|
-
type ComparableAttribute = any
|
|
89
|
-
type ComparableProduct = any
|
|
90
|
-
type ComparableItem = any
|
|
91
|
-
type CompareList = any
|
|
92
|
-
|
|
93
|
-
// Store / state aliases
|
|
94
|
-
type CheckoutState = any
|
|
95
|
-
type ProductState = any
|
|
96
|
-
type ReviewState = any
|
|
97
|
-
type StorePickupState = any
|
|
98
|
-
type WishlistState = any
|
|
99
|
-
|
|
100
|
-
// Provide permissive module declarations for local app type modules
|
|
101
|
-
declare module '~/app/types' {
|
|
102
|
-
export type Product = any
|
|
103
|
-
export type Price = any
|
|
104
|
-
export type HeroProps = any
|
|
105
|
-
export type CategoryCardProps = any
|
|
106
|
-
export type HeadingProps = any
|
|
107
|
-
export type DisplayProps = any
|
|
108
|
-
export type ProductSliderProps = any
|
|
109
|
-
export type Cart = any
|
|
110
|
-
export type Maybe<T = any> = T | null | undefined
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Export order-related types used by stores
|
|
114
|
-
declare module '~/app/types' {
|
|
115
|
-
export type Order = any
|
|
116
|
-
export type Return = any
|
|
117
|
-
export type Transaction = any
|
|
118
|
-
export type Invoice = any
|
|
119
|
-
export type CreditMemo = any
|
|
120
|
-
export type OrderFilters = any
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Component-level type shims
|
|
124
|
-
declare module '~/components/Heading/types' {
|
|
125
|
-
export type HeadingProps = any
|
|
126
|
-
}
|
|
127
|
-
declare module '~/components/ProductSlider/types' {
|
|
128
|
-
export type ProductSliderProps = any
|
|
129
|
-
}
|
|
130
|
-
declare module '~/components/ui/CategoryCard/types' {
|
|
131
|
-
export type CategoryCardProps = any
|
|
132
|
-
}
|
|
133
|
-
declare module '~/components/ui/Display/types' {
|
|
134
|
-
export type DisplayProps = any
|
|
135
|
-
}
|
|
136
|
-
declare module '~/components/ui/Hero/types' {
|
|
137
|
-
export type HeroProps = any
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Local alias modules used by stores
|
|
141
|
-
declare module '@/types/product' {
|
|
142
|
-
export type Product = any
|
|
143
|
-
export type ProductState = any
|
|
144
|
-
}
|
|
145
|
-
declare module '@/types/review' {
|
|
146
|
-
export type Review = any
|
|
147
|
-
export type ReviewState = any
|
|
148
|
-
}
|
|
149
|
-
|
package/index.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|