@doswiftly/cli 0.1.18 → 0.1.19

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 (210) 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.map +1 -1
  5. package/dist/commands/deploy.js +39 -20
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/commands/doctor.js +3 -3
  8. package/dist/commands/doctor.js.map +1 -1
  9. package/dist/commands/init.js +4 -4
  10. package/dist/commands/sdk.js +5 -5
  11. package/dist/commands/sdk.js.map +1 -1
  12. package/dist/commands/template.js +4 -4
  13. package/dist/commands/template.js.map +1 -1
  14. package/dist/commands/types.js +5 -5
  15. package/dist/commands/types.js.map +1 -1
  16. package/dist/commands/verify.js +2 -2
  17. package/dist/commands/verify.js.map +1 -1
  18. package/dist/lib/package-manager.d.ts +1 -1
  19. package/dist/lib/package-manager.js +1 -1
  20. package/package.json +1 -1
  21. package/templates/storefront-nextjs/README.md +16 -12
  22. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  23. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  24. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  25. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  26. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  27. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  28. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  29. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/page.tsx +1 -1
  32. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  34. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  35. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  36. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  37. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  38. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  39. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  40. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  43. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  44. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  45. package/templates/storefront-nextjs/lib/format.ts +1 -1
  46. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  47. package/templates/storefront-nextjs/package.dev.json +1 -1
  48. package/templates/storefront-nextjs/package.json +1 -1
  49. package/templates/storefront-nextjs/package.json.template +1 -1
  50. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  51. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  52. package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
  53. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  54. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
  55. package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
  56. package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
  57. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
  58. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
  59. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
  60. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
  61. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
  62. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
  63. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  64. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  65. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
  66. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
  67. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
  68. package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
  69. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
  70. package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
  71. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
  72. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
  73. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
  74. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
  75. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
  76. package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
  77. package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
  78. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
  79. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
  80. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
  81. package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
  82. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
  83. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  84. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  85. package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
  86. package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
  87. package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
  88. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
  89. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
  90. package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
  91. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
  92. package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
  93. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
  94. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  95. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  96. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
  97. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
  98. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  99. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
  100. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
  101. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
  102. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
  103. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
  104. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
  105. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  106. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
  107. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
  108. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
  109. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
  110. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
  111. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  112. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
  113. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
  114. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  115. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
  116. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
  117. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  118. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
  119. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  120. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  121. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
  122. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  123. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
  124. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
  125. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  126. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  127. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
  128. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  129. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  130. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  131. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
  132. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
  133. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
  134. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
  135. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  136. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  137. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
  138. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  139. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
  140. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  141. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
  142. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  143. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  144. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
  145. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  146. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  147. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  148. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
  149. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  150. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  151. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  152. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
  153. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  154. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  155. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
  156. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  157. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  158. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  159. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  160. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  161. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  162. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  163. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
  164. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
  165. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  166. package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
  167. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  168. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  169. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
  170. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
  171. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  172. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  173. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
  174. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  175. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
  176. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
  177. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
  178. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  179. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  180. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  181. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  182. package/templates/storefront-nextjs-shadcn/package.json +12 -13
  183. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  184. package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
  185. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
  186. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  187. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  188. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  189. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  190. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  191. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  192. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  193. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  194. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  195. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  196. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  197. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  198. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  199. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  200. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  201. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  202. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  203. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  204. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  205. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  206. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  207. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  208. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  209. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  210. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
