@doswiftly/cli 0.1.1
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 +357 -0
- package/bin/doswiftly.js +2 -0
- package/dist/commands/auth-github.d.ts +6 -0
- package/dist/commands/auth-github.d.ts.map +1 -0
- package/dist/commands/auth-github.js +89 -0
- package/dist/commands/auth-github.js.map +1 -0
- package/dist/commands/auth-token.d.ts +12 -0
- package/dist/commands/auth-token.d.ts.map +1 -0
- package/dist/commands/auth-token.js +43 -0
- package/dist/commands/auth-token.js.map +1 -0
- package/dist/commands/auth.d.ts +22 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +348 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/check.d.ts +5 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +234 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +104 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/deploy.d.ts +37 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +580 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +8 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +83 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +363 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/domain.d.ts +13 -0
- package/dist/commands/domain.d.ts.map +1 -0
- package/dist/commands/domain.js +128 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/env.d.ts +25 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +228 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1028 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect.d.ts +12 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +162 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/migrate.d.ts +18 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +355 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/preview.d.ts +29 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +199 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/proxy.d.ts +9 -0
- package/dist/commands/proxy.d.ts.map +1 -0
- package/dist/commands/proxy.js +37 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/sdk.d.ts +5 -0
- package/dist/commands/sdk.d.ts.map +1 -0
- package/dist/commands/sdk.js +82 -0
- package/dist/commands/sdk.js.map +1 -0
- package/dist/commands/template.d.ts +107 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +1309 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/types.d.ts +5 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +82 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +103 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/upgrade.d.ts +18 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +55 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/verify.d.ts +5 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +232 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +60 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config/types.d.ts +173 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +48 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +416 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-url.d.ts +14 -0
- package/dist/lib/api-url.d.ts.map +1 -0
- package/dist/lib/api-url.js +24 -0
- package/dist/lib/api-url.js.map +1 -0
- package/dist/lib/api.d.ts +67 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +36 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +39 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +195 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/env-storage.d.ts +140 -0
- package/dist/lib/env-storage.d.ts.map +1 -0
- package/dist/lib/env-storage.js +464 -0
- package/dist/lib/env-storage.js.map +1 -0
- package/dist/lib/errors.d.ts +61 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +204 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/i18n.d.ts +99 -0
- package/dist/lib/i18n.d.ts.map +1 -0
- package/dist/lib/i18n.js +184 -0
- package/dist/lib/i18n.js.map +1 -0
- package/dist/lib/logger.d.ts +95 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +168 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/package-manager.d.ts +91 -0
- package/dist/lib/package-manager.d.ts.map +1 -0
- package/dist/lib/package-manager.js +205 -0
- package/dist/lib/package-manager.js.map +1 -0
- package/dist/lib/proxy-server.d.ts +24 -0
- package/dist/lib/proxy-server.d.ts.map +1 -0
- package/dist/lib/proxy-server.js +173 -0
- package/dist/lib/proxy-server.js.map +1 -0
- package/dist/lib/select-with-back.d.ts +34 -0
- package/dist/lib/select-with-back.d.ts.map +1 -0
- package/dist/lib/select-with-back.js +94 -0
- package/dist/lib/select-with-back.js.map +1 -0
- package/dist/lib/shared-api-client.d.ts +40 -0
- package/dist/lib/shared-api-client.d.ts.map +1 -0
- package/dist/lib/shared-api-client.js +92 -0
- package/dist/lib/shared-api-client.js.map +1 -0
- package/dist/lib/wizard-engine.d.ts +128 -0
- package/dist/lib/wizard-engine.d.ts.map +1 -0
- package/dist/lib/wizard-engine.js +168 -0
- package/dist/lib/wizard-engine.js.map +1 -0
- package/package.json +85 -0
- package/templates/storefront-minimal/.env.example +10 -0
- package/templates/storefront-minimal/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-minimal/app/globals.css +18 -0
- package/templates/storefront-minimal/app/layout.tsx +26 -0
- package/templates/storefront-minimal/app/page.tsx +93 -0
- package/templates/storefront-minimal/lib/graphql-client.ts +23 -0
- package/templates/storefront-minimal/next.config.ts +15 -0
- package/templates/storefront-minimal/open-next.config.ts +3 -0
- package/templates/storefront-minimal/package.json +30 -0
- package/templates/storefront-minimal/postcss.config.mjs +5 -0
- package/templates/storefront-minimal/tailwind.config.ts +14 -0
- package/templates/storefront-minimal/tsconfig.json +27 -0
- package/templates/storefront-minimal/wrangler.toml +9 -0
- package/templates/storefront-nextjs/.env.example +68 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-nextjs/.github/workflows/deploy.yml +25 -0
- package/templates/storefront-nextjs/.github/workflows/preview.yml +22 -0
- package/templates/storefront-nextjs/README.md +520 -0
- package/templates/storefront-nextjs/app/account/orders/page.tsx +216 -0
- package/templates/storefront-nextjs/app/account/page.tsx +167 -0
- package/templates/storefront-nextjs/app/auth/login/page.tsx +135 -0
- package/templates/storefront-nextjs/app/auth/register/page.tsx +228 -0
- package/templates/storefront-nextjs/app/cart/page.tsx +263 -0
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +200 -0
- package/templates/storefront-nextjs/app/categories/page.tsx +58 -0
- package/templates/storefront-nextjs/app/checkout/page.tsx +351 -0
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +158 -0
- package/templates/storefront-nextjs/app/collections/page.tsx +61 -0
- package/templates/storefront-nextjs/app/globals.css +98 -0
- package/templates/storefront-nextjs/app/layout.tsx +39 -0
- package/templates/storefront-nextjs/app/page.tsx +136 -0
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +119 -0
- package/templates/storefront-nextjs/app/products/page.tsx +107 -0
- package/templates/storefront-nextjs/app/search/page.tsx +127 -0
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +94 -0
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +77 -0
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +29 -0
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +217 -0
- package/templates/storefront-nextjs/components/commerce/pagination.tsx +62 -0
- package/templates/storefront-nextjs/components/commerce/product-actions.tsx +135 -0
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +109 -0
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +375 -0
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +178 -0
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +64 -0
- package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +210 -0
- package/templates/storefront-nextjs/components/layout/footer.tsx +107 -0
- package/templates/storefront-nextjs/components/layout/header.tsx +104 -0
- package/templates/storefront-nextjs/components/providers.tsx +62 -0
- package/templates/storefront-nextjs/lib/auth/routes.ts +52 -0
- package/templates/storefront-nextjs/lib/currency.tsx +140 -0
- package/templates/storefront-nextjs/lib/format.ts +159 -0
- package/templates/storefront-nextjs/lib/graphql-queries.ts +629 -0
- package/templates/storefront-nextjs/lib/hooks.ts +30 -0
- package/templates/storefront-nextjs/middleware.ts +80 -0
- package/templates/storefront-nextjs/next.config.ts +37 -0
- package/templates/storefront-nextjs/open-next.config.ts +3 -0
- package/templates/storefront-nextjs/package.dev.json +30 -0
- package/templates/storefront-nextjs/package.json +32 -0
- package/templates/storefront-nextjs/package.json.template +32 -0
- package/templates/storefront-nextjs/postcss.config.mjs +8 -0
- package/templates/storefront-nextjs/tailwind.config.ts +111 -0
- package/templates/storefront-nextjs/tsconfig.json +27 -0
- package/templates/storefront-nextjs/wrangler.toml +9 -0
- package/templates/storefront-nextjs-shadcn/.env.example +68 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +25 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +22 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +282 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +96 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +190 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +263 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +135 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +142 -0
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +448 -0
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +307 -0
- package/templates/storefront-nextjs-shadcn/README.md +195 -0
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +245 -0
- package/templates/storefront-nextjs-shadcn/app/about/page.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +215 -0
- package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +484 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +128 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/tracking/page.tsx +206 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +80 -0
- package/templates/storefront-nextjs-shadcn/app/account/page.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +195 -0
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +87 -0
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +125 -0
- package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +131 -0
- package/templates/storefront-nextjs-shadcn/app/auth/login/page.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/app/auth/register/page.tsx +20 -0
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +323 -0
- package/templates/storefront-nextjs-shadcn/app/blog/page.tsx +159 -0
- package/templates/storefront-nextjs-shadcn/app/brands/[slug]/page.tsx +170 -0
- package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +73 -0
- package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +165 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +78 -0
- package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +75 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +1752 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/success/[orderId]/page.tsx +256 -0
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +74 -0
- package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +75 -0
- package/templates/storefront-nextjs-shadcn/app/contact/page.tsx +114 -0
- package/templates/storefront-nextjs-shadcn/app/error.tsx +90 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +125 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +57 -0
- package/templates/storefront-nextjs-shadcn/app/not-found.tsx +68 -0
- package/templates/storefront-nextjs-shadcn/app/page.tsx +21 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +246 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +343 -0
- package/templates/storefront-nextjs-shadcn/app/products/page.tsx +25 -0
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +192 -0
- package/templates/storefront-nextjs-shadcn/app/returns/page.tsx +77 -0
- package/templates/storefront-nextjs-shadcn/app/robots.ts +53 -0
- package/templates/storefront-nextjs-shadcn/app/search/page.tsx +16 -0
- package/templates/storefront-nextjs-shadcn/app/search/search-client.tsx +47 -0
- package/templates/storefront-nextjs-shadcn/app/shipping/page.tsx +62 -0
- package/templates/storefront-nextjs-shadcn/app/sitemap.ts +144 -0
- package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +179 -0
- package/templates/storefront-nextjs-shadcn/codegen.ts +51 -0
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +348 -0
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +144 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +258 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +132 -0
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +188 -0
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +305 -0
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +240 -0
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +177 -0
- package/templates/storefront-nextjs-shadcn/components/blog/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/components/brand/brand-grid.tsx +64 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +48 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +112 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +84 -0
- package/templates/storefront-nextjs-shadcn/components/cart/index.ts +17 -0
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +121 -0
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +162 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/index.ts +25 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +187 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +160 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +154 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +225 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +62 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +158 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/variant-selector.tsx +210 -0
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +97 -0
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +187 -0
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +151 -0
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +166 -0
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +245 -0
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +246 -0
- package/templates/storefront-nextjs-shadcn/components/discount/index.ts +19 -0
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +113 -0
- package/templates/storefront-nextjs-shadcn/components/error/index.ts +7 -0
- package/templates/storefront-nextjs-shadcn/components/filters/attribute-filter.tsx +153 -0
- package/templates/storefront-nextjs-shadcn/components/filters/checkbox-group-filter.tsx +167 -0
- package/templates/storefront-nextjs-shadcn/components/filters/color-swatch-filter.tsx +176 -0
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +220 -0
- package/templates/storefront-nextjs-shadcn/components/filters/index.ts +36 -0
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +193 -0
- package/templates/storefront-nextjs-shadcn/components/filters/toggle-filter.tsx +132 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +321 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +309 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/index.ts +24 -0
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +72 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +85 -0
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +108 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +133 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +341 -0
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +128 -0
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +147 -0
- package/templates/storefront-nextjs-shadcn/components/layout/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +211 -0
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +95 -0
- package/templates/storefront-nextjs-shadcn/components/layout/theme-switcher.tsx +192 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/index.ts +11 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +93 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +177 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +250 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +217 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-badge.tsx +106 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +131 -0
- package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +196 -0
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +11 -0
- package/templates/storefront-nextjs-shadcn/components/order/order-tracking.tsx +200 -0
- package/templates/storefront-nextjs-shadcn/components/order/shipment-card.tsx +407 -0
- package/templates/storefront-nextjs-shadcn/components/order/tracking-status.tsx +222 -0
- package/templates/storefront-nextjs-shadcn/components/order/tracking-timeline.tsx +205 -0
- package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +161 -0
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +250 -0
- package/templates/storefront-nextjs-shadcn/components/product/discount-badge.tsx +196 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +41 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +147 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +217 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-gallery.tsx +143 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +83 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +155 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +158 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-quantity-selector.tsx +111 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +238 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +169 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +220 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +338 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-summary.tsx +143 -0
- package/templates/storefront-nextjs-shadcn/components/product/sale-countdown.tsx +166 -0
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +213 -0
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +57 -0
- package/templates/storefront-nextjs-shadcn/components/product/stock-indicator.tsx +91 -0
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +103 -0
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/providers/query-provider.tsx +260 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +13 -0
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +26 -0
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +608 -0
- package/templates/storefront-nextjs-shadcn/components/returns/return-status-card.tsx +554 -0
- package/templates/storefront-nextjs-shadcn/components/search/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-suggestions.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/components/seo/index.ts +12 -0
- package/templates/storefront-nextjs-shadcn/components/seo/json-ld.tsx +56 -0
- package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +167 -0
- package/templates/storefront-nextjs-shadcn/components/shipping/index.ts +16 -0
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +337 -0
- package/templates/storefront-nextjs-shadcn/components/ui/accordion.tsx +153 -0
- package/templates/storefront-nextjs-shadcn/components/ui/alert.tsx +59 -0
- package/templates/storefront-nextjs-shadcn/components/ui/badge.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/components/ui/button.tsx +51 -0
- package/templates/storefront-nextjs-shadcn/components/ui/card.tsx +77 -0
- package/templates/storefront-nextjs-shadcn/components/ui/checkbox.tsx +30 -0
- package/templates/storefront-nextjs-shadcn/components/ui/dialog.tsx +137 -0
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +207 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +67 -0
- package/templates/storefront-nextjs-shadcn/components/ui/input.tsx +65 -0
- package/templates/storefront-nextjs-shadcn/components/ui/label.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/components/ui/pagination.tsx +205 -0
- package/templates/storefront-nextjs-shadcn/components/ui/radio-group.tsx +44 -0
- package/templates/storefront-nextjs-shadcn/components/ui/select.tsx +160 -0
- package/templates/storefront-nextjs-shadcn/components/ui/separator.tsx +28 -0
- package/templates/storefront-nextjs-shadcn/components/ui/skeleton.tsx +20 -0
- package/templates/storefront-nextjs-shadcn/components/ui/spinner.tsx +82 -0
- package/templates/storefront-nextjs-shadcn/components/ui/tabs.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/components/ui/toast.tsx +96 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +148 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +47 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +165 -0
- package/templates/storefront-nextjs-shadcn/components.json +19 -0
- package/templates/storefront-nextjs-shadcn/generated/.gitkeep +2 -0
- package/templates/storefront-nextjs-shadcn/graphql/.gitkeep +31 -0
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +168 -0
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +160 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +310 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +286 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +110 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.test.ts +173 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.ts +298 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +220 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +57 -0
- package/templates/storefront-nextjs-shadcn/lib/config.ts +46 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +254 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +464 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +328 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +295 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +27 -0
- package/templates/storefront-nextjs-shadcn/lib/format.test.ts +397 -0
- package/templates/storefront-nextjs-shadcn/lib/format.ts +226 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +109 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +1183 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +267 -0
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +30 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +89 -0
- package/templates/storefront-nextjs-shadcn/lib/utils.ts +6 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +47 -0
- package/templates/storefront-nextjs-shadcn/open-next.config.ts +3 -0
- package/templates/storefront-nextjs-shadcn/package.dev.json +30 -0
- package/templates/storefront-nextjs-shadcn/package.json +60 -0
- package/templates/storefront-nextjs-shadcn/package.json.template +46 -0
- package/templates/storefront-nextjs-shadcn/postcss.config.mjs +8 -0
- package/templates/storefront-nextjs-shadcn/proxy.ts +80 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/apple-pay.svg +8 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/bank-transfer.svg +10 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/blik.svg +6 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/cash-on-delivery.svg +11 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/google-pay.svg +11 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/mastercard.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/paypal.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/payu.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/przelewy24.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/stripe.svg +4 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/visa.svg +5 -0
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +66 -0
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +56 -0
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +184 -0
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +103 -0
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +291 -0
- package/templates/storefront-nextjs-shadcn/tailwind.config.ts +111 -0
- package/templates/storefront-nextjs-shadcn/tsconfig.json +27 -0
- package/templates/storefront-nextjs-shadcn/wrangler.toml +9 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
# Currency Cookie Manager
|
|
2
|
+
|
|
3
|
+
A robust, type-safe solution for managing currency preferences in Next.js storefronts with full SSR support.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Cookie Manager provides a unified API for storing and retrieving currency preferences using HTTP cookies. This ensures currency preferences persist across page refreshes and work seamlessly with Server-Side Rendering (SSR), eliminating hydration mismatches.
|
|
8
|
+
|
|
9
|
+
## Why Cookies?
|
|
10
|
+
|
|
11
|
+
Previously, currency preferences were stored in localStorage, which caused several issues:
|
|
12
|
+
|
|
13
|
+
- ❌ **Not accessible during SSR** - localStorage is client-only
|
|
14
|
+
- ❌ **Hydration mismatches** - Server renders base currency, client renders selected currency
|
|
15
|
+
- ❌ **Flash of incorrect content** - Prices appear in wrong currency briefly after page load
|
|
16
|
+
- ❌ **Missing headers** - GraphQL requests from SSR couldn't include preferred currency
|
|
17
|
+
|
|
18
|
+
Cookies solve all these problems:
|
|
19
|
+
|
|
20
|
+
- ✅ **Accessible in SSR** - via `next/headers` cookies() API
|
|
21
|
+
- ✅ **Zero hydration mismatch** - Server and client read same value
|
|
22
|
+
- ✅ **Automatic header injection** - GraphQL client can read cookie in SSR
|
|
23
|
+
- ✅ **Persistent** - Survives page refreshes and navigation
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
The cookie manager requires these dependencies:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add js-cookie
|
|
31
|
+
pnpm add -D @types/js-cookie
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
### Basic Usage
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { getCookieManager } from "@/lib/currency";
|
|
40
|
+
|
|
41
|
+
// Get the cookie manager instance
|
|
42
|
+
const cookieManager = getCookieManager();
|
|
43
|
+
|
|
44
|
+
// Read currency preference
|
|
45
|
+
const currency = cookieManager.getCurrency();
|
|
46
|
+
console.log(currency); // "EUR" or null
|
|
47
|
+
|
|
48
|
+
// Set currency preference (client-side only)
|
|
49
|
+
cookieManager.setCurrency("USD");
|
|
50
|
+
|
|
51
|
+
// Remove currency preference (client-side only)
|
|
52
|
+
cookieManager.removeCurrency();
|
|
53
|
+
|
|
54
|
+
// Check execution context
|
|
55
|
+
if (cookieManager.isServer()) {
|
|
56
|
+
console.log("Running in SSR");
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Convenience Functions
|
|
61
|
+
|
|
62
|
+
For simpler usage, use the convenience functions:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import {
|
|
66
|
+
getCurrencyFromCookie,
|
|
67
|
+
setCurrencyInCookie,
|
|
68
|
+
removeCurrencyFromCookie,
|
|
69
|
+
} from "@/lib/currency";
|
|
70
|
+
|
|
71
|
+
// Read currency
|
|
72
|
+
const currency = getCurrencyFromCookie();
|
|
73
|
+
|
|
74
|
+
// Set currency
|
|
75
|
+
setCurrencyInCookie("EUR");
|
|
76
|
+
|
|
77
|
+
// Remove currency
|
|
78
|
+
removeCurrencyFromCookie();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Architecture
|
|
82
|
+
|
|
83
|
+
### Dual Implementation
|
|
84
|
+
|
|
85
|
+
The cookie manager uses different implementations for SSR and client contexts:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Client context (browser)
|
|
89
|
+
class ClientCookieManager {
|
|
90
|
+
// Uses js-cookie library
|
|
91
|
+
getCurrency() { return Cookies.get('preferred-currency'); }
|
|
92
|
+
setCurrency(currency) { Cookies.set('preferred-currency', currency, { ... }); }
|
|
93
|
+
removeCurrency() { Cookies.remove('preferred-currency'); }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Server context (SSR)
|
|
97
|
+
class ServerCookieManager {
|
|
98
|
+
// Uses Next.js cookies() API
|
|
99
|
+
getCurrency() { return cookies().get('preferred-currency')?.value; }
|
|
100
|
+
setCurrency() { /* No-op - SSR is read-only */ }
|
|
101
|
+
removeCurrency() { /* No-op - SSR is read-only */ }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Cookie Specification
|
|
106
|
+
|
|
107
|
+
- **Name**: `preferred-currency`
|
|
108
|
+
- **Path**: `/` (accessible across all pages)
|
|
109
|
+
- **Max-Age**: 365 days
|
|
110
|
+
- **SameSite**: `lax` (prevents CSRF, allows navigation)
|
|
111
|
+
- **Secure**: `true` in production (HTTPS only)
|
|
112
|
+
- **HttpOnly**: `false` (needs client-side access)
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### `getCookieManager(): CookieManager`
|
|
117
|
+
|
|
118
|
+
Returns the singleton cookie manager instance. Automatically detects SSR vs client context.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const manager = getCookieManager();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `CookieManager.getCurrency(): string | null`
|
|
125
|
+
|
|
126
|
+
Reads currency from cookie. Works in both SSR and client contexts.
|
|
127
|
+
|
|
128
|
+
**Returns:** Currency code (e.g., `"USD"`) or `null` if not set
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const currency = manager.getCurrency();
|
|
132
|
+
if (currency) {
|
|
133
|
+
console.log(`User prefers: ${currency}`);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `CookieManager.setCurrency(currency: string): void`
|
|
138
|
+
|
|
139
|
+
Writes currency to cookie. Only works in client context (SSR is read-only).
|
|
140
|
+
|
|
141
|
+
**Parameters:**
|
|
142
|
+
|
|
143
|
+
- `currency` - Currency code to store (e.g., `"EUR"`)
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
manager.setCurrency("GBP");
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `CookieManager.removeCurrency(): void`
|
|
150
|
+
|
|
151
|
+
Removes currency cookie. Only works in client context.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
manager.removeCurrency();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### `CookieManager.isServer(): boolean`
|
|
158
|
+
|
|
159
|
+
Returns `true` if running in SSR context, `false` if in browser.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
if (manager.isServer()) {
|
|
163
|
+
console.log("Rendering on server");
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Integration Patterns
|
|
168
|
+
|
|
169
|
+
### With Zustand Store
|
|
170
|
+
|
|
171
|
+
The currency store should use the cookie manager instead of localStorage:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { create } from "zustand";
|
|
175
|
+
import { getCookieManager } from "@/lib/currency";
|
|
176
|
+
|
|
177
|
+
interface CurrencyStore {
|
|
178
|
+
currency: string | null;
|
|
179
|
+
setCurrency: (currency: string) => void;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const useCurrencyStore = create<CurrencyStore>((set) => ({
|
|
183
|
+
currency: null,
|
|
184
|
+
|
|
185
|
+
setCurrency: (currency: string) => {
|
|
186
|
+
// Update Zustand state
|
|
187
|
+
set({ currency });
|
|
188
|
+
|
|
189
|
+
// Persist to cookie
|
|
190
|
+
const cookieManager = getCookieManager();
|
|
191
|
+
cookieManager.setCurrency(currency);
|
|
192
|
+
},
|
|
193
|
+
}));
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### With GraphQL Client
|
|
197
|
+
|
|
198
|
+
The GraphQL client should read from cookies for SSR compatibility:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { GraphQLClient } from "graphql-request";
|
|
202
|
+
import { getCurrencyFromCookie } from "@/lib/currency";
|
|
203
|
+
|
|
204
|
+
export function createGraphQLClient() {
|
|
205
|
+
return new GraphQLClient(API_URL, {
|
|
206
|
+
headers: () => {
|
|
207
|
+
const currency = getCurrencyFromCookie();
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
"X-Shop-Slug": SHOP_SLUG,
|
|
211
|
+
// Include header only if currency exists
|
|
212
|
+
...(currency && { "X-Preferred-Currency": currency }),
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### In Server Components
|
|
220
|
+
|
|
221
|
+
Server Components can read currency for SSR:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { getCurrencyFromCookie } from "@/lib/currency";
|
|
225
|
+
|
|
226
|
+
export default function ProductPage() {
|
|
227
|
+
// This runs on the server
|
|
228
|
+
const currency = getCurrencyFromCookie();
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div>
|
|
232
|
+
<h1>Products</h1>
|
|
233
|
+
<p>Showing prices in: {currency || "USD"}</p>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### In Client Components
|
|
240
|
+
|
|
241
|
+
Client Components can both read and write:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
"use client";
|
|
245
|
+
|
|
246
|
+
import { getCurrencyFromCookie, setCurrencyInCookie } from "@/lib/currency";
|
|
247
|
+
import { useState, useEffect } from "react";
|
|
248
|
+
|
|
249
|
+
export function CurrencySelector() {
|
|
250
|
+
const [currency, setCurrency] = useState<string | null>(null);
|
|
251
|
+
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
// Read on mount
|
|
254
|
+
setCurrency(getCurrencyFromCookie());
|
|
255
|
+
}, []);
|
|
256
|
+
|
|
257
|
+
const handleChange = (newCurrency: string) => {
|
|
258
|
+
// Update state
|
|
259
|
+
setCurrency(newCurrency);
|
|
260
|
+
|
|
261
|
+
// Persist to cookie
|
|
262
|
+
setCurrencyInCookie(newCurrency);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<select
|
|
267
|
+
value={currency || ""}
|
|
268
|
+
onChange={(e) => handleChange(e.target.value)}
|
|
269
|
+
>
|
|
270
|
+
<option value="USD">USD</option>
|
|
271
|
+
<option value="EUR">EUR</option>
|
|
272
|
+
<option value="GBP">GBP</option>
|
|
273
|
+
</select>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Error Handling
|
|
279
|
+
|
|
280
|
+
The cookie manager handles errors gracefully:
|
|
281
|
+
|
|
282
|
+
### Blocked Cookies
|
|
283
|
+
|
|
284
|
+
If cookies are blocked by the browser:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Setting fails silently
|
|
288
|
+
cookieManager.setCurrency("EUR"); // Logs warning, continues
|
|
289
|
+
|
|
290
|
+
// Reading returns null
|
|
291
|
+
const currency = cookieManager.getCurrency(); // null
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### SSR Write Attempts
|
|
295
|
+
|
|
296
|
+
If code tries to write in SSR:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// In SSR context
|
|
300
|
+
cookieManager.setCurrency("USD"); // Logs warning, no-op
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Missing Next.js Headers
|
|
304
|
+
|
|
305
|
+
If `cookies()` API is unavailable:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Returns null gracefully
|
|
309
|
+
const currency = cookieManager.getCurrency(); // null (with warning)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Testing
|
|
313
|
+
|
|
314
|
+
### Unit Tests
|
|
315
|
+
|
|
316
|
+
The cookie manager includes comprehensive unit tests:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
pnpm test lib/currency/cookie-manager.test.ts
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Tests cover:
|
|
323
|
+
|
|
324
|
+
- ✅ Client-side cookie operations
|
|
325
|
+
- ✅ Server-side cookie reading
|
|
326
|
+
- ✅ Error handling and fallbacks
|
|
327
|
+
- ✅ Singleton pattern
|
|
328
|
+
- ✅ SSR/client context detection
|
|
329
|
+
|
|
330
|
+
### Manual Testing
|
|
331
|
+
|
|
332
|
+
Test the complete flow:
|
|
333
|
+
|
|
334
|
+
1. **Set currency in browser**
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
setCurrencyInCookie("EUR");
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
2. **Refresh page** - Currency should persist
|
|
341
|
+
|
|
342
|
+
3. **Check DevTools** - Cookie should be visible in Application tab
|
|
343
|
+
|
|
344
|
+
4. **Check Network** - GraphQL requests should include `X-Preferred-Currency: EUR`
|
|
345
|
+
|
|
346
|
+
## Migration from localStorage
|
|
347
|
+
|
|
348
|
+
If you're migrating from localStorage-based storage:
|
|
349
|
+
|
|
350
|
+
### Before (localStorage)
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import { create } from "zustand";
|
|
354
|
+
import { persist } from "zustand/middleware";
|
|
355
|
+
|
|
356
|
+
export const useCurrencyStore = create(
|
|
357
|
+
persist(
|
|
358
|
+
(set) => ({
|
|
359
|
+
currency: null,
|
|
360
|
+
setCurrency: (currency) => set({ currency }),
|
|
361
|
+
}),
|
|
362
|
+
{ name: "currency-storage" }
|
|
363
|
+
)
|
|
364
|
+
);
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### After (Cookies)
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
import { create } from "zustand";
|
|
371
|
+
import { getCookieManager } from "@/lib/currency";
|
|
372
|
+
|
|
373
|
+
export const useCurrencyStore = create((set) => ({
|
|
374
|
+
currency: null,
|
|
375
|
+
|
|
376
|
+
// Initialize from cookie
|
|
377
|
+
initialize: () => {
|
|
378
|
+
const currency = getCookieManager().getCurrency();
|
|
379
|
+
set({ currency });
|
|
380
|
+
},
|
|
381
|
+
|
|
382
|
+
setCurrency: (currency) => {
|
|
383
|
+
set({ currency });
|
|
384
|
+
getCookieManager().setCurrency(currency);
|
|
385
|
+
},
|
|
386
|
+
}));
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Note:** Users will need to re-select their currency after the update. This is acceptable as it's a one-time inconvenience.
|
|
390
|
+
|
|
391
|
+
## Best Practices
|
|
392
|
+
|
|
393
|
+
### ✅ DO
|
|
394
|
+
|
|
395
|
+
- Use `getCookieManager()` for SSR-safe access
|
|
396
|
+
- Read from cookie in GraphQL client for header injection
|
|
397
|
+
- Handle `null` return values gracefully
|
|
398
|
+
- Let the cookie manager handle SSR/client detection
|
|
399
|
+
|
|
400
|
+
### ❌ DON'T
|
|
401
|
+
|
|
402
|
+
- Access cookies directly with `document.cookie`
|
|
403
|
+
- Cache the currency value (always read fresh)
|
|
404
|
+
- Try to write cookies in SSR context
|
|
405
|
+
- Assume cookies are always available (they can be blocked)
|
|
406
|
+
|
|
407
|
+
## Troubleshooting
|
|
408
|
+
|
|
409
|
+
### Currency not persisting
|
|
410
|
+
|
|
411
|
+
**Symptom:** Currency resets to default on page refresh
|
|
412
|
+
|
|
413
|
+
**Causes:**
|
|
414
|
+
|
|
415
|
+
1. Cookies are blocked by browser
|
|
416
|
+
2. Third-party cookie restrictions
|
|
417
|
+
3. Incognito/private browsing mode
|
|
418
|
+
|
|
419
|
+
**Solution:** Check browser DevTools > Application > Cookies
|
|
420
|
+
|
|
421
|
+
### SSR hydration mismatch
|
|
422
|
+
|
|
423
|
+
**Symptom:** React warning about hydration mismatch
|
|
424
|
+
|
|
425
|
+
**Causes:**
|
|
426
|
+
|
|
427
|
+
1. Reading from Zustand store instead of cookie in SSR
|
|
428
|
+
2. Using `useEffect` to initialize currency
|
|
429
|
+
|
|
430
|
+
**Solution:** Initialize currency from cookie in `initialize()` method, call it before SSR
|
|
431
|
+
|
|
432
|
+
### GraphQL header missing
|
|
433
|
+
|
|
434
|
+
**Symptom:** Backend returns prices in base currency
|
|
435
|
+
|
|
436
|
+
**Causes:**
|
|
437
|
+
|
|
438
|
+
1. GraphQL client reads from Zustand instead of cookie
|
|
439
|
+
2. Cookie not set yet
|
|
440
|
+
3. SSR context can't access cookie
|
|
441
|
+
|
|
442
|
+
**Solution:** Use `getCurrencyFromCookie()` in GraphQL client headers function
|
|
443
|
+
|
|
444
|
+
## Constants
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
export const CURRENCY_COOKIE_NAME = "preferred-currency";
|
|
448
|
+
export const CURRENCY_COOKIE_MAX_AGE = 365 * 24 * 60 * 60; // 365 days in seconds
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Type Definitions
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
export interface CookieManager {
|
|
455
|
+
getCurrency(): string | null;
|
|
456
|
+
setCurrency(currency: string): void;
|
|
457
|
+
removeCurrency(): void;
|
|
458
|
+
isServer(): boolean;
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
## License
|
|
463
|
+
|
|
464
|
+
MIT
|