@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
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { Truck, MapPin } from "lucide-react";
|
|
5
6
|
import { Input } from "@/components/ui/input";
|
|
6
7
|
import { Button } from "@/components/ui/button";
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Select,
|
|
10
|
+
SelectContent,
|
|
11
|
+
SelectItem,
|
|
12
|
+
SelectTrigger,
|
|
13
|
+
SelectValue,
|
|
14
|
+
} from "@/components/ui/select";
|
|
8
15
|
import { cn } from "@/lib/utils";
|
|
9
16
|
|
|
10
17
|
export interface ShippingOption {
|
|
@@ -33,6 +40,8 @@ export function ShippingEstimator({
|
|
|
33
40
|
selectedOption,
|
|
34
41
|
className,
|
|
35
42
|
}: ShippingEstimatorProps) {
|
|
43
|
+
const t = useTranslations("cart");
|
|
44
|
+
const tCountries = useTranslations("countries");
|
|
36
45
|
const [country, setCountry] = useState("PL");
|
|
37
46
|
const [postalCode, setPostalCode] = useState("");
|
|
38
47
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -40,16 +49,16 @@ export function ShippingEstimator({
|
|
|
40
49
|
const [error, setError] = useState<string | null>(null);
|
|
41
50
|
|
|
42
51
|
const countries = [
|
|
43
|
-
{ value: "PL", label: "
|
|
44
|
-
{ value: "DE", label: "
|
|
45
|
-
{ value: "FR", label: "
|
|
46
|
-
{ value: "GB", label: "
|
|
47
|
-
{ value: "US", label: "
|
|
52
|
+
{ value: "PL", label: tCountries("PL") },
|
|
53
|
+
{ value: "DE", label: tCountries("DE") },
|
|
54
|
+
{ value: "FR", label: tCountries("FR") },
|
|
55
|
+
{ value: "GB", label: tCountries("GB") },
|
|
56
|
+
{ value: "US", label: tCountries("US") },
|
|
48
57
|
];
|
|
49
58
|
|
|
50
59
|
const handleEstimate = async () => {
|
|
51
60
|
if (!postalCode.trim()) {
|
|
52
|
-
setError("
|
|
61
|
+
setError(t("enterPostalCode"));
|
|
53
62
|
return;
|
|
54
63
|
}
|
|
55
64
|
|
|
@@ -62,10 +71,10 @@ export function ShippingEstimator({
|
|
|
62
71
|
setOptions(result);
|
|
63
72
|
|
|
64
73
|
if (result.length === 0) {
|
|
65
|
-
setError("
|
|
74
|
+
setError(t("noShippingOptions"));
|
|
66
75
|
}
|
|
67
76
|
} catch (err) {
|
|
68
|
-
setError("
|
|
77
|
+
setError(t("failedCalculate"));
|
|
69
78
|
} finally {
|
|
70
79
|
setIsLoading(false);
|
|
71
80
|
}
|
|
@@ -84,25 +93,34 @@ export function ShippingEstimator({
|
|
|
84
93
|
<div className="flex items-center gap-2">
|
|
85
94
|
<Truck className="h-5 w-5 text-muted-foreground" />
|
|
86
95
|
<h3 className="text-sm font-medium text-foreground">
|
|
87
|
-
|
|
96
|
+
{t("estimateShipping")}
|
|
88
97
|
</h3>
|
|
89
98
|
</div>
|
|
90
99
|
|
|
91
100
|
{/* Form */}
|
|
92
101
|
<div className="space-y-3">
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
<div>
|
|
103
|
+
<label className="text-sm font-medium text-foreground">{t("country")}</label>
|
|
104
|
+
<Select value={country} onValueChange={setCountry}>
|
|
105
|
+
<SelectTrigger>
|
|
106
|
+
<SelectValue placeholder={t("selectCountry")} />
|
|
107
|
+
</SelectTrigger>
|
|
108
|
+
<SelectContent>
|
|
109
|
+
{countries.map((c) => (
|
|
110
|
+
<SelectItem key={c.value} value={c.value}>
|
|
111
|
+
{c.label}
|
|
112
|
+
</SelectItem>
|
|
113
|
+
))}
|
|
114
|
+
</SelectContent>
|
|
115
|
+
</Select>
|
|
116
|
+
</div>
|
|
99
117
|
|
|
100
118
|
<div className="flex gap-2">
|
|
101
119
|
<div className="relative flex-1">
|
|
102
120
|
<MapPin className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
103
121
|
<Input
|
|
104
122
|
type="text"
|
|
105
|
-
placeholder="
|
|
123
|
+
placeholder={t("postalCode")}
|
|
106
124
|
value={postalCode}
|
|
107
125
|
onChange={(e) => setPostalCode(e.target.value)}
|
|
108
126
|
onKeyDown={(e) => e.key === "Enter" && handleEstimate()}
|
|
@@ -114,7 +132,7 @@ export function ShippingEstimator({
|
|
|
114
132
|
onClick={handleEstimate}
|
|
115
133
|
disabled={!postalCode.trim() || isLoading}
|
|
116
134
|
>
|
|
117
|
-
{isLoading ? "
|
|
135
|
+
{isLoading ? t("calculating") : t("calculate")}
|
|
118
136
|
</Button>
|
|
119
137
|
</div>
|
|
120
138
|
|
|
@@ -125,7 +143,7 @@ export function ShippingEstimator({
|
|
|
125
143
|
{options.length > 0 && (
|
|
126
144
|
<div className="space-y-2">
|
|
127
145
|
<p className="text-sm font-medium text-foreground">
|
|
128
|
-
|
|
146
|
+
{t("availableOptions")}
|
|
129
147
|
</p>
|
|
130
148
|
<div className="space-y-2">
|
|
131
149
|
{options.map((option) => (
|
|
@@ -145,7 +163,7 @@ export function ShippingEstimator({
|
|
|
145
163
|
{option.name}
|
|
146
164
|
</p>
|
|
147
165
|
<p className="text-xs text-muted-foreground">
|
|
148
|
-
|
|
166
|
+
{t("estimatedDelivery")} {option.estimatedDays}
|
|
149
167
|
</p>
|
|
150
168
|
</div>
|
|
151
169
|
<p className="text-sm font-semibold text-foreground">
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
4
|
import { CreditCard, Building2, Wallet, Banknote, Check, Smartphone } from "lucide-react";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Payment method type enum (matches GraphQL PaymentMethodType)
|
|
@@ -65,30 +66,18 @@ function getPaymentTypeIcon(type: PaymentMethodType) {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
|
-
*
|
|
69
|
+
* Payment type to translation key mapping
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
case "APPLE_PAY":
|
|
81
|
-
return "Apple Pay";
|
|
82
|
-
case "GOOGLE_PAY":
|
|
83
|
-
return "Google Pay";
|
|
84
|
-
case "PAYPAL":
|
|
85
|
-
return "PayPal";
|
|
86
|
-
case "OTHER":
|
|
87
|
-
return "Inna metoda płatności";
|
|
88
|
-
default:
|
|
89
|
-
return type;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
71
|
+
const PAYMENT_TYPE_KEYS: Record<string, string> = {
|
|
72
|
+
CARD: "creditCard",
|
|
73
|
+
BLIK: "blik",
|
|
74
|
+
BANK_TRANSFER: "bankTransfer",
|
|
75
|
+
CASH_ON_DELIVERY: "cashOnDelivery",
|
|
76
|
+
APPLE_PAY: "applePay",
|
|
77
|
+
GOOGLE_PAY: "googlePay",
|
|
78
|
+
PAYPAL: "paypal",
|
|
79
|
+
OTHER: "other",
|
|
80
|
+
};
|
|
92
81
|
|
|
93
82
|
/**
|
|
94
83
|
* PaymentMethodCard - Selectable payment method card
|
|
@@ -108,6 +97,7 @@ export function PaymentMethodCard({
|
|
|
108
97
|
disabled = false,
|
|
109
98
|
className,
|
|
110
99
|
}: PaymentMethodCardProps) {
|
|
100
|
+
const t = useTranslations("paymentMethods");
|
|
111
101
|
const Icon = getPaymentTypeIcon(method.type);
|
|
112
102
|
|
|
113
103
|
return (
|
|
@@ -160,12 +150,12 @@ export function PaymentMethodCard({
|
|
|
160
150
|
</span>
|
|
161
151
|
{method.isDefault && (
|
|
162
152
|
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary/10 text-primary">
|
|
163
|
-
|
|
153
|
+
{t("default")}
|
|
164
154
|
</span>
|
|
165
155
|
)}
|
|
166
156
|
</div>
|
|
167
157
|
<p className="text-sm text-muted-foreground truncate">
|
|
168
|
-
{method.description ||
|
|
158
|
+
{method.description || t(PAYMENT_TYPE_KEYS[method.type] || "other")}
|
|
169
159
|
</p>
|
|
170
160
|
</div>
|
|
171
161
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, useCallback } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { cn } from "@/lib/utils";
|
|
5
6
|
import { CreditCard, AlertCircle, Loader2 } from "lucide-react";
|
|
6
7
|
import { PaymentMethodCard, PaymentMethod } from "./payment-method-card";
|
|
@@ -46,6 +47,7 @@ export function PaymentStep({
|
|
|
46
47
|
onContinue,
|
|
47
48
|
className,
|
|
48
49
|
}: PaymentStepProps) {
|
|
50
|
+
const t = useTranslations("checkout.payment");
|
|
49
51
|
const [localSelectedId, setLocalSelectedId] = useState<string | null>(
|
|
50
52
|
selectedPaymentMethodId ||
|
|
51
53
|
availablePaymentMethods.find((m) => m.isDefault)?.id ||
|
|
@@ -67,13 +69,13 @@ export function PaymentStep({
|
|
|
67
69
|
<div className={cn("space-y-4", className)}>
|
|
68
70
|
<div className="flex items-center gap-2">
|
|
69
71
|
<CreditCard className="h-5 w-5 text-muted-foreground" />
|
|
70
|
-
<h3 className="text-lg font-semibold text-foreground">
|
|
72
|
+
<h3 className="text-lg font-semibold text-foreground">{t("title")}</h3>
|
|
71
73
|
</div>
|
|
72
74
|
|
|
73
75
|
<Alert variant="destructive">
|
|
74
76
|
<AlertCircle className="h-4 w-4" />
|
|
75
77
|
<AlertDescription>
|
|
76
|
-
|
|
78
|
+
{t("noMethods")}
|
|
77
79
|
</AlertDescription>
|
|
78
80
|
</Alert>
|
|
79
81
|
</div>
|
|
@@ -89,12 +91,12 @@ export function PaymentStep({
|
|
|
89
91
|
{/* Header */}
|
|
90
92
|
<div className="flex items-center gap-2">
|
|
91
93
|
<CreditCard className="h-5 w-5 text-muted-foreground" />
|
|
92
|
-
<h3 className="text-lg font-semibold text-foreground">
|
|
94
|
+
<h3 className="text-lg font-semibold text-foreground">{t("title")}</h3>
|
|
93
95
|
</div>
|
|
94
96
|
|
|
95
97
|
{/* Description */}
|
|
96
98
|
<p className="text-sm text-muted-foreground">
|
|
97
|
-
|
|
99
|
+
{t("chooseMethod")}
|
|
98
100
|
</p>
|
|
99
101
|
|
|
100
102
|
{/* Error Alert */}
|
|
@@ -124,7 +126,7 @@ export function PaymentStep({
|
|
|
124
126
|
{isLoading && (
|
|
125
127
|
<div className="flex items-center justify-center gap-2 text-sm text-muted-foreground">
|
|
126
128
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
127
|
-
<span>
|
|
129
|
+
<span>{t("updating")}</span>
|
|
128
130
|
</div>
|
|
129
131
|
)}
|
|
130
132
|
|
|
@@ -138,10 +140,10 @@ export function PaymentStep({
|
|
|
138
140
|
{isLoading ? (
|
|
139
141
|
<>
|
|
140
142
|
<Loader2 className="h-4 w-4 animate-spin mr-2" />
|
|
141
|
-
|
|
143
|
+
{t("processing")}
|
|
142
144
|
</>
|
|
143
145
|
) : (
|
|
144
|
-
"
|
|
146
|
+
t("continueToReview")
|
|
145
147
|
)}
|
|
146
148
|
</Button>
|
|
147
149
|
)}
|
|
@@ -149,7 +151,7 @@ export function PaymentStep({
|
|
|
149
151
|
{/* Selected Method Info */}
|
|
150
152
|
{selectedMethod && (
|
|
151
153
|
<p className="text-xs text-muted-foreground text-center">
|
|
152
|
-
|
|
154
|
+
{t("selected")} {selectedMethod.name}
|
|
153
155
|
{selectedMethod.description && ` - ${selectedMethod.description}`}
|
|
154
156
|
</p>
|
|
155
157
|
)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { Receipt } from "lucide-react";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -44,6 +45,7 @@ export function TaxBreakdown({
|
|
|
44
45
|
showHeader = true,
|
|
45
46
|
compact = false,
|
|
46
47
|
}: TaxBreakdownProps) {
|
|
48
|
+
const t = useTranslations("checkout.tax");
|
|
47
49
|
const formatPrice = (money: Money) => {
|
|
48
50
|
const amount = parseFloat(money.amount);
|
|
49
51
|
return new Intl.NumberFormat("pl-PL", {
|
|
@@ -65,7 +67,7 @@ export function TaxBreakdown({
|
|
|
65
67
|
if (compact) {
|
|
66
68
|
return (
|
|
67
69
|
<div className={cn("flex items-center justify-between", className)}>
|
|
68
|
-
<span className="text-sm text-muted-foreground">
|
|
70
|
+
<span className="text-sm text-muted-foreground">{t("title")}</span>
|
|
69
71
|
<span className="text-sm font-medium text-foreground">
|
|
70
72
|
{formatPrice(totalTax)}
|
|
71
73
|
</span>
|
|
@@ -79,7 +81,7 @@ export function TaxBreakdown({
|
|
|
79
81
|
{showHeader && (
|
|
80
82
|
<div className="flex items-center gap-2">
|
|
81
83
|
<Receipt className="h-4 w-4 text-muted-foreground" />
|
|
82
|
-
<h4 className="text-sm font-medium text-foreground">
|
|
84
|
+
<h4 className="text-sm font-medium text-foreground">{t("breakdown")}</h4>
|
|
83
85
|
</div>
|
|
84
86
|
)}
|
|
85
87
|
|
|
@@ -104,7 +106,7 @@ export function TaxBreakdown({
|
|
|
104
106
|
<>
|
|
105
107
|
<div className="border-t border-border my-2" />
|
|
106
108
|
<div className="flex items-center justify-between text-sm">
|
|
107
|
-
<span className="font-medium text-foreground">
|
|
109
|
+
<span className="font-medium text-foreground">{t("total")}</span>
|
|
108
110
|
<span className="font-semibold text-foreground">
|
|
109
111
|
{formatPrice(totalTax)}
|
|
110
112
|
</span>
|
|
@@ -116,7 +118,7 @@ export function TaxBreakdown({
|
|
|
116
118
|
{/* Tax exemption note (for B2B) */}
|
|
117
119
|
{parseFloat(totalTax.amount) === 0 && taxLines.length === 0 && (
|
|
118
120
|
<p className="text-xs text-muted-foreground">
|
|
119
|
-
|
|
121
|
+
{t("exempt")}
|
|
120
122
|
</p>
|
|
121
123
|
)}
|
|
122
124
|
</div>
|
|
@@ -128,13 +130,14 @@ export function TaxBreakdown({
|
|
|
128
130
|
*/
|
|
129
131
|
export function TaxSummaryLine({
|
|
130
132
|
totalTax,
|
|
131
|
-
label
|
|
133
|
+
label,
|
|
132
134
|
className,
|
|
133
135
|
}: {
|
|
134
136
|
totalTax: Money;
|
|
135
137
|
label?: string;
|
|
136
138
|
className?: string;
|
|
137
139
|
}) {
|
|
140
|
+
const t = useTranslations("checkout.tax");
|
|
138
141
|
const formatPrice = (money: Money) => {
|
|
139
142
|
const amount = parseFloat(money.amount);
|
|
140
143
|
return new Intl.NumberFormat("pl-PL", {
|
|
@@ -145,7 +148,7 @@ export function TaxSummaryLine({
|
|
|
145
148
|
|
|
146
149
|
return (
|
|
147
150
|
<div className={cn("flex items-center justify-between text-sm", className)}>
|
|
148
|
-
<span className="text-muted-foreground">{label}</span>
|
|
151
|
+
<span className="text-muted-foreground">{label ?? t("title")}</span>
|
|
149
152
|
<span className="text-foreground">{formatPrice(totalTax)}</span>
|
|
150
153
|
</div>
|
|
151
154
|
);
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { useState, useRef, useEffect } from "react";
|
|
4
4
|
import { ChevronDown, Check, Globe } from "lucide-react";
|
|
5
|
-
import { useCurrencyStore } from "
|
|
5
|
+
import { useCurrencyStore } from "@doswiftly/storefront-sdk/react";
|
|
6
6
|
import { useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import { useTranslations } from "next-intl";
|
|
7
8
|
|
|
8
9
|
// ============================================================================
|
|
9
10
|
// CURRENCY DATA
|
|
@@ -81,6 +82,7 @@ export function CurrencySelector({
|
|
|
81
82
|
className = "",
|
|
82
83
|
variant = "default",
|
|
83
84
|
}: CurrencySelectorProps) {
|
|
85
|
+
const t = useTranslations("currency");
|
|
84
86
|
const [isOpen, setIsOpen] = useState(false);
|
|
85
87
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
86
88
|
const queryClient = useQueryClient();
|
|
@@ -89,7 +91,7 @@ export function CurrencySelector({
|
|
|
89
91
|
const currency = useCurrencyStore((state) => state.currency);
|
|
90
92
|
const supportedCurrencies = useCurrencyStore((state) => state.supportedCurrencies);
|
|
91
93
|
const setCurrency = useCurrencyStore((state) => state.setCurrency);
|
|
92
|
-
const isHydrated = useCurrencyStore((state) => state.
|
|
94
|
+
const isHydrated = useCurrencyStore((state) => state.isLoaded);
|
|
93
95
|
|
|
94
96
|
// Handle currency change
|
|
95
97
|
const handleCurrencyChange = (newCurrency: string) => {
|
|
@@ -141,7 +143,7 @@ export function CurrencySelector({
|
|
|
141
143
|
<button
|
|
142
144
|
onClick={() => setIsOpen(!isOpen)}
|
|
143
145
|
className="flex items-center gap-1 rounded-md px-2 py-1 text-sm hover:bg-muted"
|
|
144
|
-
aria-label="
|
|
146
|
+
aria-label={t("selectCurrency")}
|
|
145
147
|
>
|
|
146
148
|
<span className="font-medium">{currentSymbol}</span>
|
|
147
149
|
<ChevronDown className="h-3 w-3" />
|
|
@@ -191,10 +193,10 @@ export function CurrencySelector({
|
|
|
191
193
|
<div className="absolute right-0 top-full z-50 mt-2 w-64 rounded-md border border-border bg-background shadow-lg">
|
|
192
194
|
<div className="border-b border-border p-3">
|
|
193
195
|
<p className="text-sm font-medium text-foreground">
|
|
194
|
-
|
|
196
|
+
{t("selectTitle")}
|
|
195
197
|
</p>
|
|
196
198
|
<p className="text-xs text-muted-foreground">
|
|
197
|
-
|
|
199
|
+
{t("selectDescription")}
|
|
198
200
|
</p>
|
|
199
201
|
</div>
|
|
200
202
|
<div className="max-h-64 overflow-y-auto p-1">
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useSearchParams
|
|
4
|
-
import
|
|
3
|
+
import { useSearchParams } from "next/navigation";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
5
|
+
import { usePathname, Link } from "@/i18n/navigation";
|
|
5
6
|
|
|
6
7
|
interface PaginationProps {
|
|
7
8
|
hasMore: boolean;
|
|
@@ -21,6 +22,8 @@ export function Pagination({
|
|
|
21
22
|
}: PaginationProps) {
|
|
22
23
|
const pathname = usePathname();
|
|
23
24
|
const searchParams = useSearchParams();
|
|
25
|
+
const t = useTranslations("product");
|
|
26
|
+
const tCommon = useTranslations("common");
|
|
24
27
|
|
|
25
28
|
// Build URL preserving current filters
|
|
26
29
|
const buildUrl = (cursor?: string | null) => {
|
|
@@ -44,10 +47,10 @@ export function Pagination({
|
|
|
44
47
|
!currentCursor ? "pointer-events-none opacity-50" : ""
|
|
45
48
|
}`}
|
|
46
49
|
>
|
|
47
|
-
|
|
50
|
+
{t("firstPage")}
|
|
48
51
|
</Link>
|
|
49
52
|
<span className="flex items-center px-4 text-gray-600">
|
|
50
|
-
|
|
53
|
+
{t("showingProducts", { count: totalShown })}
|
|
51
54
|
</span>
|
|
52
55
|
<Link
|
|
53
56
|
href={hasMore && endCursor ? buildUrl(endCursor) : "#"}
|
|
@@ -55,7 +58,7 @@ export function Pagination({
|
|
|
55
58
|
!hasMore ? "pointer-events-none opacity-50" : ""
|
|
56
59
|
}`}
|
|
57
60
|
>
|
|
58
|
-
|
|
61
|
+
{tCommon("next")}
|
|
59
62
|
</Link>
|
|
60
63
|
</div>
|
|
61
64
|
);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, useMemo } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { VariantSelector } from "@/components/commerce/variant-selector";
|
|
5
6
|
import { AddToCartButton } from "@/components/product/add-to-cart-button";
|
|
6
|
-
import { formatPrice } from "
|
|
7
|
+
import { formatPrice } from "@doswiftly/storefront-sdk";
|
|
7
8
|
|
|
8
9
|
interface ProductVariant {
|
|
9
10
|
id: string;
|
|
@@ -48,6 +49,7 @@ export function ProductActions({
|
|
|
48
49
|
productTitle,
|
|
49
50
|
productImages = []
|
|
50
51
|
}: ProductActionsProps) {
|
|
52
|
+
const t = useTranslations("product");
|
|
51
53
|
// Store only variant ID - derive variant object from props (SSOT)
|
|
52
54
|
const [selectedVariantId, setSelectedVariantId] = useState<string | null>(
|
|
53
55
|
() => variants[0]?.id ?? null
|
|
@@ -99,12 +101,12 @@ export function ProductActions({
|
|
|
99
101
|
{inStock ? (
|
|
100
102
|
<span className="inline-flex items-center gap-2 text-green-600">
|
|
101
103
|
<span className="h-2 w-2 rounded-full bg-green-600" />
|
|
102
|
-
|
|
104
|
+
{t("inStock")}
|
|
103
105
|
</span>
|
|
104
106
|
) : (
|
|
105
107
|
<span className="inline-flex items-center gap-2 text-red-600">
|
|
106
108
|
<span className="h-2 w-2 rounded-full bg-red-600" />
|
|
107
|
-
|
|
109
|
+
{t("outOfStock")}
|
|
108
110
|
</span>
|
|
109
111
|
)}
|
|
110
112
|
</div>
|
|
@@ -112,7 +114,7 @@ export function ProductActions({
|
|
|
112
114
|
{/* Quantity & Add to Cart */}
|
|
113
115
|
<div className="space-y-4">
|
|
114
116
|
<div className="flex items-center gap-4">
|
|
115
|
-
<label className="text-sm font-medium text-gray-700">
|
|
117
|
+
<label className="text-sm font-medium text-gray-700">{t("quantity")}</label>
|
|
116
118
|
<div className="flex items-center rounded-lg border border-gray-300">
|
|
117
119
|
<button
|
|
118
120
|
type="button"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
5
|
+
import { useRouter, Link } from "@/i18n/navigation";
|
|
5
6
|
import { Search, X, Loader2 } from "lucide-react";
|
|
6
7
|
import { useGraphQLQuery } from "@/lib/graphql/hooks";
|
|
7
8
|
import { ProductSearchDocument } from "@/generated/graphql";
|
|
8
|
-
import { useDebouncedValue } from "
|
|
9
|
-
import Link from "next/link";
|
|
9
|
+
import { useDebouncedValue } from "@doswiftly/storefront-sdk/react";
|
|
10
10
|
|
|
11
11
|
interface SearchInputProps {
|
|
12
12
|
placeholder?: string;
|
|
@@ -20,9 +20,10 @@ interface SearchInputProps {
|
|
|
20
20
|
* Pressing Enter navigates to full search page.
|
|
21
21
|
*/
|
|
22
22
|
export function SearchInput({
|
|
23
|
-
placeholder
|
|
23
|
+
placeholder,
|
|
24
24
|
className = "",
|
|
25
25
|
}: SearchInputProps) {
|
|
26
|
+
const t = useTranslations("search");
|
|
26
27
|
const router = useRouter();
|
|
27
28
|
const [query, setQuery] = useState("");
|
|
28
29
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -93,7 +94,7 @@ export function SearchInput({
|
|
|
93
94
|
setIsOpen(true);
|
|
94
95
|
}}
|
|
95
96
|
onFocus={() => query.length >= 2 && setIsOpen(true)}
|
|
96
|
-
placeholder={placeholder}
|
|
97
|
+
placeholder={placeholder ?? t("placeholder")}
|
|
97
98
|
className="h-10 w-full rounded-md border border-border bg-background pl-9 pr-9 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
98
99
|
/>
|
|
99
100
|
{query && (
|
|
@@ -118,12 +119,12 @@ export function SearchInput({
|
|
|
118
119
|
<div className="flex items-center justify-center p-4">
|
|
119
120
|
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
|
120
121
|
<span className="ml-2 text-sm text-muted-foreground">
|
|
121
|
-
|
|
122
|
+
{t("searching")}
|
|
122
123
|
</span>
|
|
123
124
|
</div>
|
|
124
125
|
) : hasResults ? (
|
|
125
126
|
<div className="max-h-96 overflow-y-auto">
|
|
126
|
-
{products.slice(0, 5).map((product
|
|
127
|
+
{products.slice(0, 5).map((product) => (
|
|
127
128
|
<Link
|
|
128
129
|
key={product.id}
|
|
129
130
|
href={`/products/${product.handle}`}
|
|
@@ -159,12 +160,12 @@ export function SearchInput({
|
|
|
159
160
|
}}
|
|
160
161
|
className="block border-t border-border p-3 text-center text-sm text-primary hover:bg-muted"
|
|
161
162
|
>
|
|
162
|
-
|
|
163
|
+
{t("viewAllResults", { query })}
|
|
163
164
|
</Link>
|
|
164
165
|
</div>
|
|
165
166
|
) : (
|
|
166
167
|
<div className="p-4 text-center text-sm text-muted-foreground">
|
|
167
|
-
|
|
168
|
+
{t("noProductsFound", { query: debouncedQuery })}
|
|
168
169
|
</div>
|
|
169
170
|
)}
|
|
170
171
|
</div>
|