@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.
- 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 +39 -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-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-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/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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function CheckoutLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
<Skeleton className="mb-8 h-10 w-40" />
|
|
7
|
+
<div className="grid gap-8 lg:grid-cols-5">
|
|
8
|
+
{/* Checkout form */}
|
|
9
|
+
<div className="space-y-6 lg:col-span-3">
|
|
10
|
+
<Skeleton className="h-6 w-48" />
|
|
11
|
+
<div className="space-y-4">
|
|
12
|
+
<div className="grid grid-cols-2 gap-4">
|
|
13
|
+
<Skeleton className="h-10 w-full" />
|
|
14
|
+
<Skeleton className="h-10 w-full" />
|
|
15
|
+
</div>
|
|
16
|
+
<Skeleton className="h-10 w-full" />
|
|
17
|
+
<Skeleton className="h-10 w-full" />
|
|
18
|
+
<div className="grid grid-cols-2 gap-4">
|
|
19
|
+
<Skeleton className="h-10 w-full" />
|
|
20
|
+
<Skeleton className="h-10 w-full" />
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
{/* Order summary */}
|
|
25
|
+
<div className="lg:col-span-2">
|
|
26
|
+
<Skeleton className="h-80 w-full rounded-lg" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import Link from "next/link";
|
|
6
|
+
import { StorefrontError } from "@doswiftly/storefront-sdk";
|
|
6
7
|
import { useCartStore } from "@/stores/cart-store";
|
|
7
8
|
import { useCartSync } from "@/hooks/use-cart-sync";
|
|
8
9
|
import {
|
|
@@ -18,7 +19,7 @@ import {
|
|
|
18
19
|
useCheckoutComplete,
|
|
19
20
|
useCheckout,
|
|
20
21
|
} from "@/lib/graphql/hooks";
|
|
21
|
-
import { formatAmount } from "
|
|
22
|
+
import { formatAmount } from "@doswiftly/storefront-sdk";
|
|
22
23
|
import { Button } from "@/components/ui/button";
|
|
23
24
|
import { Input } from "@/components/ui/input";
|
|
24
25
|
import { Label } from "@/components/ui/label";
|
|
@@ -345,8 +346,8 @@ export default function CheckoutPage() {
|
|
|
345
346
|
|
|
346
347
|
// Sync discount codes from checkout (transferred from cart) to form state
|
|
347
348
|
useEffect(() => {
|
|
348
|
-
if (checkout?.discountCodes?.length > 0 && !formState.appliedDiscountCode) {
|
|
349
|
-
const applicableCode = checkout
|
|
349
|
+
if ((checkout?.discountCodes?.length ?? 0) > 0 && !formState.appliedDiscountCode) {
|
|
350
|
+
const applicableCode = checkout?.discountCodes?.find((dc) => dc.applicable);
|
|
350
351
|
if (applicableCode) {
|
|
351
352
|
setFormState((prev) => ({
|
|
352
353
|
...prev,
|
|
@@ -429,8 +430,9 @@ export default function CheckoutPage() {
|
|
|
429
430
|
}
|
|
430
431
|
|
|
431
432
|
setCurrentStep(allGiftCards ? "payment" : "shipping");
|
|
432
|
-
} catch (error:
|
|
433
|
-
|
|
433
|
+
} catch (error: unknown) {
|
|
434
|
+
const message = error instanceof Error ? error.message : "Nie udało się przetworzyć danych kontaktowych";
|
|
435
|
+
toast.error(message);
|
|
434
436
|
}
|
|
435
437
|
};
|
|
436
438
|
|
|
@@ -510,8 +512,9 @@ export default function CheckoutPage() {
|
|
|
510
512
|
// Refetch checkout to get shipping rates
|
|
511
513
|
await refetchCheckout();
|
|
512
514
|
setCurrentStep("delivery");
|
|
513
|
-
} catch (error:
|
|
514
|
-
|
|
515
|
+
} catch (error: unknown) {
|
|
516
|
+
const message = error instanceof Error ? error.message : "Nie udało się zaktualizować adresu";
|
|
517
|
+
toast.error(message);
|
|
515
518
|
}
|
|
516
519
|
};
|
|
517
520
|
|
|
@@ -544,8 +547,9 @@ export default function CheckoutPage() {
|
|
|
544
547
|
|
|
545
548
|
await refetchCheckout();
|
|
546
549
|
setCurrentStep("payment");
|
|
547
|
-
} catch (error:
|
|
548
|
-
|
|
550
|
+
} catch (error: unknown) {
|
|
551
|
+
const message = error instanceof Error ? error.message : "Nie udało się wybrać metody dostawy";
|
|
552
|
+
toast.error(message);
|
|
549
553
|
}
|
|
550
554
|
};
|
|
551
555
|
|
|
@@ -556,10 +560,10 @@ export default function CheckoutPage() {
|
|
|
556
560
|
const handlePaymentMethodSelect = (paymentMethodId: string) => {
|
|
557
561
|
// Validate payment method supports current currency
|
|
558
562
|
const selectedMethod = checkout?.availablePaymentMethods?.find(
|
|
559
|
-
(pm
|
|
563
|
+
(pm) => pm.id === paymentMethodId
|
|
560
564
|
);
|
|
561
565
|
|
|
562
|
-
if (selectedMethod?.supportedCurrencies
|
|
566
|
+
if (selectedMethod?.supportedCurrencies && selectedMethod.supportedCurrencies.length > 0) {
|
|
563
567
|
const supportsCurrency = selectedMethod.supportedCurrencies.includes(currencyCode);
|
|
564
568
|
if (!supportsCurrency) {
|
|
565
569
|
setErrors({
|
|
@@ -581,7 +585,7 @@ export default function CheckoutPage() {
|
|
|
581
585
|
|
|
582
586
|
// Validate selected payment method still exists and is valid
|
|
583
587
|
const selectedMethod = checkout?.availablePaymentMethods?.find(
|
|
584
|
-
(pm
|
|
588
|
+
(pm) => pm.id === formState.selectedPaymentMethodId
|
|
585
589
|
);
|
|
586
590
|
|
|
587
591
|
if (!selectedMethod) {
|
|
@@ -591,7 +595,7 @@ export default function CheckoutPage() {
|
|
|
591
595
|
}
|
|
592
596
|
|
|
593
597
|
// Validate currency support
|
|
594
|
-
if (selectedMethod.supportedCurrencies
|
|
598
|
+
if (selectedMethod.supportedCurrencies && selectedMethod.supportedCurrencies.length > 0) {
|
|
595
599
|
const supportsCurrency = selectedMethod.supportedCurrencies.includes(currencyCode);
|
|
596
600
|
if (!supportsCurrency) {
|
|
597
601
|
setErrors({
|
|
@@ -644,8 +648,9 @@ export default function CheckoutPage() {
|
|
|
644
648
|
}));
|
|
645
649
|
await refetchCheckout();
|
|
646
650
|
toast.success("Kod rabatowy został zastosowany");
|
|
647
|
-
} catch (error:
|
|
648
|
-
|
|
651
|
+
} catch (error: unknown) {
|
|
652
|
+
const message = error instanceof Error ? error.message : "Nie udało się zastosować kodu rabatowego";
|
|
653
|
+
toast.error(message);
|
|
649
654
|
}
|
|
650
655
|
};
|
|
651
656
|
|
|
@@ -671,8 +676,9 @@ export default function CheckoutPage() {
|
|
|
671
676
|
}));
|
|
672
677
|
await refetchCheckout();
|
|
673
678
|
toast.success("Kod rabatowy został usunięty");
|
|
674
|
-
} catch (error:
|
|
675
|
-
|
|
679
|
+
} catch (error: unknown) {
|
|
680
|
+
const message = error instanceof Error ? error.message : "Nie udało się usunąć kodu rabatowego";
|
|
681
|
+
toast.error(message);
|
|
676
682
|
}
|
|
677
683
|
};
|
|
678
684
|
|
|
@@ -703,10 +709,10 @@ export default function CheckoutPage() {
|
|
|
703
709
|
GIFT_CARD_NOT_FOUND: "Nie znaleziono karty podarunkowej o podanym kodzie",
|
|
704
710
|
GIFT_CARD_EXPIRED: "Ta karta podarunkowa wygasła",
|
|
705
711
|
GIFT_CARD_DISABLED: "Ta karta podarunkowa jest wyłączona",
|
|
706
|
-
|
|
707
|
-
|
|
712
|
+
GIFT_CARD_DEPLETED: "Ta karta podarunkowa nie ma dostępnego salda",
|
|
713
|
+
GIFT_CARD_UNUSABLE: "Ta karta jest już zastosowana",
|
|
708
714
|
};
|
|
709
|
-
toast.error(errorMessages[error.code] || error.message);
|
|
715
|
+
toast.error((error.code && errorMessages[error.code]) || error.message);
|
|
710
716
|
return;
|
|
711
717
|
}
|
|
712
718
|
|
|
@@ -716,8 +722,9 @@ export default function CheckoutPage() {
|
|
|
716
722
|
}));
|
|
717
723
|
await refetchCheckout();
|
|
718
724
|
toast.success("Karta podarunkowa została zastosowana");
|
|
719
|
-
} catch (error:
|
|
720
|
-
|
|
725
|
+
} catch (error: unknown) {
|
|
726
|
+
const message = error instanceof Error ? error.message : "Nie udało się zastosować karty podarunkowej";
|
|
727
|
+
toast.error(message);
|
|
721
728
|
}
|
|
722
729
|
};
|
|
723
730
|
|
|
@@ -739,8 +746,9 @@ export default function CheckoutPage() {
|
|
|
739
746
|
|
|
740
747
|
await refetchCheckout();
|
|
741
748
|
toast.success("Karta podarunkowa została usunięta");
|
|
742
|
-
} catch (error:
|
|
743
|
-
|
|
749
|
+
} catch (error: unknown) {
|
|
750
|
+
const message = error instanceof Error ? error.message : "Nie udało się usunąć karty podarunkowej";
|
|
751
|
+
toast.error(message);
|
|
744
752
|
}
|
|
745
753
|
};
|
|
746
754
|
|
|
@@ -781,27 +789,20 @@ export default function CheckoutPage() {
|
|
|
781
789
|
const errorMessage = error.message;
|
|
782
790
|
|
|
783
791
|
// Handle specific payment-related error codes
|
|
784
|
-
|
|
792
|
+
// Cast to string since backend may return codes not in the generated enum
|
|
793
|
+
const codeStr = errorCode as string | null | undefined;
|
|
794
|
+
switch (codeStr) {
|
|
785
795
|
case "INVALID_PAYMENT_METHOD":
|
|
786
|
-
case "
|
|
796
|
+
case "NO_PAYMENT_METHODS":
|
|
787
797
|
setErrors({ payment: "Wybrana metoda płatności jest niedostępna. Wybierz inną metodę." });
|
|
788
798
|
setFormState((prev) => ({ ...prev, selectedPaymentMethodId: null }));
|
|
789
799
|
setCurrentStep("payment");
|
|
790
800
|
toast.error("Metoda płatności jest niedostępna");
|
|
791
801
|
break;
|
|
792
|
-
case "
|
|
793
|
-
setErrors({ payment: `Metoda płatności nie obsługuje wybranej waluty (${currencyCode}).` });
|
|
794
|
-
setCurrentStep("payment");
|
|
795
|
-
toast.error("Waluta nie jest obsługiwana przez tę metodę płatności");
|
|
796
|
-
break;
|
|
797
|
-
case "PAYMENT_DECLINED":
|
|
798
|
-
toast.error("Płatność została odrzucona. Spróbuj ponownie lub wybierz inną metodę.");
|
|
799
|
-
setCurrentStep("payment");
|
|
800
|
-
break;
|
|
801
|
-
case "CHECKOUT_EXPIRED":
|
|
802
|
+
case "ALREADY_COMPLETED":
|
|
802
803
|
toast.error("Sesja checkout wygasła. Proszę odświeżyć stronę i spróbować ponownie.");
|
|
803
804
|
break;
|
|
804
|
-
case "
|
|
805
|
+
case "NOT_ENOUGH_IN_STOCK":
|
|
805
806
|
toast.error("Niektóre produkty są niedostępne. Sprawdź swój koszyk.");
|
|
806
807
|
break;
|
|
807
808
|
default:
|
|
@@ -821,7 +822,7 @@ export default function CheckoutPage() {
|
|
|
821
822
|
const orderId = completeResult.checkoutComplete.order.id;
|
|
822
823
|
const paymentType = formState.selectedPaymentMethodId
|
|
823
824
|
? checkout?.availablePaymentMethods?.find(
|
|
824
|
-
(pm
|
|
825
|
+
(pm) => pm.id === formState.selectedPaymentMethodId
|
|
825
826
|
)?.type
|
|
826
827
|
: null;
|
|
827
828
|
|
|
@@ -832,8 +833,9 @@ export default function CheckoutPage() {
|
|
|
832
833
|
// Fallback: no payment URL and no order - show error
|
|
833
834
|
toast.error("Wystąpił nieoczekiwany błąd. Skontaktuj się z obsługą.");
|
|
834
835
|
}
|
|
835
|
-
} catch (error:
|
|
836
|
-
|
|
836
|
+
} catch (error: unknown) {
|
|
837
|
+
const message = error instanceof Error ? error.message : "Nie udało się sfinalizować zamówienia";
|
|
838
|
+
toast.error(message);
|
|
837
839
|
}
|
|
838
840
|
};
|
|
839
841
|
|
|
@@ -1283,7 +1285,7 @@ export default function CheckoutPage() {
|
|
|
1283
1285
|
{/* PaymentStep component handles payment method selection */}
|
|
1284
1286
|
<PaymentStep
|
|
1285
1287
|
availablePaymentMethods={(checkout.availablePaymentMethods || []).map(
|
|
1286
|
-
(pm
|
|
1288
|
+
(pm): PaymentMethod => ({
|
|
1287
1289
|
id: pm.id,
|
|
1288
1290
|
name: pm.name,
|
|
1289
1291
|
provider: pm.provider,
|
|
@@ -1417,7 +1419,7 @@ export default function CheckoutPage() {
|
|
|
1417
1419
|
{formState.selectedPaymentMethodId && (
|
|
1418
1420
|
<p className="text-sm text-muted-foreground">
|
|
1419
1421
|
{checkout.availablePaymentMethods?.find(
|
|
1420
|
-
(pm
|
|
1422
|
+
(pm) => pm.id === formState.selectedPaymentMethodId
|
|
1421
1423
|
)?.name || "Wybrana metoda płatności"}
|
|
1422
1424
|
</p>
|
|
1423
1425
|
)}
|
|
@@ -1497,43 +1499,78 @@ export default function CheckoutPage() {
|
|
|
1497
1499
|
<CardContent className="space-y-4">
|
|
1498
1500
|
{/* Line Items */}
|
|
1499
1501
|
<div className="space-y-3">
|
|
1500
|
-
{(checkout?.lineItems
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1502
|
+
{(checkout?.lineItems ?? []).length > 0
|
|
1503
|
+
? checkout!.lineItems.map((item) => (
|
|
1504
|
+
<div
|
|
1505
|
+
key={item.id}
|
|
1506
|
+
className="flex gap-3 text-sm"
|
|
1507
|
+
>
|
|
1508
|
+
<div className="relative h-16 w-16 flex-shrink-0 overflow-hidden rounded-md border bg-muted">
|
|
1509
|
+
{item.image?.url ? (
|
|
1510
|
+
<img
|
|
1511
|
+
src={item.image.url}
|
|
1512
|
+
alt={item.title}
|
|
1513
|
+
className="h-full w-full object-cover"
|
|
1514
|
+
/>
|
|
1515
|
+
) : (
|
|
1516
|
+
<div className="flex h-full w-full items-center justify-center">
|
|
1517
|
+
<Package className="h-6 w-6 text-muted-foreground" />
|
|
1518
|
+
</div>
|
|
1519
|
+
)}
|
|
1520
|
+
<span className="absolute -right-2 -top-2 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-xs text-primary-foreground">
|
|
1521
|
+
{item.quantity}
|
|
1522
|
+
</span>
|
|
1515
1523
|
</div>
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
item.
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1524
|
+
<div className="flex-1">
|
|
1525
|
+
<p className="font-medium line-clamp-2">
|
|
1526
|
+
{item.title}
|
|
1527
|
+
</p>
|
|
1528
|
+
{item.variantTitle && item.variantTitle !== "Default" && (
|
|
1529
|
+
<p className="text-xs text-muted-foreground">{item.variantTitle}</p>
|
|
1530
|
+
)}
|
|
1531
|
+
</div>
|
|
1532
|
+
<p className="font-medium">
|
|
1533
|
+
{formatPrice(item.totalPrice.amount)}
|
|
1534
|
+
</p>
|
|
1535
|
+
</div>
|
|
1536
|
+
))
|
|
1537
|
+
: items.map((item) => (
|
|
1538
|
+
<div
|
|
1539
|
+
key={item.lineId}
|
|
1540
|
+
className="flex gap-3 text-sm"
|
|
1541
|
+
>
|
|
1542
|
+
<div className="relative h-16 w-16 flex-shrink-0 overflow-hidden rounded-md border bg-muted">
|
|
1543
|
+
{item.image?.url ? (
|
|
1544
|
+
<img
|
|
1545
|
+
src={item.image.url}
|
|
1546
|
+
alt={item.productTitle}
|
|
1547
|
+
className="h-full w-full object-cover"
|
|
1548
|
+
/>
|
|
1549
|
+
) : (
|
|
1550
|
+
<div className="flex h-full w-full items-center justify-center">
|
|
1551
|
+
<Package className="h-6 w-6 text-muted-foreground" />
|
|
1552
|
+
</div>
|
|
1553
|
+
)}
|
|
1554
|
+
<span className="absolute -right-2 -top-2 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-xs text-primary-foreground">
|
|
1555
|
+
{item.quantity}
|
|
1556
|
+
</span>
|
|
1557
|
+
</div>
|
|
1558
|
+
<div className="flex-1">
|
|
1559
|
+
<p className="font-medium line-clamp-2">
|
|
1560
|
+
{item.productTitle}
|
|
1561
|
+
</p>
|
|
1562
|
+
{item.variantTitle && item.variantTitle !== "Default" && (
|
|
1563
|
+
<p className="text-xs text-muted-foreground">{item.variantTitle}</p>
|
|
1564
|
+
)}
|
|
1565
|
+
</div>
|
|
1566
|
+
<p className="font-medium">
|
|
1567
|
+
{formatPrice(
|
|
1568
|
+
parseFloat(item.price.amount) * item.quantity
|
|
1569
|
+
)}
|
|
1570
|
+
</p>
|
|
1571
|
+
</div>
|
|
1572
|
+
))
|
|
1573
|
+
}
|
|
1537
1574
|
</div>
|
|
1538
1575
|
|
|
1539
1576
|
{/* Discount Code */}
|
|
@@ -1591,7 +1628,7 @@ export default function CheckoutPage() {
|
|
|
1591
1628
|
{/* Applied Gift Cards */}
|
|
1592
1629
|
{checkout?.appliedGiftCards && checkout.appliedGiftCards.length > 0 && (
|
|
1593
1630
|
<div className="space-y-2">
|
|
1594
|
-
{checkout.appliedGiftCards.map((giftCard
|
|
1631
|
+
{checkout.appliedGiftCards.map((giftCard) => (
|
|
1595
1632
|
<div
|
|
1596
1633
|
key={giftCard.lastCharacters}
|
|
1597
1634
|
className="flex items-center justify-between rounded-lg bg-purple-50 p-3 dark:bg-purple-950"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function CollectionLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
<Skeleton className="mb-2 h-10 w-64" />
|
|
7
|
+
<Skeleton className="mb-8 h-5 w-96" />
|
|
8
|
+
<div className="grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4">
|
|
9
|
+
{[...Array(8)].map((_, i) => (
|
|
10
|
+
<div key={i} className="space-y-3">
|
|
11
|
+
<Skeleton className="aspect-square w-full rounded-lg" />
|
|
12
|
+
<Skeleton className="h-4 w-3/4" />
|
|
13
|
+
<Skeleton className="h-4 w-1/2" />
|
|
14
|
+
</div>
|
|
15
|
+
))}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -14,7 +14,7 @@ export default function CollectionPage() {
|
|
|
14
14
|
const { data, isLoading, error } = useCollection(handle);
|
|
15
15
|
|
|
16
16
|
const collection = data?.collection;
|
|
17
|
-
const products = collection?.products?.edges?.map((edge
|
|
17
|
+
const products = collection?.products?.edges?.map((edge) => edge.node) ?? [];
|
|
18
18
|
|
|
19
19
|
if (isLoading) {
|
|
20
20
|
return (
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function CollectionsLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
<Skeleton className="mb-8 h-10 w-48" />
|
|
7
|
+
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
8
|
+
{[...Array(6)].map((_, i) => (
|
|
9
|
+
<div key={i} className="space-y-3">
|
|
10
|
+
<Skeleton className="aspect-[3/2] w-full rounded-lg" />
|
|
11
|
+
<Skeleton className="h-5 w-3/4" />
|
|
12
|
+
<Skeleton className="h-4 w-1/2" />
|
|
13
|
+
</div>
|
|
14
|
+
))}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -12,11 +12,14 @@ export const metadata: Metadata = {
|
|
|
12
12
|
export const revalidate = 60;
|
|
13
13
|
|
|
14
14
|
export default async function CollectionsPage() {
|
|
15
|
-
|
|
16
|
-
const { collections } = await fetchCollections({ first: 20 });
|
|
15
|
+
let collectionList: Awaited<ReturnType<typeof fetchCollections>>['collections'] = [];
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
try {
|
|
18
|
+
const { collections } = await fetchCollections({ first: 20 });
|
|
19
|
+
collectionList = collections || [];
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('[CollectionsPage] Failed to fetch collections:', error instanceof Error ? error.message : error);
|
|
22
|
+
}
|
|
20
23
|
|
|
21
24
|
return (
|
|
22
25
|
<div className="container mx-auto px-4 py-8">
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GlobalError — catches errors from root layout (where error.tsx cannot reach).
|
|
5
|
+
*
|
|
6
|
+
* This replaces the entire <html> document, so it must include its own
|
|
7
|
+
* <html> and <body> tags. No providers, no Header/Footer — just a
|
|
8
|
+
* self-contained error page.
|
|
9
|
+
*
|
|
10
|
+
* Next.js docs: https://nextjs.org/docs/app/api-reference/file-conventions/error#global-errorjs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useEffect } from 'react';
|
|
14
|
+
|
|
15
|
+
interface GlobalErrorProps {
|
|
16
|
+
error: Error & { digest?: string };
|
|
17
|
+
reset: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function GlobalError({ error, reset }: GlobalErrorProps) {
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
console.error('[GlobalError]', error);
|
|
23
|
+
}, [error]);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<html lang="pl">
|
|
27
|
+
<body
|
|
28
|
+
style={{
|
|
29
|
+
margin: 0,
|
|
30
|
+
fontFamily:
|
|
31
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
32
|
+
backgroundColor: '#fafafa',
|
|
33
|
+
color: '#1e293b',
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
minHeight: '100vh',
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
maxWidth: '28rem',
|
|
43
|
+
width: '100%',
|
|
44
|
+
padding: '2rem',
|
|
45
|
+
textAlign: 'center',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
style={{
|
|
50
|
+
width: '4rem',
|
|
51
|
+
height: '4rem',
|
|
52
|
+
margin: '0 auto 1.5rem',
|
|
53
|
+
borderRadius: '50%',
|
|
54
|
+
backgroundColor: '#fef2f2',
|
|
55
|
+
display: 'flex',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
justifyContent: 'center',
|
|
58
|
+
fontSize: '1.5rem',
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
!
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<h1 style={{ fontSize: '1.5rem', fontWeight: 600, margin: '0 0 0.5rem' }}>
|
|
65
|
+
Serwer tymczasowo niedostępny
|
|
66
|
+
</h1>
|
|
67
|
+
|
|
68
|
+
<p style={{ color: '#64748b', margin: '0 0 2rem', lineHeight: 1.6 }}>
|
|
69
|
+
Nie udało się załadować strony. Serwer może być tymczasowo niedostępny.
|
|
70
|
+
Spróbuj odświeżyć stronę za chwilę.
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
{process.env.NODE_ENV === 'development' && (
|
|
74
|
+
<div
|
|
75
|
+
style={{
|
|
76
|
+
backgroundColor: '#f1f5f9',
|
|
77
|
+
borderRadius: '0.5rem',
|
|
78
|
+
padding: '0.75rem 1rem',
|
|
79
|
+
marginBottom: '1.5rem',
|
|
80
|
+
textAlign: 'left',
|
|
81
|
+
fontSize: '0.75rem',
|
|
82
|
+
wordBreak: 'break-word',
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<strong style={{ color: '#ef4444' }}>{error.message}</strong>
|
|
86
|
+
{error.digest && (
|
|
87
|
+
<p style={{ color: '#64748b', margin: '0.25rem 0 0' }}>
|
|
88
|
+
Digest: {error.digest}
|
|
89
|
+
</p>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
<button
|
|
95
|
+
onClick={reset}
|
|
96
|
+
style={{
|
|
97
|
+
display: 'inline-flex',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
justifyContent: 'center',
|
|
100
|
+
width: '100%',
|
|
101
|
+
padding: '0.625rem 1.25rem',
|
|
102
|
+
fontSize: '0.875rem',
|
|
103
|
+
fontWeight: 500,
|
|
104
|
+
color: '#fff',
|
|
105
|
+
backgroundColor: '#3b82f6',
|
|
106
|
+
border: 'none',
|
|
107
|
+
borderRadius: '0.5rem',
|
|
108
|
+
cursor: 'pointer',
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
Spróbuj ponownie
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</body>
|
|
115
|
+
</html>
|
|
116
|
+
);
|
|
117
|
+
}
|