@@ -1,307 +0,0 @@
1
- # Product Detail Page Implementation
2
-
3
- ## Overview
4
-
5
- This document describes the implementation of the product detail page (Task 21) following the Next.js 15+ App Router architecture with Server Components and Client Components.
6
-
7
- ## Implementation Summary
8
-
9
- ### Files Created/Modified
10
-
11
- 1. **`app/products/[slug]/page.tsx`** - Server Component (MODIFIED)
12
- - Converted from Client Component to Server Component
13
- - Added metadata generation for SEO
14
- - Added structured data (JSON-LD) for search engines
15
- - Added static params generation for top 100 products
16
- - Implemented ISR with 60-second revalidation
17
-
18
- 2. **`app/products/[slug]/product-client.tsx`** - Client Component (MODIFIED)
19
- - Enhanced to handle SSR hydration with currency switching
20
- - Added logic to refetch product data when user's preferred currency differs from SSR currency
21
- - Added `suppressHydrationWarning` to prevent hydration mismatches
22
- - Maintains selected variant across currency changes
23
-
24
- 3. **`app/not-found.tsx`** - 404 Page (CREATED)
25
- - Created custom 404 page for better error handling
26
- - Provides helpful navigation back to the site
27
-
28
- ## Architecture
29
-
30
- ### Server Component Flow
31
-
32
- ```
33
- 1. Build Time (SSG)
34
- ├─ generateStaticParams() fetches top 100 products
35
- ├─ Pre-renders pages for each product handle
36
- └─ Uses base currency (no X-Preferred-Currency header)
37
-
38
- 2. Request Time
39
- ├─ Server Component fetches product data (base currency)
40
- ├─ Generates metadata (title, description, Open Graph)
41
- ├─ Generates JSON-LD structured data
42
- └─ Passes initial data to Client Component
43
-
44
- 3. ISR Revalidation
45
- └─ Pages revalidate every 60 seconds
46
- ```
47
-
48
- ### Client Component Flow
49
-
50
- ```
51
- 1. Initial Render
52
- ├─ Receives product data from Server Component (base currency)
53
- ├─ Displays product with SSR data
54
- └─ suppressHydrationWarning prevents mismatch
55
-
56
- 2. Currency Store Initialization
57
- ├─ CurrencyProvider initializes from Shop data
58
- ├─ Checks localStorage for saved currency
59
- ├─ Detects browser locale
60
- └─ Sets preferred currency
61
-
62
- 3. Currency-Aware Refetch
63
- ├─ Compares preferred currency vs SSR currency
64
- ├─ If different, refetches product with new currency
65
- ├─ Updates prices dynamically
66
- └─ Maintains selected variant
67
- ```
68
-
69
- ## Key Features
70
-
71
- ### 1. Metadata Generation (Requirement 13.1, 13.3)
72
-
73
- ```typescript
74
- export async function generateMetadata({ params }): Promise<Metadata> {
75
- const data = await fetchProduct(params.slug);
76
- const product = data?.product;
77
-
78
- return {
79
- title: product.title,
80
- description: product.description,
81
- openGraph: {
82
- title: product.title,
83
- description: product.description,
84
- images: [product.images[0]],
85
- },
86
- twitter: {
87
- card: "summary_large_image",
88
- // ...
89
- },
90
- };
91
- }
92
- ```
93
-
94
- **Benefits:**
95
- - Improved SEO with proper meta tags
96
- - Better social media sharing with Open Graph
97
- - Twitter Card support for rich previews
98
-
99
- ### 2. Structured Data (JSON-LD) (Requirement 13.3)
100
-
101
- ```typescript
102
- const jsonLd = {
103
- "@context": "https://schema.org",
104
- "@type": "Product",
105
- name: product.title,
106
- description: product.description,
107
- image: product.images[0].url,
108
- brand: { "@type": "Brand", name: product.vendor },
109
- offers: {
110
- "@type": "Offer",
111
- price: product.priceRange.minVariantPrice.amount,
112
- priceCurrency: product.priceRange.minVariantPrice.currencyCode,
113
- availability: "https://schema.org/InStock",
114
- },
115
- };
116
- ```
117
-
118
- **Benefits:**
119
- - Rich snippets in search results
120
- - Better product visibility in Google Shopping
121
- - Improved search engine understanding
122
-
123
- ### 3. Static Params Generation (Requirement 2.2, 6.4)
124
-
125
- ```typescript
126
- export async function generateStaticParams() {
127
- const { products } = await fetchProducts({
128
- first: 100,
129
- sortKey: "BEST_SELLING",
130
- });
131
-
132
- return products.map((product) => ({
133
- slug: product.handle,
134
- }));
135
- }
136
- ```
137
-
138
- **Benefits:**
139
- - Pre-renders top 100 products at build time
140
- - Instant page loads for popular products
141
- - Reduced server load
142
- - Better Core Web Vitals scores
143
-
144
- ### 4. SSR with Client Hydration (Requirement 2.2, 3.2, 6.4)
145
-
146
- **Server Component:**
147
- ```typescript
148
- export default async function ProductPage({ params }) {
149
- const data = await fetchProduct(params.slug);
150
- return <ProductClient product={data.product} />;
151
- }
152
- ```
153
-
154
- **Client Component:**
155
- ```typescript
156
- export function ProductClient({ product: initialProduct }) {
157
- const currency = useCurrencyStore((s) => s.currency);
158
- const needsRefetch = currency !== initialProduct.priceRange.minVariantPrice.currencyCode;
159
-
160
- const { data } = useProduct(initialProduct.handle, {
161
- initialData: { product: initialProduct },
162
- enabled: needsRefetch,
163
- });
164
-
165
- const product = data?.product || initialProduct;
166
-
167
- return (
168
- <div suppressHydrationWarning>
169
- <ProductPrice price={product.priceRange.minVariantPrice} />
170
- </div>
171
- );
172
- }
173
- ```
174
-
175
- **Benefits:**
176
- - Fast initial render with SSR
177
- - Dynamic currency switching without page reload
178
- - No hydration mismatches
179
- - Optimal user experience
180
-
181
- ### 5. ISR Configuration
182
-
183
- ```typescript
184
- export const revalidate = 60;
185
- ```
186
-
187
- **Benefits:**
188
- - Pages stay fresh with 60-second revalidation
189
- - Maintains static generation benefits
190
- - Automatic updates when products change
191
- - No manual cache invalidation needed
192
-
193
- ## Requirements Validation
194
-
195
- ✅ **Requirement 2.2**: Server Component renders prices in base currency for SSG
196
- ✅ **Requirement 3.2**: Client Component renders prices in preferred currency
197
- ✅ **Requirement 6.4**: Clear separation between server and client data fetching
198
- ✅ **Requirement 13.1**: Metadata generation with title, description, Open Graph
199
- ✅ **Requirement 13.3**: Structured data (JSON-LD) with Product schema
200
-
201
- ## Testing Recommendations
202
-
203
- ### Manual Testing
204
-
205
- 1. **SSG Verification**
206
- - Build the project: `npm run build`
207
- - Check `.next/server/app/products/[slug]` for pre-rendered pages
208
- - Verify top 100 products are statically generated
209
-
210
- 2. **Metadata Verification**
211
- - View page source in browser
212
- - Check `<head>` for meta tags
213
- - Verify Open Graph tags
214
- - Test social media sharing
215
-
216
- 3. **Structured Data Verification**
217
- - View page source
218
- - Find `<script type="application/ld+json">`
219
- - Validate with Google's Rich Results Test
220
- - Check schema.org compliance
221
-
222
- 4. **Currency Switching**
223
- - Load product page (should show base currency)
224
- - Change currency in selector
225
- - Verify prices update without page reload
226
- - Check no hydration warnings in console
227
-
228
- 5. **ISR Verification**
229
- - Update product in backend
230
- - Wait 60 seconds
231
- - Refresh page
232
- - Verify changes appear
233
-
234
- ### Automated Testing
235
-
236
- ```typescript
237
- // Example test for metadata generation
238
- describe('Product Page Metadata', () => {
239
- it('should generate correct metadata', async () => {
240
- const metadata = await generateMetadata({ params: { slug: 'test-product' } });
241
- expect(metadata.title).toBeDefined();
242
- expect(metadata.description).toBeDefined();
243
- expect(metadata.openGraph).toBeDefined();
244
- });
245
- });
246
-
247
- // Example test for static params
248
- describe('Static Params Generation', () => {
249
- it('should generate params for top products', async () => {
250
- const params = await generateStaticParams();
251
- expect(params.length).toBeGreaterThan(0);
252
- expect(params[0]).toHaveProperty('slug');
253
- });
254
- });
255
- ```
256
-
257
- ## Performance Considerations
258
-
259
- 1. **Static Generation**: Top 100 products are pre-rendered at build time
260
- 2. **ISR**: Pages revalidate every 60 seconds for fresh data
261
- 3. **React Cache**: Server-side requests are deduplicated within a render
262
- 4. **Client-side Caching**: React Query caches product data with currency in key
263
- 5. **Image Optimization**: Next.js Image component handles optimization
264
-
265
- ## Future Enhancements
266
-
267
- 1. **Related Products**: Add similar products section based on tags/category
268
- 2. **Product Reviews**: Integrate review system with structured data
269
- 3. **Variant Images**: Show variant-specific images when variant changes
270
- 4. **Breadcrumbs**: Add dynamic breadcrumbs based on product category
271
- 5. **Share Buttons**: Add social media share buttons
272
- 6. **Recently Viewed**: Track and display recently viewed products
273
-
274
- ## Troubleshooting
275
-
276
- ### Hydration Mismatch Errors
277
-
278
- **Problem**: Console shows hydration mismatch warnings
279
- **Solution**: Ensure `suppressHydrationWarning` is on price elements
280
-
281
- ### Currency Not Switching
282
-
283
- **Problem**: Prices don't update when currency changes
284
- **Solution**: Check currency store initialization and query key includes currency
285
-
286
- ### 404 Errors
287
-
288
- **Problem**: Product pages return 404
289
- **Solution**: Verify product handle matches exactly, check generateStaticParams
290
-
291
- ### Metadata Not Showing
292
-
293
- **Problem**: Meta tags not appearing in page source
294
- **Solution**: Ensure generateMetadata is async and returns Metadata object
295
-
296
- ## Conclusion
297
-
298
- The product detail page implementation follows Next.js 15+ best practices with:
299
- - Server Components for optimal performance
300
- - Client Components for interactivity
301
- - Proper metadata for SEO
302
- - Structured data for search engines
303
- - Static generation for popular products
304
- - ISR for fresh data
305
- - Currency-aware price display
306
-
307
- This implementation satisfies all requirements (2.2, 3.2, 6.4, 13.1, 13.3) and provides a solid foundation for a production-ready e-commerce storefront.
@@ -1,245 +0,0 @@
1
- # Theme Customization Guide
2
-
3
- This guide explains how to customize the theme colors and appearance of your storefront.
4
-
5
- ## Overview
6
-
7
- The storefront uses a theme system based on CSS variables and Tailwind CSS v4. The theme supports:
8
- - Light mode
9
- - Dark mode
10
- - System preference detection
11
- - Smooth transitions between themes
12
- - Persistent theme selection (localStorage)
13
-
14
- ## Theme Configuration
15
-
16
- The main theme configuration is located in `lib/theme/theme-config.ts`:
17
-
18
- ```typescript
19
- export const themeConfig = {
20
- defaultTheme: "system",
21
- themes: ["light", "dark", "system"],
22
- enableSystem: true,
23
- disableTransitionOnChange: false,
24
- storageKey: "doswiftly-theme",
25
- attribute: "class",
26
- colors: {
27
- light: { /* ... */ },
28
- dark: { /* ... */ }
29
- }
30
- }
31
- ```
32
-
33
- ## Customizing Colors
34
-
35
- ### Method 1: Update CSS Variables (Recommended)
36
-
37
- Edit `app/globals.css` to change theme colors:
38
-
39
- ```css
40
- @theme {
41
- /* Light mode colors */
42
- --color-primary: rgb(59 130 246); /* Change this */
43
- --color-primary-foreground: rgb(255 255 255);
44
- /* ... other colors */
45
- }
46
-
47
- .dark {
48
- /* Dark mode colors */
49
- --color-primary: rgb(96 165 250); /* Change this */
50
- --color-primary-foreground: rgb(15 23 42);
51
- /* ... other colors */
52
- }
53
- ```
54
-
55
- ### Method 2: Update Theme Config
56
-
57
- Edit `lib/theme/theme-config.ts`:
58
-
59
- ```typescript
60
- export const themeConfig = {
61
- // ...
62
- colors: {
63
- light: {
64
- primary: "220 90% 56%", // HSL format
65
- // ...
66
- },
67
- dark: {
68
- primary: "220 90% 70%",
69
- // ...
70
- }
71
- }
72
- }
73
- ```
74
-
75
- ## Available Color Variables
76
-
77
- The following CSS variables are available for customization:
78
-
79
- ### Core Colors
80
- - `--color-background` - Main background color
81
- - `--color-foreground` - Main text color
82
- - `--color-primary` - Primary brand color
83
- - `--color-primary-foreground` - Text on primary color
84
- - `--color-secondary` - Secondary brand color
85
- - `--color-secondary-foreground` - Text on secondary color
86
-
87
- ### UI Colors
88
- - `--color-muted` - Muted background (for disabled states, etc.)
89
- - `--color-muted-foreground` - Muted text color
90
- - `--color-accent` - Accent color (for highlights)
91
- - `--color-accent-foreground` - Text on accent color
92
- - `--color-border` - Border color
93
- - `--color-ring` - Focus ring color
94
-
95
- ### Component Colors
96
- - `--color-card` - Card background
97
- - `--color-card-foreground` - Card text
98
- - `--color-destructive` - Error/danger color
99
- - `--color-destructive-foreground` - Text on destructive color
100
-
101
- ## Brand Color Examples
102
-
103
- ### Blue Theme (Default)
104
- ```css
105
- --color-primary: rgb(59 130 246); /* blue-500 */
106
- ```
107
-
108
- ### Green Theme
109
- ```css
110
- --color-primary: rgb(34 197 94); /* green-500 */
111
- --color-accent: rgb(74 222 128); /* green-400 */
112
- ```
113
-
114
- ### Purple Theme
115
- ```css
116
- --color-primary: rgb(168 85 247); /* purple-500 */
117
- --color-accent: rgb(192 132 252); /* purple-400 */
118
- ```
119
-
120
- ### Orange Theme
121
- ```css
122
- --color-primary: rgb(249 115 22); /* orange-500 */
123
- --color-accent: rgb(251 146 60); /* orange-400 */
124
- ```
125
-
126
- ## Theme Switcher Components
127
-
128
- Three theme switcher variants are available:
129
-
130
- ### 1. Simple Toggle (Default)
131
- ```tsx
132
- import { ThemeSwitcher } from "@/components/layout/theme-switcher";
133
-
134
- <ThemeSwitcher />
135
- ```
136
-
137
- ### 2. Dropdown Menu
138
- ```tsx
139
- import { ThemeSwitcherDropdown } from "@/components/layout/theme-switcher";
140
-
141
- <ThemeSwitcherDropdown />
142
- ```
143
-
144
- ### 3. Compact Buttons
145
- ```tsx
146
- import { ThemeSwitcherCompact } from "@/components/layout/theme-switcher";
147
-
148
- <ThemeSwitcherCompact showLabel />
149
- ```
150
-
151
- ## Programmatic Theme Control
152
-
153
- Use the `useTheme` hook from `next-themes`:
154
-
155
- ```tsx
156
- "use client";
157
-
158
- import { useTheme } from "next-themes";
159
-
160
- export function MyComponent() {
161
- const { theme, setTheme, systemTheme } = useTheme();
162
-
163
- return (
164
- <button onClick={() => setTheme("dark")}>
165
- Switch to Dark Mode
166
- </button>
167
- );
168
- }
169
- ```
170
-
171
- ## Disable Theme Transitions
172
-
173
- To disable transitions when theme changes (prevents flash):
174
-
175
- ```typescript
176
- // lib/theme/theme-config.ts
177
- export const themeConfig = {
178
- // ...
179
- disableTransitionOnChange: true, // Set to true
180
- }
181
- ```
182
-
183
- ## Custom Theme Storage
184
-
185
- To use a different storage key:
186
-
187
- ```typescript
188
- // lib/theme/theme-config.ts
189
- export const themeConfig = {
190
- // ...
191
- storageKey: "my-custom-theme-key",
192
- }
193
- ```
194
-
195
- ## Force a Specific Theme
196
-
197
- To force light or dark mode without system detection:
198
-
199
- ```typescript
200
- // lib/theme/theme-config.ts
201
- export const themeConfig = {
202
- defaultTheme: "light", // or "dark"
203
- enableSystem: false, // Disable system detection
204
- }
205
- ```
206
-
207
- ## Testing Themes
208
-
209
- 1. **Manual Testing**: Use the theme switcher in the header
210
- 2. **Browser DevTools**: Toggle dark mode in DevTools
211
- 3. **System Preference**: Change your OS theme settings
212
-
213
- ## Troubleshooting
214
-
215
- ### Theme Flashing on Page Load
216
-
217
- Add `suppressHydrationWarning` to the `<html>` tag (already done in `app/layout.tsx`):
218
-
219
- ```tsx
220
- <html lang="en" suppressHydrationWarning>
221
- ```
222
-
223
- ### Theme Not Persisting
224
-
225
- Check that localStorage is enabled and the storage key is correct in `theme-config.ts`.
226
-
227
- ### Colors Not Updating
228
-
229
- 1. Clear browser cache
230
- 2. Restart dev server
231
- 3. Check CSS variable names match in both `globals.css` and components
232
-
233
- ## Best Practices
234
-
235
- 1. **Use CSS Variables**: Always use CSS variables instead of hardcoded colors
236
- 2. **Test Both Themes**: Ensure your custom colors work in both light and dark mode
237
- 3. **Maintain Contrast**: Ensure sufficient contrast for accessibility (WCAG AA)
238
- 4. **Consistent Naming**: Keep color variable names consistent across themes
239
- 5. **Document Changes**: Document any custom color choices for your team
240
-
241
- ## Resources
242
-
243
- - [next-themes Documentation](https://github.com/pacocoursey/next-themes)
244
- - [Tailwind CSS v4 Documentation](https://tailwindcss.com/docs)
245
- - [WCAG Contrast Checker](https://webaim.org/resources/contrastchecker/)
@@ -1,103 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * CurrencyProvider - Initializes currency store with Shop data
5
- *
6
- * This provider:
7
- * 1. Receives Shop data from server (via root layout)
8
- * 2. Initializes currency store on mount
9
- * 3. Handles currency detection from:
10
- * - localStorage (saved preference)
11
- * - Browser locale (auto-detection)
12
- * - Shop base currency (fallback)
13
- *
14
- * The currency store manages:
15
- * - User's preferred currency
16
- * - Supported currencies list
17
- * - Base currency for the shop
18
- * - Persistence to localStorage
19
- *
20
- * @module storefront-nextjs/components/providers/currency-provider
21
- */
22
-
23
- import { useEffect, type ReactNode } from 'react';
24
- import { useCurrencyStore, type ShopCurrencyData } from '@/stores/currency-store';
25
-
26
- // ============================================================================
27
- // TYPES
28
- // ============================================================================
29
-
30
- interface CurrencyProviderProps {
31
- /**
32
- * Shop data containing currency configuration
33
- * Fetched from GraphQL Shop query in root layout
34
- */
35
- shopData: ShopCurrencyData;
36
-
37
- /**
38
- * Child components
39
- */
40
- children: ReactNode;
41
- }
42
-
43
- // ============================================================================
44
- // COMPONENT
45
- // ============================================================================
46
-
47
- /**
48
- * CurrencyProvider - Initializes currency store with Shop data
49
- *
50
- * This component should be placed in the root layout after fetching Shop data.
51
- * It initializes the currency store once on mount, which triggers:
52
- * 1. Loading saved currency from localStorage (if valid)
53
- * 2. Auto-detecting currency from browser locale (if no saved preference)
54
- * 3. Falling back to shop's base currency
55
- *
56
- * The initialization only happens once per session. Subsequent currency changes
57
- * are handled by the currency store's setCurrency action.
58
- *
59
- * @example
60
- * ```tsx
61
- * // app/layout.tsx
62
- * import { fetchShop } from '@/lib/graphql/server';
63
- * import { CurrencyProvider } from '@/components/providers/currency-provider';
64
- *
65
- * export default async function RootLayout({ children }) {
66
- * const { shop } = await fetchShop();
67
- *
68
- * return (
69
- * <html lang="en">
70
- * <body>
71
- * <QueryProvider>
72
- * <CurrencyProvider shopData={shop}>
73
- * <Header />
74
- * <main>{children}</main>
75
- * <Footer />
76
- * </CurrencyProvider>
77
- * </QueryProvider>
78
- * </body>
79
- * </html>
80
- * );
81
- * }
82
- * ```
83
- *
84
- * @param props - Component props
85
- * @param props.shopData - Shop currency configuration
86
- * @param props.children - Child components to render
87
- */
88
- export function CurrencyProvider({ shopData, children }: CurrencyProviderProps) {
89
- const initialize = useCurrencyStore((state: any) => state.initialize);
90
-
91
- useEffect(() => {
92
- // Initialize currency store with Shop data
93
- // This will:
94
- // 1. Set base currency and supported currencies
95
- // 2. Restore saved currency from localStorage (if valid)
96
- // 3. Auto-detect from browser locale (if no saved preference)
97
- // 4. Fall back to base currency
98
- initialize(shopData);
99
- }, [shopData, initialize]);
100
-
101
- // Simply render children - the store initialization happens in the background
102
- return <>{children}</>;
103
- }