@thorprovider/storefront 0.3.1 → 0.4.0-mvp.2
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 +321 -152
- package/VENDOR.md +69 -0
- package/assets/openspec/config.yaml +38 -0
- package/assets/templates/AGENTS.md +76 -0
- package/assets/templates/app/app/[[...slug]]/page.tsx +54 -2
- package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
- package/assets/templates/app/app/globals.css +5 -8
- package/assets/templates/app/app/layout.tsx +17 -7
- package/assets/templates/app/app/robots.ts +19 -0
- package/assets/templates/app/app/sitemap.ts +71 -0
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +612 -0
- package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +50 -57
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +679 -0
- package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +197 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +5 -36
- package/assets/templates/app/lib/__STOREFRONT__/icon-map.ts +27 -0
- package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +13 -11
- package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +264 -51
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +6 -3
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +136 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.core.ts +470 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.ts +169 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +120 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +38 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +129 -10
- package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +191 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.core.ts +257 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.ts +7 -31
- package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +161 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.client.tsx +25 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.tsx +16 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.client.tsx +24 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +5 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +26 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +36 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.client.tsx +100 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.cta.ts +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.faq.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.products.ts +39 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +35 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +31 -13
- package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +5 -3
- package/assets/templates/features/checkout/handlers.ts +159 -0
- package/assets/templates/features/checkout/state.ts +61 -0
- package/assets/templates/features/customer-auth/handlers.ts +59 -0
- package/assets/templates/features/customer-auth/state.ts +45 -0
- package/assets/templates/features/recommendations/state.ts +11 -0
- package/assets/templates/views/account/content.ts +35 -0
- package/assets/templates/views/account/index.tsx +114 -0
- package/assets/templates/views/account/registry.tsx +439 -0
- package/assets/templates/views/account/schema.ts +53 -0
- package/assets/templates/views/cart/content.ts +11 -0
- package/assets/templates/views/cart/data.ts +23 -0
- package/assets/templates/views/cart/index.tsx +53 -0
- package/assets/templates/views/cart/props.ts +12 -0
- package/assets/templates/views/cart/registry.tsx +81 -0
- package/assets/templates/views/cart/schema.ts +52 -0
- package/assets/templates/views/category/assembly/assembly.json +29 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +251 -0
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +34 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/catalog.part +5 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/element.part +34 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/registry.part +71 -0
- package/assets/templates/views/category/content.ts +30 -0
- package/assets/templates/views/category/data.ts +12 -0
- package/assets/templates/views/category/index.tsx +299 -0
- package/assets/templates/views/category/props.ts +23 -0
- package/assets/templates/views/category/registry.tsx +122 -0
- package/assets/templates/views/category/schema.ts +91 -0
- package/assets/templates/views/checkout/content.ts +105 -0
- package/assets/templates/views/checkout/data.ts +23 -0
- package/assets/templates/views/checkout/index.tsx +111 -0
- package/assets/templates/views/checkout/props.ts +49 -0
- package/assets/templates/views/checkout/registry.tsx +217 -0
- package/assets/templates/views/checkout/schema.ts +229 -0
- package/assets/templates/views/home/assembly/assembly.json +33 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +90 -0
- package/assets/templates/views/home/assembly/registry.skeleton.tsx +25 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/registry.part +11 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/registry.part +10 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/registry.part +16 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +26 -0
- package/assets/templates/views/home/content.ts +70 -0
- package/assets/templates/views/home/data.ts +24 -0
- package/assets/templates/views/home/index.tsx +57 -85
- package/assets/templates/views/home/props.ts +22 -0
- package/assets/templates/views/home/registry.tsx +38 -22
- package/assets/templates/views/home/schema.ts +93 -0
- package/assets/templates/views/product/content.ts +25 -0
- package/assets/templates/views/product/data.ts +50 -0
- package/assets/templates/views/product/index.tsx +148 -0
- package/assets/templates/views/product/props.ts +27 -0
- package/assets/templates/views/product/registry.tsx +103 -0
- package/assets/templates/views/product/schema.ts +121 -0
- package/assets/templates/views/static/content.ts +99 -0
- package/assets/templates/views/static/index.tsx +60 -0
- package/assets/templates/views/static/registry.tsx +66 -0
- package/assets/templates/views/static/schema.ts +45 -0
- package/bin/storefront.js +2424 -148
- package/examples/merchandising/category-led.json +37 -0
- package/examples/merchandising/collection-led.json +37 -0
- package/package.json +15 -9
- package/recipes/archetypes.json +28 -14
- package/recipes/catalog.json +400 -0
- package/recipes/catalog.mjs +128 -0
- package/recipes/catalog.schema.json +64 -0
- package/recipes/feature.schema.json +89 -0
- package/recipes/features.json +162 -0
- package/recipes/manifest.schema.json +69 -0
- package/recipes/operations.schema.json +43 -0
- package/recipes/recipe.schema.json +11 -2
- package/recipes/recipes.json +76 -19
- package/recipes/sections.json +34 -5
- package/recipes/validate.mjs +838 -32
- package/scripts/candidate.mjs +236 -0
- package/scripts/composers.mjs +160 -0
- package/scripts/env-file.mjs +86 -0
- package/scripts/file-classes.mjs +121 -0
- package/scripts/logical-controls.mjs +61 -0
- package/scripts/manifest.mjs +298 -0
- package/scripts/migrate-english-routes.mjs +276 -0
- package/scripts/operation-registry.mjs +256 -0
- package/scripts/operations.mjs +720 -0
- package/scripts/ownership-conflict.mjs +356 -0
- package/scripts/pinning.mjs +573 -0
- package/scripts/plan-apply.mjs +987 -0
- package/scripts/preflight.mjs +51 -0
- package/scripts/reconcile.mjs +549 -0
- package/scripts/render-templates.mjs +338 -68
- package/scripts/schema-validate.mjs +132 -0
- package/scripts/section-compat.mjs +300 -0
- package/scripts/section-config.mjs +253 -0
- package/scripts/section-operations.mjs +508 -0
- package/scripts/starter.mjs +17 -0
- package/scripts/sync-assets.mjs +22 -15
- package/scripts/theme/color.mjs +185 -0
- package/scripts/theme/css-theme.mjs +233 -0
- package/scripts/theme/fonts.mjs +123 -0
- package/scripts/theme/import-export.mjs +125 -0
- package/scripts/theme/preset.mjs +93 -0
- package/scripts/theme/theme-plan.mjs +292 -0
- package/scripts/theme/tokens.mjs +137 -0
- package/scripts/view-assembly.mjs +337 -0
- package/scripts/view-selection.mjs +211 -0
- package/skills/sf-feature/SKILL.md +80 -0
- package/skills/sf-setup/SKILL.md +79 -0
- package/skills/sf-theme-gen/SKILL.md +100 -30
- package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
- package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
- package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
- package/skills/sf-view-gen/SKILL.md +146 -93
- package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -14
- package/skills/sf-view-gen/assets/recipes/catalog.json +400 -0
- package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
- package/skills/sf-view-gen/assets/recipes/features.json +162 -0
- package/skills/sf-view-gen/assets/recipes/recipes.json +76 -19
- package/skills/sf-view-gen/assets/recipes/sections.json +34 -5
- package/skills/sf-view-gen/assets/templates/views/sections/cta.client.tsx +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/cta.tsx +16 -0
- package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +12 -8
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +14 -10
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +2 -9
- package/skills/sf-view-gen/assets/templates/views/sections/products.client.tsx +100 -0
- package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.cta.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.faq.ts +18 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.logoCloud.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.pricing.ts +26 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.products.ts +39 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.statistics.ts +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.testimonials.ts +23 -0
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +16 -8
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +2 -5
- package/skills/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
- package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
- package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
- package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
- package/skills/sf-view-gen/references/views.md +58 -33
- package/skills/sf-view-gen/scripts/catalog.mjs +128 -0
- package/skills/sf-view-gen/scripts/schema-validate.mjs +132 -0
- package/skills/sf-view-gen/scripts/validate.mjs +838 -32
- package/skills/storefront-workflow/SKILL.md +179 -0
- package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
- package/CHANGELOG.md +0 -61
- package/commands/sf-add-view.md +0 -26
- package/commands/sf-theme.md +0 -20
- package/commands/sf-view.md +0 -25
- package/skills/building-storefronts/SKILL.md +0 -178
- package/skills/building-storefronts/references/frontend-integration.md +0 -229
- package/skills/json-render-remotion/SKILL.md +0 -111
- package/skills/json-render-solid/SKILL.md +0 -204
- package/skills/nextjs-shadcn/SKILL.md +0 -367
- package/skills/nextjs-shadcn/references/architecture.md +0 -499
- package/skills/nextjs-shadcn/references/project-setup.md +0 -162
- package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
- package/skills/nextjs-shadcn/references/sidebar.md +0 -274
- package/skills/nextjs-shadcn/references/styling.md +0 -555
- package/skills/sf-view-gen/assets/templates/views/category/index.tsx +0 -86
- package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +0 -48
- package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +0 -192
- package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +0 -45
- package/skills/sf-view-gen/assets/templates/views/product/index.tsx +0 -122
- package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +0 -49
- package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +0 -168
- package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +0 -49
- package/skills/shadcn-component-discovery/SKILL.md +0 -273
- package/skills/shadcn-component-discovery/references/registries.md +0 -226
- package/skills/shadcn-theming/SKILL.md +0 -104
- package/skills/storefront-best-practices/SKILL.md +0 -421
- package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
- package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
- package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
- package/skills/storefront-best-practices/reference/components/footer.md +0 -112
- package/skills/storefront-best-practices/reference/components/hero.md +0 -241
- package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
- package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
- package/skills/storefront-best-practices/reference/components/popups.md +0 -221
- package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
- package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
- package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
- package/skills/storefront-best-practices/reference/components/search.md +0 -101
- package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
- package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
- package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
- package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
- package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
- package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
- package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
- package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
- package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
- package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
- package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
- package/skills/storefront-best-practices/reference/medusa.md +0 -307
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
# Connecting to Backend
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
|
|
5
|
-
- [Overview](#overview)
|
|
6
|
-
- [Detecting the Backend](#detecting-the-backend-critical)
|
|
7
|
-
- [Framework Detection](#framework-detection)
|
|
8
|
-
- [Environment Configuration](#environment-configuration)
|
|
9
|
-
- [Backend-Specific Integration](#backend-specific-integration)
|
|
10
|
-
- [Authentication Patterns](#authentication-patterns)
|
|
11
|
-
- [Cart State Management](#cart-state-management)
|
|
12
|
-
- [Error Handling for Ecommerce](#error-handling-for-ecommerce)
|
|
13
|
-
- [Performance Patterns](#performance-patterns)
|
|
14
|
-
- [Data Fetching with TanStack Query](#data-fetching-with-tanstack-query-recommended)
|
|
15
|
-
- [Checklist](#checklist)
|
|
16
|
-
|
|
17
|
-
## Overview
|
|
18
|
-
|
|
19
|
-
Best practices for connecting storefront to ecommerce backend APIs. Framework-agnostic patterns for authentication, cart state management, error handling, and performance optimization.
|
|
20
|
-
|
|
21
|
-
**For Medusa-specific integration**, see `reference/medusa.md` for SDK setup, pricing, regions, and Medusa patterns.
|
|
22
|
-
|
|
23
|
-
## Detecting the Backend (CRITICAL)
|
|
24
|
-
|
|
25
|
-
**Before implementing any backend integration, identify which ecommerce backend is being used.**
|
|
26
|
-
|
|
27
|
-
### Detection Strategy
|
|
28
|
-
|
|
29
|
-
**1. Check for monorepo structure:**
|
|
30
|
-
```bash
|
|
31
|
-
# Look for backend directory
|
|
32
|
-
ls -la ../backend
|
|
33
|
-
ls -la ./backend
|
|
34
|
-
ls -la ../../apps/backend
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Common monorepo patterns:
|
|
38
|
-
- `/apps/storefront` + `/apps/backend`
|
|
39
|
-
- `/frontend` + `/backend`
|
|
40
|
-
- `/packages/web` + `/packages/api`
|
|
41
|
-
|
|
42
|
-
**2. Check package.json dependencies:**
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"dependencies": {
|
|
46
|
-
"@medusajs/js-sdk": "...", // Medusa
|
|
47
|
-
// check other ecommerce frameworks...
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**3. Check environment variables:**
|
|
53
|
-
```bash
|
|
54
|
-
# Look in .env, .env.local, .env.example
|
|
55
|
-
grep -i "api\|backend\|medusa\|shopify\|commerce" .env*
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Common patterns:
|
|
59
|
-
- `NEXT_PUBLIC_MEDUSA_BACKEND_URL` → Medusa
|
|
60
|
-
- Custom `API_URL` or `BACKEND_URL` → Other backend
|
|
61
|
-
|
|
62
|
-
**4. If unsure, ASK THE USER:**
|
|
63
|
-
|
|
64
|
-
```markdown
|
|
65
|
-
I need to connect to the ecommerce backend. Which backend are you using?
|
|
66
|
-
|
|
67
|
-
Options:
|
|
68
|
-
- Medusa (open-source headless commerce)
|
|
69
|
-
- Custom backend
|
|
70
|
-
- Other
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Backend Documentation and MCP Servers
|
|
74
|
-
|
|
75
|
-
**ALWAYS refer to the backend's official documentation or MCP server for:**
|
|
76
|
-
|
|
77
|
-
- API endpoints and data structures
|
|
78
|
-
- Authentication requirements
|
|
79
|
-
- SDK usage and installation
|
|
80
|
-
- Environment configuration
|
|
81
|
-
- Rate limits and best practices
|
|
82
|
-
|
|
83
|
-
**For Medusa:**
|
|
84
|
-
- Documentation: https://docs.medusajs.com
|
|
85
|
-
- MCP Server: If available, use Medusa MCP server for real-time API information
|
|
86
|
-
- JS SDK docs: https://docs.medusajs.com/resources/js-sdk
|
|
87
|
-
- See `reference/medusa.md` for detailed integration guide
|
|
88
|
-
|
|
89
|
-
**For other backends:**
|
|
90
|
-
- Check the backend's documentation portal
|
|
91
|
-
- Look for MCP server if available
|
|
92
|
-
- Verify API endpoints and authentication methods
|
|
93
|
-
- Never assume API structure without verification
|
|
94
|
-
|
|
95
|
-
**Important:** Do not guess API endpoints or data formats. Always verify with documentation or ask the user to confirm the backend's API structure.
|
|
96
|
-
|
|
97
|
-
## Framework Detection
|
|
98
|
-
|
|
99
|
-
Identify the frontend framework to determine appropriate data fetching patterns:
|
|
100
|
-
|
|
101
|
-
**Next.js:**
|
|
102
|
-
- App Router: Server Components (async/await), Client Components (useEffect/TanStack Query)
|
|
103
|
-
- Pages Router: getServerSideProps/getStaticProps (server), useEffect (client)
|
|
104
|
-
|
|
105
|
-
**SvelteKit:**
|
|
106
|
-
- Load functions for server-side data
|
|
107
|
-
- Client-side: fetch in component lifecycle
|
|
108
|
-
|
|
109
|
-
**TanStack Start:**
|
|
110
|
-
- Server functions for server-side data
|
|
111
|
-
- Client-side: fetch with React hooks
|
|
112
|
-
|
|
113
|
-
**General Rule:**
|
|
114
|
-
- **Server-side for initial load**: SEO, performance, security (product pages, listings)
|
|
115
|
-
- **Client-side for interactions**: Cart, filters, search, user-specific data
|
|
116
|
-
|
|
117
|
-
## Environment Configuration
|
|
118
|
-
|
|
119
|
-
**Store API URLs and keys in environment variables:**
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
// .env.local
|
|
123
|
-
NEXT_PUBLIC_API_URL=https://api.example.com
|
|
124
|
-
NEXT_PUBLIC_PUBLISHABLE_KEY=pk_...
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**Framework-specific prefixes:**
|
|
128
|
-
- Next.js: `NEXT_PUBLIC_` for client-side
|
|
129
|
-
- SvelteKit: `PUBLIC_` for client-side
|
|
130
|
-
- Vite-based (TanStack Start): `VITE_` for client-side
|
|
131
|
-
|
|
132
|
-
**Security:**
|
|
133
|
-
- ❌ NEVER expose secret/admin keys in client-side code
|
|
134
|
-
- ✅ Publishable keys are safe for client (Medusa, Stripe)
|
|
135
|
-
- ✅ Secret keys only in server-side code or environment
|
|
136
|
-
|
|
137
|
-
## Backend-Specific Integration
|
|
138
|
-
|
|
139
|
-
### Medusa Backend
|
|
140
|
-
|
|
141
|
-
**For complete Medusa integration guide**, see `reference/medusa.md` which covers:
|
|
142
|
-
- SDK installation and setup
|
|
143
|
-
- Vite configuration (for TanStack Start, etc.)
|
|
144
|
-
- TypeScript types from `@medusajs/types`
|
|
145
|
-
- Price display (never divide by 100)
|
|
146
|
-
- Common operations (products, cart, categories, customers)
|
|
147
|
-
- Custom endpoints
|
|
148
|
-
- Region state management
|
|
149
|
-
- Error handling with SDK
|
|
150
|
-
|
|
151
|
-
### Other Backends
|
|
152
|
-
|
|
153
|
-
For non-Medusa backends (custom APIs, third-party platforms):
|
|
154
|
-
|
|
155
|
-
**1. Consult backend's API documentation** for:
|
|
156
|
-
- Authentication requirements
|
|
157
|
-
- Available endpoints
|
|
158
|
-
- Request/response formats
|
|
159
|
-
- SDK availability (check if official SDK exists)
|
|
160
|
-
|
|
161
|
-
**2. Use backend's official SDK if available** - provides type safety, error handling, and best practices
|
|
162
|
-
|
|
163
|
-
**3. If no SDK, create API client wrapper:**
|
|
164
|
-
- Centralize API calls in one module
|
|
165
|
-
- Group by resource (products, cart, customers, orders)
|
|
166
|
-
- Handle authentication (include tokens/cookies)
|
|
167
|
-
- Handle errors consistently
|
|
168
|
-
- Use native fetch or axios
|
|
169
|
-
|
|
170
|
-
## Authentication Patterns
|
|
171
|
-
|
|
172
|
-
### Customer Authentication
|
|
173
|
-
|
|
174
|
-
**Session-based (cookies):**
|
|
175
|
-
- Backend manages session via cookies
|
|
176
|
-
- No manual token management needed
|
|
177
|
-
- Works across page refreshes
|
|
178
|
-
- Common in traditional ecommerce backends
|
|
179
|
-
- Call backend login endpoint, check auth state, logout methods
|
|
180
|
-
|
|
181
|
-
**Token-based (JWT, OAuth):**
|
|
182
|
-
- Store token in localStorage or secure cookie after login
|
|
183
|
-
- Include token in Authorization header for all authenticated requests
|
|
184
|
-
- Common in headless/API-first backends
|
|
185
|
-
- Format: `Authorization: Bearer {token}`
|
|
186
|
-
|
|
187
|
-
### Protecting Customer Routes
|
|
188
|
-
|
|
189
|
-
**Check authentication before rendering customer-specific pages** (account, orders, addresses):
|
|
190
|
-
|
|
191
|
-
- **Server-side**: Check auth in server functions (getServerSideProps, load functions, etc.). Redirect to login if not authenticated.
|
|
192
|
-
- **Client-side**: Check auth state on mount. Redirect to login if not authenticated.
|
|
193
|
-
|
|
194
|
-
Use framework-specific auth patterns for redirects.
|
|
195
|
-
|
|
196
|
-
### Cart Access Pattern
|
|
197
|
-
|
|
198
|
-
**Guest carts:**
|
|
199
|
-
- Store cart ID in localStorage or cookie
|
|
200
|
-
- Check for existing cart ID on app load
|
|
201
|
-
- Create new cart if none exists
|
|
202
|
-
- Allows shopping without account
|
|
203
|
-
- Persists across sessions
|
|
204
|
-
|
|
205
|
-
**Logged-in carts:**
|
|
206
|
-
- Associate cart with customer account
|
|
207
|
-
- Syncs across devices
|
|
208
|
-
- **CRITICAL: Merge guest cart with customer cart on login** - Transfer guest cart items to customer's account cart, then clear guest cart ID from localStorage
|
|
209
|
-
|
|
210
|
-
## Cart State Management
|
|
211
|
-
|
|
212
|
-
**Critical ecommerce pattern**: Cart must be accessible throughout the app.
|
|
213
|
-
|
|
214
|
-
### Global Cart State
|
|
215
|
-
|
|
216
|
-
**React Context (for simple cases):**
|
|
217
|
-
- Create CartContext and CartProvider
|
|
218
|
-
- Store cart state and cartId (from localStorage)
|
|
219
|
-
- Load cart on mount if cartId exists
|
|
220
|
-
- Provide methods: addItem, removeItem, updateQuantity, clearCart
|
|
221
|
-
- Update cart state after each operation
|
|
222
|
-
|
|
223
|
-
**State management libraries (Zustand, Redux):**
|
|
224
|
-
- Use for complex state requirements
|
|
225
|
-
- Better for large applications
|
|
226
|
-
- Easier to debug with DevTools
|
|
227
|
-
- Same pattern: Store cart, provide actions, sync with backend
|
|
228
|
-
|
|
229
|
-
**Key requirements:**
|
|
230
|
-
- Cart accessible from any component
|
|
231
|
-
- Real-time cart count updates
|
|
232
|
-
- Optimistic UI updates (update UI immediately, sync with backend)
|
|
233
|
-
|
|
234
|
-
### Cart Cleanup After Order Placement (CRITICAL)
|
|
235
|
-
|
|
236
|
-
**IMPORTANT: After order is successfully placed, you MUST reset the cart state.**
|
|
237
|
-
|
|
238
|
-
**Common issue:** Cart popup and global cart state still show old items after order completion. This happens when cart state isn't cleared after checkout.
|
|
239
|
-
|
|
240
|
-
**Required cleanup actions:**
|
|
241
|
-
|
|
242
|
-
1. **Clear cart from global state** - Reset cart state to null/empty in Context/Zustand/Redux
|
|
243
|
-
2. **Clear localStorage cart ID** - Remove cart ID: `localStorage.removeItem('cart_id')`
|
|
244
|
-
3. **Invalidate cart queries** - If using TanStack Query: `queryClient.invalidateQueries({ queryKey: ['cart'] })`
|
|
245
|
-
4. **Update cart count to 0** - Navbar and UI should reflect empty cart
|
|
246
|
-
|
|
247
|
-
**When to clear:**
|
|
248
|
-
- After successful order placement (order confirmed)
|
|
249
|
-
- On navigation to order confirmation page
|
|
250
|
-
- Before redirecting to thank you page
|
|
251
|
-
|
|
252
|
-
**Why this is critical:**
|
|
253
|
-
- Prevents "phantom cart" from appearing in cart popup after order
|
|
254
|
-
- Ensures clean state for next shopping session
|
|
255
|
-
- Improves UX by not showing old cart items
|
|
256
|
-
|
|
257
|
-
## Error Handling for Ecommerce
|
|
258
|
-
|
|
259
|
-
### Ecommerce-Specific Errors
|
|
260
|
-
|
|
261
|
-
**Out of stock:**
|
|
262
|
-
- Catch errors when adding to cart
|
|
263
|
-
- Check for "out of stock" or "inventory" in error message
|
|
264
|
-
- Show user-friendly message: "Sorry, this item is now out of stock"
|
|
265
|
-
- Update product availability UI to show out of stock
|
|
266
|
-
|
|
267
|
-
**Price changed during checkout:**
|
|
268
|
-
- Compare cart total with expected total
|
|
269
|
-
- If different, show warning: "Prices have been updated. Please review your cart."
|
|
270
|
-
- Highlight changed prices in cart
|
|
271
|
-
|
|
272
|
-
**Payment failed:**
|
|
273
|
-
- Catch errors during order completion
|
|
274
|
-
- Check for specific payment errors: payment_declined, insufficient_funds, etc.
|
|
275
|
-
- Show specific messages:
|
|
276
|
-
- Payment declined → "Payment declined. Please try a different payment method."
|
|
277
|
-
- Insufficient funds → "Insufficient funds. Please use a different card."
|
|
278
|
-
- Generic → "Payment failed. Please try again or contact support."
|
|
279
|
-
|
|
280
|
-
**Session expired:**
|
|
281
|
-
- Catch 401/Unauthorized errors
|
|
282
|
-
- Clear auth state
|
|
283
|
-
- Redirect to login with message: "Your session has expired. Please log in again."
|
|
284
|
-
|
|
285
|
-
### User-Friendly Error Messages
|
|
286
|
-
|
|
287
|
-
**Transform technical errors to clear messages:**
|
|
288
|
-
- Network/fetch errors → "Unable to connect. Please check your internet connection."
|
|
289
|
-
- Timeout errors → "Request timed out. Please try again."
|
|
290
|
-
- Inventory errors → "This item is no longer available in the requested quantity."
|
|
291
|
-
- Generic fallback → "Something went wrong. Please try again or contact support."
|
|
292
|
-
|
|
293
|
-
**Pattern**: Check error message or status code, map to user-friendly message, show in UI (toast, banner, inline).
|
|
294
|
-
|
|
295
|
-
## Performance Patterns
|
|
296
|
-
|
|
297
|
-
### Data Fetching with TanStack Query (RECOMMENDED)
|
|
298
|
-
|
|
299
|
-
**Use TanStack Query for all backend API calls** - provides automatic caching, request deduplication, loading/error states, and optimistic updates.
|
|
300
|
-
|
|
301
|
-
**Installation:** `npm install @tanstack/react-query`
|
|
302
|
-
|
|
303
|
-
**Setup:**
|
|
304
|
-
- Create QueryClient with default options (staleTime: 5 min, retry: 1)
|
|
305
|
-
- Wrap app with QueryClientProvider
|
|
306
|
-
|
|
307
|
-
**Query pattern (for fetching data):**
|
|
308
|
-
- Use `useQuery` with queryKey and queryFn
|
|
309
|
-
- queryKey: Array with resource and identifier `['products', categoryId]`
|
|
310
|
-
- queryFn: API call function
|
|
311
|
-
- Returns: `data`, `isLoading`, `error`
|
|
312
|
-
- Use for: Products, cart, customer data, categories
|
|
313
|
-
|
|
314
|
-
**Mutation pattern (for modifying data):**
|
|
315
|
-
- Use `useMutation` with mutationFn
|
|
316
|
-
- mutationFn: API operation (add to cart, update, delete)
|
|
317
|
-
- onSuccess: Update cache or invalidate queries
|
|
318
|
-
- Returns: `mutate` function, `isPending` state
|
|
319
|
-
- Use for: Add to cart, remove from cart, update quantities, place order
|
|
320
|
-
|
|
321
|
-
**Benefits:**
|
|
322
|
-
- Automatic caching (no manual cache management)
|
|
323
|
-
- Built-in loading/error states
|
|
324
|
-
- Request deduplication
|
|
325
|
-
- Optimistic updates (update UI before server responds)
|
|
326
|
-
- Cache invalidation strategies
|
|
327
|
-
|
|
328
|
-
**Ecommerce-specific usage:**
|
|
329
|
-
- Products: Long stale time (5-10 min) - products don't change often
|
|
330
|
-
- Cart: Short or no stale time - prices/inventory can change
|
|
331
|
-
- Categories: Long stale time - rarely change
|
|
332
|
-
|
|
333
|
-
### Caching Strategy
|
|
334
|
-
|
|
335
|
-
**Client-side caching:**
|
|
336
|
-
- TanStack Query handles automatically with `staleTime` and `cacheTime`
|
|
337
|
-
- Configure globally or per-query
|
|
338
|
-
- Product data: 5-10 min stale time
|
|
339
|
-
- Cart data: Fresh on every fetch
|
|
340
|
-
- Categories: Long stale time
|
|
341
|
-
|
|
342
|
-
**Server-side caching (framework-specific):**
|
|
343
|
-
- Next.js: Use `revalidate` export or cache configuration
|
|
344
|
-
- Set revalidation period (e.g., 300 seconds for product pages)
|
|
345
|
-
- Static generation with ISR for product pages
|
|
346
|
-
|
|
347
|
-
### Request Deduplication
|
|
348
|
-
|
|
349
|
-
TanStack Query and modern frameworks handle this automatically - multiple components requesting same data result in single request.
|
|
350
|
-
|
|
351
|
-
### Pagination Pattern
|
|
352
|
-
|
|
353
|
-
**Offset-based:** Pass limit and offset parameters to API `limit: 24, offset: page * 24`
|
|
354
|
-
|
|
355
|
-
**Cursor-based (better performance):** Pass limit and cursor (last item ID) `limit: 24, cursor: lastProductId`
|
|
356
|
-
|
|
357
|
-
Check backend documentation for supported pagination type.
|
|
358
|
-
|
|
359
|
-
## Checklist
|
|
360
|
-
|
|
361
|
-
**Essential backend integration:**
|
|
362
|
-
|
|
363
|
-
- [ ] Backend detected (Medusa, Shopify, custom, etc.)
|
|
364
|
-
- [ ] Environment variables configured (API URL, keys)
|
|
365
|
-
- [ ] Framework-specific data fetching patterns identified
|
|
366
|
-
- [ ] **RECOMMENDED: TanStack Query installed and configured for API calls**
|
|
367
|
-
- [ ] Server-side fetching for product pages (SEO)
|
|
368
|
-
- [ ] Client-side fetching for cart and user interactions (use TanStack Query)
|
|
369
|
-
- [ ] Authentication flow implemented (login/logout)
|
|
370
|
-
- [ ] Cart ID persisted in localStorage or cookies
|
|
371
|
-
- [ ] Global cart state management (context or store)
|
|
372
|
-
- [ ] Cart count synced across app
|
|
373
|
-
- [ ] Optimistic UI updates for cart operations
|
|
374
|
-
- [ ] Error handling for out of stock scenarios
|
|
375
|
-
- [ ] Error handling for payment failures
|
|
376
|
-
- [ ] Session expiration handling (redirect to login)
|
|
377
|
-
- [ ] User-friendly error messages (not technical)
|
|
378
|
-
- [ ] Caching strategy for product data
|
|
379
|
-
- [ ] Stock availability checks before checkout
|
|
380
|
-
- [ ] Price change detection and warnings
|
|
381
|
-
|
|
382
|
-
**For Medusa backends, also check:**
|
|
383
|
-
- [ ] Medusa SDK installed (`@medusajs/js-sdk` + `@medusajs/types`)
|
|
384
|
-
- [ ] SDK initialized with baseUrl and publishableKey
|
|
385
|
-
- [ ] Vite SSR config added (if using TanStack Start/Vite)
|
|
386
|
-
- [ ] Using official types from `@medusajs/types`
|
|
387
|
-
- [ ] Not dividing prices by 100 (display as-is)
|
|
388
|
-
- [ ] Region context implemented for multi-region stores
|
|
389
|
-
- [ ] Region passed to cart and product queries
|
|
390
|
-
|
|
391
|
-
See `reference/medusa.md` for complete Medusa integration guide.
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
# Promotions Feature
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
|
|
5
|
-
- [Overview](#overview)
|
|
6
|
-
- [Promotion Types and When to Use](#promotion-types-and-when-to-use)
|
|
7
|
-
- [Sale Price Display](#sale-price-display)
|
|
8
|
-
- [Promo Code Input](#promo-code-input)
|
|
9
|
-
- [Free Shipping Threshold](#free-shipping-threshold)
|
|
10
|
-
- [Promotional Banners](#promotional-banners)
|
|
11
|
-
- [Countdown Timers](#countdown-timers)
|
|
12
|
-
- [Mobile Considerations](#mobile-considerations)
|
|
13
|
-
- [Checklist](#checklist)
|
|
14
|
-
|
|
15
|
-
## Overview
|
|
16
|
-
|
|
17
|
-
Promotions are temporary price reductions, discounts, or special offers designed to drive sales and incentivize purchases. Effective promotion UI clearly communicates value, creates urgency, and makes redemption easy.
|
|
18
|
-
|
|
19
|
-
**Backend Integration (CRITICAL):**
|
|
20
|
-
|
|
21
|
-
All promotion logic and data must come from the ecommerce backend. Do this based on backend integrated. Fetch active promotions, discount codes, and price rules from backend API. Never hardcode promotion logic in frontend.
|
|
22
|
-
|
|
23
|
-
### Key Ecommerce Requirements
|
|
24
|
-
|
|
25
|
-
- Clear discount communication (strikethrough pricing, percentage off)
|
|
26
|
-
- Promo code input (cart/checkout)
|
|
27
|
-
- Free shipping threshold progress (increase AOV)
|
|
28
|
-
- Countdown timers (create urgency)
|
|
29
|
-
- Automatic discount application
|
|
30
|
-
- Sale badges (product discovery)
|
|
31
|
-
|
|
32
|
-
### Purpose
|
|
33
|
-
|
|
34
|
-
**Conversion optimization:**
|
|
35
|
-
- Drive sales and increase conversion rate
|
|
36
|
-
- Increase average order value (free shipping thresholds, tiered discounts)
|
|
37
|
-
- Acquire new customers (first-order discounts)
|
|
38
|
-
- Create urgency (limited-time offers)
|
|
39
|
-
- Clear inventory (seasonal sales)
|
|
40
|
-
- Reward loyalty (VIP codes, member discounts)
|
|
41
|
-
|
|
42
|
-
## Promotion Types and When to Use
|
|
43
|
-
|
|
44
|
-
### Sales (Price Reductions)
|
|
45
|
-
|
|
46
|
-
**What it is**: Select products with reduced prices, automatically applied. No code needed.
|
|
47
|
-
|
|
48
|
-
**Use when:**
|
|
49
|
-
- Seasonal sales (Black Friday, holiday sales)
|
|
50
|
-
- Clearance or end-of-season inventory
|
|
51
|
-
- Product-specific promotions
|
|
52
|
-
- You want reduced prices visible on product pages (increases click-through)
|
|
53
|
-
|
|
54
|
-
**Display:**
|
|
55
|
-
- Strikethrough original price (provides context for savings)
|
|
56
|
-
- Sale price bold and prominent (red or brand color)
|
|
57
|
-
- Sale badge on product cards ("Sale", "30% Off")
|
|
58
|
-
|
|
59
|
-
**Medusa implementation:**
|
|
60
|
-
Use Price Lists with special prices for products. Provides automatic strikethrough pricing in cart and on product pages.
|
|
61
|
-
|
|
62
|
-
### Discount Codes
|
|
63
|
-
|
|
64
|
-
**What it is**: Customer enters code to unlock discount (percentage, fixed amount, or free shipping).
|
|
65
|
-
|
|
66
|
-
**Use when:**
|
|
67
|
-
- Newsletter signups ("Get 10% off with WELCOME10")
|
|
68
|
-
- VIP or loyalty program members (exclusive codes)
|
|
69
|
-
- Targeted marketing campaigns (email, social media)
|
|
70
|
-
- First-time customer incentives
|
|
71
|
-
- Friends and family discounts (limited distribution)
|
|
72
|
-
|
|
73
|
-
**Display:**
|
|
74
|
-
- Promo code input field in cart/checkout
|
|
75
|
-
- Success message: "Code applied: WELCOME10"
|
|
76
|
-
- Discount shown in order summary with code name
|
|
77
|
-
- Remove option (X icon or "Remove" link)
|
|
78
|
-
|
|
79
|
-
**Medusa implementation:**
|
|
80
|
-
Discount/promo code system with advanced logic (order-level discounts, usage limits, expiration dates).
|
|
81
|
-
|
|
82
|
-
### Automatic Discounts
|
|
83
|
-
|
|
84
|
-
**What it is**: Discount automatically applied when conditions met. No code entry required.
|
|
85
|
-
|
|
86
|
-
**Use when:**
|
|
87
|
-
- Free shipping thresholds ("Free shipping over $50")
|
|
88
|
-
- Volume discounts ("Spend $100, get $20 off")
|
|
89
|
-
- Buy One Get One (BOGO) offers
|
|
90
|
-
- Encouraging larger cart values (increase AOV)
|
|
91
|
-
|
|
92
|
-
**Display:**
|
|
93
|
-
- Banner announcing the promotion
|
|
94
|
-
- Progress indicator toward threshold (see Free Shipping Threshold section)
|
|
95
|
-
- "Discount applied" message in cart
|
|
96
|
-
- Automatic addition to order summary
|
|
97
|
-
|
|
98
|
-
### Buy X, Get Y (BOGO)
|
|
99
|
-
|
|
100
|
-
**What it is**: Purchase certain products to unlock free/discounted items.
|
|
101
|
-
|
|
102
|
-
**Use when:**
|
|
103
|
-
- Moving inventory (clear out slow-moving products)
|
|
104
|
-
- Cross-selling related products ("Buy sunscreen, get beach bag 50% off")
|
|
105
|
-
- Increasing units per transaction
|
|
106
|
-
|
|
107
|
-
**Display:**
|
|
108
|
-
- Clear promotion text on product page ("Buy 2, Get 1 Free")
|
|
109
|
-
- Free/discounted item shown in cart with explanation
|
|
110
|
-
- Discount line in order summary
|
|
111
|
-
|
|
112
|
-
**Medusa implementation:**
|
|
113
|
-
Buy X Get Y automatic discount. Free/discounted item must be added to cart to activate.
|
|
114
|
-
|
|
115
|
-
## Sale Price Display
|
|
116
|
-
|
|
117
|
-
### Strikethrough Pricing Pattern
|
|
118
|
-
|
|
119
|
-
**Format:**
|
|
120
|
-
```
|
|
121
|
-
$49.99 $34.99
|
|
122
|
-
(Original, strikethrough) (Sale price, bold)
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Design:**
|
|
126
|
-
- Original price: Strikethrough, muted gray color, smaller
|
|
127
|
-
- Sale price: Bold, larger, red or accent color
|
|
128
|
-
- Clear visual hierarchy (sale price dominates)
|
|
129
|
-
|
|
130
|
-
**Placement:**
|
|
131
|
-
- Product cards: Below image
|
|
132
|
-
- Product page: Near "Add to Cart" button
|
|
133
|
-
- Cart: Item price column
|
|
134
|
-
|
|
135
|
-
### Percentage Off Display
|
|
136
|
-
|
|
137
|
-
Show savings to emphasize value.
|
|
138
|
-
|
|
139
|
-
**Options:**
|
|
140
|
-
- "Save 30%" badge
|
|
141
|
-
- "30% off" label
|
|
142
|
-
- "$15 off" (absolute savings)
|
|
143
|
-
|
|
144
|
-
**Placement:**
|
|
145
|
-
- Badge on product image (top-left or top-right corner)
|
|
146
|
-
- Near price (inline or below)
|
|
147
|
-
- In cart summary ("Total savings: $45")
|
|
148
|
-
|
|
149
|
-
### Sale Badge
|
|
150
|
-
|
|
151
|
-
Bright badge on product image (red, orange, yellow) in top corner. 48-64px desktop, 40-48px mobile. Text: "Sale", "30% Off", or "Save $15".
|
|
152
|
-
|
|
153
|
-
## Promo Code Input
|
|
154
|
-
|
|
155
|
-
### Placement and Design
|
|
156
|
-
|
|
157
|
-
**Location:**
|
|
158
|
-
Cart page order summary or checkout page. Position in right sidebar (desktop) or below items (mobile).
|
|
159
|
-
|
|
160
|
-
**Layout:**
|
|
161
|
-
- Label: "Promo code" or "Discount code"
|
|
162
|
-
- Text input (200-280px desktop, full-width mobile)
|
|
163
|
-
- "Apply" button inline or stacked (mobile)
|
|
164
|
-
- Auto-uppercase on submit (codes usually uppercase)
|
|
165
|
-
|
|
166
|
-
**Expandable pattern (optional):**
|
|
167
|
-
"Have a promo code?" link that expands to show input. Saves vertical space, reduces visual clutter.
|
|
168
|
-
|
|
169
|
-
### Success and Error States
|
|
170
|
-
|
|
171
|
-
**Success:**
|
|
172
|
-
- Green checkmark or success message: "Code applied: WELCOME10"
|
|
173
|
-
- Discount shown in order summary with code name: "Discount (WELCOME10) -$10.00"
|
|
174
|
-
- Remove option: X icon or "Remove" link
|
|
175
|
-
- Update cart total immediately
|
|
176
|
-
|
|
177
|
-
**Error:**
|
|
178
|
-
- Red error message below input: "Invalid code", "Code expired", or "Minimum purchase not met"
|
|
179
|
-
- Input remains visible for retry
|
|
180
|
-
- Don't clear input field (user may have typo)
|
|
181
|
-
|
|
182
|
-
**Applied code display in order summary:**
|
|
183
|
-
```
|
|
184
|
-
Subtotal $100.00
|
|
185
|
-
Discount (WELCOME10) -$10.00
|
|
186
|
-
Shipping $5.00
|
|
187
|
-
─────────────────────
|
|
188
|
-
Total $95.00
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Free Shipping Threshold
|
|
192
|
-
|
|
193
|
-
**Purpose (CRITICAL)**: Increase average order value by encouraging customers to add more items to reach free shipping.
|
|
194
|
-
|
|
195
|
-
### Progress Bar Pattern
|
|
196
|
-
|
|
197
|
-
**Display in cart:**
|
|
198
|
-
- "Add $25 more for FREE SHIPPING"
|
|
199
|
-
- Horizontal progress bar showing proximity to threshold
|
|
200
|
-
- Updates automatically as cart value changes
|
|
201
|
-
- Green when threshold reached
|
|
202
|
-
|
|
203
|
-
**Example:**
|
|
204
|
-
```
|
|
205
|
-
Add $25.00 more for FREE SHIPPING
|
|
206
|
-
[███████░░░░░░░░] 50%
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
**When threshold met:**
|
|
210
|
-
- "You've unlocked free shipping!" (success message)
|
|
211
|
-
- Green checkmark or badge
|
|
212
|
-
- Crossed-out shipping charge in order summary
|
|
213
|
-
|
|
214
|
-
**Why it works:**
|
|
215
|
-
- Visualizes proximity to goal (loss aversion)
|
|
216
|
-
- Increases AOV by 15-30% on average
|
|
217
|
-
- Reduces cart abandonment (free shipping is top reason to complete purchase)
|
|
218
|
-
|
|
219
|
-
### Free Shipping Banner
|
|
220
|
-
|
|
221
|
-
Sitewide announcement: "Free shipping on orders over $50". Display in top banner or near cart icon. Visible on all pages for awareness.
|
|
222
|
-
|
|
223
|
-
## Promotional Banners
|
|
224
|
-
|
|
225
|
-
### Top Banner
|
|
226
|
-
|
|
227
|
-
Full-width strip at top of page (48-64px height). Bright color contrasting with navbar. Short message: "Free shipping on orders over $50" or "Sale: Up to 50% off - Shop Now".
|
|
228
|
-
|
|
229
|
-
**Position:**
|
|
230
|
-
- Above navbar (most common)
|
|
231
|
-
- Below navbar (alternative)
|
|
232
|
-
- Sticky (stays visible on scroll, optional)
|
|
233
|
-
|
|
234
|
-
**CTA:**
|
|
235
|
-
Link to sale page ("Shop Now", "Learn More") or whole banner clickable.
|
|
236
|
-
|
|
237
|
-
### Hero Banner
|
|
238
|
-
|
|
239
|
-
Large hero section on homepage with promotional message. Background image, headline ("Black Friday Sale"), subheading ("Up to 60% off sitewide"), CTA button ("Shop the Sale"), optional countdown timer.
|
|
240
|
-
|
|
241
|
-
### Inline Banners
|
|
242
|
-
|
|
243
|
-
Within page content (product pages, cart). Examples: Free shipping reminder on cart page, "Sale ends soon" on product page. Less prominent than hero.
|
|
244
|
-
|
|
245
|
-
## Countdown Timers
|
|
246
|
-
|
|
247
|
-
Use for time-sensitive promotions to create urgency and FOMO.
|
|
248
|
-
|
|
249
|
-
**When to use:**
|
|
250
|
-
- Flash sales (24-hour sales)
|
|
251
|
-
- Limited-time offers
|
|
252
|
-
- Holiday promotions
|
|
253
|
-
- Never for permanent sales (fake urgency harms trust)
|
|
254
|
-
|
|
255
|
-
**Display format:**
|
|
256
|
-
- "Sale ends in: 2d 14h 32m 15s"
|
|
257
|
-
- Or simpler: "Ends in 2 days"
|
|
258
|
-
- Or: "Hurry! Only 14 hours left"
|
|
259
|
-
|
|
260
|
-
**Placement:**
|
|
261
|
-
Top banner, product page near price, cart page, or hero section.
|
|
262
|
-
|
|
263
|
-
**Implementation:**
|
|
264
|
-
Server-side time to prevent client manipulation, auto-hide when expired, update in real-time.
|
|
265
|
-
|
|
266
|
-
## Mobile Considerations
|
|
267
|
-
|
|
268
|
-
**Top banner:**
|
|
269
|
-
Shorter text (fewer words), smaller height (40-48px), dismissible (X button).
|
|
270
|
-
|
|
271
|
-
**Sale badges:**
|
|
272
|
-
Slightly smaller (40-48px), still clearly visible, don't obstruct product image.
|
|
273
|
-
|
|
274
|
-
**Promo code input:**
|
|
275
|
-
Full-width input and button, stacked layout (input above button), large touch targets (48px height), expandable section to save space.
|
|
276
|
-
|
|
277
|
-
**Countdown timer:**
|
|
278
|
-
Simplified format ("Ends in 14 hours" vs full d:h:m:s), larger text for readability.
|
|
279
|
-
|
|
280
|
-
## Checklist
|
|
281
|
-
|
|
282
|
-
**Essential features:**
|
|
283
|
-
|
|
284
|
-
- [ ] Strikethrough original price for sales
|
|
285
|
-
- [ ] Sale price bold, prominent, colored
|
|
286
|
-
- [ ] Sale badges on product images (40-64px)
|
|
287
|
-
- [ ] Percentage off displayed ("30% Off")
|
|
288
|
-
- [ ] Promo code input field in cart/checkout
|
|
289
|
-
- [ ] "Apply" button next to promo input
|
|
290
|
-
- [ ] Success message after applying code
|
|
291
|
-
- [ ] Error message for invalid codes
|
|
292
|
-
- [ ] Applied code displayed in order summary with name
|
|
293
|
-
- [ ] Remove code option (X icon or "Remove" link)
|
|
294
|
-
- [ ] Total savings highlighted in cart
|
|
295
|
-
- [ ] Free shipping progress bar (if applicable)
|
|
296
|
-
- [ ] Progress updates as cart value changes
|
|
297
|
-
- [ ] Success message when threshold met
|
|
298
|
-
- [ ] Countdown timer for time-limited offers (server-side)
|
|
299
|
-
- [ ] Promotional banners (top banner, hero)
|
|
300
|
-
- [ ] Backend integration (fetch promotions from API)
|
|
301
|
-
- [ ] Mobile: Full-width promo input, stacked layout
|
|
302
|
-
- [ ] Mobile: Large touch targets (48px)
|
|
303
|
-
- [ ] Expandable promo section (optional, saves space)
|
|
304
|
-
- [ ] ARIA labels on promo input
|
|
305
|
-
- [ ] Screen reader announcements for price changes
|
|
306
|
-
- [ ] Keyboard accessible (Tab, Enter)
|
|
307
|
-
- [ ] High contrast text (4.5:1 minimum)
|