@doswiftly/cli 0.1.18 → 0.1.20

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 (277) hide show
  1. package/README.md +23 -323
  2. package/dist/commands/check.js +1 -1
  3. package/dist/commands/check.js.map +1 -1
  4. package/dist/commands/deploy.d.ts +20 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +249 -17
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/doctor.js +3 -3
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/init.js +4 -4
  11. package/dist/commands/sdk.js +5 -5
  12. package/dist/commands/sdk.js.map +1 -1
  13. package/dist/commands/template.js +4 -4
  14. package/dist/commands/template.js.map +1 -1
  15. package/dist/commands/types.js +5 -5
  16. package/dist/commands/types.js.map +1 -1
  17. package/dist/commands/verify.js +2 -2
  18. package/dist/commands/verify.js.map +1 -1
  19. package/dist/lib/package-manager.d.ts +1 -1
  20. package/dist/lib/package-manager.js +1 -1
  21. package/package.json +4 -4
  22. package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
  23. package/templates/storefront-minimal/wrangler.toml +11 -0
  24. package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
  25. package/templates/storefront-nextjs/README.md +16 -12
  26. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  27. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  28. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  29. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  32. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  34. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  35. package/templates/storefront-nextjs/app/page.tsx +1 -1
  36. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  37. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  38. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  39. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  40. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  43. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  44. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  45. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  46. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  47. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  48. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  49. package/templates/storefront-nextjs/lib/format.ts +1 -1
  50. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  51. package/templates/storefront-nextjs/package.dev.json +1 -1
  52. package/templates/storefront-nextjs/package.json +1 -1
  53. package/templates/storefront-nextjs/package.json.template +1 -1
  54. package/templates/storefront-nextjs/wrangler.toml +11 -0
  55. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
  56. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  57. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  58. package/templates/storefront-nextjs-shadcn/CLAUDE.md +172 -35
  59. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  60. package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
  61. package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
  62. package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
  63. package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
  64. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
  65. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
  66. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
  67. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
  68. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
  69. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
  70. package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
  71. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
  72. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
  73. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
  74. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
  75. package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
  76. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
  77. package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
  78. package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
  79. package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
  80. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
  81. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
  82. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
  83. package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
  84. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
  85. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
  86. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
  87. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
  88. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
  89. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
  90. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
  91. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
  92. package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
  93. package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
  94. package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
  95. package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
  96. package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
  97. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
  98. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
  99. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
  100. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
  101. package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
  102. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
  103. package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
  104. package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
  105. package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
  106. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  107. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  108. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  109. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  110. package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
  111. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  112. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
  113. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
  114. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  115. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
  116. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
  117. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  118. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
  119. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
  120. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
  121. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
  122. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
  123. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
  124. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
  125. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
  126. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
  127. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  128. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
  129. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
  130. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
  131. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
  132. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
  133. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
  134. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
  135. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
  136. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
  137. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
  138. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
  139. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
  140. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  141. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
  142. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
  143. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
  144. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
  145. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
  146. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  147. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
  148. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
  149. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
  150. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  151. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
  152. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
  153. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
  154. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  155. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
  156. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  157. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
  158. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  159. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
  160. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
  161. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
  162. package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
  163. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
  164. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
  165. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  166. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  167. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +32 -42
  168. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  169. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  170. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  171. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
  172. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
  173. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
  174. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
  175. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -0
  176. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  177. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  178. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +11 -37
  179. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  180. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
  181. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  182. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
  183. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  184. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  185. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +44 -19
  186. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  187. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  188. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  189. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +26 -34
  190. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  191. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  192. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  193. package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
  194. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -0
  195. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  196. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  197. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +59 -72
  198. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
  199. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  200. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
  201. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
  202. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  203. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  204. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  205. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  206. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  207. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  208. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
  209. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
  210. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
  211. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
  212. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  213. package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -0
  214. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  215. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  216. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +34 -229
  217. package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
  218. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
  219. package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
  220. package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
  221. package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
  222. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  223. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  224. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +33 -0
  225. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  226. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
  227. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
  228. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -182
  229. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  230. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  231. package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
  232. package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
  233. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  234. package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
  235. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  236. package/templates/storefront-nextjs-shadcn/package.json +14 -14
  237. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  238. package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
  239. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
  240. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  241. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  242. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  243. package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
  244. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  245. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  246. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  247. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  248. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  249. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  250. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  251. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  252. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +0 -215
  253. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
  254. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
  255. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
  256. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
  257. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
  258. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  259. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  260. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  261. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  262. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  263. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  264. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  265. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  266. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  267. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  268. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  269. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  270. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  271. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
  272. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
  273. /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
  274. /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
  275. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
  276. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
  277. /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
