@astralweb/nova-recently-viewed 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +17 -16
  2. package/README.md +96 -233
  3. package/dist/module.d.mts +5 -0
  4. package/dist/module.json +12 -0
  5. package/dist/module.mjs +26 -0
  6. package/dist/{api → runtime/api}/extendMiddleware.d.ts +4 -5
  7. package/dist/runtime/api/extendMiddleware.js +64 -0
  8. package/dist/runtime/api/index.d.ts +1 -0
  9. package/dist/runtime/api/index.js +1 -0
  10. package/dist/runtime/composables/index.d.ts +3 -0
  11. package/dist/runtime/composables/index.js +3 -0
  12. package/dist/runtime/composables/useRecentlyViewedApi.d.ts +5 -0
  13. package/dist/runtime/composables/useRecentlyViewedApi.js +21 -0
  14. package/dist/runtime/composables/useRecentlyViewedList.d.ts +2 -0
  15. package/dist/runtime/composables/useRecentlyViewedList.js +67 -0
  16. package/dist/runtime/composables/useRecentlyViewedStorage.d.ts +3 -0
  17. package/dist/runtime/composables/useRecentlyViewedStorage.js +133 -0
  18. package/dist/runtime/index.d.ts +3 -0
  19. package/dist/runtime/index.js +3 -0
  20. package/dist/runtime/server/tsconfig.json +3 -0
  21. package/dist/{types → runtime/types}/api.d.ts +0 -1
  22. package/dist/runtime/types/api.js +0 -0
  23. package/dist/{types → runtime/types}/composables.d.ts +11 -3
  24. package/dist/runtime/types/composables.js +0 -0
  25. package/dist/runtime/types/index.d.ts +2 -0
  26. package/dist/runtime/types/index.js +2 -0
  27. package/dist/types.d.mts +7 -0
  28. package/package.json +51 -61
  29. package/dist/api/extendMiddleware.d.ts.map +0 -1
  30. package/dist/api/index.d.ts +0 -4
  31. package/dist/api/index.d.ts.map +0 -1
  32. package/dist/api/queryFields.d.ts +0 -3
  33. package/dist/api/queryFields.d.ts.map +0 -1
  34. package/dist/api/web.d.ts +0 -27
  35. package/dist/api/web.d.ts.map +0 -1
  36. package/dist/api.cjs +0 -46
  37. package/dist/api.js +0 -2201
  38. package/dist/chunks/useRecentlyViewed-BMqCM4G9.js +0 -1
  39. package/dist/chunks/useRecentlyViewed-DmIwibiG.js +0 -96
  40. package/dist/chunks/web-DMlcd6E0.js +0 -1
  41. package/dist/chunks/web-WoqqfD6L.js +0 -26
  42. package/dist/composables/index.d.ts +0 -2
  43. package/dist/composables/index.d.ts.map +0 -1
  44. package/dist/composables/useRecentlyViewed.d.ts +0 -7
  45. package/dist/composables/useRecentlyViewed.d.ts.map +0 -1
  46. package/dist/composables.cjs +0 -1
  47. package/dist/composables.js +0 -4
  48. package/dist/index.cjs +0 -1
  49. package/dist/index.d.ts +0 -4
  50. package/dist/index.d.ts.map +0 -1
  51. package/dist/index.js +0 -14
  52. package/dist/types/api.d.ts.map +0 -1
  53. package/dist/types/composables.d.ts.map +0 -1
  54. package/dist/types/index.d.ts +0 -3
  55. package/dist/types/index.d.ts.map +0 -1
  56. package/dist/types.cjs +0 -1
  57. package/dist/types.js +0 -1
package/LICENSE CHANGED
@@ -1,23 +1,24 @@
1
- Proprietary License
1
+ PROPRIETARY LICENSE
2
2
 
3
- Copyright (c) 2024 Astral Web
3
+ Copyright (c) 2025 Astral Web
4
4
 
5
5
  This software and associated documentation files (the "Software") are proprietary
6
- to Astral Web and are intended for internal use only.
6
+ to Astral Web and are intended solely for internal use by Astral Web and its
7
+ authorized personnel.
7
8
 
8
9
  RESTRICTIONS:
