@doswiftly/cli 0.1.23 → 0.2.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/dist/commands/check.js +2 -2
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +34 -7
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +155 -63
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +3 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +271 -166
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/sdk.d.ts +1 -1
- package/dist/commands/sdk.js +3 -3
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/template.js +4 -31
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/verify.js +5 -5
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/i18n.d.ts +12 -0
- package/dist/lib/i18n.d.ts.map +1 -1
- package/dist/lib/i18n.js +24 -0
- package/dist/lib/i18n.js.map +1 -1
- package/dist/lib/proxy-server.d.ts +22 -6
- package/dist/lib/proxy-server.d.ts.map +1 -1
- package/dist/lib/proxy-server.js +174 -75
- package/dist/lib/proxy-server.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/types.d.ts +0 -5
- package/dist/commands/types.d.ts.map +0 -1
- package/dist/commands/types.js +0 -82
- package/dist/commands/types.js.map +0 -1
- package/templates/storefront-minimal/.env.example +0 -10
- package/templates/storefront-minimal/.github/workflows/build-template.yml +0 -119
- package/templates/storefront-minimal/app/globals.css +0 -18
- package/templates/storefront-minimal/app/layout.tsx +0 -26
- package/templates/storefront-minimal/app/page.tsx +0 -93
- package/templates/storefront-minimal/lib/graphql-client.ts +0 -23
- package/templates/storefront-minimal/next.config.ts +0 -15
- package/templates/storefront-minimal/open-next.config.ts +0 -3
- package/templates/storefront-minimal/package.json +0 -30
- package/templates/storefront-minimal/postcss.config.mjs +0 -5
- package/templates/storefront-minimal/tailwind.config.ts +0 -14
- package/templates/storefront-minimal/tsconfig.json +0 -27
- package/templates/storefront-minimal/wrangler.toml +0 -24
- package/templates/storefront-nextjs/.env.example +0 -68
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +0 -119
- package/templates/storefront-nextjs/README.md +0 -524
- package/templates/storefront-nextjs/app/account/orders/page.tsx +0 -216
- package/templates/storefront-nextjs/app/account/page.tsx +0 -167
- package/templates/storefront-nextjs/app/auth/login/page.tsx +0 -135
- package/templates/storefront-nextjs/app/auth/register/page.tsx +0 -212
- package/templates/storefront-nextjs/app/cart/page.tsx +0 -263
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +0 -200
- package/templates/storefront-nextjs/app/categories/page.tsx +0 -58
- package/templates/storefront-nextjs/app/checkout/page.tsx +0 -351
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +0 -158
- package/templates/storefront-nextjs/app/collections/page.tsx +0 -61
- package/templates/storefront-nextjs/app/globals.css +0 -98
- package/templates/storefront-nextjs/app/layout.tsx +0 -39
- package/templates/storefront-nextjs/app/page.tsx +0 -136
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +0 -119
- package/templates/storefront-nextjs/app/products/page.tsx +0 -107
- package/templates/storefront-nextjs/app/search/page.tsx +0 -127
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +0 -94
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +0 -77
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +0 -29
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +0 -217
- package/templates/storefront-nextjs/components/commerce/pagination.tsx +0 -62
- package/templates/storefront-nextjs/components/commerce/product-actions.tsx +0 -135
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +0 -109
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +0 -375
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +0 -178
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +0 -64
- package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +0 -210
- package/templates/storefront-nextjs/components/layout/footer.tsx +0 -107
- package/templates/storefront-nextjs/components/layout/header.tsx +0 -104
- package/templates/storefront-nextjs/components/providers.tsx +0 -62
- package/templates/storefront-nextjs/lib/auth/routes.ts +0 -52
- package/templates/storefront-nextjs/lib/currency.tsx +0 -140
- package/templates/storefront-nextjs/lib/format.ts +0 -159
- package/templates/storefront-nextjs/lib/graphql-queries.ts +0 -629
- package/templates/storefront-nextjs/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs/middleware.ts +0 -80
- package/templates/storefront-nextjs/next.config.ts +0 -37
- package/templates/storefront-nextjs/open-next.config.ts +0 -3
- package/templates/storefront-nextjs/package.dev.json +0 -30
- package/templates/storefront-nextjs/package.json +0 -32
- package/templates/storefront-nextjs/package.json.template +0 -32
- package/templates/storefront-nextjs/postcss.config.mjs +0 -8
- package/templates/storefront-nextjs/tailwind.config.ts +0 -111
- package/templates/storefront-nextjs/tsconfig.json +0 -27
- package/templates/storefront-nextjs/wrangler.toml +0 -24
|
@@ -1,629 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated This file is DEPRECATED and will be removed in future versions.
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ DO NOT USE - Use SDK factory instead!
|
|
5
|
-
*
|
|
6
|
-
* ## Migration Path:
|
|
7
|
-
*
|
|
8
|
-
* Instead of raw GraphQL queries, use the auto-generated SDK with factory:
|
|
9
|
-
*
|
|
10
|
-
* ```typescript
|
|
11
|
-
* import { createStorefrontSdkFromEnv } from "@doswiftly/storefront-sdk/graphql";
|
|
12
|
-
*
|
|
13
|
-
* const sdk = createStorefrontSdkFromEnv();
|
|
14
|
-
* const { products } = await sdk.Products({ first: 20 });
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* ## Why migrate?
|
|
18
|
-
* - ✅ Full TypeScript type safety
|
|
19
|
-
* - ✅ Auto-generated from backend operations (SSOT)
|
|
20
|
-
* - ✅ Automatic header management (X-Shop-Slug, X-Preferred-Currency)
|
|
21
|
-
* - ✅ No manual GraphQL string maintenance
|
|
22
|
-
*
|
|
23
|
-
* ## Adding custom queries:
|
|
24
|
-
* See: packages/@doswiftly/storefront-sdk/CUSTOM_OPERATIONS.md
|
|
25
|
-
*
|
|
26
|
-
* ---
|
|
27
|
-
*
|
|
28
|
-
* Raw GraphQL Queries for Currency-enabled Storefront
|
|
29
|
-
*
|
|
30
|
-
* These queries work with the new price structure where:
|
|
31
|
-
* - `price` / `priceRange` = converted price (customer's preferred currency)
|
|
32
|
-
* - `originalPrice` / `originalPriceRange` = original price (shop's base currency)
|
|
33
|
-
*
|
|
34
|
-
* Usage: Send with `x-preferred-currency` header to get prices in desired currency.
|
|
35
|
-
*
|
|
36
|
-
* Types are imported from SDK (SSOT) - auto-generated from GraphQL schema.
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
import type { PriceMoney, Money } from "@doswiftly/storefront-sdk/graphql";
|
|
40
|
-
export type { PriceMoney, Money };
|
|
41
|
-
|
|
42
|
-
// ============================================================================
|
|
43
|
-
// FRAGMENTS
|
|
44
|
-
// ============================================================================
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* PriceMoney fragment - full conversion transparency
|
|
48
|
-
*/
|
|
49
|
-
export const PRICE_MONEY_FRAGMENT = /* GraphQL */ `
|
|
50
|
-
fragment PriceMoneyFields on PriceMoney {
|
|
51
|
-
amount
|
|
52
|
-
currencyCode
|
|
53
|
-
baseAmount
|
|
54
|
-
baseCurrencyCode
|
|
55
|
-
exchangeRate
|
|
56
|
-
marginApplied
|
|
57
|
-
rateTimestamp
|
|
58
|
-
isConverted
|
|
59
|
-
}
|
|
60
|
-
`;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Money fragment - simple price (for original prices)
|
|
64
|
-
*/
|
|
65
|
-
export const MONEY_FRAGMENT = /* GraphQL */ `
|
|
66
|
-
fragment MoneyFields on Money {
|
|
67
|
-
amount
|
|
68
|
-
currencyCode
|
|
69
|
-
}
|
|
70
|
-
`;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Product variant with prices
|
|
74
|
-
*/
|
|
75
|
-
export const PRODUCT_VARIANT_FRAGMENT = /* GraphQL */ `
|
|
76
|
-
fragment ProductVariantFields on ProductVariant {
|
|
77
|
-
id
|
|
78
|
-
title
|
|
79
|
-
sku
|
|
80
|
-
available
|
|
81
|
-
quantityAvailable
|
|
82
|
-
price {
|
|
83
|
-
...PriceMoneyFields
|
|
84
|
-
}
|
|
85
|
-
originalPrice {
|
|
86
|
-
...MoneyFields
|
|
87
|
-
}
|
|
88
|
-
compareAtPrice {
|
|
89
|
-
...PriceMoneyFields
|
|
90
|
-
}
|
|
91
|
-
originalCompareAtPrice {
|
|
92
|
-
...MoneyFields
|
|
93
|
-
}
|
|
94
|
-
image {
|
|
95
|
-
id
|
|
96
|
-
url
|
|
97
|
-
altText
|
|
98
|
-
}
|
|
99
|
-
selectedOptions {
|
|
100
|
-
name
|
|
101
|
-
value
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Product with prices
|
|
108
|
-
*/
|
|
109
|
-
export const PRODUCT_FRAGMENT = /* GraphQL */ `
|
|
110
|
-
fragment ProductFields on Product {
|
|
111
|
-
id
|
|
112
|
-
title
|
|
113
|
-
handle
|
|
114
|
-
description
|
|
115
|
-
descriptionHtml
|
|
116
|
-
priceRange {
|
|
117
|
-
minVariantPrice {
|
|
118
|
-
...PriceMoneyFields
|
|
119
|
-
}
|
|
120
|
-
maxVariantPrice {
|
|
121
|
-
...PriceMoneyFields
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
originalPriceRange {
|
|
125
|
-
minVariantPrice {
|
|
126
|
-
...MoneyFields
|
|
127
|
-
}
|
|
128
|
-
maxVariantPrice {
|
|
129
|
-
...MoneyFields
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
featuredImage {
|
|
133
|
-
id
|
|
134
|
-
url
|
|
135
|
-
altText
|
|
136
|
-
}
|
|
137
|
-
images(first: 10) {
|
|
138
|
-
id
|
|
139
|
-
url
|
|
140
|
-
altText
|
|
141
|
-
}
|
|
142
|
-
totalInventory
|
|
143
|
-
vendor
|
|
144
|
-
productType
|
|
145
|
-
tags
|
|
146
|
-
createdAt
|
|
147
|
-
updatedAt
|
|
148
|
-
}
|
|
149
|
-
`;
|
|
150
|
-
|
|
151
|
-
// ============================================================================
|
|
152
|
-
// QUERIES
|
|
153
|
-
// ============================================================================
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Get shop info with currency configuration
|
|
157
|
-
*/
|
|
158
|
-
export const SHOP_QUERY = /* GraphQL */ `
|
|
159
|
-
query Shop {
|
|
160
|
-
shop {
|
|
161
|
-
id
|
|
162
|
-
name
|
|
163
|
-
description
|
|
164
|
-
currencyCode
|
|
165
|
-
supportedCurrencies
|
|
166
|
-
defaultLanguage
|
|
167
|
-
supportedLanguages
|
|
168
|
-
primaryDomain
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
`;
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Get products list with converted prices
|
|
175
|
-
*/
|
|
176
|
-
export const PRODUCTS_QUERY = /* GraphQL */ `
|
|
177
|
-
${PRICE_MONEY_FRAGMENT}
|
|
178
|
-
${MONEY_FRAGMENT}
|
|
179
|
-
|
|
180
|
-
query Products(
|
|
181
|
-
$first: Int!
|
|
182
|
-
$after: String
|
|
183
|
-
$query: String
|
|
184
|
-
$sortKey: ProductSortKeys
|
|
185
|
-
$reverse: Boolean
|
|
186
|
-
) {
|
|
187
|
-
products(
|
|
188
|
-
first: $first
|
|
189
|
-
after: $after
|
|
190
|
-
query: $query
|
|
191
|
-
sortKey: $sortKey
|
|
192
|
-
reverse: $reverse
|
|
193
|
-
) {
|
|
194
|
-
edges {
|
|
195
|
-
node {
|
|
196
|
-
id
|
|
197
|
-
title
|
|
198
|
-
handle
|
|
199
|
-
description
|
|
200
|
-
priceRange {
|
|
201
|
-
minVariantPrice {
|
|
202
|
-
...PriceMoneyFields
|
|
203
|
-
}
|
|
204
|
-
maxVariantPrice {
|
|
205
|
-
...PriceMoneyFields
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
originalPriceRange {
|
|
209
|
-
minVariantPrice {
|
|
210
|
-
...MoneyFields
|
|
211
|
-
}
|
|
212
|
-
maxVariantPrice {
|
|
213
|
-
...MoneyFields
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
featuredImage {
|
|
217
|
-
id
|
|
218
|
-
url
|
|
219
|
-
altText
|
|
220
|
-
}
|
|
221
|
-
totalInventory
|
|
222
|
-
vendor
|
|
223
|
-
tags
|
|
224
|
-
}
|
|
225
|
-
cursor
|
|
226
|
-
}
|
|
227
|
-
pageInfo {
|
|
228
|
-
hasNextPage
|
|
229
|
-
hasPreviousPage
|
|
230
|
-
startCursor
|
|
231
|
-
endCursor
|
|
232
|
-
}
|
|
233
|
-
totalCount
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
`;
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Get single product with all variants and prices
|
|
240
|
-
*/
|
|
241
|
-
export const PRODUCT_QUERY = /* GraphQL */ `
|
|
242
|
-
${PRICE_MONEY_FRAGMENT}
|
|
243
|
-
${MONEY_FRAGMENT}
|
|
244
|
-
${PRODUCT_VARIANT_FRAGMENT}
|
|
245
|
-
|
|
246
|
-
query Product($id: ID, $handle: String) {
|
|
247
|
-
product(id: $id, handle: $handle) {
|
|
248
|
-
id
|
|
249
|
-
title
|
|
250
|
-
handle
|
|
251
|
-
description
|
|
252
|
-
descriptionHtml
|
|
253
|
-
priceRange {
|
|
254
|
-
minVariantPrice {
|
|
255
|
-
...PriceMoneyFields
|
|
256
|
-
}
|
|
257
|
-
maxVariantPrice {
|
|
258
|
-
...PriceMoneyFields
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
originalPriceRange {
|
|
262
|
-
minVariantPrice {
|
|
263
|
-
...MoneyFields
|
|
264
|
-
}
|
|
265
|
-
maxVariantPrice {
|
|
266
|
-
...MoneyFields
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
featuredImage {
|
|
270
|
-
id
|
|
271
|
-
url
|
|
272
|
-
altText
|
|
273
|
-
}
|
|
274
|
-
images(first: 20) {
|
|
275
|
-
id
|
|
276
|
-
url
|
|
277
|
-
altText
|
|
278
|
-
}
|
|
279
|
-
variants(first: 100) {
|
|
280
|
-
...ProductVariantFields
|
|
281
|
-
}
|
|
282
|
-
totalInventory
|
|
283
|
-
vendor
|
|
284
|
-
productType
|
|
285
|
-
tags
|
|
286
|
-
seo {
|
|
287
|
-
title
|
|
288
|
-
description
|
|
289
|
-
}
|
|
290
|
-
createdAt
|
|
291
|
-
updatedAt
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
`;
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Get cart with converted prices
|
|
298
|
-
*/
|
|
299
|
-
export const CART_QUERY = /* GraphQL */ `
|
|
300
|
-
${PRICE_MONEY_FRAGMENT}
|
|
301
|
-
${MONEY_FRAGMENT}
|
|
302
|
-
|
|
303
|
-
query Cart($id: ID!) {
|
|
304
|
-
cart(id: $id) {
|
|
305
|
-
id
|
|
306
|
-
checkoutUrl
|
|
307
|
-
totalQuantity
|
|
308
|
-
cost {
|
|
309
|
-
subtotalAmount {
|
|
310
|
-
...PriceMoneyFields
|
|
311
|
-
}
|
|
312
|
-
totalAmount {
|
|
313
|
-
...PriceMoneyFields
|
|
314
|
-
}
|
|
315
|
-
totalTaxAmount {
|
|
316
|
-
...PriceMoneyFields
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
lines(first: 100) {
|
|
320
|
-
id
|
|
321
|
-
quantity
|
|
322
|
-
merchandise {
|
|
323
|
-
id
|
|
324
|
-
title
|
|
325
|
-
sku
|
|
326
|
-
price {
|
|
327
|
-
...PriceMoneyFields
|
|
328
|
-
}
|
|
329
|
-
originalPrice {
|
|
330
|
-
...MoneyFields
|
|
331
|
-
}
|
|
332
|
-
image {
|
|
333
|
-
url
|
|
334
|
-
altText
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
cost {
|
|
338
|
-
amountPerQuantity {
|
|
339
|
-
...PriceMoneyFields
|
|
340
|
-
}
|
|
341
|
-
subtotalAmount {
|
|
342
|
-
...PriceMoneyFields
|
|
343
|
-
}
|
|
344
|
-
totalAmount {
|
|
345
|
-
...PriceMoneyFields
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
createdAt
|
|
350
|
-
updatedAt
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
`;
|
|
354
|
-
|
|
355
|
-
// ============================================================================
|
|
356
|
-
// MUTATIONS
|
|
357
|
-
// ============================================================================
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Create cart
|
|
361
|
-
*/
|
|
362
|
-
export const CART_CREATE_MUTATION = /* GraphQL */ `
|
|
363
|
-
${PRICE_MONEY_FRAGMENT}
|
|
364
|
-
${MONEY_FRAGMENT}
|
|
365
|
-
|
|
366
|
-
mutation CartCreate($input: CartCreateInput) {
|
|
367
|
-
cartCreate(input: $input) {
|
|
368
|
-
cart {
|
|
369
|
-
id
|
|
370
|
-
checkoutUrl
|
|
371
|
-
totalQuantity
|
|
372
|
-
cost {
|
|
373
|
-
totalAmount {
|
|
374
|
-
...PriceMoneyFields
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
lines(first: 10) {
|
|
378
|
-
id
|
|
379
|
-
quantity
|
|
380
|
-
merchandise {
|
|
381
|
-
id
|
|
382
|
-
title
|
|
383
|
-
price {
|
|
384
|
-
...PriceMoneyFields
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
userErrors {
|
|
390
|
-
message
|
|
391
|
-
field
|
|
392
|
-
code
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
`;
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Add lines to cart
|
|
400
|
-
*/
|
|
401
|
-
export const CART_LINES_ADD_MUTATION = /* GraphQL */ `
|
|
402
|
-
${PRICE_MONEY_FRAGMENT}
|
|
403
|
-
|
|
404
|
-
mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
|
|
405
|
-
cartLinesAdd(cartId: $cartId, lines: $lines) {
|
|
406
|
-
cart {
|
|
407
|
-
id
|
|
408
|
-
totalQuantity
|
|
409
|
-
cost {
|
|
410
|
-
totalAmount {
|
|
411
|
-
...PriceMoneyFields
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
userErrors {
|
|
416
|
-
message
|
|
417
|
-
field
|
|
418
|
-
code
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
`;
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Update cart lines
|
|
426
|
-
*/
|
|
427
|
-
export const CART_LINES_UPDATE_MUTATION = /* GraphQL */ `
|
|
428
|
-
${PRICE_MONEY_FRAGMENT}
|
|
429
|
-
|
|
430
|
-
mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
|
|
431
|
-
cartLinesUpdate(cartId: $cartId, lines: $lines) {
|
|
432
|
-
cart {
|
|
433
|
-
id
|
|
434
|
-
totalQuantity
|
|
435
|
-
cost {
|
|
436
|
-
totalAmount {
|
|
437
|
-
...PriceMoneyFields
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
userErrors {
|
|
442
|
-
message
|
|
443
|
-
field
|
|
444
|
-
code
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
`;
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Remove lines from cart
|
|
452
|
-
*/
|
|
453
|
-
export const CART_LINES_REMOVE_MUTATION = /* GraphQL */ `
|
|
454
|
-
${PRICE_MONEY_FRAGMENT}
|
|
455
|
-
|
|
456
|
-
mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
|
|
457
|
-
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
|
|
458
|
-
cart {
|
|
459
|
-
id
|
|
460
|
-
totalQuantity
|
|
461
|
-
cost {
|
|
462
|
-
totalAmount {
|
|
463
|
-
...PriceMoneyFields
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
userErrors {
|
|
468
|
-
message
|
|
469
|
-
field
|
|
470
|
-
code
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
`;
|
|
475
|
-
|
|
476
|
-
// ============================================================================
|
|
477
|
-
// FETCH HELPER
|
|
478
|
-
// ============================================================================
|
|
479
|
-
|
|
480
|
-
interface GraphQLResponse<T> {
|
|
481
|
-
data?: T;
|
|
482
|
-
errors?: Array<{ message: string }>;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* Execute GraphQL query with currency header
|
|
487
|
-
*
|
|
488
|
-
* Note: For most use cases, prefer SDK hooks (useProducts, etc.)
|
|
489
|
-
* which automatically normalize responses.
|
|
490
|
-
*
|
|
491
|
-
* @example
|
|
492
|
-
* ```typescript
|
|
493
|
-
* const data = await fetchGraphQL(PRODUCTS_QUERY, { first: 10 }, "EUR");
|
|
494
|
-
* console.log(data.products.edges); // Raw GraphQL structure
|
|
495
|
-
* ```
|
|
496
|
-
*/
|
|
497
|
-
export async function fetchGraphQL<T = any>(
|
|
498
|
-
query: string,
|
|
499
|
-
variables: Record<string, any> = {},
|
|
500
|
-
preferredCurrency?: string
|
|
501
|
-
): Promise<T> {
|
|
502
|
-
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
|
|
503
|
-
const shopSlug = process.env.NEXT_PUBLIC_SHOP_SLUG || "demo-shop";
|
|
504
|
-
|
|
505
|
-
const headers: Record<string, string> = {
|
|
506
|
-
"Content-Type": "application/json",
|
|
507
|
-
"x-shop-slug": shopSlug,
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
if (preferredCurrency) {
|
|
511
|
-
headers["x-preferred-currency"] = preferredCurrency;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const response = await fetch(`${apiUrl}/storefront/graphql`, {
|
|
515
|
-
method: "POST",
|
|
516
|
-
headers,
|
|
517
|
-
body: JSON.stringify({ query, variables }),
|
|
518
|
-
cache: "no-store", // For dynamic pricing
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
if (!response.ok) {
|
|
522
|
-
throw new Error(
|
|
523
|
-
`GraphQL request failed: ${response.status} ${response.statusText}`
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
const json: GraphQLResponse<T> = await response.json();
|
|
528
|
-
|
|
529
|
-
if (json.errors?.length) {
|
|
530
|
-
throw new Error(
|
|
531
|
-
`GraphQL errors: ${json.errors.map((e) => e.message).join(", ")}`
|
|
532
|
-
);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
return json.data as T;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// ============================================================================
|
|
539
|
-
// TYPED FETCH FUNCTIONS
|
|
540
|
-
// ============================================================================
|
|
541
|
-
|
|
542
|
-
export interface ShopData {
|
|
543
|
-
shop: {
|
|
544
|
-
id: string;
|
|
545
|
-
name: string;
|
|
546
|
-
description?: string;
|
|
547
|
-
currencyCode: string;
|
|
548
|
-
supportedCurrencies: string[];
|
|
549
|
-
defaultLanguage: string;
|
|
550
|
-
supportedLanguages: string[];
|
|
551
|
-
primaryDomain?: string;
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
export interface ProductsData {
|
|
556
|
-
products: {
|
|
557
|
-
edges: Array<{
|
|
558
|
-
node: {
|
|
559
|
-
id: string;
|
|
560
|
-
title: string;
|
|
561
|
-
handle: string;
|
|
562
|
-
description?: string;
|
|
563
|
-
priceRange: {
|
|
564
|
-
minVariantPrice: PriceMoney;
|
|
565
|
-
maxVariantPrice: PriceMoney;
|
|
566
|
-
};
|
|
567
|
-
originalPriceRange?: {
|
|
568
|
-
minVariantPrice: Money;
|
|
569
|
-
maxVariantPrice: Money;
|
|
570
|
-
};
|
|
571
|
-
featuredImage?: {
|
|
572
|
-
id: string;
|
|
573
|
-
url: string;
|
|
574
|
-
altText?: string;
|
|
575
|
-
};
|
|
576
|
-
totalInventory?: number;
|
|
577
|
-
vendor?: string;
|
|
578
|
-
tags: string[];
|
|
579
|
-
};
|
|
580
|
-
cursor: string;
|
|
581
|
-
}>;
|
|
582
|
-
pageInfo: {
|
|
583
|
-
hasNextPage: boolean;
|
|
584
|
-
hasPreviousPage: boolean;
|
|
585
|
-
startCursor?: string;
|
|
586
|
-
endCursor?: string;
|
|
587
|
-
};
|
|
588
|
-
totalCount: number;
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
// PriceMoney and Money types are imported from SDK at the top of this file
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* Fetch shop info
|
|
596
|
-
*/
|
|
597
|
-
export async function getShop(
|
|
598
|
-
preferredCurrency?: string
|
|
599
|
-
): Promise<ShopData["shop"]> {
|
|
600
|
-
const data = await fetchGraphQL<ShopData>(SHOP_QUERY, {}, preferredCurrency);
|
|
601
|
-
return data.shop;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Fetch products with pagination
|
|
606
|
-
*/
|
|
607
|
-
export async function getProducts(
|
|
608
|
-
params: {
|
|
609
|
-
first?: number;
|
|
610
|
-
after?: string;
|
|
611
|
-
query?: string;
|
|
612
|
-
sortKey?: string;
|
|
613
|
-
reverse?: boolean;
|
|
614
|
-
} = {},
|
|
615
|
-
preferredCurrency?: string
|
|
616
|
-
): Promise<ProductsData["products"]> {
|
|
617
|
-
const data = await fetchGraphQL<ProductsData>(
|
|
618
|
-
PRODUCTS_QUERY,
|
|
619
|
-
{
|
|
620
|
-
first: params.first ?? 20,
|
|
621
|
-
after: params.after,
|
|
622
|
-
query: params.query,
|
|
623
|
-
sortKey: params.sortKey,
|
|
624
|
-
reverse: params.reverse,
|
|
625
|
-
},
|
|
626
|
-
preferredCurrency
|
|
627
|
-
);
|
|
628
|
-
return data.products;
|
|
629
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from "react";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* useDebouncedValue - Debounce a value
|
|
5
|
-
*
|
|
6
|
-
* @param value - Value to debounce
|
|
7
|
-
* @param delay - Delay in ms (default: 300)
|
|
8
|
-
* @returns Debounced value
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```tsx
|
|
12
|
-
* const [query, setQuery] = useState("");
|
|
13
|
-
* const debouncedQuery = useDebouncedValue(query, 300);
|
|
14
|
-
*
|
|
15
|
-
* // debouncedQuery updates 300ms after query stops changing
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export function useDebouncedValue<T>(value: T, delay = 300): T {
|
|
19
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
const timer = setTimeout(() => {
|
|
23
|
-
setDebouncedValue(value);
|
|
24
|
-
}, delay);
|
|
25
|
-
|
|
26
|
-
return () => clearTimeout(timer);
|
|
27
|
-
}, [value, delay]);
|
|
28
|
-
|
|
29
|
-
return debouncedValue;
|
|
30
|
-
}
|