@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
package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx
RENAMED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* Requirements: R7, R8, R10.4
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { useState
|
|
18
|
-
import
|
|
17
|
+
import { useState } from 'react';
|
|
18
|
+
import { useTranslations } from 'next-intl';
|
|
19
|
+
import { Link } from '@/i18n/navigation';
|
|
19
20
|
import { ArrowLeft, Gift, Award, History, Loader2, Users, AlertCircle } from 'lucide-react';
|
|
20
21
|
import { Button } from '@/components/ui/button';
|
|
21
22
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
@@ -27,100 +28,7 @@ import { TierProgress } from '@/components/loyalty/tier-progress';
|
|
|
27
28
|
import { RewardsCatalog } from '@/components/loyalty/rewards-catalog';
|
|
28
29
|
import { PointsHistory } from '@/components/loyalty/points-history';
|
|
29
30
|
import { ReferralSection } from '@/components/loyalty/referral-section';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
// Type imports - these match the GraphQL schema
|
|
33
|
-
type TierType = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINUM' | 'DIAMOND';
|
|
34
|
-
|
|
35
|
-
interface CustomBenefit {
|
|
36
|
-
name: string;
|
|
37
|
-
description?: string | null;
|
|
38
|
-
icon?: string | null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface LoyaltyTier {
|
|
42
|
-
id: string;
|
|
43
|
-
name: string;
|
|
44
|
-
type?: TierType | null;
|
|
45
|
-
minPoints: number;
|
|
46
|
-
minAnnualSpend?: { amount: string; currencyCode: string } | null;
|
|
47
|
-
pointsMultiplier: number;
|
|
48
|
-
customBenefits: CustomBenefit[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface PointsSummary {
|
|
52
|
-
totalPoints: number;
|
|
53
|
-
currentPoints: number;
|
|
54
|
-
pendingPoints: number;
|
|
55
|
-
redeemedPoints: number;
|
|
56
|
-
expiredPoints: number;
|
|
57
|
-
expiringPoints?: number;
|
|
58
|
-
nextExpiryDate?: string;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface TierProgressData {
|
|
62
|
-
currentTier: LoyaltyTier;
|
|
63
|
-
nextTier?: LoyaltyTier;
|
|
64
|
-
pointsToNextTier: number;
|
|
65
|
-
progressPercent: number;
|
|
66
|
-
spendToNextTier?: { amount: string; currencyCode: string };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
interface LoyaltyMember {
|
|
70
|
-
id: string;
|
|
71
|
-
customerId: string;
|
|
72
|
-
points: PointsSummary;
|
|
73
|
-
tier?: LoyaltyTier;
|
|
74
|
-
tierProgress?: TierProgressData;
|
|
75
|
-
annualSpend: { amount: string; currencyCode: string };
|
|
76
|
-
lastActivityAt?: string;
|
|
77
|
-
enrolledAt: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface LoyaltyReward {
|
|
81
|
-
id: string;
|
|
82
|
-
name: string;
|
|
83
|
-
slug: string;
|
|
84
|
-
type: string;
|
|
85
|
-
pointsCost: number;
|
|
86
|
-
discountPercent?: number | null;
|
|
87
|
-
discountAmount?: { amount: string; currencyCode: string } | null;
|
|
88
|
-
description?: string | null;
|
|
89
|
-
image?: { url: string; altText?: string | null } | null;
|
|
90
|
-
available: boolean;
|
|
91
|
-
tierRequired?: LoyaltyTier | null;
|
|
92
|
-
remainingRedemptions?: number | null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
interface LoyaltyTransaction {
|
|
96
|
-
id: string;
|
|
97
|
-
type: string;
|
|
98
|
-
points: number;
|
|
99
|
-
balanceAfter: number;
|
|
100
|
-
orderId?: string;
|
|
101
|
-
description?: string;
|
|
102
|
-
expiresAt?: string;
|
|
103
|
-
createdAt: string;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
interface LoyaltySettings {
|
|
107
|
-
enabled: boolean;
|
|
108
|
-
pointsName: string;
|
|
109
|
-
pointsPerCurrency: number;
|
|
110
|
-
pointsExpiryMonths?: number;
|
|
111
|
-
referralEnabled: boolean;
|
|
112
|
-
referralPoints?: number;
|
|
113
|
-
referralBonusPoints?: number;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
interface ReferralStats {
|
|
117
|
-
referralCode: string;
|
|
118
|
-
shareUrl: string;
|
|
119
|
-
totalReferred: number;
|
|
120
|
-
completedReferrals: number;
|
|
121
|
-
pendingReferrals: number;
|
|
122
|
-
totalPointsEarned: number;
|
|
123
|
-
}
|
|
31
|
+
import { useAuthStore, useAuthHydrated } from '@doswiftly/storefront-sdk/react';
|
|
124
32
|
|
|
125
33
|
// Real hooks from generated GraphQL
|
|
126
34
|
import {
|
|
@@ -133,21 +41,27 @@ import {
|
|
|
133
41
|
} from '@/lib/graphql/hooks';
|
|
134
42
|
|
|
135
43
|
export default function LoyaltyPage() {
|
|
44
|
+
const t = useTranslations("account");
|
|
45
|
+
const tl = useTranslations("loyalty.page");
|
|
46
|
+
const ta = useTranslations("auth");
|
|
136
47
|
const [activeTab, setActiveTab] = useState('overview');
|
|
137
|
-
const { isAuthenticated } =
|
|
48
|
+
const { isAuthenticated } = useAuthStore();
|
|
49
|
+
const isHydrated = useAuthHydrated();
|
|
138
50
|
|
|
139
51
|
// Fetch loyalty data using real GraphQL hooks
|
|
140
|
-
|
|
141
|
-
const { data: rewardsData, isLoading: rewardsLoading } = useLoyaltyRewards();
|
|
142
|
-
const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
|
|
52
|
+
// Settings don't require auth — always fetch
|
|
143
53
|
const { data: settingsData } = useLoyaltySettings();
|
|
54
|
+
// All other queries require auth — hooks internally gate with `enabled: !!accessToken`
|
|
55
|
+
const { data: memberData, isLoading: memberLoading, error: memberError } = useLoyaltyMember();
|
|
56
|
+
const { data: rewardsData, isLoading: rewardsLoading, error: rewardsError } = useLoyaltyRewards();
|
|
57
|
+
const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
|
|
144
58
|
const { data: referralData } = useReferralStats();
|
|
145
59
|
const redeemMutation = useRedeemLoyaltyReward();
|
|
146
60
|
|
|
147
61
|
// Extract data from query responses
|
|
148
62
|
const member = memberData?.loyaltyMember;
|
|
149
63
|
const rewards = rewardsData?.loyaltyRewards ?? [];
|
|
150
|
-
const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e
|
|
64
|
+
const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e) => e.node) ?? [];
|
|
151
65
|
const settings = settingsData?.loyaltySettings;
|
|
152
66
|
const referralStats = referralData?.referralStats;
|
|
153
67
|
|
|
@@ -164,7 +78,7 @@ export default function LoyaltyPage() {
|
|
|
164
78
|
const payload = result.redeemLoyaltyReward;
|
|
165
79
|
|
|
166
80
|
if (payload?.userErrors?.length) {
|
|
167
|
-
throw new Error(payload.userErrors[0]);
|
|
81
|
+
throw new Error(payload.userErrors[0] || 'Unknown error');
|
|
168
82
|
}
|
|
169
83
|
|
|
170
84
|
if (payload?.success) {
|
|
@@ -176,12 +90,23 @@ export default function LoyaltyPage() {
|
|
|
176
90
|
};
|
|
177
91
|
}
|
|
178
92
|
|
|
179
|
-
throw new Error('
|
|
93
|
+
throw new Error(tl('redeemFailed'));
|
|
180
94
|
} catch (error) {
|
|
181
95
|
throw error;
|
|
182
96
|
}
|
|
183
97
|
};
|
|
184
98
|
|
|
99
|
+
// Show skeleton while Zustand persist is hydrating from localStorage
|
|
100
|
+
if (!isHydrated) {
|
|
101
|
+
return (
|
|
102
|
+
<div className="container max-w-6xl py-8">
|
|
103
|
+
<div className="flex items-center justify-center min-h-[400px]">
|
|
104
|
+
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
185
110
|
// Show login prompt if not authenticated
|
|
186
111
|
if (!isAuthenticated) {
|
|
187
112
|
return (
|
|
@@ -189,7 +114,7 @@ export default function LoyaltyPage() {
|
|
|
189
114
|
<Link href="/account">
|
|
190
115
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
191
116
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
192
|
-
|
|
117
|
+
{t("backToAccount")}
|
|
193
118
|
</Button>
|
|
194
119
|
</Link>
|
|
195
120
|
|
|
@@ -197,15 +122,15 @@ export default function LoyaltyPage() {
|
|
|
197
122
|
<CardHeader>
|
|
198
123
|
<CardTitle className="flex items-center gap-2">
|
|
199
124
|
<Award className="h-5 w-5" />
|
|
200
|
-
|
|
125
|
+
{t("loyalty")}
|
|
201
126
|
</CardTitle>
|
|
202
127
|
</CardHeader>
|
|
203
128
|
<CardContent>
|
|
204
129
|
<p className="text-muted-foreground mb-4">
|
|
205
|
-
|
|
130
|
+
{tl("signInToView")}
|
|
206
131
|
</p>
|
|
207
132
|
<Link href="/auth/login?redirect=/account/loyalty">
|
|
208
|
-
<Button className="w-full">
|
|
133
|
+
<Button className="w-full">{ta("signIn")}</Button>
|
|
209
134
|
</Link>
|
|
210
135
|
</CardContent>
|
|
211
136
|
</Card>
|
|
@@ -224,6 +149,27 @@ export default function LoyaltyPage() {
|
|
|
224
149
|
);
|
|
225
150
|
}
|
|
226
151
|
|
|
152
|
+
// Show error state if primary queries failed
|
|
153
|
+
if (memberError || rewardsError) {
|
|
154
|
+
return (
|
|
155
|
+
<div className="container max-w-6xl py-8">
|
|
156
|
+
<Link href="/account">
|
|
157
|
+
<Button variant="ghost" size="sm" className="mb-4">
|
|
158
|
+
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
159
|
+
{t("backToAccount")}
|
|
160
|
+
</Button>
|
|
161
|
+
</Link>
|
|
162
|
+
|
|
163
|
+
<Alert variant="destructive">
|
|
164
|
+
<AlertCircle className="h-4 w-4" />
|
|
165
|
+
<AlertDescription>
|
|
166
|
+
{tl("loadFailed")}
|
|
167
|
+
</AlertDescription>
|
|
168
|
+
</Alert>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
227
173
|
// Show disabled program message
|
|
228
174
|
if (programDisabled) {
|
|
229
175
|
return (
|
|
@@ -231,14 +177,14 @@ export default function LoyaltyPage() {
|
|
|
231
177
|
<Link href="/account">
|
|
232
178
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
233
179
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
234
|
-
|
|
180
|
+
{t("backToAccount")}
|
|
235
181
|
</Button>
|
|
236
182
|
</Link>
|
|
237
183
|
|
|
238
184
|
<Alert>
|
|
239
185
|
<AlertCircle className="h-4 w-4" />
|
|
240
186
|
<AlertDescription>
|
|
241
|
-
|
|
187
|
+
{tl("unavailable")}
|
|
242
188
|
</AlertDescription>
|
|
243
189
|
</Alert>
|
|
244
190
|
</div>
|
|
@@ -252,7 +198,7 @@ export default function LoyaltyPage() {
|
|
|
252
198
|
<Link href="/account">
|
|
253
199
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
254
200
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
255
|
-
|
|
201
|
+
{t("backToAccount")}
|
|
256
202
|
</Button>
|
|
257
203
|
</Link>
|
|
258
204
|
|
|
@@ -260,16 +206,15 @@ export default function LoyaltyPage() {
|
|
|
260
206
|
<CardHeader>
|
|
261
207
|
<CardTitle className="flex items-center gap-2">
|
|
262
208
|
<Award className="h-5 w-5" />
|
|
263
|
-
|
|
209
|
+
{tl("joinTitle")}
|
|
264
210
|
</CardTitle>
|
|
265
211
|
</CardHeader>
|
|
266
212
|
<CardContent>
|
|
267
213
|
<p className="text-muted-foreground mb-4">
|
|
268
|
-
|
|
269
|
-
przy pierwszym zakupie.
|
|
214
|
+
{tl("joinDescription")}
|
|
270
215
|
</p>
|
|
271
216
|
<Link href="/products">
|
|
272
|
-
<Button className="w-full">
|
|
217
|
+
<Button className="w-full">{t("browseProducts")}</Button>
|
|
273
218
|
</Link>
|
|
274
219
|
</CardContent>
|
|
275
220
|
</Card>
|
|
@@ -277,43 +222,6 @@ export default function LoyaltyPage() {
|
|
|
277
222
|
);
|
|
278
223
|
}
|
|
279
224
|
|
|
280
|
-
// Map tier data for components
|
|
281
|
-
const tierData = member.tier
|
|
282
|
-
? {
|
|
283
|
-
id: member.tier.id,
|
|
284
|
-
name: member.tier.name,
|
|
285
|
-
type: member.tier.type,
|
|
286
|
-
minPoints: member.tier.minPoints,
|
|
287
|
-
pointsMultiplier: member.tier.pointsMultiplier,
|
|
288
|
-
customBenefits: member.tier.customBenefits ?? [],
|
|
289
|
-
}
|
|
290
|
-
: null;
|
|
291
|
-
|
|
292
|
-
const progressData = member.tierProgress
|
|
293
|
-
? {
|
|
294
|
-
currentTier: {
|
|
295
|
-
id: member.tierProgress.currentTier.id,
|
|
296
|
-
name: member.tierProgress.currentTier.name,
|
|
297
|
-
type: member.tierProgress.currentTier.type,
|
|
298
|
-
minPoints: member.tierProgress.currentTier.minPoints,
|
|
299
|
-
pointsMultiplier: member.tierProgress.currentTier.pointsMultiplier,
|
|
300
|
-
customBenefits: member.tierProgress.currentTier.customBenefits ?? [],
|
|
301
|
-
},
|
|
302
|
-
nextTier: member.tierProgress.nextTier
|
|
303
|
-
? {
|
|
304
|
-
id: member.tierProgress.nextTier.id,
|
|
305
|
-
name: member.tierProgress.nextTier.name,
|
|
306
|
-
type: member.tierProgress.nextTier.type,
|
|
307
|
-
minPoints: member.tierProgress.nextTier.minPoints,
|
|
308
|
-
pointsMultiplier: member.tierProgress.nextTier.pointsMultiplier,
|
|
309
|
-
customBenefits: member.tierProgress.nextTier.customBenefits ?? [],
|
|
310
|
-
}
|
|
311
|
-
: undefined,
|
|
312
|
-
pointsToNextTier: member.tierProgress.pointsToNextTier,
|
|
313
|
-
progressPercent: member.tierProgress.progressPercent,
|
|
314
|
-
}
|
|
315
|
-
: null;
|
|
316
|
-
|
|
317
225
|
// Check if referral tab should be shown
|
|
318
226
|
const showReferralTab = settings?.referralEnabled && referralStats;
|
|
319
227
|
|
|
@@ -324,18 +232,18 @@ export default function LoyaltyPage() {
|
|
|
324
232
|
<Link href="/account">
|
|
325
233
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
326
234
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
327
|
-
|
|
235
|
+
{t("backToAccount")}
|
|
328
236
|
</Button>
|
|
329
237
|
</Link>
|
|
330
238
|
|
|
331
239
|
<div className="flex items-center justify-between">
|
|
332
240
|
<div>
|
|
333
|
-
<h1 className="text-3xl font-bold mb-2">
|
|
241
|
+
<h1 className="text-3xl font-bold mb-2">{t("loyalty")}</h1>
|
|
334
242
|
<p className="text-muted-foreground">
|
|
335
|
-
|
|
243
|
+
{tl("collectAndRedeem", { pointsName: settings?.pointsName ?? 'punkty' })}
|
|
336
244
|
</p>
|
|
337
245
|
</div>
|
|
338
|
-
{
|
|
246
|
+
{member.tier && <TierBadge tier={member.tier.type} name={member.tier.name} size="lg" />}
|
|
339
247
|
</div>
|
|
340
248
|
</div>
|
|
341
249
|
|
|
@@ -344,20 +252,20 @@ export default function LoyaltyPage() {
|
|
|
344
252
|
<TabsList className="mb-6">
|
|
345
253
|
<TabsTrigger value="overview" className="gap-2">
|
|
346
254
|
<Award className="h-4 w-4" />
|
|
347
|
-
|
|
255
|
+
{tl("tabOverview")}
|
|
348
256
|
</TabsTrigger>
|
|
349
257
|
<TabsTrigger value="rewards" className="gap-2">
|
|
350
258
|
<Gift className="h-4 w-4" />
|
|
351
|
-
|
|
259
|
+
{tl("tabRewards")}
|
|
352
260
|
</TabsTrigger>
|
|
353
261
|
<TabsTrigger value="history" className="gap-2">
|
|
354
262
|
<History className="h-4 w-4" />
|
|
355
|
-
|
|
263
|
+
{tl("tabHistory")}
|
|
356
264
|
</TabsTrigger>
|
|
357
265
|
{showReferralTab && (
|
|
358
266
|
<TabsTrigger value="referral" className="gap-2">
|
|
359
267
|
<Users className="h-4 w-4" />
|
|
360
|
-
|
|
268
|
+
{tl("tabReferrals")}
|
|
361
269
|
</TabsTrigger>
|
|
362
270
|
)}
|
|
363
271
|
</TabsList>
|
|
@@ -366,22 +274,22 @@ export default function LoyaltyPage() {
|
|
|
366
274
|
<TabsContent value="overview" className="space-y-6">
|
|
367
275
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
368
276
|
<PointsBalance points={member.points} />
|
|
369
|
-
{
|
|
277
|
+
{member.tierProgress && <TierProgress progress={member.tierProgress} />}
|
|
370
278
|
</div>
|
|
371
279
|
|
|
372
280
|
{/* Tier Benefits */}
|
|
373
|
-
{
|
|
281
|
+
{member.tier && (
|
|
374
282
|
<div className="p-6 bg-gradient-to-r from-amber-50 to-yellow-50 dark:from-amber-950/30 dark:to-yellow-950/30 rounded-lg border border-amber-200 dark:border-amber-800">
|
|
375
283
|
<h3 className="font-semibold mb-4 flex items-center gap-2">
|
|
376
284
|
<Award className="h-5 w-5 text-amber-600" />
|
|
377
|
-
|
|
285
|
+
{tl("tierBenefits", { tierName: member.tier.name })}
|
|
378
286
|
</h3>
|
|
379
287
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm">
|
|
380
288
|
<div className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
|
|
381
|
-
<div className="font-medium">
|
|
382
|
-
<div className="text-2xl font-bold text-amber-600">x{
|
|
289
|
+
<div className="font-medium">{tl("pointsMultiplier")}</div>
|
|
290
|
+
<div className="text-2xl font-bold text-amber-600">x{member.tier.pointsMultiplier}</div>
|
|
383
291
|
</div>
|
|
384
|
-
{
|
|
292
|
+
{member.tier.customBenefits?.slice(0, 2).map((benefit, idx) => (
|
|
385
293
|
<div key={idx} className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
|
|
386
294
|
<div className="font-medium">{benefit.name}</div>
|
|
387
295
|
{benefit.description && (
|
|
@@ -390,9 +298,9 @@ export default function LoyaltyPage() {
|
|
|
390
298
|
</div>
|
|
391
299
|
))}
|
|
392
300
|
</div>
|
|
393
|
-
{
|
|
301
|
+
{(member.tier.customBenefits?.length ?? 0) > 2 && (
|
|
394
302
|
<div className="mt-4 flex flex-wrap gap-2">
|
|
395
|
-
{
|
|
303
|
+
{member.tier.customBenefits?.slice(2).map((benefit, idx) => (
|
|
396
304
|
<div key={idx} className="px-3 py-1.5 bg-white/50 dark:bg-black/20 rounded-full text-sm">
|
|
397
305
|
{benefit.name}
|
|
398
306
|
</div>
|
|
@@ -406,16 +314,16 @@ export default function LoyaltyPage() {
|
|
|
406
314
|
<div className="flex flex-wrap gap-4">
|
|
407
315
|
<Button onClick={() => setActiveTab('rewards')}>
|
|
408
316
|
<Gift className="h-4 w-4 mr-2" />
|
|
409
|
-
|
|
317
|
+
{tl("browseRewards")}
|
|
410
318
|
</Button>
|
|
411
319
|
<Button variant="outline" onClick={() => setActiveTab('history')}>
|
|
412
320
|
<History className="h-4 w-4 mr-2" />
|
|
413
|
-
|
|
321
|
+
{tl("viewHistory")}
|
|
414
322
|
</Button>
|
|
415
323
|
{showReferralTab && (
|
|
416
324
|
<Button variant="outline" onClick={() => setActiveTab('referral')}>
|
|
417
325
|
<Users className="h-4 w-4 mr-2" />
|
|
418
|
-
|
|
326
|
+
{tl("referFriend")}
|
|
419
327
|
</Button>
|
|
420
328
|
)}
|
|
421
329
|
</div>
|
|
@@ -424,20 +332,13 @@ export default function LoyaltyPage() {
|
|
|
424
332
|
{/* Rewards Tab */}
|
|
425
333
|
<TabsContent value="rewards">
|
|
426
334
|
<div className="mb-6">
|
|
427
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
335
|
+
<h2 className="text-xl font-semibold mb-2">{tl("availableRewards")}</h2>
|
|
428
336
|
<p className="text-muted-foreground">
|
|
429
|
-
|
|
337
|
+
{tl("redeemDescription", { pointsName: settings?.pointsName ?? 'punkty' })}
|
|
430
338
|
</p>
|
|
431
339
|
</div>
|
|
432
340
|
<RewardsCatalog
|
|
433
|
-
rewards={rewards
|
|
434
|
-
...r,
|
|
435
|
-
discountAmount: r.discountAmount
|
|
436
|
-
? { amount: r.discountAmount.amount, currencyCode: r.discountAmount.currencyCode }
|
|
437
|
-
: undefined,
|
|
438
|
-
// Map tierRequired from LoyaltyTier object to just the type string
|
|
439
|
-
tierRequired: r.tierRequired?.type,
|
|
440
|
-
}))}
|
|
341
|
+
rewards={rewards}
|
|
441
342
|
currentPoints={member.points.currentPoints}
|
|
442
343
|
currentTier={member.tier?.type}
|
|
443
344
|
onRedeem={handleRedeemReward}
|
|
@@ -447,8 +348,8 @@ export default function LoyaltyPage() {
|
|
|
447
348
|
{/* History Tab */}
|
|
448
349
|
<TabsContent value="history">
|
|
449
350
|
<div className="mb-6">
|
|
450
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
451
|
-
<p className="text-muted-foreground">
|
|
351
|
+
<h2 className="text-xl font-semibold mb-2">{tl("pointsHistory")}</h2>
|
|
352
|
+
<p className="text-muted-foreground">{tl("historyDescription")}</p>
|
|
452
353
|
</div>
|
|
453
354
|
<PointsHistory transactions={transactions} />
|
|
454
355
|
</TabsContent>
|
|
@@ -457,21 +358,16 @@ export default function LoyaltyPage() {
|
|
|
457
358
|
{showReferralTab && referralStats && (
|
|
458
359
|
<TabsContent value="referral">
|
|
459
360
|
<div className="mb-6">
|
|
460
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
361
|
+
<h2 className="text-xl font-semibold mb-2">{tl("referFriend")}</h2>
|
|
461
362
|
<p className="text-muted-foreground">
|
|
462
|
-
|
|
463
|
-
|
|
363
|
+
{tl("referFriendDescription", {
|
|
364
|
+
points: settings?.referralPoints ?? 0,
|
|
365
|
+
pointsName: settings?.pointsName ?? 'punktów',
|
|
366
|
+
})}
|
|
464
367
|
</p>
|
|
465
368
|
</div>
|
|
466
369
|
<ReferralSection
|
|
467
|
-
|
|
468
|
-
shareUrl={referralStats.shareUrl}
|
|
469
|
-
stats={{
|
|
470
|
-
totalReferred: referralStats.totalReferred,
|
|
471
|
-
completedReferrals: referralStats.completedReferrals,
|
|
472
|
-
pendingReferrals: referralStats.pendingReferrals,
|
|
473
|
-
totalPointsEarned: referralStats.totalPointsEarned,
|
|
474
|
-
}}
|
|
370
|
+
referralStats={referralStats}
|
|
475
371
|
pointsName={settings?.pointsName ?? 'punktów'}
|
|
476
372
|
referralPoints={settings?.referralPoints ?? 0}
|
|
477
373
|
bonusPoints={settings?.referralBonusPoints ?? 0}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function OrderDetailLoading() {
|
|
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
|
+
{/* Back button */}
|
|
10
|
+
<Skeleton className="mb-6 h-10 w-40" />
|
|
11
|
+
|
|
12
|
+
{/* Order header card */}
|
|
13
|
+
<div className="mb-6 rounded-lg border p-6">
|
|
14
|
+
<div className="flex items-center justify-between">
|
|
15
|
+
<div className="space-y-2">
|
|
16
|
+
<Skeleton className="h-7 w-48" />
|
|
17
|
+
<Skeleton className="h-4 w-32" />
|
|
18
|
+
</div>
|
|
19
|
+
<Skeleton className="h-8 w-24 rounded-full" />
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
{/* Order items card */}
|
|
24
|
+
<div className="mb-6 rounded-lg border p-6">
|
|
25
|
+
<Skeleton className="mb-4 h-6 w-24" />
|
|
26
|
+
<div className="space-y-4">
|
|
27
|
+
{[...Array(3)].map((_, i) => (
|
|
28
|
+
<div key={i} className="flex items-center gap-4">
|
|
29
|
+
<Skeleton className="h-16 w-16 rounded-md" />
|
|
30
|
+
<div className="flex-1 space-y-2">
|
|
31
|
+
<Skeleton className="h-4 w-3/4" />
|
|
32
|
+
<Skeleton className="h-4 w-1/4" />
|
|
33
|
+
</div>
|
|
34
|
+
<Skeleton className="h-5 w-20" />
|
|
35
|
+
</div>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
<div className="mt-4 border-t pt-4 space-y-2">
|
|
39
|
+
<Skeleton className="ml-auto h-4 w-32" />
|
|
40
|
+
<Skeleton className="ml-auto h-4 w-32" />
|
|
41
|
+
<Skeleton className="ml-auto h-5 w-36" />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{/* Address cards */}
|
|
46
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
47
|
+
{[...Array(2)].map((_, i) => (
|
|
48
|
+
<div key={i} className="rounded-lg border p-6">
|
|
49
|
+
<Skeleton className="mb-3 h-5 w-36" />
|
|
50
|
+
<div className="space-y-2">
|
|
51
|
+
<Skeleton className="h-4 w-48" />
|
|
52
|
+
<Skeleton className="h-4 w-40" />
|
|
53
|
+
<Skeleton className="h-4 w-32" />
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
))}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useParams } from "next/navigation";
|
|
4
|
+
import { Link } from "@/i18n/navigation";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
6
|
+
import { ChevronLeft } from "lucide-react";
|
|
7
|
+
import { useCustomerOrder } from "@/lib/graphql/hooks";
|
|
8
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
9
|
+
import { Button } from "@/components/ui/button";
|
|
10
|
+
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
11
|
+
import {
|
|
12
|
+
OrderDetails,
|
|
13
|
+
type OrderDetailsData,
|
|
14
|
+
} from "@/components/account/order-details";
|
|
15
|
+
|
|
16
|
+
export default function OrderDetailPage() {
|
|
17
|
+
const t = useTranslations("account");
|
|
18
|
+
const params = useParams();
|
|
19
|
+
const orderId = params.id as string;
|
|
20
|
+
const hydrated = useHydrated();
|
|
21
|
+
|
|
22
|
+
const { data, isPending, error } = useCustomerOrder(orderId);
|
|
23
|
+
|
|
24
|
+
const order = data?.customerOrder;
|
|
25
|
+
|
|
26
|
+
if (!hydrated || isPending) {
|
|
27
|
+
return (
|
|
28
|
+
<div className="container mx-auto px-4 py-8">
|
|
29
|
+
<div className="animate-pulse space-y-4">
|
|
30
|
+
<div className="h-8 bg-muted rounded w-1/4"></div>
|
|
31
|
+
<div className="h-64 bg-muted rounded"></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (error) {
|
|
38
|
+
return (
|
|
39
|
+
<div className="container mx-auto px-4 py-8">
|
|
40
|
+
<div className="text-center">
|
|
41
|
+
<h1 className="text-2xl font-bold text-destructive">{t("failedLoadOrder")}</h1>
|
|
42
|
+
<p className="mt-2 text-muted-foreground">{t("tryAgainLater")}</p>
|
|
43
|
+
<Link href="/account/orders">
|
|
44
|
+
<Button className="mt-4">{t("backToOrders")}</Button>
|
|
45
|
+
</Link>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!order) {
|
|
52
|
+
return (
|
|
53
|
+
<div className="container mx-auto px-4 py-8">
|
|
54
|
+
<div className="text-center">
|
|
55
|
+
<h1 className="text-2xl font-bold">{t("orderNotFound")}</h1>
|
|
56
|
+
<Link href="/account/orders">
|
|
57
|
+
<Button className="mt-4">{t("backToOrders")}</Button>
|
|
58
|
+
</Link>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const mapFulfillmentStatus = (status?: string | null): OrderDetailsData["status"] => {
|
|
65
|
+
switch (status) {
|
|
66
|
+
case "DELIVERED": return "delivered";
|
|
67
|
+
case "IN_TRANSIT":
|
|
68
|
+
case "FULFILLED": return "shipped";
|
|
69
|
+
case "UNFULFILLED":
|
|
70
|
+
case "PARTIALLY_FULFILLED": return "processing";
|
|
71
|
+
default: return "processing";
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const orderDetails: OrderDetailsData = {
|
|
76
|
+
id: order.id,
|
|
77
|
+
orderNumber: order.orderNumber?.toString() || order.id,
|
|
78
|
+
date: new Date(order.processedAt).toLocaleDateString(),
|
|
79
|
+
status: mapFulfillmentStatus(order.fulfillmentStatus),
|
|
80
|
+
items: [],
|
|
81
|
+
subtotal: order.subtotalPrice?.amount || "0",
|
|
82
|
+
shipping: order.totalShipping?.amount || "0",
|
|
83
|
+
tax: order.totalTax?.amount || "0",
|
|
84
|
+
total: order.totalPrice.amount,
|
|
85
|
+
currency: order.totalPrice.currencyCode,
|
|
86
|
+
shippingAddress: order.shippingAddress
|
|
87
|
+
? {
|
|
88
|
+
firstName: order.shippingAddress.firstName || "",
|
|
89
|
+
lastName: order.shippingAddress.lastName || "",
|
|
90
|
+
address1: order.shippingAddress.address1 || "",
|
|
91
|
+
address2: order.shippingAddress.address2 || "",
|
|
92
|
+
city: order.shippingAddress.city || "",
|
|
93
|
+
province: order.shippingAddress.province || "",
|
|
94
|
+
zip: order.shippingAddress.zip || "",
|
|
95
|
+
country: order.shippingAddress.country || "",
|
|
96
|
+
phone: order.shippingAddress.phone || "",
|
|
97
|
+
}
|
|
98
|
+
: undefined,
|
|
99
|
+
trackingNumber: undefined,
|
|
100
|
+
estimatedDelivery: undefined,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="container mx-auto px-4 py-8">
|
|
105
|
+
<Breadcrumbs className="mb-6" />
|
|
106
|
+
|
|
107
|
+
<div className="mb-6">
|
|
108
|
+
<Button variant="ghost" asChild>
|
|
109
|
+
<Link href="/account/orders">
|
|
110
|
+
<ChevronLeft className="mr-2 h-4 w-4" />
|
|
111
|
+
{t("backToOrders")}
|
|
112
|
+
</Link>
|
|
113
|
+
</Button>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<OrderDetails order={orderDetails} />
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|