@doswiftly/cli 0.1.17 → 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 (213) 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 +43 -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-minimal/wrangler.toml +4 -0
  22. package/templates/storefront-nextjs/README.md +16 -12
  23. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  24. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  25. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  26. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  27. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  28. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  29. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  32. package/templates/storefront-nextjs/app/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  34. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  35. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  36. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  37. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  38. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  39. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  40. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  43. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  44. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  45. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  46. package/templates/storefront-nextjs/lib/format.ts +1 -1
  47. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  48. package/templates/storefront-nextjs/package.dev.json +1 -1
  49. package/templates/storefront-nextjs/package.json +1 -1
  50. package/templates/storefront-nextjs/package.json.template +1 -1
  51. package/templates/storefront-nextjs/wrangler.toml +4 -0
  52. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  53. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  54. package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
  55. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  56. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
  57. package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
  58. package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
  59. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
  60. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
  61. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
  62. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
  63. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
  64. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
  65. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  66. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  67. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
  68. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
  69. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
  70. package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
  71. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
  72. package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
  73. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
  74. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
  75. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
  76. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
  77. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
  78. package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
  79. package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
  80. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
  81. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
  82. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
  83. package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
  84. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
  85. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  86. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  87. package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
  88. package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
  89. package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
  90. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
  91. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
  92. package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
  93. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
  94. package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
  95. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
  96. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  97. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  98. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
  99. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
  100. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  101. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
  102. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
  103. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
  104. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
  105. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
  106. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
  107. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  108. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
  109. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
  110. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
  111. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
  112. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
  113. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  114. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
  115. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
  116. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  117. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
  118. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
  119. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  120. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
  121. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  122. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  123. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
  124. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  125. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
  126. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
  127. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  128. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  129. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
  130. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  131. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  132. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  133. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
  134. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
  135. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
  136. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
  137. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  138. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  139. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
  140. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  141. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
  142. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  143. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
  144. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  145. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  146. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
  147. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  148. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  149. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  150. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
  151. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  152. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  153. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  154. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
  155. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  156. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  157. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
  158. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  159. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  160. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  161. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  162. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  163. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  164. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  165. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
  166. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
  167. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  168. package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
  169. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  170. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  171. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
  172. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
  173. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  174. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  175. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
  176. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  177. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
  178. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
  179. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
  180. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  181. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  182. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  183. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  184. package/templates/storefront-nextjs-shadcn/package.json +12 -13
  185. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  186. package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
  187. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
  188. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  189. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  190. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  191. package/templates/storefront-nextjs-shadcn/wrangler.toml +4 -0
  192. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  193. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  194. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  195. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  196. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  197. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  198. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  199. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  200. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  201. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  202. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  203. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  204. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  205. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  206. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  207. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  208. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  209. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  210. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  211. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  212. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  213. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import { TrendingDown, DollarSign, Percent } from "lucide-react";
4
- import { useCurrencyStore } from "@/stores/currency-store";
5
- import { formatAmount } from "@/lib/format";
4
+ import { useCurrencyStore } from "@doswiftly/storefront-sdk/react";
5
+ import { formatAmount } from "@doswiftly/storefront-sdk";
6
6
 
