@doswiftly/cli 0.1.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 (453) hide show
  1. package/README.md +357 -0
  2. package/bin/doswiftly.js +2 -0
  3. package/dist/commands/auth-github.d.ts +6 -0
  4. package/dist/commands/auth-github.d.ts.map +1 -0
  5. package/dist/commands/auth-github.js +89 -0
  6. package/dist/commands/auth-github.js.map +1 -0
  7. package/dist/commands/auth-token.d.ts +12 -0
  8. package/dist/commands/auth-token.d.ts.map +1 -0
  9. package/dist/commands/auth-token.js +43 -0
  10. package/dist/commands/auth-token.js.map +1 -0
  11. package/dist/commands/auth.d.ts +22 -0
  12. package/dist/commands/auth.d.ts.map +1 -0
  13. package/dist/commands/auth.js +348 -0
  14. package/dist/commands/auth.js.map +1 -0
  15. package/dist/commands/check.d.ts +5 -0
  16. package/dist/commands/check.d.ts.map +1 -0
  17. package/dist/commands/check.js +234 -0
  18. package/dist/commands/check.js.map +1 -0
  19. package/dist/commands/config.d.ts +3 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +104 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/deploy.d.ts +37 -0
  24. package/dist/commands/deploy.d.ts.map +1 -0
  25. package/dist/commands/deploy.js +580 -0
  26. package/dist/commands/deploy.js.map +1 -0
  27. package/dist/commands/dev.d.ts +8 -0
  28. package/dist/commands/dev.d.ts.map +1 -0
  29. package/dist/commands/dev.js +83 -0
  30. package/dist/commands/dev.js.map +1 -0
  31. package/dist/commands/doctor.d.ts +5 -0
  32. package/dist/commands/doctor.d.ts.map +1 -0
  33. package/dist/commands/doctor.js +363 -0
  34. package/dist/commands/doctor.js.map +1 -0
  35. package/dist/commands/domain.d.ts +13 -0
  36. package/dist/commands/domain.d.ts.map +1 -0
  37. package/dist/commands/domain.js +128 -0
  38. package/dist/commands/domain.js.map +1 -0
  39. package/dist/commands/env.d.ts +25 -0
  40. package/dist/commands/env.d.ts.map +1 -0
  41. package/dist/commands/env.js +228 -0
  42. package/dist/commands/env.js.map +1 -0
  43. package/dist/commands/init.d.ts +11 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +1028 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/inspect.d.ts +12 -0
  48. package/dist/commands/inspect.d.ts.map +1 -0
  49. package/dist/commands/inspect.js +162 -0
  50. package/dist/commands/inspect.js.map +1 -0
  51. package/dist/commands/migrate.d.ts +18 -0
  52. package/dist/commands/migrate.d.ts.map +1 -0
  53. package/dist/commands/migrate.js +355 -0
  54. package/dist/commands/migrate.js.map +1 -0
  55. package/dist/commands/preview.d.ts +29 -0
  56. package/dist/commands/preview.d.ts.map +1 -0
  57. package/dist/commands/preview.js +199 -0
  58. package/dist/commands/preview.js.map +1 -0
  59. package/dist/commands/proxy.d.ts +9 -0
  60. package/dist/commands/proxy.d.ts.map +1 -0
  61. package/dist/commands/proxy.js +37 -0
  62. package/dist/commands/proxy.js.map +1 -0
  63. package/dist/commands/sdk.d.ts +5 -0
  64. package/dist/commands/sdk.d.ts.map +1 -0
  65. package/dist/commands/sdk.js +82 -0
  66. package/dist/commands/sdk.js.map +1 -0
  67. package/dist/commands/template.d.ts +107 -0
  68. package/dist/commands/template.d.ts.map +1 -0
  69. package/dist/commands/template.js +1309 -0
  70. package/dist/commands/template.js.map +1 -0
  71. package/dist/commands/types.d.ts +5 -0
  72. package/dist/commands/types.d.ts.map +1 -0
  73. package/dist/commands/types.js +82 -0
  74. package/dist/commands/types.js.map +1 -0
  75. package/dist/commands/update.d.ts +2 -0
  76. package/dist/commands/update.d.ts.map +1 -0
  77. package/dist/commands/update.js +103 -0
  78. package/dist/commands/update.js.map +1 -0
  79. package/dist/commands/upgrade.d.ts +18 -0
  80. package/dist/commands/upgrade.d.ts.map +1 -0
  81. package/dist/commands/upgrade.js +55 -0
  82. package/dist/commands/upgrade.js.map +1 -0
  83. package/dist/commands/verify.d.ts +5 -0
  84. package/dist/commands/verify.d.ts.map +1 -0
  85. package/dist/commands/verify.js +232 -0
  86. package/dist/commands/verify.js.map +1 -0
  87. package/dist/commands/whoami.d.ts +5 -0
  88. package/dist/commands/whoami.d.ts.map +1 -0
  89. package/dist/commands/whoami.js +60 -0
  90. package/dist/commands/whoami.js.map +1 -0
  91. package/dist/config/types.d.ts +173 -0
  92. package/dist/config/types.d.ts.map +1 -0
  93. package/dist/config/types.js +48 -0
  94. package/dist/config/types.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +416 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/lib/api-url.d.ts +14 -0
  100. package/dist/lib/api-url.d.ts.map +1 -0
  101. package/dist/lib/api-url.js +24 -0
  102. package/dist/lib/api-url.js.map +1 -0
  103. package/dist/lib/api.d.ts +67 -0
  104. package/dist/lib/api.d.ts.map +1 -0
  105. package/dist/lib/api.js +36 -0
  106. package/dist/lib/api.js.map +1 -0
  107. package/dist/lib/config.d.ts +39 -0
  108. package/dist/lib/config.d.ts.map +1 -0
  109. package/dist/lib/config.js +195 -0
  110. package/dist/lib/config.js.map +1 -0
  111. package/dist/lib/env-storage.d.ts +140 -0
  112. package/dist/lib/env-storage.d.ts.map +1 -0
  113. package/dist/lib/env-storage.js +464 -0
  114. package/dist/lib/env-storage.js.map +1 -0
  115. package/dist/lib/errors.d.ts +61 -0
  116. package/dist/lib/errors.d.ts.map +1 -0
  117. package/dist/lib/errors.js +204 -0
  118. package/dist/lib/errors.js.map +1 -0
  119. package/dist/lib/i18n.d.ts +99 -0
  120. package/dist/lib/i18n.d.ts.map +1 -0
  121. package/dist/lib/i18n.js +184 -0
  122. package/dist/lib/i18n.js.map +1 -0
  123. package/dist/lib/logger.d.ts +95 -0
  124. package/dist/lib/logger.d.ts.map +1 -0
  125. package/dist/lib/logger.js +168 -0
  126. package/dist/lib/logger.js.map +1 -0
  127. package/dist/lib/package-manager.d.ts +91 -0
  128. package/dist/lib/package-manager.d.ts.map +1 -0
  129. package/dist/lib/package-manager.js +205 -0
  130. package/dist/lib/package-manager.js.map +1 -0
  131. package/dist/lib/proxy-server.d.ts +24 -0
  132. package/dist/lib/proxy-server.d.ts.map +1 -0
  133. package/dist/lib/proxy-server.js +173 -0
  134. package/dist/lib/proxy-server.js.map +1 -0
  135. package/dist/lib/select-with-back.d.ts +34 -0
  136. package/dist/lib/select-with-back.d.ts.map +1 -0
  137. package/dist/lib/select-with-back.js +94 -0
  138. package/dist/lib/select-with-back.js.map +1 -0
  139. package/dist/lib/shared-api-client.d.ts +40 -0
  140. package/dist/lib/shared-api-client.d.ts.map +1 -0
  141. package/dist/lib/shared-api-client.js +92 -0
  142. package/dist/lib/shared-api-client.js.map +1 -0
  143. package/dist/lib/wizard-engine.d.ts +128 -0
  144. package/dist/lib/wizard-engine.d.ts.map +1 -0
  145. package/dist/lib/wizard-engine.js +168 -0
  146. package/dist/lib/wizard-engine.js.map +1 -0
  147. package/package.json +85 -0
  148. package/templates/storefront-minimal/.env.example +10 -0
  149. package/templates/storefront-minimal/.github/workflows/build-template.yml +109 -0
  150. package/templates/storefront-minimal/app/globals.css +18 -0
  151. package/templates/storefront-minimal/app/layout.tsx +26 -0
  152. package/templates/storefront-minimal/app/page.tsx +93 -0
  153. package/templates/storefront-minimal/lib/graphql-client.ts +23 -0
  154. package/templates/storefront-minimal/next.config.ts +15 -0
  155. package/templates/storefront-minimal/open-next.config.ts +3 -0
  156. package/templates/storefront-minimal/package.json +30 -0
  157. package/templates/storefront-minimal/postcss.config.mjs +5 -0
  158. package/templates/storefront-minimal/tailwind.config.ts +14 -0
  159. package/templates/storefront-minimal/tsconfig.json +27 -0
  160. package/templates/storefront-minimal/wrangler.toml +9 -0
  161. package/templates/storefront-nextjs/.env.example +68 -0
  162. package/templates/storefront-nextjs/.github/workflows/build-template.yml +109 -0
  163. package/templates/storefront-nextjs/.github/workflows/deploy.yml +25 -0
  164. package/templates/storefront-nextjs/.github/workflows/preview.yml +22 -0
  165. package/templates/storefront-nextjs/README.md +520 -0
  166. package/templates/storefront-nextjs/app/account/orders/page.tsx +216 -0
  167. package/templates/storefront-nextjs/app/account/page.tsx +167 -0
  168. package/templates/storefront-nextjs/app/auth/login/page.tsx +135 -0
  169. package/templates/storefront-nextjs/app/auth/register/page.tsx +228 -0
  170. package/templates/storefront-nextjs/app/cart/page.tsx +263 -0
  171. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +200 -0
  172. package/templates/storefront-nextjs/app/categories/page.tsx +58 -0
  173. package/templates/storefront-nextjs/app/checkout/page.tsx +351 -0
  174. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +158 -0
  175. package/templates/storefront-nextjs/app/collections/page.tsx +61 -0
  176. package/templates/storefront-nextjs/app/globals.css +98 -0
  177. package/templates/storefront-nextjs/app/layout.tsx +39 -0
  178. package/templates/storefront-nextjs/app/page.tsx +136 -0
  179. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +119 -0
  180. package/templates/storefront-nextjs/app/products/page.tsx +107 -0
  181. package/templates/storefront-nextjs/app/search/page.tsx +127 -0
  182. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +94 -0
  183. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +77 -0
  184. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +29 -0
  185. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +217 -0
  186. package/templates/storefront-nextjs/components/commerce/pagination.tsx +62 -0
  187. package/templates/storefront-nextjs/components/commerce/product-actions.tsx +135 -0
  188. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +109 -0
  189. package/templates/storefront-nextjs/components/commerce/product-price.tsx +375 -0
  190. package/templates/storefront-nextjs/components/commerce/search-input.tsx +178 -0
  191. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +64 -0
  192. package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +210 -0
  193. package/templates/storefront-nextjs/components/layout/footer.tsx +107 -0
  194. package/templates/storefront-nextjs/components/layout/header.tsx +104 -0
  195. package/templates/storefront-nextjs/components/providers.tsx +62 -0
  196. package/templates/storefront-nextjs/lib/auth/routes.ts +52 -0
  197. package/templates/storefront-nextjs/lib/currency.tsx +140 -0
  198. package/templates/storefront-nextjs/lib/format.ts +159 -0
  199. package/templates/storefront-nextjs/lib/graphql-queries.ts +629 -0
  200. package/templates/storefront-nextjs/lib/hooks.ts +30 -0
  201. package/templates/storefront-nextjs/middleware.ts +80 -0
  202. package/templates/storefront-nextjs/next.config.ts +37 -0
  203. package/templates/storefront-nextjs/open-next.config.ts +3 -0
  204. package/templates/storefront-nextjs/package.dev.json +30 -0
  205. package/templates/storefront-nextjs/package.json +32 -0
  206. package/templates/storefront-nextjs/package.json.template +32 -0
  207. package/templates/storefront-nextjs/postcss.config.mjs +8 -0
  208. package/templates/storefront-nextjs/tailwind.config.ts +111 -0
  209. package/templates/storefront-nextjs/tsconfig.json +27 -0
  210. package/templates/storefront-nextjs/wrangler.toml +9 -0
  211. package/templates/storefront-nextjs-shadcn/.env.example +68 -0
  212. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +109 -0
  213. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +25 -0
  214. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +22 -0
  215. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +282 -0
  216. package/templates/storefront-nextjs-shadcn/CLAUDE.md +96 -0
  217. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +190 -0
  218. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +263 -0
  219. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +135 -0
  220. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +142 -0
  221. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +448 -0
  222. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +307 -0
  223. package/templates/storefront-nextjs-shadcn/README.md +195 -0
  224. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +245 -0
  225. package/templates/storefront-nextjs-shadcn/app/about/page.tsx +34 -0
  226. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +215 -0
  227. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +484 -0
  228. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +128 -0
  229. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/tracking/page.tsx +206 -0
  230. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +80 -0
  231. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +107 -0
  232. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +195 -0
  233. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +87 -0
  234. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +125 -0
  235. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +131 -0
  236. package/templates/storefront-nextjs-shadcn/app/auth/login/page.tsx +24 -0
  237. package/templates/storefront-nextjs-shadcn/app/auth/register/page.tsx +20 -0
  238. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +323 -0
  239. package/templates/storefront-nextjs-shadcn/app/blog/page.tsx +159 -0
  240. package/templates/storefront-nextjs-shadcn/app/brands/[slug]/page.tsx +170 -0
  241. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +73 -0
  242. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +165 -0
  243. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +78 -0
  244. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +75 -0
  245. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +1752 -0
  246. package/templates/storefront-nextjs-shadcn/app/checkout/success/[orderId]/page.tsx +256 -0
  247. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +74 -0
  248. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +75 -0
  249. package/templates/storefront-nextjs-shadcn/app/contact/page.tsx +114 -0
  250. package/templates/storefront-nextjs-shadcn/app/error.tsx +90 -0
  251. package/templates/storefront-nextjs-shadcn/app/globals.css +125 -0
  252. package/templates/storefront-nextjs-shadcn/app/layout.tsx +57 -0
  253. package/templates/storefront-nextjs-shadcn/app/not-found.tsx +68 -0
  254. package/templates/storefront-nextjs-shadcn/app/page.tsx +21 -0
  255. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +246 -0
  256. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +343 -0
  257. package/templates/storefront-nextjs-shadcn/app/products/page.tsx +25 -0
  258. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +192 -0
  259. package/templates/storefront-nextjs-shadcn/app/returns/page.tsx +77 -0
  260. package/templates/storefront-nextjs-shadcn/app/robots.ts +53 -0
  261. package/templates/storefront-nextjs-shadcn/app/search/page.tsx +16 -0
  262. package/templates/storefront-nextjs-shadcn/app/search/search-client.tsx +47 -0
  263. package/templates/storefront-nextjs-shadcn/app/shipping/page.tsx +62 -0
  264. package/templates/storefront-nextjs-shadcn/app/sitemap.ts +144 -0
  265. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +179 -0
  266. package/templates/storefront-nextjs-shadcn/codegen.ts +51 -0
  267. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +348 -0
  268. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +144 -0
  269. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +258 -0
  270. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +107 -0
  271. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +132 -0
  272. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +188 -0
  273. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +305 -0
  274. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +240 -0
  275. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +177 -0
  276. package/templates/storefront-nextjs-shadcn/components/blog/index.ts +8 -0
  277. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +119 -0
  278. package/templates/storefront-nextjs-shadcn/components/brand/brand-grid.tsx +64 -0
  279. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +140 -0
  280. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +48 -0
  281. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +112 -0
  282. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +84 -0
  283. package/templates/storefront-nextjs-shadcn/components/cart/index.ts +17 -0
  284. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +121 -0
  285. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +162 -0
  286. package/templates/storefront-nextjs-shadcn/components/checkout/index.ts +25 -0
  287. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +187 -0
  288. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +160 -0
  289. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +154 -0
  290. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +225 -0
  291. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +62 -0
  292. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +158 -0
  293. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +174 -0
  294. package/templates/storefront-nextjs-shadcn/components/commerce/variant-selector.tsx +210 -0
  295. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +97 -0
  296. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +187 -0
  297. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +151 -0
  298. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +166 -0
  299. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +245 -0
  300. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +246 -0
  301. package/templates/storefront-nextjs-shadcn/components/discount/index.ts +19 -0
  302. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +113 -0
  303. package/templates/storefront-nextjs-shadcn/components/error/index.ts +7 -0
  304. package/templates/storefront-nextjs-shadcn/components/filters/attribute-filter.tsx +153 -0
  305. package/templates/storefront-nextjs-shadcn/components/filters/checkbox-group-filter.tsx +167 -0
  306. package/templates/storefront-nextjs-shadcn/components/filters/color-swatch-filter.tsx +176 -0
  307. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +220 -0
  308. package/templates/storefront-nextjs-shadcn/components/filters/index.ts +36 -0
  309. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +193 -0
  310. package/templates/storefront-nextjs-shadcn/components/filters/toggle-filter.tsx +132 -0
  311. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +321 -0
  312. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +309 -0
  313. package/templates/storefront-nextjs-shadcn/components/gift-card/index.ts +24 -0
  314. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +72 -0
  315. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +107 -0
  316. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +85 -0
  317. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +34 -0
  318. package/templates/storefront-nextjs-shadcn/components/home/index.ts +8 -0
  319. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +108 -0
  320. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +133 -0
  321. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +341 -0
  322. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +128 -0
  323. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +147 -0
  324. package/templates/storefront-nextjs-shadcn/components/layout/index.ts +9 -0
  325. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +211 -0
  326. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +95 -0
  327. package/templates/storefront-nextjs-shadcn/components/layout/theme-switcher.tsx +192 -0
  328. package/templates/storefront-nextjs-shadcn/components/loyalty/index.ts +11 -0
  329. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +93 -0
  330. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +177 -0
  331. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +250 -0
  332. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +217 -0
  333. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-badge.tsx +106 -0
  334. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +131 -0
  335. package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +196 -0
  336. package/templates/storefront-nextjs-shadcn/components/order/index.ts +11 -0
  337. package/templates/storefront-nextjs-shadcn/components/order/order-tracking.tsx +200 -0
  338. package/templates/storefront-nextjs-shadcn/components/order/shipment-card.tsx +407 -0
  339. package/templates/storefront-nextjs-shadcn/components/order/tracking-status.tsx +222 -0
  340. package/templates/storefront-nextjs-shadcn/components/order/tracking-timeline.tsx +205 -0
  341. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +161 -0
  342. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +250 -0
  343. package/templates/storefront-nextjs-shadcn/components/product/discount-badge.tsx +196 -0
  344. package/templates/storefront-nextjs-shadcn/components/product/index.ts +41 -0
  345. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +147 -0
  346. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +217 -0
  347. package/templates/storefront-nextjs-shadcn/components/product/product-gallery.tsx +143 -0
  348. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +83 -0
  349. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +155 -0
  350. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +158 -0
  351. package/templates/storefront-nextjs-shadcn/components/product/product-quantity-selector.tsx +111 -0
  352. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +238 -0
  353. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +58 -0
  354. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +169 -0
  355. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +220 -0
  356. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +338 -0
  357. package/templates/storefront-nextjs-shadcn/components/product/review-summary.tsx +143 -0
  358. package/templates/storefront-nextjs-shadcn/components/product/sale-countdown.tsx +166 -0
  359. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +213 -0
  360. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +57 -0
  361. package/templates/storefront-nextjs-shadcn/components/product/stock-indicator.tsx +91 -0
  362. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +103 -0
  363. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +8 -0
  364. package/templates/storefront-nextjs-shadcn/components/providers/query-provider.tsx +260 -0
  365. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +13 -0
  366. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +26 -0
  367. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +608 -0
  368. package/templates/storefront-nextjs-shadcn/components/returns/return-status-card.tsx +554 -0
  369. package/templates/storefront-nextjs-shadcn/components/search/index.ts +8 -0
  370. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +140 -0
  371. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +58 -0
  372. package/templates/storefront-nextjs-shadcn/components/search/search-suggestions.tsx +43 -0
  373. package/templates/storefront-nextjs-shadcn/components/seo/index.ts +12 -0
  374. package/templates/storefront-nextjs-shadcn/components/seo/json-ld.tsx +56 -0
  375. package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +167 -0
  376. package/templates/storefront-nextjs-shadcn/components/shipping/index.ts +16 -0
  377. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +337 -0
  378. package/templates/storefront-nextjs-shadcn/components/ui/accordion.tsx +153 -0
  379. package/templates/storefront-nextjs-shadcn/components/ui/alert.tsx +59 -0
  380. package/templates/storefront-nextjs-shadcn/components/ui/badge.tsx +34 -0
  381. package/templates/storefront-nextjs-shadcn/components/ui/button.tsx +51 -0
  382. package/templates/storefront-nextjs-shadcn/components/ui/card.tsx +77 -0
  383. package/templates/storefront-nextjs-shadcn/components/ui/checkbox.tsx +30 -0
  384. package/templates/storefront-nextjs-shadcn/components/ui/dialog.tsx +137 -0
  385. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +207 -0
  386. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +67 -0
  387. package/templates/storefront-nextjs-shadcn/components/ui/input.tsx +65 -0
  388. package/templates/storefront-nextjs-shadcn/components/ui/label.tsx +26 -0
  389. package/templates/storefront-nextjs-shadcn/components/ui/pagination.tsx +205 -0
  390. package/templates/storefront-nextjs-shadcn/components/ui/radio-group.tsx +44 -0
  391. package/templates/storefront-nextjs-shadcn/components/ui/select.tsx +160 -0
  392. package/templates/storefront-nextjs-shadcn/components/ui/separator.tsx +28 -0
  393. package/templates/storefront-nextjs-shadcn/components/ui/skeleton.tsx +20 -0
  394. package/templates/storefront-nextjs-shadcn/components/ui/spinner.tsx +82 -0
  395. package/templates/storefront-nextjs-shadcn/components/ui/tabs.tsx +119 -0
  396. package/templates/storefront-nextjs-shadcn/components/ui/toast.tsx +96 -0
  397. package/templates/storefront-nextjs-shadcn/components/wishlist/index.ts +9 -0
  398. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +148 -0
  399. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +47 -0
  400. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +165 -0
  401. package/templates/storefront-nextjs-shadcn/components.json +19 -0
  402. package/templates/storefront-nextjs-shadcn/generated/.gitkeep +2 -0
  403. package/templates/storefront-nextjs-shadcn/graphql/.gitkeep +31 -0
  404. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +168 -0
  405. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +160 -0
  406. package/templates/storefront-nextjs-shadcn/hooks/index.ts +9 -0
  407. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +310 -0
  408. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +286 -0
  409. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +110 -0
  410. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.test.ts +173 -0
  411. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.ts +298 -0
  412. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +220 -0
  413. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +57 -0
  414. package/templates/storefront-nextjs-shadcn/lib/config.ts +46 -0
  415. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +254 -0
  416. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +464 -0
  417. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +328 -0
  418. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +295 -0
  419. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +27 -0
  420. package/templates/storefront-nextjs-shadcn/lib/format.test.ts +397 -0
  421. package/templates/storefront-nextjs-shadcn/lib/format.ts +226 -0
  422. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +109 -0
  423. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +1183 -0
  424. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +267 -0
  425. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +30 -0
  426. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +89 -0
  427. package/templates/storefront-nextjs-shadcn/lib/utils.ts +6 -0
  428. package/templates/storefront-nextjs-shadcn/next.config.ts +47 -0
  429. package/templates/storefront-nextjs-shadcn/open-next.config.ts +3 -0
  430. package/templates/storefront-nextjs-shadcn/package.dev.json +30 -0
  431. package/templates/storefront-nextjs-shadcn/package.json +60 -0
  432. package/templates/storefront-nextjs-shadcn/package.json.template +46 -0
  433. package/templates/storefront-nextjs-shadcn/postcss.config.mjs +8 -0
  434. package/templates/storefront-nextjs-shadcn/proxy.ts +80 -0
  435. package/templates/storefront-nextjs-shadcn/public/icons/payment/apple-pay.svg +8 -0
  436. package/templates/storefront-nextjs-shadcn/public/icons/payment/bank-transfer.svg +10 -0
  437. package/templates/storefront-nextjs-shadcn/public/icons/payment/blik.svg +6 -0
  438. package/templates/storefront-nextjs-shadcn/public/icons/payment/cash-on-delivery.svg +11 -0
  439. package/templates/storefront-nextjs-shadcn/public/icons/payment/google-pay.svg +11 -0
  440. package/templates/storefront-nextjs-shadcn/public/icons/payment/mastercard.svg +7 -0
  441. package/templates/storefront-nextjs-shadcn/public/icons/payment/paypal.svg +7 -0
  442. package/templates/storefront-nextjs-shadcn/public/icons/payment/payu.svg +7 -0
  443. package/templates/storefront-nextjs-shadcn/public/icons/payment/przelewy24.svg +7 -0
  444. package/templates/storefront-nextjs-shadcn/public/icons/payment/stripe.svg +4 -0
  445. package/templates/storefront-nextjs-shadcn/public/icons/payment/visa.svg +5 -0
  446. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +66 -0
  447. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +56 -0
  448. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +184 -0
  449. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +103 -0
  450. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +291 -0
  451. package/templates/storefront-nextjs-shadcn/tailwind.config.ts +111 -0
  452. package/templates/storefront-nextjs-shadcn/tsconfig.json +27 -0
  453. package/templates/storefront-nextjs-shadcn/wrangler.toml +9 -0