9
- - This Software is for internal use by Astral Web employees and authorized personnel only.
10
- - No part of this Software may be reproduced, distributed, or transmitted in any form
11
- or by any means, including photocopying, recording, or other electronic or mechanical
12
- methods, without the prior written permission of Astral Web.
13
- - This Software may not be used outside of Astral Web's business operations.
14
- - Reverse engineering, decompilation, or disassembly of this Software is prohibited.
10
+ - The Software may not be copied, modified, distributed, or used by any party
11
+ other than Astral Web without express written permission.
12
+ - No part of the Software may be reverse engineered, decompiled, or disassembled.
13
+ - The Software may not be sublicensed, sold, or transferred to any third party.
14
+ - Use of the Software is restricted to internal business operations of Astral Web.
15
15
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
17
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ASTRAL WEB BE LIABLE FOR
19
- ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21
- OTHER DEALINGS IN THE SOFTWARE.
16
+ DISCLAIMER:
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ ASTRAL WEB BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23
 
23
- For permissions beyond the scope of this license, please contact Astral Web.
24
+ For licensing inquiries, contact: Astral Web
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # Recently Viewed 套件使用指南
1
+ # Recently Viewed 模組使用指南
2
2
 
3
3
  > ⚠️ **內部使用套件** - 此套件僅供 Astral Web 內部使用,未經授權不得用於其他用途。
4
4
 
5
5
  ## 概覽
6
6
 
7
- Recently Viewed 套件採用 Composable 模式設計,提供完整的最近瀏覽商品功能。支援本地儲存管理、後端同步、訪客與會員資料合併,以及靈活的配置選項。
7
+ Recently Viewed 是一個 Nuxt 3 模組,提供完整的最近瀏覽商品追蹤與管理功能。模組採用 Nuxt Module 架構設計,支援本地儲存與伺服器同步、訪客與會員資料自動合併,並提供靈活的配置選項。
8
8
 
9
9
  ## 安裝與設定
10
10
 
@@ -16,296 +16,159 @@ Recently Viewed 套件採用 Composable 模式設計,提供完整的最近瀏
16
16
  yarn add @astralweb/nova-recently-viewed
17
17
  ```
18
18
 
19
- ### 2. middleware 擴充
19
+ ### 2. Middleware 擴充
20
+
20
21
  ```typescript
21
22
  // apps/server/extendApiMethods/index.ts
22
23
 
23
24
  export {
24
- recentlyViewedProducts,
25
+ recentlyViewedProducts,
25
26
  addRecentlyViewedProducts,
26
27
  } from '@astralweb/nova-recently-viewed/api';
27
28
  ```
28
29
 
29
- ### 3. SDK 設定
30
- ```typescript
31
- // apps/web/plugins/sdk.client.ts
32
- import { setSdk } from '@astralweb/nova-recently-viewed/api';
33
-
34
- export default defineNuxtPlugin(() => {
35
- // 設定 SDK 實例
36
- setSdk(sdkInstance);
37
- });
38
- ```
30
+ ### 3. 註冊模組
39
31
 
40
- ### 4. 新增 nuxt.config.ts 設定
41
32
  ```typescript
33
+ // apps/web/nuxt.config.ts
34
+
42
35
  export default defineNuxtConfig({
43
- vite: {
44
- ssr: {
45
- noExternal: ['@astralweb/nova-recently-viewed'],
46
- },
47
- },
36
+ modules: [
37
+ '@astralweb/nova-recently-viewed',
38
+ ],
48
39
  })
49
40
  ```
50
41
 
51
- ## 組件基本使用
42
+ ## 架構設計
43
+
44
+ ### 三層架構
45
+
46
+ 1. **API Layer** (`useRecentlyViewedApi`)
47
+ - 處理與 GraphQL 後端的通信
48
+ - 提供 `syncToServer` 和 `fetchFromServer` 方法
52
49
 
53
- ### 在商品頁面中使用
50
+ 2. **Storage Layer** (`useRecentlyViewedStorage`)
51
+ - 管理本地儲存與核心業務邏輯
52
+ - 處理訪客/會員資料合併
53
+ - 提供完整的 CRUD 操作
54
+
55
+ 3. **List Layer** (`useRecentlyViewedList`)
56
+ - 高階封裝,適用於產品詳情頁
57
+ - 自動處理初始化、登入狀態變化、SKU 更新
58
+ - 提供開箱即用的體驗
59
+
60
+ ## 使用方式
61
+
62
+ 適合產品詳情頁,自動處理所有邏輯。
54
63
 
55
64
  ```vue
