feat: implement header/footer visibility controls for checkout and thankyou pages
- Created LayoutWrapper component to conditionally render header/footer based on route - Created MinimalHeader component (logo only) - Created MinimalFooter component (trust badges + policy links) - Created usePageVisibility hook to get visibility settings per page - Wrapped ClassicLayout with LayoutWrapper for conditional rendering - Header/footer visibility now controlled directly in React SPA - Settings: show/minimal/hide for both header and footer - Background color support for checkout and thankyou pages
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useCartStore, type CartItem } from '@/lib/cart/store';
|
||||
import { useCartSettings } from '@/hooks/useAppearanceSettings';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -18,6 +19,7 @@ import { toast } from 'sonner';
|
||||
export default function Cart() {
|
||||
const navigate = useNavigate();
|
||||
const { cart, removeItem, updateQuantity, clearCart } = useCartStore();
|
||||
const { layout, elements } = useCartSettings();
|
||||
const [showClearDialog, setShowClearDialog] = useState(false);
|
||||
|
||||
// Calculate total from items
|
||||
@@ -60,7 +62,7 @@ export default function Cart() {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="py-8">
|
||||
<div className={`py-8 ${layout.style === 'boxed' ? 'max-w-5xl mx-auto' : ''}`}>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<h1 className="text-3xl font-bold">Shopping Cart</h1>
|
||||
@@ -70,34 +72,52 @@ export default function Cart() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
<div className={`grid gap-8 ${layout.summary_position === 'bottom' ? 'grid-cols-1' : 'lg:grid-cols-3'}`}>
|
||||
{/* Cart Items */}
|
||||
<div className="lg:col-span-2 space-y-4">
|
||||
<div className={`space-y-4 ${layout.summary_position === 'bottom' ? '' : 'lg:col-span-2'}`}>
|
||||
{cart.items.map((item: CartItem) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex gap-4 p-4 border rounded-lg bg-white"
|
||||
>
|
||||
{/* Product Image */}
|
||||
<div className="relative w-24 h-24 flex-shrink-0 rounded-lg overflow-hidden bg-gray-100">
|
||||
{item.image ? (
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className="block w-full !h-full object-cover object-center"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full !h-full flex items-center justify-center text-gray-400 text-xs">
|
||||
No Image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{elements.product_images && (
|
||||
<div className="relative w-24 h-24 flex-shrink-0 rounded-lg overflow-hidden bg-gray-100">
|
||||
{item.image ? (
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className="block w-full !h-full object-cover object-center"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full !h-full flex items-center justify-center text-gray-400 text-xs">
|
||||
No Image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Product Info */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-lg mb-1 truncate">
|
||||
{item.name}
|
||||
</h3>
|
||||
|
||||
{/* Variation Attributes */}
|
||||
{item.attributes && Object.keys(item.attributes).length > 0 && (
|
||||
<div className="text-sm text-gray-500 mb-1">
|
||||
{Object.entries(item.attributes).map(([key, value]) => {
|
||||
// Format attribute name: capitalize first letter
|
||||
const formattedKey = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
return (
|
||||
<span key={key} className="mr-3">
|
||||
{formattedKey}: <span className="font-medium">{value}</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-gray-600 mb-2">
|
||||
{formatPrice(item.price)}
|
||||
</p>
|
||||
@@ -149,6 +169,36 @@ export default function Cart() {
|
||||
<div className="border rounded-lg p-6 bg-white sticky top-4">
|
||||
<h2 className="text-xl font-bold mb-4">Cart Summary</h2>
|
||||
|
||||
{/* Coupon Field */}
|
||||
{elements.coupon_field && (
|
||||
<div className="mb-6">
|
||||
<label className="block text-sm font-medium mb-2">Coupon Code</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter coupon code"
|
||||
className="flex-1 px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
/>
|
||||
<Button variant="outline" size="sm">Apply</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Shipping Calculator */}
|
||||
{elements.shipping_calculator && (
|
||||
<div className="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||
<h3 className="font-medium mb-3">Calculate Shipping</h3>
|
||||
<div className="space-y-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Postal Code"
|
||||
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
/>
|
||||
<Button variant="outline" size="sm" className="w-full">Calculate</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-3 mb-6">
|
||||
<div className="flex justify-between text-gray-600">
|
||||
<span>Subtotal</span>
|
||||
@@ -172,14 +222,16 @@ export default function Cart() {
|
||||
Proceed to Checkout
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => navigate('/shop')}
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Continue Shopping
|
||||
</Button>
|
||||
{elements.continue_shopping_button && (
|
||||
<Button
|
||||
onClick={() => navigate('/shop')}
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Continue Shopping
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user