@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.
- package/README.md +23 -323
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +43 -20
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/sdk.js +5 -5
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.js +4 -4
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/types.js +5 -5
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/lib/package-manager.d.ts +1 -1
- package/dist/lib/package-manager.js +1 -1
- package/package.json +1 -1
- package/templates/storefront-minimal/wrangler.toml +4 -0
- package/templates/storefront-nextjs/README.md +16 -12
- package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs/app/account/page.tsx +2 -2
- package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
- package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
- package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
- package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
- package/templates/storefront-nextjs/app/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/page.tsx +2 -2
- package/templates/storefront-nextjs/app/search/page.tsx +1 -1
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
- package/templates/storefront-nextjs/components/providers.tsx +1 -1
- package/templates/storefront-nextjs/lib/currency.tsx +3 -3
- package/templates/storefront-nextjs/lib/format.ts +1 -1
- package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
- package/templates/storefront-nextjs/package.dev.json +1 -1
- package/templates/storefront-nextjs/package.json +1 -1
- package/templates/storefront-nextjs/package.json.template +1 -1
- package/templates/storefront-nextjs/wrangler.toml +4 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
- package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
- package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
- package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
- package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
- package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
- package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
- package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
- package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
- package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
- package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
- package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
- package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +12 -13
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
- package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
- package/templates/storefront-nextjs-shadcn/wrangler.toml +4 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
- package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
- package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
- 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 "
|
|
5
|
-
import { formatAmount } from "
|
|
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
|
|
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:
|
|
8
|
+
products: ProductCardFields[];
|
|
8
9
|
title?: string;
|
|
9
10
|
className?: string;
|
|
10
11
|
columns?: 2 | 3 | 4;
|
|
@@ -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
|
|
5
|
+
import { type ThemeProviderProps } from "next-themes";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* ThemeProvider - Provides theme context (light/dark/system)
|
|
@@ -248,8 +248,9 @@ export function ReturnRequestForm({
|
|
|
248
248
|
});
|
|
249
249
|
|
|
250
250
|
setSubmitSuccess(true);
|
|
251
|
-
} catch (error:
|
|
252
|
-
|
|
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
|
|
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:
|
|
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 {
|
|
17
|
-
|
|
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
|
|
24
|
+
const { getTotalItems } = useWishlistStore();
|
|
25
|
+
const isHydrated = useHydrated();
|
|
24
26
|
|
|
25
27
|
const totalItems = getTotalItems();
|
|
26
28
|
|