56
65
  <template>
57
- <div>
58
- <!-- 商品內容 -->
59
- <ProductDetails :product="product" />
60
-
61
- <!-- 最近瀏覽商品區塊 -->
62
- <section v-if="recentlyViewedSkus && recentlyViewedSkus.length > 0" class="mb-10">
63
- <ProductSlider
64
- :title="t('product.section.recentlyViewed')"
65
- :products-sku="recentlyViewedSkus"
66
- maintain-order
67
- />
68
- </section>
69
- </div>
66
+ <ProductSlider :products-sku="recentlyViewedSkus" />
70
67
  </template>
71
68
 
72
69
  <script setup lang="ts">
73
- import { useRecentlyViewed } from '@astralweb/nova-recently-viewed';
74
-
75
- const route = useRoute();
76
- const { t } = useI18n();
77
-
78
- // 獲取當前商品資料
79
- const { data: product } = await useAsyncData('product', () =>
80
- fetchProduct(route.params.slug)
81
- );
82
-
83
- // 使用最近瀏覽功能
84
- const {
85
- addRecentlyViewed,
86
- getRecentlyViewedSkus,
87
- mergeGuestToCustomer,
88
- isLoggedIn
89
- } = useRecentlyViewed();
90
-
91
- const recentlyViewedSkus = ref<string[]>([]);
92
-
93
- // 初始化最近瀏覽商品
94
- const initializeRecentlyViewed = async (currentSku: string) => {
95
- if (!currentSku) return;
96
-
97
- if (isLoggedIn.value) {
98
- // 登入用戶:先合併資料 > 再添加當前商品 > 最後獲取列表
99
- await mergeGuestToCustomer();
100
- await addRecentlyViewed(currentSku);
101
- recentlyViewedSkus.value = await getRecentlyViewedSkus(currentSku);
102
- } else {
103
- // 訪客用戶:先顯示現有資料 > 再添加當前商品
104
- recentlyViewedSkus.value = await getRecentlyViewedSkus(currentSku);
105
- await addRecentlyViewed(currentSku);
106
- }
107
- };
108
-
109
- // 在商品頁面掛載時調用
110
- onMounted(() => {
111
- if (product.value?.sku) {
112
- initializeRecentlyViewed(product.value.sku);
113
- }
70
+ const { recentlyViewedSkus } = useRecentlyViewedList({
71
+ currentSku: computed(() => product.value?.sku ?? ''),
72
+ isLoggedIn: computed(() => !!user.value),
73
+ enableServerSync: true,
114
74
  });
115
75
  </script>
116
76
  ```
117
77
 
118
- ### 登入狀態處理
78
+ **自動處理:**
79
+ - ✅ 組件掛載時初始化
80
+ - ✅ SKU 變化時更新列表
81
+ - ✅ 登入狀態變化時合併資料
82
+ - ✅ 本地緩存優化
119
83
 
120
- ```typescript
121
- <script setup lang="ts">
122
- import { useRecentlyViewed } from '@astralweb/nova-recently-viewed';
123
84
 
124
- const { mergeGuestToCustomer, isLoggedIn } = useRecentlyViewed();
85
+ ## API 參考
86
+
87
+ ### useRecentlyViewedList
125
88
 
126
- // 監聽登入狀態變化
127
- watch(isLoggedIn, async (newValue, oldValue) => {
128
- // 當用戶從未登入變為登入狀態時,合併訪客資料
129
- if (!oldValue && newValue) {
130
- await mergeGuestToCustomer();
131
- }
89
+ ```typescript
90
+ const { recentlyViewedSkus } = useRecentlyViewedList({
91
+ currentSku: Ref<string> | ComputedRef<string>,
92
+ isLoggedIn: ComputedRef<boolean>,
93
+ maxItems?: number, // 預設:20
94
+ guestStorageKey?: string, // 預設:'recently-viewed-guest'
95
+ customerStorageKey?: string, // 預設:'recently-viewed-customer'
96
+ enableServerSync?: boolean, // 預設:true
97
+ autoInit?: boolean, // 預設:true
132
98
  });
133
- </script>
134
99
  ```
135
100
 
136
- ## API 參考
101
+ **返回值:**
102
+ - `recentlyViewedSkus`: `Ref<string[]>` - 最近瀏覽商品的 SKU 列表
137
103
 
138
- ### Composables
104
+ ### useRecentlyViewedStorage
139
105
 
140
- #### useRecentlyViewed
106
+ 核心 composable,提供完整的儲存管理功能。
141
107
 
142
108
  ```typescript
143
109
  const {
144
110
  addRecentlyViewed,
145
111
  getRecentlyViewedSkus,
112
+ getSkusFromLocalStorage,
146
113
  clearAllRecentlyViewed,
147
114
  mergeGuestToCustomer,
148
- isLoggedIn
149
- } = useRecentlyViewed(
150
- config?: RecentlyViewedConfig,
151
- isLoggedIn?: ComputedRef<boolean>
152
- ): UseRecentlyViewedReturn;
153
- ```
154
-
155
- ##### 參數
156
-
157
- | 參數 | 類型 | 預設值 | 說明 |
158
- |------|------|--------|------|
159
- | `config` | `RecentlyViewedConfig` | `{}` | 可選的配置選項 |
160
- | `isLoggedIn` | `ComputedRef<boolean>` | `computed(() => false)` | 可選的登入狀態 |
161
-
162
- ##### 配置選項 (RecentlyViewedConfig)
163
-
164
- | 屬性 | 類型 | 預設值 | 說明 |
165
- |------|------|--------|------|
166
- | `maxItems` | `number` | `20` | 最大儲存商品數量 |
167
- | `guestStorageKey` | `string` | `'recently_viewed_products_guest'` | 訪客本地儲存鍵 |
168
- | `customerStorageKey` | `string` | `'recently_viewed_products_customer'` | 會員本地儲存鍵 |
169
- | `enableServerSync` | `boolean` | `true` | 是否啟用後端同步 |
170
-
171
- ##### 返回值 (UseRecentlyViewedReturn)
172
-
173
- | 方法 | 類型 | 說明 |
174
- |------|------|------|
175
- | `addRecentlyViewed` | `(sku: string) => Promise<void>` | 添加商品到最近瀏覽 |
176
- | `getRecentlyViewedSkus` | `(excludeSku?: string) => Promise<string[]>` | 獲取最近瀏覽商品 SKU 列表 |
177
- | `clearAllRecentlyViewed` | `() => Promise<void>` | 清除所有最近瀏覽記錄 |
178
- | `mergeGuestToCustomer` | `() => Promise<void>` | 合併訪客資料到會員帳戶 |
179
- | `isLoggedIn` | `ComputedRef<boolean>` | 登入狀態響應式引用 |
180
-
181
- ### API Functions
182
-
183
- #### Web 客戶端 API
184
-
185
- ```typescript
186
- import {
187
- fetchRecentlyViewedWeb,
188
- addRecentlyViewedWeb,
189
- setSdk,
190
- getSdk
191
- } from '@astralweb/nova-recently-viewed/api';
192
-
193
- // 設定 SDK
194
- setSdk(sdkInstance);
195
-
196
- // 獲取最近瀏覽商品
197
- const products = await fetchRecentlyViewedWeb();
198
-
199
- // 添加最近瀏覽商品
200
- const result = await addRecentlyViewedWeb([
201
- { product_sku: 'SKU001', viewed_at: 1234567890 }
202
- ]);
115
+ isLoggedIn,
116
+ } = useRecentlyViewedStorage(config, isLoggedIn);
203
117
  ```
204
118
 
205
- #### Middleware API
206
-
119
+ **配置選項:**
207
120
  ```typescript
208
- import {
209
- recentlyViewedProducts,
210
- addRecentlyViewedProducts
211
- } from '@astralweb/nova-recently-viewed/api';
212
-
213
- // 在 middleware 中使用
214
- export const customRecentlyViewedProducts = async (context, variables) => {
215
- return await recentlyViewedProducts(context, variables);
216
- };
217
-
218
- export const customAddRecentlyViewedProducts = async (context, variables) => {
219
- return await addRecentlyViewedProducts(context, variables);
220
- };
221
- ```
222
-
223
- ### 類型定義
224
-
225
- #### 核心類型
226
-
227
- ```typescript
228
- // 最近瀏覽商品項目
229
- interface RecentlyViewedItem {
230
- sku: string;
231
- viewedAt: number; // JavaScript timestamp (毫秒)
232
- }
233
-
234
- // API 輸入類型
235
- interface AddRecentlyViewedInputItem {
236
- product_sku: string;
237
- viewed_at: number; // Unix timestamp (秒)
238
- }
239
-
240
- // API 回應類型
241
- interface AddRecentlyViewedResponse {
242
- success: boolean;
243
- message?: string;
121
+ interface RecentlyViewedConfig {
122
+ maxItems?: number; // 最多儲存數量(預設:20)
123
+ guestStorageKey?: string; // 訪客 localStorage key
124
+ customerStorageKey?: string; // 會員 localStorage key
125
+ enableServerSync?: boolean; // 啟用伺服器同步(預設:true)
244
126
  }
245
127
  ```
246
128
 
247
- ## 故障排除
248
-
249
- ### 常見問題
129
+ **方法:**
130
+ - `addRecentlyViewed(sku: string): Promise<void>` - 添加商品到最近瀏覽
131
+ - `getRecentlyViewedSkus(excludeSku?: string): Promise<string[]>` - 獲取 SKU 列表(伺服器優先)
132
+ - `getSkusFromLocalStorage(excludeSku?: string): string[]` - 從本地儲存獲取 SKU 列表
133
+ - `clearAllRecentlyViewed(): void` - 清除所有記錄
134
+ - `mergeGuestToCustomer(): Promise<void>` - 合併訪客資料到會員帳戶
250
135
 
251
- #### 1. 最近瀏覽商品不顯示
136
+ ### useRecentlyViewedApi
252
137
 
253
- **問題**:調用 `getRecentlyViewedSkus()` 返回空陣列
254
-
255
- **解決方案**:
256
- - 檢查是否正確調用了 `addRecentlyViewed()`
257
- - 確認 localStorage 是否可用
258
- - 檢查是否有 JavaScript 錯誤
138
+ API composable,處理與後端的通信。
259
139
 
260
140
  ```typescript
261
- // 調試用的詳細日誌
262
- const debugRecentlyViewed = async () => {
263
- console.log('Browser check:', typeof window !== 'undefined');
264
- console.log('LocalStorage check:', typeof localStorage !== 'undefined');
265
-
266
- const skus = await getRecentlyViewedSkus();
267
- console.log('Recently viewed SKUs:', skus);
268
- };
141
+ const {
142
+ syncToServer,
143
+ fetchFromServer,
144
+ } = useRecentlyViewedApi();
269
145
  ```
270
146
 
271
- #### 2. 後端同步失敗
147
+ **方法:**
148
+ - `syncToServer(input: AddRecentlyViewedInputItem[]): Promise<void>` - 同步資料到伺服器
149
+ - `fetchFromServer(): Promise<AddRecentlyViewedInputItem[]>` - 從伺服器獲取資料
272
150
 
273
- **問題**:商品添加到本地但不同步到後端
151
+ ## 工作原理
274
152
 
275
- **解決方案**:
276
- - 檢查 SDK 是否正確設定
277
- - 確認 middleware 是否正確導出
278
- - 檢查網路連接和 API 權限
153
+ ### 訪客模式
279
154
 
280
- ```typescript
281
- // 檢查 SDK 設定
282
- try {
283
- const sdk = getSdk();
284
- console.log('SDK configured:', !!sdk);
285
- } catch (error) {
286
- console.error('SDK not configured:', error);
287
- }
288
- ```
155
+ - 資料保存在 `localStorage`(key: `recently-viewed-guest`)
156
+ - 不進行伺服器同步
157
+ - 本地去重與數量限制
289
158
 
290
- #### 3. 訪客資料合併問題
159
+ ### 登入模式
291
160
 
292
- **問題**:登入後訪客資料沒有合併
161
+ - 主要資料來源:伺服器
162
+ - 本地緩存:加速 UI 更新
163
+ - 新增時:同步到伺服器 → 更新本地緩存
293
164
 
294
- **解決方案**:
295
- - 確認 `mergeGuestToCustomer()` 在適當時機被調用
296
- - 檢查登入狀態監聽是否正確設定
165
+ ### 登入時資料合併
297
166
 
298
- ```typescript
299
- // 確保合併在登入後執行
300
- const handleLogin = async () => {
301
- // 執行登入邏輯
302
- await loginUser();
303
-
304
- // 登入成功後合併資料
305
- await mergeGuestToCustomer();
306
- };
307
- ```
167
+ 1. 讀取訪客 `localStorage` 資料
168
+ 2. 同步到伺服器(合併到會員帳戶)
169
+ 3. 清除訪客資料
170
+ 4. 從伺服器獲取最新資料
308
171
 
309
- ## 授權聲明
172
+ ## 授權
310
173
 
311
174
  此套件僅供 Astral Web 內部使用,未經授權不得用於其他用途。
@@ -0,0 +1,5 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
4
+
5
+ export { _default as default };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "recently-viewed",
3
+ "configKey": "recentlyViewed",
4
+ "compatibility": {
5
+ "nuxt": ">=3.0.0"
6
+ },
7
+ "version": "1.0.1",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.2",
10
+ "unbuild": "3.6.1"
11
+ }
12
+ }
@@ -0,0 +1,26 @@
1
+ import { defineNuxtModule, createResolver, addImports } from '@nuxt/kit';
2
+
3
+ const module = defineNuxtModule({
4
+ meta: {
5
+ name: "recently-viewed",
6
+ configKey: "recentlyViewed",
7
+ compatibility: {
8
+ nuxt: ">=3.0.0"
9
+ }
10
+ },
11
+ // Default configuration options of the Nuxt module
12
+ defaults: {},
13
+ setup(_options, _nuxt) {
14
+ const resolver = createResolver(import.meta.url);
15
+ addImports({
16
+ name: "useRecentlyViewedStorage",
17
+ from: resolver.resolve("./runtime/composables/useRecentlyViewedStorage")
18
+ });
19
+ addImports({
20
+ name: "useRecentlyViewedList",
21
+ from: resolver.resolve("./runtime/composables/useRecentlyViewedList")
22
+ });
23
+ }
24
+ });
25
+
26
+ export { module as default };
@@ -1,6 +1,6 @@
1
- import { ApolloQueryResult } from '@apollo/client/core';
2
- import { Context, TObject } from '@vue-storefront/middleware';
3
- import { AddRecentlyViewedInputItem, AddRecentlyViewedResponse } from '../types';
1
+ import type { ApolloQueryResult, FetchResult } from '@apollo/client/core';
2
+ import type { Context, TObject } from '@vue-storefront/middleware';
3
+ import type { AddRecentlyViewedInputItem, AddRecentlyViewedResponse } from '../types/index.js';
4
4
  /**
5
5
  * 查詢最近瀏覽商品
6
6
  */
@@ -10,7 +10,6 @@ export declare const recentlyViewedProducts: (context: Context, variables: TObje
10
10
  /**
11
11
  * 添加商品到最近瀏覽列表
12
12
  */
13
- export declare const addRecentlyViewedProducts: (context: Context, variables: TObject) => Promise<ApolloQueryResult<{
13
+ export declare const addRecentlyViewedProducts: (context: Context, variables: TObject) => Promise<FetchResult<{
14
14
  addRecentlyViewedProducts: AddRecentlyViewedResponse;
15
15
  }>>;
16
- //# sourceMappingURL=extendMiddleware.d.ts.map
@@ -0,0 +1,64 @@
1
+ import { consola } from "consola";
2
+ import { gql } from "graphql-tag";
3
+ const getHeaders = (context, customHeaders = {}) => {
4
+ const { getCustomerToken, getStore, getCurrency } = context.config.state;
5
+ return {
6
+ ...getCustomerToken() && { Authorization: `Bearer ${getCustomerToken()}` },
7
+ ...getStore() && { store: getStore() },
8
+ ...getCurrency() && { "Content-Currency": getCurrency() },
9
+ ...customHeaders
10
+ };
11
+ };
12
+ export const recentlyViewedProducts = async (context, variables) => {
13
+ const { client } = context;
14
+ try {
15
+ return await client.query({
16
+ query: gql`
17
+ query recentlyViewedProducts {
18
+ recentlyViewedProducts {
19
+ product_sku
20
+ viewed_at
21
+ }
22
+ }
23
+ `,
24
+ variables,
25
+ context: { headers: getHeaders(context) }
26
+ });
27
+ } catch (error) {
28
+ const typedError = error;
29
+ throw typedError;
30
+ }
31
+ };
32
+ export const addRecentlyViewedProducts = async (context, variables) => {
33
+ const { client } = context;
34
+ try {
35
+ return await client.mutate({
36
+ mutation: gql`
37
+ mutation addRecentlyViewedProducts($input: [RecentlyViewedProductInput!]!) {
38
+ addRecentlyViewedProducts(input: $input) {
39
+ success
40
+ message
41
+ }
42
+ }
43
+ `,
44
+ variables,
45
+ context: { headers: getHeaders(context) }
46
+ });
47
+ } catch (error) {
48
+ const typedError = error;
49
+ if (typedError.graphQLErrors) {
50
+ consola.debug(typedError);
51
+ return {
52
+ errors: typedError.graphQLErrors,
53
+ data: null
54
+ };
55
+ }
56
+ const networkError = typedError.networkError;
57
+ if (networkError && "result" in networkError) {
58
+ consola.error(networkError.result);
59
+ throw networkError.result;
60
+ }
61
+ consola.error(typedError);
62
+ throw error;
63
+ }
64
+ };
@@ -0,0 +1 @@
1
+ export * from './extendMiddleware.js';
@@ -0,0 +1 @@
1
+ export * from "./extendMiddleware.js";
@@ -0,0 +1,3 @@
1
+ export * from './useRecentlyViewedApi.js';
2
+ export * from './useRecentlyViewedStorage.js';
3
+ export * from './useRecentlyViewedList.js';
@@ -0,0 +1,3 @@
1
+ export * from "./useRecentlyViewedApi.js";
2
+ export * from "./useRecentlyViewedStorage.js";
3
+ export * from "./useRecentlyViewedList.js";
@@ -0,0 +1,5 @@
1
+ import type { AddRecentlyViewedInputItem } from '../types/index.js';
2
+ export declare function useRecentlyViewedApi(): {
3
+ syncToServer: (input: AddRecentlyViewedInputItem[]) => Promise<void>;
4
+ fetchFromServer: () => Promise<AddRecentlyViewedInputItem[]>;
5
+ };
@@ -0,0 +1,21 @@
1
+ import { useNuxtApp } from "#app";
2
+ export function useRecentlyViewedApi() {
3
+ const { sdk } = useNuxtApp().$alokai;
4
+ const syncToServer = async (input) => {
5
+ const { errors } = await sdk.magento.addRecentlyViewedProducts({ input });
6
+ if (errors && errors.length > 0) {
7
+ throw new Error(errors.map((e) => e.message).join(", "));
8
+ }
9
+ };
10
+ const fetchFromServer = async () => {
11
+ const { data, errors } = await sdk.magento.recentlyViewedProducts({});
12
+ if (errors && errors.length > 0) {
13
+ throw new Error(errors.map((e) => e.message).join(", "));
14
+ }
15
+ return data?.recentlyViewedProducts ?? [];
16
+ };
17
+ return {
18
+ syncToServer,
19
+ fetchFromServer
20
+ };
21
+ }
@@ -0,0 +1,2 @@
1
+ import type { UseRecentlyViewedListOptions, UseRecentlyViewedListReturn } from '../types/index.js';
2
+ export declare function useRecentlyViewedList(options: UseRecentlyViewedListOptions): UseRecentlyViewedListReturn;