@@ -14,8 +14,9 @@
14
14
  * Requirements: R7, R8, R10.4
15
15
  */
16
16
 
17
- import { useState, useEffect } from 'react';
18
- import Link from 'next/link';
17
+ import { useState } from 'react';
18
+ import { useTranslations } from 'next-intl';
19
+ import { Link } from '@/i18n/navigation';
19
20
  import { ArrowLeft, Gift, Award, History, Loader2, Users, AlertCircle } from 'lucide-react';
20
21
  import { Button } from '@/components/ui/button';
21
22
  import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
@@ -27,100 +28,7 @@ import { TierProgress } from '@/components/loyalty/tier-progress';
27
28
  import { RewardsCatalog } from '@/components/loyalty/rewards-catalog';
28
29
  import { PointsHistory } from '@/components/loyalty/points-history';
29
30
  import { ReferralSection } from '@/components/loyalty/referral-section';
30
- import { useAuth } from '@doswiftly/commerce-sdk/graphql/react';
31
-
32
- // Type imports - these match the GraphQL schema
33
- type TierType = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINUM' | 'DIAMOND';
34
-
35
- interface CustomBenefit {
36
- name: string;
37
- description?: string | null;
38
- icon?: string | null;
39
- }
40
-
41
- interface LoyaltyTier {
42
- id: string;
43
- name: string;
44
- type?: TierType | null;
45
- minPoints: number;
46
- minAnnualSpend?: { amount: string; currencyCode: string } | null;
47
- pointsMultiplier: number;
48
- customBenefits: CustomBenefit[];
49
- }
50
-
51
- interface PointsSummary {
52
- totalPoints: number;
53
- currentPoints: number;
54
- pendingPoints: number;
55
- redeemedPoints: number;
56
- expiredPoints: number;
57
- expiringPoints?: number;
58
- nextExpiryDate?: string;
59
- }
60
-
61
- interface TierProgressData {
62
- currentTier: LoyaltyTier;
63
- nextTier?: LoyaltyTier;
64
- pointsToNextTier: number;
65
- progressPercent: number;
66
- spendToNextTier?: { amount: string; currencyCode: string };
67
- }
68
-
69
- interface LoyaltyMember {
70
- id: string;
71
- customerId: string;
72
- points: PointsSummary;
73
- tier?: LoyaltyTier;
74
- tierProgress?: TierProgressData;
75
- annualSpend: { amount: string; currencyCode: string };
76
- lastActivityAt?: string;
77
- enrolledAt: string;
78
- }
79
-
80
- interface LoyaltyReward {
81
- id: string;
82
- name: string;
83
- slug: string;
84
- type: string;
85
- pointsCost: number;
86
- discountPercent?: number | null;
87
- discountAmount?: { amount: string; currencyCode: string } | null;
88
- description?: string | null;
89
- image?: { url: string; altText?: string | null } | null;
90
- available: boolean;
91
- tierRequired?: LoyaltyTier | null;
92
- remainingRedemptions?: number | null;
93
- }
94
-
95
- interface LoyaltyTransaction {
96
- id: string;
97
- type: string;
98
- points: number;
99
- balanceAfter: number;
100
- orderId?: string;
101
- description?: string;
102
- expiresAt?: string;
103
- createdAt: string;
104
- }
105
-
106
- interface LoyaltySettings {
107
- enabled: boolean;
108
- pointsName: string;
109
- pointsPerCurrency: number;
110
- pointsExpiryMonths?: number;
111
- referralEnabled: boolean;
112
- referralPoints?: number;
113
- referralBonusPoints?: number;
114
- }
115
-
116
- interface ReferralStats {
117
- referralCode: string;
118
- shareUrl: string;
119
- totalReferred: number;
120
- completedReferrals: number;
121
- pendingReferrals: number;
122
- totalPointsEarned: number;
123
- }
31
+ import { useAuthStore, useAuthHydrated } from '@doswiftly/storefront-sdk/react';
124
32
 