@@ -0,0 +1,64 @@
1
+ "use client";
2
+
3
+ import { useRouter, useSearchParams, usePathname } from "next/navigation";
4
+ import { useCallback } from "react";
5
+ import { ProductSortKeys } from "@doswiftly/commerce-sdk/graphql";
6
+
7
+ interface SortSelectProps {
8
+ currentSort?: string;
9
+ currentOrder?: string;
10
+ }
11
+
12
+ /**
13
+ * SortSelect - Client Component for sorting products
14
+ *
15
+ * Uses URL params for sort state (Server Component compatible).
16
+ */
17
+ export function SortSelect({ currentSort, currentOrder }: SortSelectProps) {
18
+ const router = useRouter();
19
+ const pathname = usePathname();
20
+ const searchParams = useSearchParams();
21
+
22
+ // Build combined value for select
23
+ const sortValue =
24
+ currentSort === ProductSortKeys.Price && currentOrder === "asc"
25
+ ? "PRICE_asc"
26
+ : currentSort === ProductSortKeys.Price && currentOrder === "desc"
27
+ ? "PRICE_desc"
28
+ : "RELEVANCE";
29
+
30
+ const handleSortChange = useCallback(
31
+ (e: React.ChangeEvent<HTMLSelectElement>) => {
32
+ const value = e.target.value;
33
+ const params = new URLSearchParams(searchParams.toString());
34
+
35
+ if (value === ProductSortKeys.Relevance) {
36
+ params.delete("sort");
37
+ params.delete("order");
38
+ } else {
39
+ // Parse combined sort value (e.g., "PRICE_asc")
40
+ const [sortKey, order] = value.split("_");
41
+ params.set("sort", sortKey);
42
+ params.set("order", order);
43
+ }
44
+
45
+ // Reset pagination when sort changes
46
+ params.delete("after");
47
+
48
+ router.push(`${pathname}?${params.toString()}`);
49
+ },
50
+ [router, pathname, searchParams]
51
+ );
52
+
53
+ return (
54
+ <select
55
+ value={sortValue}
56
+ onChange={handleSortChange}
57
+ className="rounded border border-gray-200 px-3 py-2 text-sm focus:border-gray-900 focus:outline-none"
58
+ >
59
+ <option value={ProductSortKeys.Relevance}>Relevance</option>
60
+ <option value="PRICE_asc">Price: Low to High</option>
61
+ <option value="PRICE_desc">Price: High to Low</option>
62
+ </select>
63
+ );
64
+ }
@@ -0,0 +1,210 @@
1
+ "use client";
2
+
3
+ import { useState, useMemo, useEffect } from "react";
4
+
5
+ interface VariantOption {
6
+ name: string;
7
+ value: string;
8
+ }
9
+
10
+ interface ProductVariant {
11
+ id: string;
12
+ title: string;
13
+ available: boolean;
14
+ selectedOptions: VariantOption[];
15
+ price: {
16
+ amount: string;
17
+ currencyCode: string;
18
+ };
19
+ compareAtPrice?: {
20
+ amount: string;
21
+ currencyCode: string;
22
+ } | null;
23
+ image?: {
24
+ url: string;
25
+ altText?: string | null;
26
+ } | null;
27
+ }
28
+
29
+ interface VariantSelectorProps {
30
+ variants: ProductVariant[];
31
+ selectedVariantId?: string;
32
+ onVariantChange: (variant: ProductVariant) => void;
33
+ }
34
+
35
+ /**
36
+ * VariantSelector - Select product options (size, color, etc.)
37
+ *
38
+ * Extracts unique options from variants and allows selection.
39
+ * Automatically finds matching variant when options change.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <VariantSelector
44
+ * variants={product.variants}
45
+ * selectedVariantId={selectedVariant?.id}
46
+ * onVariantChange={setSelectedVariant}
47
+ * />
48
+ * ```
49
+ */
50
+ export function VariantSelector({
51
+ variants,
52
+ selectedVariantId,
53
+ onVariantChange,
54
+ }: VariantSelectorProps) {
55
+ // Extract unique option names and their values
56
+ const options = useMemo(() => {
57
+ const optionMap = new Map<string, Set<string>>();
58
+
59
+ variants.forEach((variant) => {
60
+ variant.selectedOptions.forEach((opt) => {
61
+ if (!optionMap.has(opt.name)) {
62
+ optionMap.set(opt.name, new Set());
63
+ }
64
+ optionMap.get(opt.name)!.add(opt.value);
65
+ });
66
+ });
67
+
68
+ return Array.from(optionMap.entries()).map(([name, values]) => ({
69
+ name,
70
+ values: Array.from(values),
71
+ }));
72
+ }, [variants]);
73
+
74
+ // Currently selected values for each option
75
+ const [selectedOptions, setSelectedOptions] = useState<
76
+ Record<string, string>
77
+ >(() => {
78
+ // Initialize from selected variant or first variant
79
+ const initialVariant = selectedVariantId
80
+ ? variants.find((v) => v.id === selectedVariantId)
81
+ : variants[0];
82
+
83
+ if (!initialVariant) return {};
84
+
85
+ return initialVariant.selectedOptions.reduce(
86
+ (acc, opt) => ({
87
+ ...acc,
88
+ [opt.name]: opt.value,
89
+ }),
90
+ {}
91
+ );
92
+ });
93
+
94
+ // Find variant matching current selection
95
+ const findMatchingVariant = (
96
+ opts: Record<string, string>
97
+ ): ProductVariant | undefined => {
98
+ return variants.find((variant) =>
99
+ variant.selectedOptions.every((opt) => opts[opt.name] === opt.value)
100
+ );
101
+ };
102
+
103
+ // Check if a specific option value is available
104
+ const isOptionAvailable = (
105
+ optionName: string,
106
+ optionValue: string
107
+ ): boolean => {
108
+ const testOptions = { ...selectedOptions, [optionName]: optionValue };
109
+ const matchingVariant = findMatchingVariant(testOptions);
110
+ return !!matchingVariant;
111
+ };
112
+
113
+ // Check if option value leads to in-stock variant
114
+ const isOptionInStock = (
115
+ optionName: string,
116
+ optionValue: string
117
+ ): boolean => {
118
+ const testOptions = { ...selectedOptions, [optionName]: optionValue };
119
+ const matchingVariant = findMatchingVariant(testOptions);
120
+ return matchingVariant?.available ?? false;
121
+ };
122
+
123
+ // Handle option selection
124
+ const handleOptionChange = (optionName: string, optionValue: string) => {
125
+ const newOptions = { ...selectedOptions, [optionName]: optionValue };
126
+ setSelectedOptions(newOptions);
127
+
128
+ const matchingVariant = findMatchingVariant(newOptions);
129
+ if (matchingVariant) {
130
+ onVariantChange(matchingVariant);
131
+ }
132
+ };
133
+
134
+ // Sync when selectedVariantId changes externally
135
+ useEffect(() => {
136
+ if (selectedVariantId) {
137
+ const variant = variants.find((v) => v.id === selectedVariantId);
138
+ if (variant) {
139
+ const opts = variant.selectedOptions.reduce(
140
+ (acc, opt) => ({ ...acc, [opt.name]: opt.value }),
141
+ {}
142
+ );
143
+ setSelectedOptions(opts);
144
+ }
145
+ }
146
+ }, [selectedVariantId, variants]);
147
+
148
+ // Sync parent when variants prop changes (e.g., after currency change)
149
+ // This ensures parent gets the updated variant object with new prices
150
+ useEffect(() => {
151
+ if (selectedVariantId && variants.length > 0) {
152
+ const updatedVariant = variants.find((v) => v.id === selectedVariantId);
153
+ if (updatedVariant) {
154
+ // Notify parent with updated variant (containing new prices)
155
+ onVariantChange(updatedVariant);
156
+ }
157
+ }
158
+ }, [variants]); // Only trigger when variants change, not on every render
159
+
160
+ // Don't render if only one variant with no meaningful options
161
+ if (variants.length <= 1 && options.every((o) => o.values.length <= 1)) {
162
+ return null;
163
+ }
164
+
165
+ return (
166
+ <div className="space-y-4">
167
+ {options.map((option) => (
168
+ <div key={option.name}>
169
+ <label className="mb-2 block text-sm font-medium text-gray-700">
170
+ {option.name}
171
+ </label>
172
+ <div className="flex flex-wrap gap-2">
173
+ {option.values.map((value) => {
174
+ const isSelected = selectedOptions[option.name] === value;
175
+ const available = isOptionAvailable(option.name, value);
176
+ const inStock = isOptionInStock(option.name, value);
177
+
178
+ return (
179
+ <button
180
+ key={value}
181
+ type="button"
182
+ onClick={() => handleOptionChange(option.name, value)}
183
+ disabled={!available}
184
+ className={`
185
+ relative min-w-[3rem] rounded-lg border px-4 py-2 text-sm font-medium
186
+ transition-all
187
+ ${
188
+ isSelected
189
+ ? "border-primary bg-primary text-white"
190
+ : available
191
+ ? "border-gray-300 bg-white text-gray-900 hover:border-primary"
192
+ : "cursor-not-allowed border-gray-200 bg-gray-50 text-gray-400"
193
+ }
194
+ ${!inStock && available ? "text-gray-500" : ""}
195
+ `}
196
+ >
197
+ {value}
198
+ {/* Out of stock indicator */}
199
+ {!inStock && available && (
200
+ <span className="absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-white bg-gray-400" />
201
+ )}
202
+ </button>
203
+ );
204
+ })}
205
+ </div>
206
+ </div>
207
+ ))}
208
+ </div>
209
+ );
210
+ }
@@ -0,0 +1,107 @@
1
+ import Link from "next/link";
2
+
3
+ export function Footer() {
4
+ return (
5
+ <footer className="border-t border-gray-200 bg-gray-50">
6
+ <div className="container mx-auto px-4 py-12">
7
+ <div className="grid grid-cols-1 gap-8 md:grid-cols-4">
8
+ {/* Brand */}
9
+ <div>
10
+ <Link href="/" className="text-xl font-bold text-primary">
11
+ {process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}
12
+ </Link>
13
+ <p className="mt-4 text-sm text-gray-600">
14
+ Quality products at affordable prices. Powered by DoSwiftly
15
+ Commerce.
16
+ </p>
17
+ </div>
18
+
19
+ {/* Shop */}
20
+ <div>
21
+ <h3 className="mb-4 font-semibold text-gray-900">Shop</h3>
22
+ <ul className="space-y-2 text-sm text-gray-600">
23
+ <li>
24
+ <Link href="/products" className="hover:text-primary">
25
+ All Products
26
+ </Link>
27
+ </li>
28
+ <li>
29
+ <Link href="/collections" className="hover:text-primary">
30
+ Collections
31
+ </Link>
32
+ </li>
33
+ <li>
34
+ <Link href="/products?sale=true" className="hover:text-primary">
35
+ Sale
36
+ </Link>
37
+ </li>
38
+ </ul>
39
+ </div>
40
+
41
+ {/* Account */}
42
+ <div>
43
+ <h3 className="mb-4 font-semibold text-gray-900">Account</h3>
44
+ <ul className="space-y-2 text-sm text-gray-600">
45
+ <li>
46
+ <Link href="/account" className="hover:text-primary">
47
+ My Account
48
+ </Link>
49
+ </li>
50
+ <li>
51
+ <Link href="/account/orders" className="hover:text-primary">
52
+ Order History
53
+ </Link>
54
+ </li>
55
+ <li>
56
+ <Link href="/cart" className="hover:text-primary">
57
+ Cart
58
+ </Link>
59
+ </li>
60
+ </ul>
61
+ </div>
62
+
63
+ {/* Support */}
64
+ <div>
65
+ <h3 className="mb-4 font-semibold text-gray-900">Support</h3>
66
+ <ul className="space-y-2 text-sm text-gray-600">
67
+ <li>
68
+ <Link href="/contact" className="hover:text-primary">
69
+ Contact Us
70
+ </Link>
71
+ </li>
72
+ <li>
73
+ <Link href="/shipping" className="hover:text-primary">
74
+ Shipping Info
75
+ </Link>
76
+ </li>
77
+ <li>
78
+ <Link href="/returns" className="hover:text-primary">
79
+ Returns & Refunds
80
+ </Link>
81
+ </li>
82
+ </ul>
83
+ </div>
84
+ </div>
85
+
86
+ <div className="mt-12 border-t border-gray-200 pt-8 text-center text-sm text-gray-600">
87
+ <p>
88
+ © {new Date().getFullYear()}{" "}
89
+ {process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}. All rights
90
+ reserved.
91
+ </p>
92
+ <p className="mt-2">
93
+ Powered by{" "}
94
+ <a
95
+ href="https://doswiftly.pl"
96
+ target="_blank"
97
+ rel="noopener noreferrer"
98
+ className="text-primary hover:underline"
99
+ >
100
+ DoSwiftly Commerce
101
+ </a>
102
+ </p>
103
+ </div>
104
+ </div>
105
+ </footer>
106
+ );
107
+ }
@@ -0,0 +1,104 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { useState } from "react";
5
+ import { User, Menu, X } from "lucide-react";
6
+ import CurrencySelector from "@/components/commerce/currency-selector";
7
+ import { CartIcon } from "@/components/commerce/cart-icon";
8
+ import { SearchInput } from "@/components/commerce/search-input";
9
+
10
+ export function Header() {
11
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
12
+
13
+ return (
14
+ <header className="sticky top-0 z-50 border-b border-gray-200 bg-white">
15
+ <div className="container mx-auto px-4">
16
+ <div className="flex h-16 items-center justify-between">
17
+ {/* Logo */}
18
+ <Link href="/" className="text-xl font-bold text-primary">
19
+ {process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}
20
+ </Link>
21
+
22
+ {/* Desktop Navigation */}
23
+ <nav className="hidden items-center gap-6 md:flex">
24
+ <Link href="/products" className="text-gray-600 hover:text-primary">
25
+ Products
26
+ </Link>
27
+ <Link
28
+ href="/collections"
29
+ className="text-gray-600 hover:text-primary"
30
+ >
31
+ Collections
32
+ </Link>
33
+ <Link href="/about" className="text-gray-600 hover:text-primary">
34
+ About
35
+ </Link>
36
+ </nav>
37
+
38
+ {/* Search & Actions */}
39
+ <div className="flex items-center gap-4">
40
+ {/* Search */}
41
+ <div className="hidden w-64 lg:block">
42
+ <SearchInput placeholder="Search..." />
43
+ </div>
44
+ {/* Currency Selector */}
45
+ <div className="hidden md:block">
46
+ <CurrencySelector variant="compact" />
47
+ </div>
48
+ <Link
49
+ href="/account"
50
+ className="p-2 text-gray-600 hover:text-primary"
51
+ >
52
+ <User className="h-5 w-5" />
53
+ </Link>
54
+ <CartIcon />
55
+ <button
56
+ className="p-2 text-gray-600 md:hidden"
57
+ onClick={() => setIsMenuOpen(!isMenuOpen)}
58
+ >
59
+ {isMenuOpen ? (
60
+ <X className="h-5 w-5" />
61
+ ) : (
62
+ <Menu className="h-5 w-5" />
63
+ )}
64
+ </button>
65
+ </div>
66
+ </div>
67
+
68
+ {/* Mobile Navigation */}
69
+ {isMenuOpen && (
70
+ <nav className="border-t border-gray-200 py-4 md:hidden">
71
+ <div className="flex flex-col gap-4">
72
+ {/* Mobile Currency Selector */}
73
+ <div className="flex items-center justify-between">
74
+ <span className="text-sm text-gray-500">Currency</span>
75
+ <CurrencySelector variant="compact" />
76
+ </div>
77
+ <Link
78
+ href="/products"
79
+ className="text-gray-600 hover:text-primary"
80
+ onClick={() => setIsMenuOpen(false)}
81
+ >
82
+ Products
83
+ </Link>
84
+ <Link
85
+ href="/collections"
86
+ className="text-gray-600 hover:text-primary"
87
+ onClick={() => setIsMenuOpen(false)}
88
+ >
89
+ Collections
90
+ </Link>
91
+ <Link
92
+ href="/about"
93
+ className="text-gray-600 hover:text-primary"
94
+ onClick={() => setIsMenuOpen(false)}
95
+ >
96
+ About
97
+ </Link>
98
+ </div>
99
+ </nav>
100
+ )}
101
+ </div>
102
+ </header>
103
+ );
104
+ }
@@ -0,0 +1,62 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Providers - Client-side providers wrapper
5
+ *
6
+ * Uses StorefrontProvider from commerce-sdk which handles:
7
+ * - Currency management with persistence
8
+ * - Authentication state
9
+ * - React Query for data fetching
10
+ * - Dynamic SDK headers (currency changes trigger automatic data refetch)
11
+ *
12
+ * @module storefront-nextjs/components/providers
13
+ */
14
+
15
+ import { ReactNode } from "react";
16
+ import { StorefrontProvider } from "@doswiftly/commerce-sdk/graphql/react";
17
+
18
+ // ============================================================================
19
+ // TYPES
20
+ // ============================================================================
21
+
22
+ interface ProvidersProps {
23
+ children: ReactNode;
24
+ }
25
+
26
+ // ============================================================================
27
+ // COMPONENT
28
+ // ============================================================================
29
+
30
+ /**
31
+ * Providers - Wraps the app with StorefrontProvider
32
+ *
33
+ * The StorefrontProvider handles:
34
+ * 1. Fetching shop configuration (currencies, etc.)
35
+ * 2. Managing currency state with cookie persistence
36
+ * 3. Managing auth token state
37
+ * 4. Providing React Query client for data caching
38
+ * 5. Dynamic SDK headers - when currency changes, all data refetches automatically
39
+ *
40
+ * NOTE: We must pass apiUrl and shopSlug explicitly because NEXT_PUBLIC_* env vars
41
+ * are only inlined in Next.js app code, not in external packages like commerce-sdk.
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * // In layout.tsx
46
+ * <Providers>
47
+ * <Header />
48
+ * <main>{children}</main>
49
+ * <Footer />
50
+ * </Providers>
51
+ * ```
52
+ */
53
+ export function Providers({ children }: ProvidersProps) {
54
+ return (
55
+ <StorefrontProvider
56
+ apiUrl={process.env.NEXT_PUBLIC_API_URL!}
57
+ shopSlug={process.env.NEXT_PUBLIC_SHOP_SLUG!}
58
+ >
59
+ {children}
60
+ </StorefrontProvider>
61
+ );
62
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Auth Routes Configuration (SSOT)
3
+ *
4
+ * This file is the single source of truth for authentication routes.
5
+ * Used by middleware.ts and can be imported by components if needed.
6
+ *
7
+ * @example
8
+ * // Add new protected route
9
+ * export const protectedRoutes = ['/account', '/checkout', '/wishlist'];
10
+ *
11
+ * @example
12
+ * // Add new guest-only route
13
+ * export const guestOnlyRoutes = ['/auth/login', '/auth/register', '/auth/forgot-password'];
14
+ */
15
+
16
+ /**
17
+ * Routes that require authentication.
18
+ * Unauthenticated users will be redirected to login.
19
+ */
20
+ export const protectedRoutes = ["/account", "/checkout"];
21
+
22
+ /**
23
+ * Routes only accessible to guests (unauthenticated users).
24
+ * Authenticated users will be redirected to account.
25
+ */
26
+ export const guestOnlyRoutes = ["/auth/login", "/auth/register"];
27
+
28
+ /**
29
+ * Cookie name for customer access token.
30
+ * Must match the cookie name used by commerce-sdk.
31
+ */
32
+ export const AUTH_COOKIE_NAME = "customerAccessToken";
33
+
34
+ /**
35
+ * Default redirect paths
36
+ */
37
+ export const redirects = {
38
+ /** Where to redirect unauthenticated users trying to access protected routes */
39
+ unauthenticated: "/auth/login",
40
+ /** Where to redirect authenticated users trying to access guest-only routes */
41
+ authenticated: "/account",
42
+ } as const;
43
+
44
+ /**
45
+ * Check if a pathname matches any route in the list.
46
+ * Supports both exact matches and prefix matches (e.g., /account matches /account/orders).
47
+ */
48
+ export function matchesRoute(pathname: string, routes: string[]): boolean {
49
+ return routes.some(
50
+ (route) => pathname === route || pathname.startsWith(`${route}/`)
51
+ );
52
+ }