@doswiftly/cli 0.1.18 → 0.1.20
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 +20 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +249 -17
- 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 +4 -4
- package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-minimal/wrangler.toml +11 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -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 +11 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -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 +172 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
- package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
- package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
- package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
- package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
- package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
- package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
- 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/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
- package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
- 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 +32 -42
- 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/add-to-cart-button.tsx +6 -14
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -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 +11 -37
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
- 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 +44 -19
- 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 +26 -34
- 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/language-sync-provider.tsx +27 -0
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -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 +59 -72
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
- 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-button.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -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 +34 -229
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
- package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
- package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
- package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
- 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 +33 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -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/messages/en.json +869 -0
- package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +14 -14
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
- 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 +11 -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/app/account/addresses/page.tsx +0 -215
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
- 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
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { Metadata } from 'next';
|
|
8
8
|
import Image from 'next/image';
|
|
9
|
-
import Link from '
|
|
9
|
+
import { Link } from '@/i18n/navigation';
|
|
10
10
|
import { notFound } from 'next/navigation';
|
|
11
11
|
import { Calendar, Clock, Eye, User, ChevronLeft, Share2 } from 'lucide-react';
|
|
12
12
|
import { Breadcrumbs } from '@/components/layout/breadcrumbs';
|
|
@@ -16,9 +16,50 @@ import { Card, CardContent } from '@/components/ui/card';
|
|
|
16
16
|
import { Separator } from '@/components/ui/separator';
|
|
17
17
|
import { BlogCard } from '@/components/blog/blog-card';
|
|
18
18
|
import { BlogSidebar } from '@/components/blog/blog-sidebar';
|
|
19
|
+
import { sanitizeHtml } from '@doswiftly/storefront-sdk';
|
|
20
|
+
|
|
21
|
+
interface BlogImage {
|
|
22
|
+
url: string;
|
|
23
|
+
altText?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface BlogPost {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
slug: string;
|
|
30
|
+
excerpt: string;
|
|
31
|
+
content: string;
|
|
32
|
+
contentType: string;
|
|
33
|
+
featuredImage: BlogImage | null;
|
|
34
|
+
author: {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
bio: string;
|
|
38
|
+
avatar: BlogImage | null;
|
|
39
|
+
};
|
|
40
|
+
category: {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
slug: string;
|
|
44
|
+
} | null;
|
|
45
|
+
tags: { id: string; name: string; slug: string; postCount: number }[];
|
|
46
|
+
status: string;
|
|
47
|
+
publishedAt: string;
|
|
48
|
+
readingTime: number;
|
|
49
|
+
viewCount: number;
|
|
50
|
+
commentCount: number;
|
|
51
|
+
allowComments: boolean;
|
|
52
|
+
isFeatured: boolean;
|
|
53
|
+
seo: {
|
|
54
|
+
title: string;
|
|
55
|
+
description: string;
|
|
56
|
+
} | null;
|
|
57
|
+
createdAt: string;
|
|
58
|
+
updatedAt: string;
|
|
59
|
+
}
|
|
19
60
|
|
|
20
61
|
// Mock data - replace with actual GraphQL fetch
|
|
21
|
-
const mockPost = {
|
|
62
|
+
const mockPost: BlogPost = {
|
|
22
63
|
id: '1',
|
|
23
64
|
title: 'Jak wybrać idealny produkt dla siebie',
|
|
24
65
|
slug: 'jak-wybrac-idealny-produkt',
|
|
@@ -234,7 +275,7 @@ export default async function BlogPostPage({ params }: BlogPostPageProps) {
|
|
|
234
275
|
{/* Content */}
|
|
235
276
|
<div
|
|
236
277
|
className="prose prose-lg max-w-none dark:prose-invert mb-8"
|
|
237
|
-
dangerouslySetInnerHTML={{ __html: post.content }}
|
|
278
|
+
dangerouslySetInnerHTML={{ __html: sanitizeHtml(post.content) }}
|
|
238
279
|
/>
|
|
239
280
|
|
|
240
281
|
{/* Tags */}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function BlogLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
<Skeleton className="mb-8 h-10 w-32" />
|
|
7
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
8
|
+
{[...Array(6)].map((_, i) => (
|
|
9
|
+
<div key={i} className="space-y-3">
|
|
10
|
+
<Skeleton className="aspect-video w-full rounded-lg" />
|
|
11
|
+
<Skeleton className="h-4 w-24" />
|
|
12
|
+
<Skeleton className="h-6 w-full" />
|
|
13
|
+
<Skeleton className="h-4 w-5/6" />
|
|
14
|
+
</div>
|
|
15
|
+
))}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
4
|
-
import { BrandGrid
|
|
4
|
+
import { BrandGrid } from "@/components/brand/brand-grid";
|
|
5
|
+
import type { BrandCardProps } from "@/components/brand/brand-card";
|
|
5
6
|
|
|
6
7
|
export default function BrandsPage() {
|
|
7
8
|
// TODO: Fetch brands from backend using GraphQL
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function CartLoading() {
|
|
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 gap-8 lg:grid-cols-3">
|
|
8
|
+
<div className="space-y-4 lg:col-span-2">
|
|
9
|
+
{[...Array(3)].map((_, i) => (
|
|
10
|
+
<div key={i} className="flex gap-4 rounded-lg border p-4">
|
|
11
|
+
<Skeleton className="h-24 w-24 shrink-0 rounded-md" />
|
|
12
|
+
<div className="flex-1 space-y-2">
|
|
13
|
+
<Skeleton className="h-5 w-3/4" />
|
|
14
|
+
<Skeleton className="h-4 w-1/3" />
|
|
15
|
+
<Skeleton className="h-8 w-24" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
))}
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<Skeleton className="h-64 w-full rounded-lg" />
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import Link from "
|
|
4
|
-
import {
|
|
3
|
+
import { Link, useRouter } from "@/i18n/navigation";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
5
|
+
import { useCartStoreApi } from "@/stores/cart-store";
|
|
5
6
|
import { useCartSync } from "@/hooks/use-cart-sync";
|
|
6
7
|
import { useCartActions } from "@/hooks/use-cart-actions";
|
|
7
8
|
import { useCartDiscountCodesUpdate } from "@/lib/graphql/hooks";
|
|
@@ -14,6 +15,9 @@ import { Button } from "@/components/ui/button";
|
|
|
14
15
|
import { ArrowLeft, Loader2 } from "lucide-react";
|
|
15
16
|
|
|
16
17
|
export default function CartPage() {
|
|
18
|
+
const t = useTranslations("cart");
|
|
19
|
+
const router = useRouter();
|
|
20
|
+
|
|
17
21
|
// Server cart data (source of truth)
|
|
18
22
|
const {
|
|
19
23
|
items,
|
|
@@ -26,6 +30,9 @@ export default function CartPage() {
|
|
|
26
30
|
isLoading,
|
|
27
31
|
} = useCartSync();
|
|
28
32
|
|
|
33
|
+
// Cart store API for getState() in callbacks
|
|
34
|
+
const cartStoreApi = useCartStoreApi();
|
|
35
|
+
|
|
29
36
|
// Actions that mutate via GraphQL
|
|
30
37
|
const { updateQuantity, removeFromCart } = useCartActions();
|
|
31
38
|
|
|
@@ -44,14 +51,14 @@ export default function CartPage() {
|
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
const handleCheckout = () => {
|
|
47
|
-
|
|
54
|
+
router.push("/checkout");
|
|
48
55
|
};
|
|
49
56
|
|
|
50
57
|
const handleApplyPromo = async (code: string) => {
|
|
51
58
|
try {
|
|
52
|
-
const cartId =
|
|
59
|
+
const cartId = cartStoreApi.getState().cartId;
|
|
53
60
|
if (!cartId) {
|
|
54
|
-
return { success: false, message: "
|
|
61
|
+
return { success: false, message: t("empty") };
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
const result = await discountMutation.mutateAsync({
|
|
@@ -71,22 +78,22 @@ export default function CartPage() {
|
|
|
71
78
|
if (!payload?.cart) {
|
|
72
79
|
return {
|
|
73
80
|
success: false,
|
|
74
|
-
message: "
|
|
81
|
+
message: t("promoError"),
|
|
75
82
|
};
|
|
76
83
|
}
|
|
77
84
|
|
|
78
|
-
return { success: true, message: "
|
|
85
|
+
return { success: true, message: t("promoApplied") };
|
|
79
86
|
} catch (error) {
|
|
80
87
|
return {
|
|
81
88
|
success: false,
|
|
82
|
-
message: "
|
|
89
|
+
message: t("promoError"),
|
|
83
90
|
};
|
|
84
91
|
}
|
|
85
92
|
};
|
|
86
93
|
|
|
87
94
|
const handleRemovePromo = async () => {
|
|
88
95
|
try {
|
|
89
|
-
const cartId =
|
|
96
|
+
const cartId = cartStoreApi.getState().cartId;
|
|
90
97
|
if (!cartId) return;
|
|
91
98
|
|
|
92
99
|
await discountMutation.mutateAsync({
|
|
@@ -101,7 +108,7 @@ export default function CartPage() {
|
|
|
101
108
|
if (items.length === 0) {
|
|
102
109
|
return (
|
|
103
110
|
<div className="container mx-auto px-4 py-16">
|
|
104
|
-
<EmptyCart onContinueShopping={() => (
|
|
111
|
+
<EmptyCart onContinueShopping={() => router.push("/products")} />
|
|
105
112
|
</div>
|
|
106
113
|
);
|
|
107
114
|
}
|
|
@@ -113,11 +120,11 @@ export default function CartPage() {
|
|
|
113
120
|
<Breadcrumbs className="mb-6" />
|
|
114
121
|
|
|
115
122
|
<div className="mb-8 flex items-center justify-between">
|
|
116
|
-
<h1 className="text-3xl font-bold text-foreground">
|
|
123
|
+
<h1 className="text-3xl font-bold text-foreground">{t("title")}</h1>
|
|
117
124
|
<Button variant="ghost" asChild>
|
|
118
125
|
<Link href="/products">
|
|
119
126
|
<ArrowLeft className="mr-2 h-4 w-4" />
|
|
120
|
-
|
|
127
|
+
{t("continueShopping")}
|
|
121
128
|
</Link>
|
|
122
129
|
</Button>
|
|
123
130
|
</div>
|
|
@@ -141,7 +148,7 @@ export default function CartPage() {
|
|
|
141
148
|
{/* Summary */}
|
|
142
149
|
<div className="lg:col-span-1">
|
|
143
150
|
<div className="sticky top-4 space-y-4 rounded-lg border border-border bg-muted/50 p-6">
|
|
144
|
-
<h2 className="text-lg font-semibold text-foreground">
|
|
151
|
+
<h2 className="text-lg font-semibold text-foreground">{t("yourOrder")}</h2>
|
|
145
152
|
|
|
146
153
|
<PromoCodeInput
|
|
147
154
|
onApply={handleApplyPromo}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
4
|
+
import { ProductGrid } from "@/components/product/product-grid";
|
|
5
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
6
|
+
import { useProducts } from "@/lib/graphql/hooks";
|
|
7
|
+
|
|
8
|
+
interface CategoryProductsClientProps {
|
|
9
|
+
categoryId: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Client component for category product listing.
|
|
14
|
+
*
|
|
15
|
+
* Receives categoryId from server and uses filters.categoryId
|
|
16
|
+
* for correct backend filtering.
|
|
17
|
+
*/
|
|
18
|
+
export function CategoryProductsClient({
|
|
19
|
+
categoryId,
|
|
20
|
+
}: CategoryProductsClientProps) {
|
|
21
|
+
const t = useTranslations("product");
|
|
22
|
+
const { data, isLoading, error } = useProducts({
|
|
23
|
+
first: 20,
|
|
24
|
+
filters: { categoryId },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const products = data?.products ?? [];
|
|
28
|
+
|
|
29
|
+
if (isLoading) {
|
|
30
|
+
return (
|
|
31
|
+
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
|
32
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
33
|
+
<Skeleton key={i} className="aspect-square w-full rounded-lg" />
|
|
34
|
+
))}
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (error) {
|
|
40
|
+
return (
|
|
41
|
+
<div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
|
|
42
|
+
<p className="text-muted-foreground">
|
|
43
|
+
{t("failedLoadProducts")}
|
|
44
|
+
</p>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<ProductGrid
|
|
51
|
+
products={products}
|
|
52
|
+
columns={4}
|
|
53
|
+
priorityCount={8}
|
|
54
|
+
showBadges
|
|
55
|
+
emptyMessage={t("noProductsInCategory")}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function CategoryLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
{/* Breadcrumbs */}
|
|
7
|
+
<Skeleton className="mb-6 h-5 w-64" />
|
|
8
|
+
|
|
9
|
+
{/* Category title */}
|
|
10
|
+
<Skeleton className="mb-2 h-9 w-48" />
|
|
11
|
+
<Skeleton className="mb-6 h-5 w-96" />
|
|
12
|
+
|
|
13
|
+
{/* Subcategory chips */}
|
|
14
|
+
<div className="mb-8 flex gap-2">
|
|
15
|
+
{[...Array(4)].map((_, i) => (
|
|
16
|
+
<Skeleton key={i} className="h-8 w-24 rounded-full" />
|
|
17
|
+
))}
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
{/* Product grid 2x4 */}
|
|
21
|
+
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
|
|
22
|
+
{[...Array(8)].map((_, i) => (
|
|
23
|
+
<div key={i} className="space-y-3">
|
|
24
|
+
<Skeleton className="aspect-square w-full rounded-lg" />
|
|
25
|
+
<Skeleton className="h-4 w-3/4" />
|
|
26
|
+
<Skeleton className="h-4 w-1/2" />
|
|
27
|
+
</div>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Metadata } from "next";
|
|
2
|
+
import { notFound } from "next/navigation";
|
|
3
|
+
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
4
|
+
import { fetchCategory } from "@/lib/graphql/server";
|
|
5
|
+
import { CategoryProductsClient } from "./category-products-client";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generate metadata for category pages (SEO)
|
|
9
|
+
*/
|
|
10
|
+
export async function generateMetadata({
|
|
11
|
+
params,
|
|
12
|
+
}: {
|
|
13
|
+
params: Promise<{ slug: string }>;
|
|
14
|
+
}): Promise<Metadata> {
|
|
15
|
+
try {
|
|
16
|
+
const { slug } = await params;
|
|
17
|
+
const data = await fetchCategory(slug);
|
|
18
|
+
const category = data?.category;
|
|
19
|
+
|
|
20
|
+
if (!category) {
|
|
21
|
+
return { title: "Category Not Found" };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
title: category.name,
|
|
26
|
+
description:
|
|
27
|
+
category.description || `Browse ${category.name} products`,
|
|
28
|
+
};
|
|
29
|
+
} catch {
|
|
30
|
+
return { title: "Category" };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Category detail page — Server Component
|
|
36
|
+
*
|
|
37
|
+
* Fetches category metadata on the server for SEO,
|
|
38
|
+
* passes category ID to client component for product filtering.
|
|
39
|
+
*/
|
|
40
|
+
export default async function CategoryPage({
|
|
41
|
+
params,
|
|
42
|
+
}: {
|
|
43
|
+
params: Promise<{ slug: string }>;
|
|
44
|
+
}) {
|
|
45
|
+
const { slug } = await params;
|
|
46
|
+
|
|
47
|
+
let category;
|
|
48
|
+
try {
|
|
49
|
+
const data = await fetchCategory(slug);
|
|
50
|
+
category = data?.category;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('[CategoryPage] Failed to fetch category:', error instanceof Error ? error.message : error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!category) {
|
|
56
|
+
notFound();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="container mx-auto px-4 py-8">
|
|
61
|
+
<Breadcrumbs className="mb-6" />
|
|
62
|
+
|
|
63
|
+
{/* Category Header — SSR, SEO-friendly */}
|
|
64
|
+
<div className="mb-8">
|
|
65
|
+
<h1 className="text-3xl font-bold text-foreground">{category.name}</h1>
|
|
66
|
+
{category.description && (
|
|
67
|
+
<p className="mt-2 text-muted-foreground">{category.description}</p>
|
|
68
|
+
)}
|
|
69
|
+
{category.children.length > 0 && (
|
|
70
|
+
<div className="mt-4 flex flex-wrap gap-2">
|
|
71
|
+
{category.children.map((child) => (
|
|
72
|
+
<a
|
|
73
|
+
key={child.id}
|
|
74
|
+
href={`/categories/${child.slug}`}
|
|
75
|
+
className="rounded-full border border-border bg-muted px-3 py-1 text-sm text-foreground hover:bg-accent transition-colors"
|
|
76
|
+
>
|
|
77
|
+
{child.name}
|
|
78
|
+
{child.productCount > 0 && (
|
|
79
|
+
<span className="ml-1 text-muted-foreground">
|
|
80
|
+
({child.productCount})
|
|
81
|
+
</span>
|
|
82
|
+
)}
|
|
83
|
+
</a>
|
|
84
|
+
))}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{/* Client component for product listing with filters */}
|
|
90
|
+
<CategoryProductsClient categoryId={category.id} />
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const revalidate = 60;
|
|
@@ -1,35 +1,44 @@
|
|
|
1
1
|
import { Metadata } from "next";
|
|
2
|
-
import
|
|
2
|
+
import { getTranslations } from "next-intl/server";
|
|
3
|
+
import { Link } from "@/i18n/navigation";
|
|
3
4
|
import { Card } from "@/components/ui/card";
|
|
4
5
|
import { fetchCategories } from "@/lib/graphql/server";
|
|
6
|
+
import type { CategoryNodeFields } from "@/lib/graphql/fragments";
|
|
5
7
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
9
|
+
const t = await getTranslations("categories");
|
|
10
|
+
return {
|
|
11
|
+
title: t("title"),
|
|
12
|
+
description: t("description"),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
10
15
|
|
|
11
16
|
// Enable ISR with 60 second revalidation
|
|
12
17
|
export const revalidate = 60;
|
|
13
18
|
|
|
14
19
|
export default async function CategoriesPage() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const data = await fetchCategories();
|
|
20
|
+
const t = await getTranslations("categories");
|
|
21
|
+
let categoryList: CategoryNodeFields[] = [];
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
try {
|
|
24
|
+
const data = await fetchCategories();
|
|
25
|
+
categoryList = data?.categories?.roots || [];
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('[CategoriesPage] Failed to fetch categories:', error instanceof Error ? error.message : error);
|
|
28
|
+
}
|
|
20
29
|
|
|
21
30
|
return (
|
|
22
31
|
<div className="container mx-auto px-4 py-8">
|
|
23
32
|
<div className="mb-8">
|
|
24
|
-
<h1 className="text-3xl font-bold text-foreground">
|
|
33
|
+
<h1 className="text-3xl font-bold text-foreground">{t("title")}</h1>
|
|
25
34
|
<p className="mt-2 text-muted-foreground">
|
|
26
|
-
|
|
35
|
+
{t("description")}
|
|
27
36
|
</p>
|
|
28
37
|
</div>
|
|
29
38
|
|
|
30
39
|
{categoryList.length === 0 ? (
|
|
31
40
|
<div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
|
|
32
|
-
<p className="text-muted-foreground">
|
|
41
|
+
<p className="text-muted-foreground">{t("noCategories")}</p>
|
|
33
42
|
</div>
|
|
34
43
|
) : (
|
|
35
44
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { Link } from "@/i18n/navigation";
|
|
5
|
+
import { AlertCircle } from "lucide-react";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
|
+
|
|
9
|
+
export default function CheckoutError({
|
|
10
|
+
error,
|
|
11
|
+
reset,
|
|
12
|
+
}: {
|
|
13
|
+
error: Error & { digest?: string };
|
|
14
|
+
reset: () => void;
|
|
15
|
+
}) {
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
console.error("[Checkout Error]", error);
|
|
18
|
+
}, [error]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="container mx-auto flex min-h-[400px] items-center justify-center px-4 py-16">
|
|
22
|
+
<Card className="max-w-md">
|
|
23
|
+
<CardHeader>
|
|
24
|
+
<CardTitle className="flex items-center gap-2 text-destructive">
|
|
25
|
+
<AlertCircle className="h-5 w-5" />
|
|
26
|
+
Checkout error
|
|
27
|
+
</CardTitle>
|
|
28
|
+
</CardHeader>
|
|
29
|
+
<CardContent className="space-y-4">
|
|
30
|
+
<p className="text-sm text-muted-foreground">
|
|
31
|
+
Something went wrong during checkout. Your cart items are safe.
|
|
32
|
+
</p>
|
|
33
|
+
<div className="flex gap-3">
|
|
34
|
+
<Button onClick={reset}>Try again</Button>
|
|
35
|
+
<Button variant="outline" asChild>
|
|
36
|
+
<Link href="/cart">Back to cart</Link>
|
|
37
|
+
</Button>
|
|
38
|
+
</div>
|
|
39
|
+
</CardContent>
|
|
40
|
+
</Card>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -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
|
+
}
|