125
33
  // Real hooks from generated GraphQL
126
34
  import {
@@ -133,21 +41,27 @@ import {
133
41
  } from '@/lib/graphql/hooks';
134
42
 
135
43
  export default function LoyaltyPage() {
44
+ const t = useTranslations("account");
45
+ const tl = useTranslations("loyalty.page");
46
+ const ta = useTranslations("auth");
136
47
  const [activeTab, setActiveTab] = useState('overview');
137
- const { isAuthenticated } = useAuth();
48
+ const { isAuthenticated } = useAuthStore();
49
+ const isHydrated = useAuthHydrated();
138
50
 
139
51
  // Fetch loyalty data using real GraphQL hooks
140
- const { data: memberData, isLoading: memberLoading } = useLoyaltyMember();
141
- const { data: rewardsData, isLoading: rewardsLoading } = useLoyaltyRewards();
142
- const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
52
+ // Settings don't require auth always fetch
143
53
  const { data: settingsData } = useLoyaltySettings();
54
+ // All other queries require auth — hooks internally gate with `enabled: !!accessToken`
55
+ const { data: memberData, isLoading: memberLoading, error: memberError } = useLoyaltyMember();
56
+ const { data: rewardsData, isLoading: rewardsLoading, error: rewardsError } = useLoyaltyRewards();
57
+ const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
144
58
  const { data: referralData } = useReferralStats();
145
59
  const redeemMutation = useRedeemLoyaltyReward();
146
60
 
147
61
  // Extract data from query responses
148
62
  const member = memberData?.loyaltyMember;
149
63
  const rewards = rewardsData?.loyaltyRewards ?? [];
150
- const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e: any) => e.node) ?? [];
64
+ const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e) => e.node) ?? [];
151
65
  const settings = settingsData?.loyaltySettings;
152
66
  const referralStats = referralData?.referralStats;
153
67
 
@@ -164,7 +78,7 @@ export default function LoyaltyPage() {
164
78
  const payload = result.redeemLoyaltyReward;
165
79
 
166
80
  if (payload?.userErrors?.length) {
167
- throw new Error(payload.userErrors[0]);
81
+ throw new Error(payload.userErrors[0] || 'Unknown error');
168
82
  }
169
83
 
170
84
  if (payload?.success) {
@@ -176,12 +90,23 @@ export default function LoyaltyPage() {
176
90
  };
177
91
  }
178
92
 
179
- throw new Error('Nie udało się wymienić nagrody');
93
+ throw new Error(tl('redeemFailed'));
180
94
  } catch (error) {
181
95
  throw error;
182
96
  }
183
97
  };
184
98
 
99
+ // Show skeleton while Zustand persist is hydrating from localStorage
100
+ if (!isHydrated) {
101
+ return (
102
+ <div className="container max-w-6xl py-8">
103
+ <div className="flex items-center justify-center min-h-[400px]">
104
+ <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
105
+ </div>
106
+ </div>
107
+ );
108
+ }
109
+
185
110
  // Show login prompt if not authenticated