7
7
  export interface SavingsDisplayProps {
8
8
  originalPrice: number;
@@ -27,10 +27,15 @@ export function SavingsDisplay({
27
27
  className = "",
28
28
  }: SavingsDisplayProps) {
29
29
  const preferredCurrency = useCurrencyStore((state) => state.currency);
30
+ const isLoaded = useCurrencyStore((state) => state.isLoaded);
30
31
  const finalCurrency = currency || preferredCurrency || "PLN";
31
32
 
32
33
  if (salePrice >= originalPrice) return null;
33
34
 
35
+ if (!isLoaded && !currency) {
36
+ return <span className={`inline-block h-4 w-20 animate-pulse rounded bg-muted ${className}`} />;
37
+ }
38
+
34
39
  const savingsAmount = originalPrice - salePrice;
35
40
  const savingsPercentage = Math.round(
36
41
  (savingsAmount / originalPrice) * 100
@@ -127,6 +132,7 @@ export function TotalSavings({
127
132
  className = "",
128
133
  }: TotalSavingsProps) {
129
134
  const preferredCurrency = useCurrencyStore((state) => state.currency);
135
+ const isLoaded = useCurrencyStore((state) => state.isLoaded);
130
136
  const finalCurrency = currency || preferredCurrency || "PLN";
131
137
 
132
138
  const totalSavings = items.reduce((sum, item) => {
@@ -136,6 +142,10 @@ export function TotalSavings({
136
142
 
137
143
  if (totalSavings <= 0) return null;
138
144
 
145
+ if (!isLoaded && !currency) {
146
+ return <span className={`inline-block h-5 w-24 animate-pulse rounded bg-muted ${className}`} />;
147
+ }
148
+
139
149
  return (
140
150
  <div
141
151
  className={`flex items-center justify-between rounded-lg bg-green-50 dark:bg-green-900/20 px-4 py-3 ${className}`}
@@ -169,10 +179,15 @@ export function SavingsBreakdown({
169
179
  className = "",
170
180
  }: SavingsBreakdownProps) {
171
181
  const preferredCurrency = useCurrencyStore((state) => state.currency);
182
+ const isLoaded = useCurrencyStore((state) => state.isLoaded);
172
183
  const finalCurrency = currency || preferredCurrency || "PLN";
173
184
 
174
185
  if (salePrice >= originalPrice) return null;
175
186
 
187
+ if (!isLoaded && !currency) {
188
+ return <span className={`inline-block h-24 w-full animate-pulse rounded bg-muted ${className}`} />;
189
+ }
190
+
176
191
  const savingsAmount = originalPrice - salePrice;
177
192
  const savingsPercentage = Math.round(
178
193
  (savingsAmount / originalPrice) * 100
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
 
3
- import { ProductCard, type ProductCardProduct } from "./product-card";
3
+ import { ProductCard } from "./product-card";
4
4
  import { cn } from "@/lib/utils";
5
+ import type { ProductCardFields } from "@/lib/graphql/fragments";
5
6
 
6
7
  export interface SimilarProductsProps {
7
- products: ProductCardProduct[];
8
+ products: ProductCardFields[];
8
9
  title?: string;
9
10
  className?: string;
10
11
  columns?: 2 | 3 | 4;
@@ -4,5 +4,5 @@
4
4
  * @module storefront-nextjs/components/providers
5
5
  */
6
6
 
7
- export { CurrencyProvider } from './currency-provider';
8
7
  export { QueryProvider } from './query-provider';
8
+ export { StoresProvider } from './stores-provider';
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+
3
+ import { useRef, type ReactNode } from 'react';
4
+ import { CartProvider, createCartStore } from '@/stores/cart-store';
5
+ import { CheckoutProvider, createCheckoutStore } from '@/stores/checkout-store';
6
+ import { WishlistProvider, createWishlistStore } from '@/stores/wishlist-store';
7
+
8
+ /**
9
+ * Provides Context-based Zustand stores to the component tree.
10
+ *
11
+ * Creates store instances once via useRef (stable across re-renders)
12
+ * and wraps children in Provider components.
13
+ *
14
+ * Must be placed inside StorefrontProvider (SDK stores) and QueryProvider.
15
+ */
16
+ export function StoresProvider({ children }: { children: ReactNode }) {
17
+ const cartStore = useRef(createCartStore()).current;
18
+ const checkoutStore = useRef(createCheckoutStore()).current;
19
+ const wishlistStore = useRef(createWishlistStore()).current;
20
+
21
+ return (
22
+ <CartProvider store={cartStore}>
23
+ <CheckoutProvider store={checkoutStore}>
24
+ <WishlistProvider store={wishlistStore}>
25
+ {children}
26
+ </WishlistProvider>
27
+ </CheckoutProvider>
28
+ </CartProvider>
29
+ );
30
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from "react";
4
4
  import { ThemeProvider as NextThemesProvider } from "next-themes";
5
- import { type ThemeProviderProps } from "next-themes/dist/types";
5
+ import { type ThemeProviderProps } from "next-themes";
6
6
 
7
7
  /**
8
8
  * ThemeProvider - Provides theme context (light/dark/system)
@@ -9,9 +9,9 @@
9
9
 
10
10
  export {
11
11
  ReturnRequestForm,
12
- ReturnRequestFormSkeleton,
13
12
  type ReturnRequestFormProps,
14
- type EligibleOrderItem,
13
+ type ReturnableItem,
14
+ type ReturnFormData,
15
15
  } from "./return-request-form";
16
16
 
17
17
  export {
@@ -248,8 +248,9 @@ export function ReturnRequestForm({
248
248
  });
249
249
 
250
250
  setSubmitSuccess(true);
251
- } catch (error: any) {
252
- setSubmitError(error.message || "Failed to create return request");
251
+ } catch (error: unknown) {
252
+ const message = error instanceof Error ? error.message : "Failed to create return request";
253
+ setSubmitError(message);
253
254
  } finally {
254
255
  setIsSubmitting(false);
255
256
  }
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
 
3
- import { ProductGrid, type ProductCardProduct } from "@/components/product/product-grid";
3
+ import { ProductGrid } from "@/components/product/product-grid";
4
4
  import { EmptyProducts } from "@/components/ui/empty-state";
5
+ import type { ProductCardFields } from "@/lib/graphql/fragments";
5
6
 
6
7
  export interface SearchResultsProps {
7
8
  query: string;
8
- results: ProductCardProduct[];
9
+ results: ProductCardFields[];
9
10
  }
10
11
 
11
12
  /**
@@ -0,0 +1,174 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import type {
5
+ ControllerProps,
6
+ FieldPath,
7
+ FieldValues,
8
+ } from "react-hook-form"
9
+ import { Controller, FormProvider, useFormContext } from "react-hook-form"
10
+
11
+ import { cn } from "@/lib/utils"
12
+ import { Label } from "@/components/ui/label"
13
+
14
+ const Form = FormProvider
15
+
16
+ type FormFieldContextValue<
17
+ TFieldValues extends FieldValues = FieldValues,
18
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
19
+ > = {
20
+ name: TName
21
+ }
22
+
23
+ const FormFieldContext = React.createContext<FormFieldContextValue>(
24
+ {} as FormFieldContextValue
25
+ )
26
+
27
+ const FormField = <
28
+ TFieldValues extends FieldValues = FieldValues,
29
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
30
+ >({
31
+ ...props
32
+ }: ControllerProps<TFieldValues, TName>) => {
33
+ return (
34
+ <FormFieldContext.Provider value={{ name: props.name }}>
35
+ <Controller {...props} />
36
+ </FormFieldContext.Provider>
37
+ )
38
+ }
39
+
40
+ const useFormField = () => {
41
+ const fieldContext = React.useContext(FormFieldContext)
42
+ const itemContext = React.useContext(FormItemContext)
43
+ const { getFieldState, formState } = useFormContext()
44
+
45
+ const fieldState = getFieldState(fieldContext.name, formState)
46
+
47
+ if (!fieldContext) {
48
+ throw new Error("useFormField should be used within <FormField>")
49
+ }
50
+
51
+ const { id } = itemContext
52
+
53
+ return {
54
+ id,
55
+ name: fieldContext.name,
56
+ formItemId: `${id}-form-item`,
57
+ formDescriptionId: `${id}-form-item-description`,
58
+ formMessageId: `${id}-form-item-message`,
59
+ ...fieldState,
60
+ }
61
+ }
62
+
63
+ type FormItemContextValue = {
64
+ id: string
65
+ }
66
+
67
+ const FormItemContext = React.createContext<FormItemContextValue>(
68
+ {} as FormItemContextValue
69
+ )
70
+
71
+ const FormItem = React.forwardRef<
72
+ HTMLDivElement,
73
+ React.HTMLAttributes<HTMLDivElement>
74
+ >(({ className, ...props }, ref) => {
75
+ const id = React.useId()
76
+
77
+ return (
78
+ <FormItemContext.Provider value={{ id }}>
79
+ <div ref={ref} className={cn("space-y-2", className)} {...props} />
80
+ </FormItemContext.Provider>
81
+ )
82
+ })
83
+ FormItem.displayName = "FormItem"
84
+
85
+ const FormLabel = React.forwardRef<
86
+ React.ElementRef<typeof Label>,
87
+ React.ComponentPropsWithoutRef<typeof Label>
88
+ >(({ className, ...props }, ref) => {
89
+ const { error, formItemId } = useFormField()
90
+
91
+ return (
92
+ <Label
93
+ ref={ref}
94
+ className={cn(error && "text-destructive", className)}
95
+ htmlFor={formItemId}
96
+ {...props}
97
+ />
98
+ )
99
+ })
100
+ FormLabel.displayName = "FormLabel"
101
+
102
+ const FormControl = React.forwardRef<
103
+ HTMLDivElement,
104
+ React.HTMLAttributes<HTMLDivElement>
105
+ >(({ ...props }, ref) => {
106
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
107
+
108
+ return (
109
+ <div
110
+ ref={ref}
111
+ id={formItemId}
112
+ aria-describedby={
113
+ !error
114
+ ? `${formDescriptionId}`
115
+ : `${formDescriptionId} ${formMessageId}`
116
+ }
117
+ aria-invalid={!!error}
118
+ {...props}
119
+ />
120
+ )
121
+ })
122
+ FormControl.displayName = "FormControl"
123
+
124
+ const FormDescription = React.forwardRef<
125
+ HTMLParagraphElement,
126
+ React.HTMLAttributes<HTMLParagraphElement>
127
+ >(({ className, ...props }, ref) => {
128
+ const { formDescriptionId } = useFormField()
129
+
130
+ return (
131
+ <p
132
+ ref={ref}
133
+ id={formDescriptionId}
134
+ className={cn("text-sm text-muted-foreground", className)}
135
+ {...props}
136
+ />
137
+ )
138
+ })
139
+ FormDescription.displayName = "FormDescription"
140
+
141
+ const FormMessage = React.forwardRef<
142
+ HTMLParagraphElement,
143
+ React.HTMLAttributes<HTMLParagraphElement>
144
+ >(({ className, children, ...props }, ref) => {
145
+ const { error, formMessageId } = useFormField()
146
+ const body = error ? String(error?.message) : children
147
+
148
+ if (!body) {
149
+ return null
150
+ }
151
+
152
+ return (
153
+ <p
154
+ ref={ref}
155
+ id={formMessageId}
156
+ className={cn("text-sm font-medium text-destructive", className)}
157
+ {...props}
158
+ >
159
+ {body}
160
+ </p>
161
+ )
162
+ })
163
+ FormMessage.displayName = "FormMessage"
164
+
165
+ export {
166
+ useFormField,
167
+ Form,
168
+ FormItem,
169
+ FormLabel,
170
+ FormControl,
171
+ FormDescription,
172
+ FormMessage,
173
+ FormField,
174
+ }
@@ -13,8 +13,21 @@ export {
13
13
  CardContent,
14
14
  } from './card';
15
15
 
16
- export { Select } from './select';
17
- export type { SelectProps } from './select';
16
+ export {
17
+ Select,
18
+ SelectContent,
19
+ SelectGroup,
20
+ SelectItem,
21
+ SelectLabel,
22
+ SelectScrollDownButton,
23
+ SelectScrollUpButton,
24
+ SelectSeparator,
25
+ SelectTrigger,
26
+ SelectValue,
27
+ } from './select';
28
+
29
+ export { Textarea } from './textarea';
30
+ export type { TextareaProps } from './textarea';
18
31
 
19
32
  export { Badge } from './badge';
20
33
  export type { BadgeProps } from './badge';
@@ -54,6 +67,21 @@ export type {
54
67
  export { Pagination } from './pagination';
55
68
  export type { PaginationProps } from './pagination';
56
69
 
70
+ export { Slider } from './slider';
71
+
72
+ export {
73
+ Sheet,
74
+ SheetTrigger,
75
+ SheetClose,
76
+ SheetContent,
77
+ SheetHeader,
78
+ SheetTitle,
79
+ SheetDescription,
80
+ } from './sheet';
81
+
82
+ export { Progress } from './progress';
83
+ export type { ProgressProps } from './progress';
84
+
57
85
  export { Spinner, SpinnerOverlay } from './spinner';
58
86
  export type { SpinnerProps, SpinnerOverlayProps } from './spinner';
59
87
 
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ value?: number;
8
+ max?: number;
9
+ }
10
+
11
+ const Progress = React.forwardRef<HTMLDivElement, ProgressProps>(
12
+ ({ className, value = 0, max = 100, ...props }, ref) => {
13
+ const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
14
+
15
+ return (
16
+ <div
17
+ ref={ref}
18
+ role="progressbar"
19
+ aria-valuemin={0}
20
+ aria-valuemax={max}
21
+ aria-valuenow={value}
22
+ className={cn(
23
+ "relative h-4 w-full overflow-hidden rounded-full bg-secondary",
24
+ className
25
+ )}
26
+ {...props}
27
+ >
28
+ <div
29
+ className="h-full w-full flex-1 bg-primary transition-all"
30
+ style={{ transform: `translateX(-${100 - percentage}%)` }}
31
+ />
32
+ </div>
33
+ );
34
+ }
35
+ );
36
+
37
+ Progress.displayName = "Progress";
38
+
39
+ export { Progress };
40
+ export type { ProgressProps };
@@ -0,0 +1,107 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
5
+ import { X } from "lucide-react";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ const Sheet = DialogPrimitive.Root;
9
+ const SheetTrigger = DialogPrimitive.Trigger;
10
+ const SheetClose = DialogPrimitive.Close;
11
+ const SheetPortal = DialogPrimitive.Portal;
12
+
13
+ const SheetOverlay = React.forwardRef<
14
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
15
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
16
+ >(({ className, ...props }, ref) => (
17
+ <DialogPrimitive.Overlay
18
+ ref={ref}
19
+ className={cn(
20
+ "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ ));
26
+ SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
27
+
28
+ interface SheetContentProps
29
+ extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
30
+ side?: "left" | "right";
31
+ }
32
+
33
+ const SheetContent = React.forwardRef<
34
+ React.ElementRef<typeof DialogPrimitive.Content>,
35
+ SheetContentProps
36
+ >(({ side = "left", className, children, ...props }, ref) => (
37
+ <SheetPortal>
38
+ <SheetOverlay />
39
+ <DialogPrimitive.Content
40
+ ref={ref}
41
+ className={cn(
42
+ "fixed z-50 flex h-full flex-col gap-4 border bg-background shadow-lg transition-transform duration-300 ease-in-out",
43
+ side === "left" &&
44
+ "inset-y-0 left-0 w-3/4 max-w-sm border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0",
45
+ side === "right" &&
46
+ "inset-y-0 right-0 w-3/4 max-w-sm border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0",
47
+ className
48
+ )}
49
+ {...props}
50
+ >
51
+ {children}
52
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2">
53
+ <X className="h-4 w-4" />
54
+ <span className="sr-only">Close</span>
55
+ </DialogPrimitive.Close>
56
+ </DialogPrimitive.Content>
57
+ </SheetPortal>
58
+ ));
59
+ SheetContent.displayName = "SheetContent";
60
+
61
+ const SheetHeader = ({
62
+ className,
63
+ ...props
64
+ }: React.HTMLAttributes<HTMLDivElement>) => (
65
+ <div
66
+ className={cn(
67
+ "flex flex-col space-y-2 border-b border-border px-4 py-4",
68
+ className
69
+ )}
70
+ {...props}
71
+ />
72
+ );
73
+ SheetHeader.displayName = "SheetHeader";
74
+
75
+ const SheetTitle = React.forwardRef<
76
+ React.ElementRef<typeof DialogPrimitive.Title>,
77
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
78
+ >(({ className, ...props }, ref) => (
79
+ <DialogPrimitive.Title
80
+ ref={ref}
81
+ className={cn("text-lg font-semibold text-foreground", className)}
82
+ {...props}
83
+ />
84
+ ));
85
+ SheetTitle.displayName = DialogPrimitive.Title.displayName;
86
+
87
+ const SheetDescription = React.forwardRef<
88
+ React.ElementRef<typeof DialogPrimitive.Description>,
89
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
90
+ >(({ className, ...props }, ref) => (
91
+ <DialogPrimitive.Description
92
+ ref={ref}
93
+ className={cn("text-sm text-muted-foreground", className)}
94
+ {...props}
95
+ />
96
+ ));
97
+ SheetDescription.displayName = DialogPrimitive.Description.displayName;
98
+
99
+ export {
100
+ Sheet,
101
+ SheetTrigger,
102
+ SheetClose,
103
+ SheetContent,
104
+ SheetHeader,
105
+ SheetTitle,
106
+ SheetDescription,
107
+ };
@@ -0,0 +1,33 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as SliderPrimitive from "@radix-ui/react-slider";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const Slider = React.forwardRef<
8
+ React.ElementRef<typeof SliderPrimitive.Root>,
9
+ React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
10
+ >(({ className, ...props }, ref) => (
11
+ <SliderPrimitive.Root
12
+ ref={ref}
13
+ className={cn(
14
+ "relative flex w-full touch-none select-none items-center",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
20
+ <SliderPrimitive.Range className="absolute h-full bg-primary" />
21
+ </SliderPrimitive.Track>
22
+ {(props.value ?? props.defaultValue ?? [0]).map((_: number, i: number) => (
23
+ <SliderPrimitive.Thumb
24
+ key={i}
25
+ className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
26
+ />
27
+ ))}
28
+ </SliderPrimitive.Root>
29
+ ));
30
+
31
+ Slider.displayName = SliderPrimitive.Root.displayName;
32
+
33
+ export { Slider };
@@ -0,0 +1,24 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ export interface TextareaProps
6
+ extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
7
+
8
+ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
9
+ ({ className, ...props }, ref) => {
10
+ return (
11
+ <textarea
12
+ className={cn(
13
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
14
+ className
15
+ )}
16
+ ref={ref}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+ )
22
+ Textarea.displayName = "Textarea"
23
+
24
+ export { Textarea }
@@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button';
13
13
  import { Badge } from '@/components/ui/badge';
14
14
  import { cn } from '@/lib/utils';
15
15
  import { useWishlistStore } from '@/stores/wishlist-store';
16
+ import { useHydrated } from '@doswiftly/storefront-sdk/react';
16
17
 
17
18
  interface WishlistIconProps {
18
19
  className?: string;
@@ -20,7 +21,8 @@ interface WishlistIconProps {
20
21
  }
21
22
 
22
23
  export function WishlistIcon({ className, showCount = true }: WishlistIconProps) {
23
- const { getTotalItems, isHydrated } = useWishlistStore();
24
+ const { getTotalItems } = useWishlistStore();
25
+ const isHydrated = useHydrated();
24
26
 
25
27
  const totalItems = getTotalItems();
26
28