diff --git a/PRODUCT_PAGE_IMPLEMENTATION.md b/PRODUCT_PAGE_IMPLEMENTATION.md new file mode 100644 index 0000000..9292376 --- /dev/null +++ b/PRODUCT_PAGE_IMPLEMENTATION.md @@ -0,0 +1,331 @@ +# Product Page Implementation Plan + +## 🎯 What We Have (Current State) + +### Backend (API): +βœ… Product data with variations +βœ… Product attributes +βœ… Images array (featured + gallery) +βœ… Variation images +βœ… Price, stock status, SKU +βœ… Description, short description +βœ… Categories, tags +βœ… Related products + +### Frontend (Existing): +βœ… Basic product page structure +βœ… Image gallery with thumbnails (implemented but needs enhancement) +βœ… Add to cart functionality +βœ… Cart store (Zustand) +βœ… Toast notifications +βœ… Responsive layout + +### Missing: +❌ Horizontal scrollable thumbnail slider +❌ Variation selector dropdowns +❌ Variation image auto-switching +❌ Reviews section +❌ Specifications table +❌ Shipping/Returns info +❌ Wishlist/Save feature +❌ Related products display +❌ Social proof elements +❌ Trust badges + +--- + +## πŸ“‹ Implementation Priority (What Makes Sense Now) + +### **Phase 1: Core Product Page (Implement Now)** ⭐ + +#### 1.1 Image Gallery Enhancement +- βœ… Horizontal scrollable thumbnail slider +- βœ… Arrow navigation for >4 images +- βœ… Active thumbnail highlight +- βœ… Click thumbnail to change main image +- βœ… Responsive (swipeable on mobile) + +**Why:** Critical for user experience, especially for products with multiple images + +#### 1.2 Variation Selector +- βœ… Dropdown for each attribute +- βœ… Auto-switch image when variation selected +- βœ… Update price based on variation +- βœ… Update stock status +- βœ… Disable Add to Cart if no variation selected + +**Why:** Essential for variable products, directly impacts conversion + +#### 1.3 Enhanced Buy Section +- βœ… Price display (regular + sale) +- βœ… Stock status with color coding +- βœ… Quantity selector (plus/minus buttons) +- βœ… Add to Cart button (with loading state) +- βœ… Product meta (SKU, categories) + +**Why:** Core e-commerce functionality + +#### 1.4 Product Information Sections +- βœ… Tabs for Description, Additional Info, Reviews +- βœ… Vertical layout (avoid horizontal tabs) +- βœ… Specifications table (from attributes) +- βœ… Expandable sections on mobile + +**Why:** Users need detailed product info, research shows vertical > horizontal + +--- + +### **Phase 2: Trust & Conversion (Next Sprint)** 🎯 + +#### 2.1 Reviews Section +- ⏳ Display existing WooCommerce reviews +- ⏳ Star rating display +- ⏳ Review count +- ⏳ Link to write review (WooCommerce native) + +**Why:** Reviews are #2 most important content after images + +#### 2.2 Trust Elements +- ⏳ Payment method icons +- ⏳ Secure checkout badge +- ⏳ Free shipping threshold +- ⏳ Return policy link + +**Why:** Builds trust, reduces cart abandonment + +#### 2.3 Related Products +- ⏳ Display related products (from API) +- ⏳ Horizontal carousel +- ⏳ Product cards + +**Why:** Increases average order value + +--- + +### **Phase 3: Advanced Features (Future)** πŸš€ + +#### 3.1 Wishlist/Save for Later +- πŸ“… Add to wishlist button +- πŸ“… Wishlist page +- πŸ“… Persist across sessions + +#### 3.2 Social Proof +- πŸ“… "X people viewing" +- πŸ“… "X sold today" +- πŸ“… Customer photos + +#### 3.3 Enhanced Media +- πŸ“… Image zoom/lightbox +- πŸ“… Video support +- πŸ“… 360Β° view + +--- + +## πŸ› οΈ Phase 1 Implementation Details + +### Component Structure: +``` +Product/ +β”œβ”€β”€ index.tsx (main component) +β”œβ”€β”€ components/ +β”‚ β”œβ”€β”€ ImageGallery.tsx +β”‚ β”œβ”€β”€ ThumbnailSlider.tsx +β”‚ β”œβ”€β”€ VariationSelector.tsx +β”‚ β”œβ”€β”€ BuySection.tsx +β”‚ β”œβ”€β”€ ProductTabs.tsx +β”‚ β”œβ”€β”€ SpecificationTable.tsx +β”‚ └── ProductMeta.tsx +``` + +### State Management: +```typescript +// Product page state +const [product, setProduct] = useState(null); +const [selectedImage, setSelectedImage] = useState(''); +const [selectedVariation, setSelectedVariation] = useState(null); +const [selectedAttributes, setSelectedAttributes] = useState>({}); +const [quantity, setQuantity] = useState(1); +const [activeTab, setActiveTab] = useState('description'); +``` + +### Key Features: + +#### 1. Thumbnail Slider +```tsx +
+ {/* Prev Arrow */} + + + {/* Scrollable Container */} +
+ {images.map((img, i) => ( + + ))} +
+ + {/* Next Arrow */} + +
+``` + +#### 2. Variation Selector +```tsx +{product.attributes?.map(attr => ( +
+ + +
+))} +``` + +#### 3. Auto-Switch Variation Image +```typescript +useEffect(() => { + if (selectedVariation && selectedVariation.image) { + setSelectedImage(selectedVariation.image); + } +}, [selectedVariation]); + +// Find matching variation +useEffect(() => { + if (product?.variations && Object.keys(selectedAttributes).length > 0) { + const variation = product.variations.find(v => { + return Object.entries(selectedAttributes).every(([key, value]) => { + return v.attributes[key] === value; + }); + }); + setSelectedVariation(variation || null); + } +}, [selectedAttributes, product]); +``` + +--- + +## πŸ“ Layout Design + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Breadcrumb: Home > Shop > Category > Product Name β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ Product Name (H1) β”‚ +β”‚ Main Image β”‚ ⭐⭐⭐⭐⭐ (24 reviews) β”‚ +β”‚ (Large) β”‚ β”‚ +β”‚ β”‚ $99.00 $79.00 (Save 20%) β”‚ +β”‚ β”‚ βœ… In Stock β”‚ +β”‚ β”‚ β”‚ +β”‚ [Thumbnail Slider] β”‚ Short description text... β”‚ +β”‚ β—€ [img][img][img] β–Άβ”‚ β”‚ +β”‚ β”‚ Color: [Dropdown β–Ό] β”‚ +β”‚ β”‚ Size: [Dropdown β–Ό] β”‚ +β”‚ β”‚ β”‚ +β”‚ β”‚ Quantity: [-] 1 [+] β”‚ +β”‚ β”‚ β”‚ +β”‚ β”‚ [πŸ›’ Add to Cart] β”‚ +β”‚ β”‚ [β™‘ Add to Wishlist] β”‚ +β”‚ β”‚ β”‚ +β”‚ β”‚ πŸ”’ Secure Checkout β”‚ +β”‚ β”‚ 🚚 Free Shipping over $50 β”‚ +β”‚ β”‚ ↩️ 30-Day Returns β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ [Description] [Additional Info] [Reviews (24)] β”‚ +β”‚ ───────────── β”‚ +β”‚ β”‚ +β”‚ Full product description here... β”‚ +β”‚ β€’ Feature 1 β”‚ +β”‚ β€’ Feature 2 β”‚ +β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Related Products β”‚ +β”‚ [Product] [Product] [Product] [Product] β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 🎨 Styling Guidelines + +### Colors: +```css +--price-sale: #DC2626 (red) +--stock-in: #10B981 (green) +--stock-low: #F59E0B (orange) +--stock-out: #EF4444 (red) +--primary-cta: var(--primary) +--border-active: var(--primary) +``` + +### Spacing: +```css +--section-gap: 2rem +--element-gap: 1rem +--thumbnail-size: 80px +--thumbnail-gap: 0.5rem +``` + +--- + +## βœ… Acceptance Criteria + +### Image Gallery: +- [ ] Thumbnails scroll horizontally +- [ ] Show 4 thumbnails at a time on desktop +- [ ] Arrow buttons appear when >4 images +- [ ] Active thumbnail has colored border +- [ ] Click thumbnail changes main image +- [ ] Swipeable on mobile +- [ ] Smooth scroll animation + +### Variation Selector: +- [ ] Dropdown for each attribute +- [ ] "Choose an option" placeholder +- [ ] When variation selected, image auto-switches +- [ ] Price updates based on variation +- [ ] Stock status updates +- [ ] Add to Cart disabled until all attributes selected +- [ ] Clear error message if incomplete + +### Buy Section: +- [ ] Sale price shown in red +- [ ] Regular price strikethrough +- [ ] Savings percentage/amount shown +- [ ] Stock status color-coded +- [ ] Quantity buttons work correctly +- [ ] Add to Cart shows loading state +- [ ] Success toast with cart preview +- [ ] Cart count updates in header + +### Product Info: +- [ ] Tabs work correctly +- [ ] Description renders HTML +- [ ] Specifications show as table +- [ ] Mobile: sections collapsible +- [ ] Smooth scroll to reviews + +--- + +## πŸš€ Ready to Implement + +**Estimated Time:** 4-6 hours +**Priority:** HIGH +**Dependencies:** None (all APIs ready) + +Let's build Phase 1 now! 🎯 diff --git a/PRODUCT_PAGE_SOP.md b/PRODUCT_PAGE_SOP.md new file mode 100644 index 0000000..6c35f40 --- /dev/null +++ b/PRODUCT_PAGE_SOP.md @@ -0,0 +1,436 @@ +# Product Page Design SOP - Industry Best Practices + +**Document Version:** 1.0 +**Last Updated:** November 26, 2025 +**Purpose:** Guide for building industry-standard product pages in Customer SPA + +--- + +## πŸ“‹ Executive Summary + +This SOP consolidates research-backed best practices for e-commerce product pages based on Baymard Institute's 2025 UX research and industry standards. Since Customer SPA is not fully customizable by end-users, we must implement the best practices as defaults. + +--- + +## 🎯 Core Principles + +1. **Avoid Horizontal Tabs** - 27% of users overlook horizontal tabs entirely +2. **Vertical Collapsed Sections** - Only 8% overlook content (vs 27% for tabs) +3. **Images Are Critical** - After images, reviews are the most important content +4. **Trust & Social Proof** - Essential for conversion +5. **Mobile-First** - But optimize desktop experience separately + +--- + +## πŸ“ Layout Structure (Priority Order) + +### 1. **Hero Section** (Above the Fold) +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Breadcrumb β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ Product Title β”‚ +β”‚ Product β”‚ Price (with sale) β”‚ +β”‚ Images β”‚ Rating & Reviews Count β”‚ +β”‚ Gallery β”‚ Stock Status β”‚ +β”‚ β”‚ Short Description β”‚ +β”‚ β”‚ Variations Selector β”‚ +β”‚ β”‚ Quantity β”‚ +β”‚ β”‚ Add to Cart Button β”‚ +β”‚ β”‚ Wishlist/Save β”‚ +β”‚ β”‚ Trust Badges β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 2. **Product Information** (Below the Fold - Vertical Sections) +- βœ… Full Description (expandable) +- βœ… Specifications/Attributes (scannable table) +- βœ… Shipping & Returns Info +- βœ… Size Guide (if applicable) +- βœ… Reviews Section +- βœ… Related Products +- βœ… Recently Viewed + +--- + +## πŸ–ΌοΈ Image Gallery Requirements + +### Must-Have Features: +1. **Main Image Display** + - Large, zoomable image + - High resolution (min 1200px width) + - Aspect ratio: 1:1 or 4:3 + +2. **Thumbnail Slider** + - Horizontal scrollable + - 4-6 visible thumbnails + - Active thumbnail highlighted + - Arrow navigation for >4 images + - Touch/swipe enabled on mobile + +3. **Image Types Required:** + - βœ… Product on white background (default) + - βœ… "In Scale" images (with reference object/person) + - βœ… "Human Model" images (for wearables) + - βœ… Lifestyle/context images + - βœ… Detail shots (close-ups) + - βœ… 360Β° view (optional but recommended) + +4. **Variation Images:** + - Each variation should have its own image + - Auto-switch main image when variation selected + - Variation image highlighted in thumbnail slider + +### Image Gallery Interaction: +```javascript +// User Flow: +1. Click thumbnail β†’ Change main image +2. Select variation β†’ Auto-switch to variation image +3. Click main image β†’ Open lightbox/zoom +4. Swipe thumbnails β†’ Scroll horizontally +5. Hover thumbnail β†’ Preview in main (desktop) +``` + +--- + +## πŸ›’ Buy Section Elements + +### Required Elements (in order): +1. **Product Title** - H1, clear, descriptive +2. **Price Display:** + - Regular price (strikethrough if on sale) + - Sale price (highlighted in red/primary) + - Savings amount/percentage + - Unit price (for bulk items) + +3. **Rating & Reviews:** + - Star rating (visual) + - Number of reviews (clickable β†’ scroll to reviews) + - "Write a Review" link + +4. **Stock Status:** + - βœ… In Stock (green) + - ⚠️ Low Stock (orange, show quantity) + - ❌ Out of Stock (red, "Notify Me" option) + +5. **Variation Selector:** + - Dropdown for each attribute + - Visual swatches for colors + - Size chart link (for apparel) + - Clear labels + - Disabled options grayed out + +6. **Quantity Selector:** + - Plus/minus buttons + - Number input + - Min/max validation + - Bulk pricing info (if applicable) + +7. **Action Buttons:** + - **Primary:** Add to Cart (large, prominent) + - **Secondary:** Buy Now (optional) + - **Tertiary:** Add to Wishlist/Save for Later + +8. **Trust Elements:** + - Security badges (SSL, payment methods) + - Free shipping threshold + - Return policy summary + - Warranty info + +--- + +## πŸ“ Product Information Sections + +### 1. Description Section +``` +Format: Vertical collapsed/expandable +- Short description (2-3 sentences) always visible +- Full description expandable +- Rich text formatting +- Bullet points for features +- Video embed support +``` + +### 2. Specifications/Attributes +``` +Format: Scannable table +- Two-column layout (Label | Value) +- Grouped by category +- Tooltips for technical terms +- Expandable for long lists +- Copy-to-clipboard for specs +``` + +### 3. Shipping & Returns +``` +Always visible near buy section: +- Estimated delivery date +- Shipping cost calculator +- Return policy link +- Free shipping threshold +- International shipping info +``` + +### 4. Size Guide (Apparel/Footwear) +``` +- Modal/drawer popup +- Size chart table +- Measurement instructions +- Fit guide (slim, regular, loose) +- Model measurements +``` + +--- + +## ⭐ Reviews Section + +### Must-Have Features: +1. **Review Summary:** + - Overall rating (large) + - Rating distribution (5-star breakdown) + - Total review count + - Verified purchase badge + +2. **Review Filters:** + - Sort by: Most Recent, Highest Rating, Lowest Rating, Most Helpful + - Filter by: Rating (1-5 stars), Verified Purchase, With Photos + +3. **Individual Review Display:** + - Reviewer name (or anonymous) + - Rating (stars) + - Date + - Verified purchase badge + - Review text + - Helpful votes (thumbs up/down) + - Seller response (if any) + - Review images (clickable gallery) + +4. **Review Submission:** + - Star rating (required) + - Title (optional) + - Review text (required, min 50 chars) + - Photo upload (optional) + - Recommend product (yes/no) + - Fit guide (for apparel) + +5. **Review Images Gallery:** + - Navigate all customer photos + - Filter reviews by "with photos" + - Lightbox view + +--- + +## 🎁 Promotions & Offers + +### Display Locations: +1. **Product Badge** (on image) + - "Sale" / "New" / "Limited" + - Percentage off + - Free shipping + +2. **Price Section:** + - Coupon code field + - Auto-apply available coupons + - Bulk discount tiers + - Member pricing + +3. **Sticky Banner** (optional): + - Site-wide promotions + - Flash sales countdown + - Free shipping threshold + +### Coupon Integration: +``` +- Auto-detect applicable coupons +- One-click apply +- Show savings in cart preview +- Stackable coupons indicator +``` + +--- + +## πŸ”’ Trust & Social Proof Elements + +### 1. Trust Badges (Near Add to Cart): +- Payment security (SSL, PCI) +- Payment methods accepted +- Money-back guarantee +- Secure checkout badge + +### 2. Social Proof: +- "X people viewing this now" +- "X sold in last 24 hours" +- "X people added to cart today" +- Customer photos/UGC +- Influencer endorsements + +### 3. Credibility Indicators: +- Brand certifications +- Awards & recognition +- Press mentions +- Expert reviews + +--- + +## πŸ“± Mobile Optimization + +### Mobile-Specific Considerations: +1. **Image Gallery:** + - Swipeable main image + - Thumbnail strip below (horizontal scroll) + - Pinch to zoom + +2. **Sticky Add to Cart:** + - Fixed bottom bar + - Price + Add to Cart always visible + - Collapse on scroll down, expand on scroll up + +3. **Collapsed Sections:** + - All info sections collapsed by default + - Tap to expand + - Smooth animations + +4. **Touch Targets:** + - Min 44x44px for buttons + - Adequate spacing between elements + - Large, thumb-friendly controls + +--- + +## 🎨 Visual Design Guidelines + +### Typography: +- **Product Title:** 28-32px, bold +- **Price:** 24-28px, bold +- **Body Text:** 14-16px +- **Labels:** 12-14px, medium weight + +### Colors: +- **Primary CTA:** High contrast, brand color +- **Sale Price:** Red (#DC2626) or brand accent +- **Success:** Green (#10B981) +- **Warning:** Orange (#F59E0B) +- **Error:** Red (#EF4444) + +### Spacing: +- Section padding: 24-32px +- Element spacing: 12-16px +- Button padding: 12px 24px + +--- + +## πŸ”„ Interaction Patterns + +### 1. Variation Selection: +```javascript +// When user selects variation: +1. Update price +2. Update stock status +3. Switch main image +4. Update SKU +5. Highlight variation image in gallery +6. Enable/disable Add to Cart +``` + +### 2. Add to Cart: +```javascript +// On Add to Cart click: +1. Validate selection (all variations selected) +2. Show loading state +3. Add to cart (API call) +4. Show success toast with cart preview +5. Update cart count in header +6. Offer "View Cart" or "Continue Shopping" +``` + +### 3. Image Gallery: +```javascript +// Image interactions: +1. Click thumbnail β†’ Change main image +2. Click main image β†’ Open lightbox +3. Swipe main image β†’ Next/prev image +4. Hover thumbnail β†’ Preview (desktop) +``` + +--- + +## πŸ“Š Performance Metrics + +### Key Metrics to Track: +- Time to First Contentful Paint (< 1.5s) +- Largest Contentful Paint (< 2.5s) +- Image load time (< 1s) +- Add to Cart conversion rate +- Bounce rate +- Time on page +- Scroll depth + +--- + +## βœ… Implementation Checklist + +### Phase 1: Core Features (MVP) +- [ ] Responsive image gallery with thumbnails +- [ ] Horizontal scrollable thumbnail slider +- [ ] Variation selector with image switching +- [ ] Price display with sale pricing +- [ ] Stock status indicator +- [ ] Quantity selector +- [ ] Add to Cart button +- [ ] Product description (expandable) +- [ ] Specifications table +- [ ] Breadcrumb navigation + +### Phase 2: Enhanced Features +- [ ] Reviews section with filtering +- [ ] Review submission form +- [ ] Related products carousel +- [ ] Wishlist/Save for later +- [ ] Share buttons +- [ ] Shipping calculator +- [ ] Size guide modal +- [ ] Image zoom/lightbox + +### Phase 3: Advanced Features +- [ ] 360Β° product view +- [ ] Video integration +- [ ] Live chat integration +- [ ] Recently viewed products +- [ ] Personalized recommendations +- [ ] Social proof notifications +- [ ] Coupon auto-apply +- [ ] Bulk pricing display + +--- + +## 🚫 What to Avoid + +1. ❌ Horizontal tabs for content +2. ❌ Hiding critical info below the fold +3. ❌ Auto-playing videos +4. ❌ Intrusive popups +5. ❌ Tiny product images +6. ❌ Unclear variation selectors +7. ❌ Hidden shipping costs +8. ❌ Complicated checkout process +9. ❌ Fake urgency/scarcity +10. ❌ Too many CTAs (decision paralysis) + +--- + +## πŸ“š References + +- Baymard Institute - Product Page UX 2025 +- Nielsen Norman Group - E-commerce UX +- Shopify - Product Page Best Practices +- ConvertCart - Social Proof Guidelines +- Google - Mobile Page Speed Guidelines + +--- + +## πŸ”„ Version History + +| Version | Date | Changes | +|---------|------|---------| +| 1.0 | 2025-11-26 | Initial SOP creation based on industry research | + diff --git a/admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx b/admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx index edb2363..60f215c 100644 --- a/admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx +++ b/admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx @@ -209,13 +209,22 @@ export function GeneralTab({ onDragStart={(e) => { e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', index.toString()); + e.currentTarget.classList.add('opacity-50'); + }} + onDragEnd={(e) => { + e.currentTarget.classList.remove('opacity-50'); }} onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; + e.currentTarget.classList.add('ring-2', 'ring-primary', 'ring-offset-2'); + }} + onDragLeave={(e) => { + e.currentTarget.classList.remove('ring-2', 'ring-primary', 'ring-offset-2'); }} onDrop={(e) => { e.preventDefault(); + e.currentTarget.classList.remove('ring-2', 'ring-primary', 'ring-offset-2'); const fromIndex = parseInt(e.dataTransfer.getData('text/plain')); const toIndex = index; @@ -226,7 +235,7 @@ export function GeneralTab({ setImages(newImages); } }} - className="relative group aspect-square border rounded-lg overflow-hidden bg-gray-50 cursor-move hover:border-primary transition-colors" + className="relative group aspect-square border-2 border-dashed border-gray-300 rounded-lg overflow-hidden bg-gray-50 cursor-move hover:border-primary transition-all" > (); - + const { slug } = useParams<{ slug: string }>(); + const navigate = useNavigate(); + const [quantity, setQuantity] = useState(1); + const [activeTab, setActiveTab] = useState<'description' | 'additional' | 'reviews'>('description'); + const [selectedImage, setSelectedImage] = useState(); + const [selectedVariation, setSelectedVariation] = useState(null); + const [selectedAttributes, setSelectedAttributes] = useState>({}); + const thumbnailsRef = useRef(null); + const { addItem } = useCartStore(); + + // Fetch product details by slug + const { data: product, isLoading, error } = useQuery({ + queryKey: ['product', slug], + queryFn: async () => { + if (!slug) return null; + + const response = await apiClient.get(apiClient.endpoints.shop.products, { + slug, + per_page: 1, + }); + + if (response && response.products && response.products.length > 0) { + return response.products[0]; + } + + return null; + }, + enabled: !!slug, + }); + + // Set initial image when product loads + useEffect(() => { + if (product && !selectedImage) { + setSelectedImage(product.image || product.images?.[0]); + } + }, [product]); + + // Find matching variation when attributes change + useEffect(() => { + if (product?.type === 'variable' && product.variations && Object.keys(selectedAttributes).length > 0) { + const variation = (product.variations as any[]).find(v => { + return Object.entries(selectedAttributes).every(([key, value]) => { + const attrKey = `attribute_${key.toLowerCase()}`; + return v.attributes[attrKey] === value.toLowerCase(); + }); + }); + setSelectedVariation(variation || null); + } + }, [selectedAttributes, product]); + + // Auto-switch image when variation selected + useEffect(() => { + if (selectedVariation && selectedVariation.image) { + setSelectedImage(selectedVariation.image); + } + }, [selectedVariation]); + + // Scroll thumbnails + const scrollThumbnails = (direction: 'left' | 'right') => { + if (thumbnailsRef.current) { + const scrollAmount = 200; + thumbnailsRef.current.scrollBy({ + left: direction === 'left' ? -scrollAmount : scrollAmount, + behavior: 'smooth' + }); + } + }; + + const handleAttributeChange = (attributeName: string, value: string) => { + setSelectedAttributes(prev => ({ + ...prev, + [attributeName]: value + })); + }; + + const handleAddToCart = async () => { + if (!product) return; + + // Validate variation selection for variable products + if (product.type === 'variable') { + if (!selectedVariation) { + toast.error('Please select all product options'); + return; + } + } + + try { + await apiClient.post(apiClient.endpoints.cart.add, { + product_id: product.id, + quantity, + variation_id: selectedVariation?.id || 0, + }); + + addItem({ + key: `${product.id}${selectedVariation ? `-${selectedVariation.id}` : ''}`, + product_id: product.id, + name: product.name, + price: parseFloat(selectedVariation?.price || product.price), + quantity, + image: selectedImage || product.image, + }); + + toast.success(`${product.name} added to cart!`, { + action: { + label: 'View Cart', + onClick: () => navigate('/cart'), + }, + }); + } catch (error) { + toast.error('Failed to add to cart'); + console.error(error); + } + }; + + if (isLoading) { + return ( + +
+
+
+
+
+
+
+
+
+
+
+
+
+ ); + } + + if (error || !product) { + return ( + +
+

Product Not Found

+

The product you're looking for doesn't exist.

+ +
+
+ ); + } + + const currentPrice = selectedVariation?.price || product.price; + const regularPrice = selectedVariation?.regular_price || product.regular_price; + const isOnSale = selectedVariation ? parseFloat(selectedVariation.sale_price || '0') > 0 : product.on_sale; + const stockStatus = selectedVariation?.in_stock !== undefined ? (selectedVariation.in_stock ? 'instock' : 'outofstock') : product.stock_status; + return ( -
-

Product #{id}

-

Product detail coming soon...

-
+ +
+ {/* Breadcrumb */} + + +
+ {/* Product Images */} +
+ {/* Main Image */} +
+ {selectedImage ? ( + {product.name} + ) : ( +
+ No image +
+ )} +
+ + {/* Thumbnail Slider */} + {product.images && product.images.length > 1 && ( +
+ {/* Left Arrow */} + {product.images.length > 4 && ( + + )} + + {/* Scrollable Thumbnails */} +
+ {product.images.map((img, index) => ( + + ))} +
+ + {/* Right Arrow */} + {product.images.length > 4 && ( + + )} +
+ )} +
+ + {/* Product Info */} +
+

{product.name}

+ + {/* Price */} +
+ {isOnSale && regularPrice ? ( +
+ + {formatPrice(currentPrice)} + + + {formatPrice(regularPrice)} + + + SALE + +
+ ) : ( + {formatPrice(currentPrice)} + )} +
+ + {/* Stock Status */} +
+ {stockStatus === 'instock' ? ( + + + In Stock + + ) : ( + + + Out of Stock + + )} +
+ + {/* Short Description */} + {product.short_description && ( +
+ )} + + {/* Variation Selector */} + {product.type === 'variable' && product.attributes && product.attributes.length > 0 && ( +
+ {product.attributes.map((attr: any, index: number) => ( + attr.variation && ( +
+ + +
+ ) + ))} +
+ )} + + {/* Quantity & Add to Cart */} + {stockStatus === 'instock' && ( +
+ {/* Quantity Selector */} +
+ +
+ + setQuantity(Math.max(1, parseInt(e.target.value) || 1))} + className="w-16 text-center border-x border-gray-300 py-2 focus:outline-none" + min="1" + /> + +
+
+ + {/* Action Buttons */} +
+ + +
+
+ )} + + {/* Product Meta */} +
+ {product.sku && ( +
+ SKU: + {product.sku} +
+ )} + {product.categories && product.categories.length > 0 && ( +
+ Categories: + + {product.categories.map((cat: any) => cat.name).join(', ')} + +
+ )} +
+
+
+ + {/* Product Tabs */} +
+ {/* Tab Headers */} +
+
+ + + +
+
+ + {/* Tab Content */} +
+ {activeTab === 'description' && ( +
+ {product.description ? ( +
+ ) : ( +

No description available.

+ )} +
+ )} + + {activeTab === 'additional' && ( +
+ {product.attributes && product.attributes.length > 0 ? ( + + + {product.attributes.map((attr: any, index: number) => ( + + + + + ))} + +
+ {attr.name} + + {Array.isArray(attr.options) ? attr.options.join(', ') : attr.options} +
+ ) : ( +

No additional information available.

+ )} +
+ )} + + {activeTab === 'reviews' && ( +
+

Reviews coming soon...

+
+ )} +
+
+
+ ); }