186
111
  if (!isAuthenticated) {
187
112
  return (
@@ -189,7 +114,7 @@ export default function LoyaltyPage() {
189
114
  <Link href="/account">
190
115
  <Button variant="ghost" size="sm" className="mb-4">
191
116
  <ArrowLeft className="h-4 w-4 mr-2" />
192
- Powrót do konta
117
+ {t("backToAccount")}
193
118
  </Button>
194
119
  </Link>
195
120
 
@@ -197,15 +122,15 @@ export default function LoyaltyPage() {
197
122
  <CardHeader>
198
123
  <CardTitle className="flex items-center gap-2">
199
124
  <Award className="h-5 w-5" />
200
- Program lojalnościowy
125
+ {t("loyalty")}
201
126
  </CardTitle>
202
127
  </CardHeader>
203
128
  <CardContent>
204
129
  <p className="text-muted-foreground mb-4">
205
- Zaloguj się, aby zobaczyć swoje punkty i nagrody.
130
+ {tl("signInToView")}
206
131
  </p>
207
132
  <Link href="/auth/login?redirect=/account/loyalty">
208
- <Button className="w-full">Zaloguj się</Button>
133
+ <Button className="w-full">{ta("signIn")}</Button>
209
134
  </Link>
210
135
  </CardContent>
211
136
  </Card>
@@ -224,6 +149,27 @@ export default function LoyaltyPage() {
224
149
  );
225
150
  }
226
151
 
152
+ // Show error state if primary queries failed
153
+ if (memberError || rewardsError) {
154
+ return (
155
+ <div className="container max-w-6xl py-8">
156
+ <Link href="/account">
157
+ <Button variant="ghost" size="sm" className="mb-4">
158
+ <ArrowLeft className="h-4 w-4 mr-2" />
159
+ {t("backToAccount")}
160
+ </Button>
161
+ </Link>
162
+
163
+ <Alert variant="destructive">
164
+ <AlertCircle className="h-4 w-4" />
165
+ <AlertDescription>
166
+ {tl("loadFailed")}
167
+ </AlertDescription>
168
+ </Alert>
169
+ </div>
170
+ );
171
+ }
172
+
227
173
  // Show disabled program message
228
174
  if (programDisabled) {
229
175
  return (
@@ -231,14 +177,14 @@ export default function LoyaltyPage() {
231
177
  <Link href="/account">
232
178
  <Button variant="ghost" size="sm" className="mb-4">
233
179
  <ArrowLeft className="h-4 w-4 mr-2" />
234
- Powrót do konta
180
+ {t("backToAccount")}
235
181
  </Button>
236
182
  </Link>
237
183
 
238
184
  <Alert>
239
185
  <AlertCircle className="h-4 w-4" />
240
186
  <AlertDescription>
241
- Program lojalnościowy jest obecnie niedostępny. Sprawdź ponownie później.
187
+ {tl("unavailable")}
242
188
  </AlertDescription>
243
189
  </Alert>
244
190
  </div>
@@ -252,7 +198,7 @@ export default function LoyaltyPage() {
252
198
  <Link href="/account">
253
199
  <Button variant="ghost" size="sm" className="mb-4">
254
200
  <ArrowLeft className="h-4 w-4 mr-2" />
255
- Powrót do konta
201
+ {t("backToAccount")}
256
202
  </Button>
257
203
  </Link>
258
204
 
@@ -260,16 +206,15 @@ export default function LoyaltyPage() {
260
206
  <CardHeader>
261
207
  <CardTitle className="flex items-center gap-2">
262
208
  <Award className="h-5 w-5" />
263
- Dołącz do programu lojalnościowego
209
+ {tl("joinTitle")}
264
210
  </CardTitle>
265
211
  </CardHeader>
266
212
  <CardContent>
267
213
  <p className="text-muted-foreground mb-4">
268
- Zbieraj punkty za zakupy i wymieniaj je na nagrody! Zapisanie jest automatyczne
269
- przy pierwszym zakupie.
214
+ {tl("joinDescription")}
270
215
  </p>
271
216
  <Link href="/products">
272
- <Button className="w-full">Przeglądaj produkty</Button>
217
+ <Button className="w-full">{t("browseProducts")}</Button>
273
218
  </Link>
274
219
  </CardContent>
275
220
  </Card>
@@ -277,43 +222,6 @@ export default function LoyaltyPage() {
277
222
  );
278
223
  }
279
224
 
280
- // Map tier data for components
281
- const tierData = member.tier
282
- ? {
283
- id: member.tier.id,
284
- name: member.tier.name,
285
- type: member.tier.type,
286
- minPoints: member.tier.minPoints,
287
- pointsMultiplier: member.tier.pointsMultiplier,
288
- customBenefits: member.tier.customBenefits ?? [],
289
- }
290
- : null;
291
-
292
- const progressData = member.tierProgress
293
- ? {
294
- currentTier: {
295
- id: member.tierProgress.currentTier.id,
296
- name: member.tierProgress.currentTier.name,
297
- type: member.tierProgress.currentTier.type,
298
- minPoints: member.tierProgress.currentTier.minPoints,
299
- pointsMultiplier: member.tierProgress.currentTier.pointsMultiplier,
300
- customBenefits: member.tierProgress.currentTier.customBenefits ?? [],
301
- },
302
- nextTier: member.tierProgress.nextTier
303
- ? {
304
- id: member.tierProgress.nextTier.id,
305
- name: member.tierProgress.nextTier.name,
306
- type: member.tierProgress.nextTier.type,
307
- minPoints: member.tierProgress.nextTier.minPoints,
308
- pointsMultiplier: member.tierProgress.nextTier.pointsMultiplier,
309
- customBenefits: member.tierProgress.nextTier.customBenefits ?? [],
310
- }
311
- : undefined,
312
- pointsToNextTier: member.tierProgress.pointsToNextTier,
313
- progressPercent: member.tierProgress.progressPercent,
314
- }
315
- : null;
316
-
317
225
  // Check if referral tab should be shown
318
226
  const showReferralTab = settings?.referralEnabled && referralStats;
319
227
 
@@ -324,18 +232,18 @@ export default function LoyaltyPage() {
324
232
  <Link href="/account">
325
233
  <Button variant="ghost" size="sm" className="mb-4">
326
234
  <ArrowLeft className="h-4 w-4 mr-2" />
327
- Powrót do konta
235
+ {t("backToAccount")}
328
236
  </Button>
329
237
  </Link>
330
238
 
331
239
  <div className="flex items-center justify-between">
332
240
  <div>
333
- <h1 className="text-3xl font-bold mb-2">Program lojalnościowy</h1>
241
+ <h1 className="text-3xl font-bold mb-2">{t("loyalty")}</h1>
334
242
  <p className="text-muted-foreground">
335
- Zbieraj {settings?.pointsName ?? 'punkty'} i wymieniaj je na nagrody
243
+ {tl("collectAndRedeem", { pointsName: settings?.pointsName ?? 'punkty' })}
336
244
  </p>
337
245
  </div>
338
- {tierData && <TierBadge tier={tierData.type} name={tierData.name} size="lg" />}
246
+ {member.tier && <TierBadge tier={member.tier.type} name={member.tier.name} size="lg" />}
339
247
  </div>
340
248
  </div>
341
249
 
@@ -344,20 +252,20 @@ export default function LoyaltyPage() {
344
252
  <TabsList className="mb-6">
345
253
  <TabsTrigger value="overview" className="gap-2">
346
254
  <Award className="h-4 w-4" />
347
- Przegląd
255
+ {tl("tabOverview")}
348
256
  </TabsTrigger>
349
257
  <TabsTrigger value="rewards" className="gap-2">
350
258
  <Gift className="h-4 w-4" />
351
- Nagrody
259
+ {tl("tabRewards")}
352
260
  </TabsTrigger>
353
261
  <TabsTrigger value="history" className="gap-2">
354
262
  <History className="h-4 w-4" />
355
- Historia
263
+ {tl("tabHistory")}
356
264
  </TabsTrigger>
357
265
  {showReferralTab && (
358
266
  <TabsTrigger value="referral" className="gap-2">
359
267
  <Users className="h-4 w-4" />
360
- Polecenia
268
+ {tl("tabReferrals")}
361
269
  </TabsTrigger>
362
270
  )}
363
271
  </TabsList>
@@ -366,22 +274,22 @@ export default function LoyaltyPage() {
366
274
  <TabsContent value="overview" className="space-y-6">
367
275
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
368
276
  <PointsBalance points={member.points} />
369
- {progressData && <TierProgress progress={progressData} />}
277
+ {member.tierProgress && <TierProgress progress={member.tierProgress} />}
370
278
  </div>
371
279
 
372
280
  {/* Tier Benefits */}
373
- {tierData && (
281
+ {member.tier && (
374
282
  <div className="p-6 bg-gradient-to-r from-amber-50 to-yellow-50 dark:from-amber-950/30 dark:to-yellow-950/30 rounded-lg border border-amber-200 dark:border-amber-800">
375
283
  <h3 className="font-semibold mb-4 flex items-center gap-2">
376
284
  <Award className="h-5 w-5 text-amber-600" />
377
- Twoje korzyści na poziomie {tierData.name}
285
+ {tl("tierBenefits", { tierName: member.tier.name })}
378
286
  </h3>
379
287
  <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm">
380
288
  <div className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
381
- <div className="font-medium">Mnożnik punktów</div>
382
- <div className="text-2xl font-bold text-amber-600">x{tierData.pointsMultiplier}</div>
289
+ <div className="font-medium">{tl("pointsMultiplier")}</div>
290
+ <div className="text-2xl font-bold text-amber-600">x{member.tier.pointsMultiplier}</div>
383
291
  </div>
384
- {tierData.customBenefits.slice(0, 2).map((benefit, idx) => (
292
+ {member.tier.customBenefits?.slice(0, 2).map((benefit, idx) => (
385
293
  <div key={idx} className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
386
294
  <div className="font-medium">{benefit.name}</div>
387
295
  {benefit.description && (
@@ -390,9 +298,9 @@ export default function LoyaltyPage() {
390
298
  </div>
391
299
  ))}
392
300
  </div>
393
- {tierData.customBenefits.length > 2 && (
301
+ {(member.tier.customBenefits?.length ?? 0) > 2 && (
394
302
  <div className="mt-4 flex flex-wrap gap-2">
395
- {tierData.customBenefits.slice(2).map((benefit, idx) => (
303
+ {member.tier.customBenefits?.slice(2).map((benefit, idx) => (
396
304
  <div key={idx} className="px-3 py-1.5 bg-white/50 dark:bg-black/20 rounded-full text-sm">
397
305
  {benefit.name}
398
306
  </div>
@@ -406,16 +314,16 @@ export default function LoyaltyPage() {
406
314
  <div className="flex flex-wrap gap-4">
407
315
  <Button onClick={() => setActiveTab('rewards')}>
408
316
  <Gift className="h-4 w-4 mr-2" />
409
- Przeglądaj nagrody
317
+ {tl("browseRewards")}
410
318
  </Button>
411
319
  <Button variant="outline" onClick={() => setActiveTab('history')}>
412
320
  <History className="h-4 w-4 mr-2" />
413
- Zobacz historię
321
+ {tl("viewHistory")}
414
322
  </Button>
415
323
  {showReferralTab && (
416
324
  <Button variant="outline" onClick={() => setActiveTab('referral')}>
417
325
  <Users className="h-4 w-4 mr-2" />
418
- Poleć znajomego
326
+ {tl("referFriend")}
419
327
  </Button>
420
328
  )}
421
329
  </div>
@@ -424,20 +332,13 @@ export default function LoyaltyPage() {
424
332
  {/* Rewards Tab */}
425
333
  <TabsContent value="rewards">
426
334
  <div className="mb-6">
427
- <h2 className="text-xl font-semibold mb-2">Dostępne nagrody</h2>
335
+ <h2 className="text-xl font-semibold mb-2">{tl("availableRewards")}</h2>
428
336
  <p className="text-muted-foreground">
429
- Wymień swoje {settings?.pointsName ?? 'punkty'} na atrakcyjne nagrody
337
+ {tl("redeemDescription", { pointsName: settings?.pointsName ?? 'punkty' })}
430
338
  </p>
431
339
  </div>
432
340
  <RewardsCatalog
433
- rewards={rewards.map((r) => ({
434
- ...r,
435
- discountAmount: r.discountAmount
436
- ? { amount: r.discountAmount.amount, currencyCode: r.discountAmount.currencyCode }
437
- : undefined,
438
- // Map tierRequired from LoyaltyTier object to just the type string
439
- tierRequired: r.tierRequired?.type,
440
- }))}
341
+ rewards={rewards}
441
342
  currentPoints={member.points.currentPoints}
442
343
  currentTier={member.tier?.type}
443
344
  onRedeem={handleRedeemReward}
@@ -447,8 +348,8 @@ export default function LoyaltyPage() {
447
348
  {/* History Tab */}
448
349
  <TabsContent value="history">
449
350
  <div className="mb-6">
450
- <h2 className="text-xl font-semibold mb-2">Historia punktów</h2>
451
- <p className="text-muted-foreground">Przegląd wszystkich transakcji punktowych</p>
351
+ <h2 className="text-xl font-semibold mb-2">{tl("pointsHistory")}</h2>
352
+ <p className="text-muted-foreground">{tl("historyDescription")}</p>
452
353
  </div>
453
354
  <PointsHistory transactions={transactions} />
454
355
  </TabsContent>
@@ -457,21 +358,16 @@ export default function LoyaltyPage() {
457
358
  {showReferralTab && referralStats && (
458
359
  <TabsContent value="referral">
459
360
  <div className="mb-6">
460
- <h2 className="text-xl font-semibold mb-2">Poleć znajomego</h2>
361
+ <h2 className="text-xl font-semibold mb-2">{tl("referFriend")}</h2>
461
362
  <p className="text-muted-foreground">
462
- Zaproś znajomych i otrzymaj {settings?.referralPoints ?? 0}{' '}
463
- {settings?.pointsName ?? 'punktów'} za każde polecenie
363
+ {tl("referFriendDescription", {
364
+ points: settings?.referralPoints ?? 0,
365
+ pointsName: settings?.pointsName ?? 'punktów',
366
+ })}
464
367
  </p>
465
368
  </div>
466
369
  <ReferralSection
467
- referralCode={referralStats.referralCode}
468
- shareUrl={referralStats.shareUrl}
469
- stats={{
470
- totalReferred: referralStats.totalReferred,
471
- completedReferrals: referralStats.completedReferrals,
472
- pendingReferrals: referralStats.pendingReferrals,
473
- totalPointsEarned: referralStats.totalPointsEarned,
474
- }}
370
+ referralStats={referralStats}
475
371
  pointsName={settings?.pointsName ?? 'punktów'}
476
372
  referralPoints={settings?.referralPoints ?? 0}
477
373
  bonusPoints={settings?.referralBonusPoints ?? 0}
@@ -0,0 +1,60 @@
1
+ import { Skeleton } from "@/components/ui/skeleton";
2
+
3
+ export default function OrderDetailLoading() {
4
+ return (
5
+ <div className="container mx-auto px-4 py-8">
6
+ {/* Breadcrumbs */}
7
+ <Skeleton className="mb-6 h-5 w-64" />
8
+
9
+ {/* Back button */}
10
+ <Skeleton className="mb-6 h-10 w-40" />
11
+
12
+ {/* Order header card */}
13
+ <div className="mb-6 rounded-lg border p-6">
14
+ <div className="flex items-center justify-between">
15
+ <div className="space-y-2">
16
+ <Skeleton className="h-7 w-48" />
17
+ <Skeleton className="h-4 w-32" />
18
+ </div>
19
+ <Skeleton className="h-8 w-24 rounded-full" />
20
+ </div>
21
+ </div>
22
+
23
+ {/* Order items card */}
24
+ <div className="mb-6 rounded-lg border p-6">
25
+ <Skeleton className="mb-4 h-6 w-24" />
26
+ <div className="space-y-4">
27
+ {[...Array(3)].map((_, i) => (
28
+ <div key={i} className="flex items-center gap-4">
29
+ <Skeleton className="h-16 w-16 rounded-md" />
30
+ <div className="flex-1 space-y-2">
31
+ <Skeleton className="h-4 w-3/4" />
32
+ <Skeleton className="h-4 w-1/4" />
33
+ </div>
34
+ <Skeleton className="h-5 w-20" />
35
+ </div>
36
+ ))}
37
+ </div>
38
+ <div className="mt-4 border-t pt-4 space-y-2">
39
+ <Skeleton className="ml-auto h-4 w-32" />
40
+ <Skeleton className="ml-auto h-4 w-32" />
41
+ <Skeleton className="ml-auto h-5 w-36" />
42
+ </div>
43
+ </div>
44
+
45
+ {/* Address cards */}
46
+ <div className="grid gap-6 md:grid-cols-2">
47
+ {[...Array(2)].map((_, i) => (
48
+ <div key={i} className="rounded-lg border p-6">
49
+ <Skeleton className="mb-3 h-5 w-36" />
50
+ <div className="space-y-2">
51
+ <Skeleton className="h-4 w-48" />
52
+ <Skeleton className="h-4 w-40" />
53
+ <Skeleton className="h-4 w-32" />
54
+ </div>
55
+ </div>
56
+ ))}
57
+ </div>
58
+ </div>
59
+ );
60
+ }
@@ -0,0 +1,119 @@
1
+ "use client";
2
+
3
+ import { useParams } from "next/navigation";
4
+ import { Link } from "@/i18n/navigation";
5
+ import { useTranslations } from "next-intl";
6
+ import { ChevronLeft } from "lucide-react";
7
+ import { useCustomerOrder } from "@/lib/graphql/hooks";
8
+ import { useHydrated } from "@doswiftly/storefront-sdk/react";
9
+ import { Button } from "@/components/ui/button";
10
+ import { Breadcrumbs } from "@/components/layout/breadcrumbs";
11
+ import {
12
+ OrderDetails,
13
+ type OrderDetailsData,
14
+ } from "@/components/account/order-details";
15
+
16
+ export default function OrderDetailPage() {
17
+ const t = useTranslations("account");
18
+ const params = useParams();
19
+ const orderId = params.id as string;
20
+ const hydrated = useHydrated();
21
+
22
+ const { data, isPending, error } = useCustomerOrder(orderId);
23
+
24
+ const order = data?.customerOrder;
25
+
26
+ if (!hydrated || isPending) {
27
+ return (
28
+ <div className="container mx-auto px-4 py-8">
29
+ <div className="animate-pulse space-y-4">
30
+ <div className="h-8 bg-muted rounded w-1/4"></div>
31
+ <div className="h-64 bg-muted rounded"></div>
32
+ </div>
33
+ </div>
34
+ );
35
+ }
36
+
37
+ if (error) {
38
+ return (
39
+ <div className="container mx-auto px-4 py-8">
40
+ <div className="text-center">
41
+ <h1 className="text-2xl font-bold text-destructive">{t("failedLoadOrder")}</h1>
42
+ <p className="mt-2 text-muted-foreground">{t("tryAgainLater")}</p>
43
+ <Link href="/account/orders">
44
+ <Button className="mt-4">{t("backToOrders")}</Button>
45
+ </Link>
46
+ </div>
47
+ </div>
48
+ );
49
+ }
50
+
51
+ if (!order) {
52
+ return (
53
+ <div className="container mx-auto px-4 py-8">
54
+ <div className="text-center">
55
+ <h1 className="text-2xl font-bold">{t("orderNotFound")}</h1>
56
+ <Link href="/account/orders">
57
+ <Button className="mt-4">{t("backToOrders")}</Button>
58
+ </Link>
59
+ </div>
60
+ </div>
61
+ );
62
+ }
63
+
64
+ const mapFulfillmentStatus = (status?: string | null): OrderDetailsData["status"] => {
65
+ switch (status) {
66
+ case "DELIVERED": return "delivered";
67
+ case "IN_TRANSIT":
68
+ case "FULFILLED": return "shipped";
69
+ case "UNFULFILLED":
70
+ case "PARTIALLY_FULFILLED": return "processing";
71
+ default: return "processing";
72
+ }
73
+ };
74
+
75
+ const orderDetails: OrderDetailsData = {
76
+ id: order.id,
77
+ orderNumber: order.orderNumber?.toString() || order.id,
78
+ date: new Date(order.processedAt).toLocaleDateString(),
79
+ status: mapFulfillmentStatus(order.fulfillmentStatus),
80
+ items: [],
81
+ subtotal: order.subtotalPrice?.amount || "0",
82
+ shipping: order.totalShipping?.amount || "0",
83
+ tax: order.totalTax?.amount || "0",
84
+ total: order.totalPrice.amount,
85
+ currency: order.totalPrice.currencyCode,
86
+ shippingAddress: order.shippingAddress
87
+ ? {
88
+ firstName: order.shippingAddress.firstName || "",
89
+ lastName: order.shippingAddress.lastName || "",
90
+ address1: order.shippingAddress.address1 || "",
91
+ address2: order.shippingAddress.address2 || "",
92
+ city: order.shippingAddress.city || "",
93
+ province: order.shippingAddress.province || "",
94
+ zip: order.shippingAddress.zip || "",
95
+ country: order.shippingAddress.country || "",
96
+ phone: order.shippingAddress.phone || "",
97
+ }
98
+ : undefined,
99
+ trackingNumber: undefined,
100
+ estimatedDelivery: undefined,
101
+ };
102
+
103
+ return (
104
+ <div className="container mx-auto px-4 py-8">
105
+ <Breadcrumbs className="mb-6" />
106
+
107
+ <div className="mb-6">
108
+ <Button variant="ghost" asChild>
109
+ <Link href="/account/orders">
110
+ <ChevronLeft className="mr-2 h-4 w-4" />
111
+ {t("backToOrders")}
112
+ </Link>
113
+ </Button>
114
+ </div>
115
+
116
+ <OrderDetails order={orderDetails} />
117
+ </div>
118
+ );
119
+ }