redesign the website
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
dvirlabs 2026-06-04 01:58:56 +03:00
parent f02f8106f9
commit dac10f2a26
28 changed files with 1769 additions and 2015 deletions

View File

@ -8,16 +8,26 @@ export default function Footer() {
<div className="footer-container">
<div className="footer-section">
<div className="footer-brand">
<span className="footer-logo">👟</span>
<span className="footer-logo">BM</span>
<h3>Brand Master</h3>
</div>
<p>Your ultimate destination for fashion and footwear.</p>
<p>Premium sneaker boutique for collectors, fashion leaders, and modern street luxury.</p>
<div className="social-links">
<a href="https://instagram.com" target="_blank" rel="noopener noreferrer" title="Instagram">📷</a>
<a href="https://wa.me/972532441361" target="_blank" rel="noopener noreferrer" title="WhatsApp">💬</a>
<a href="https://instagram.com" target="_blank" rel="noopener noreferrer" title="Instagram">Instagram</a>
<a href="https://wa.me/972532441361" target="_blank" rel="noopener noreferrer" title="WhatsApp">WhatsApp</a>
</div>
</div>
<div className="footer-section">
<h4>Quick Links</h4>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/products">Shop</Link></li>
<li><Link to="/sales">Sale</Link></li>
<li><Link to="/wishlist">Wishlist</Link></li>
</ul>
</div>
<div className="footer-section">
<h4>Shop</h4>
<ul>
@ -30,20 +40,15 @@ export default function Footer() {
</div>
<div className="footer-section">
<h4>Company</h4>
<h4>Customer Service</h4>
<ul>
<li><Link to="/about">About Us</Link></li>
<li><Link to="/contact">Contact</Link></li>
<li><Link to="/orders">Shipping & Delivery</Link></li>
<li><a href="#">Terms & Conditions</a></li>
<li><a href="#">Privacy Policy</a></li>
<li><a href="#">Terms of Service</a></li>
</ul>
</div>
<div className="footer-section">
<h4>Contact</h4>
<p>Email: info@brandmaster.com</p>
<p>Phone: +972 53-244-1361</p>
</div>
</div>
<div className="footer-bottom">

View File

@ -24,7 +24,11 @@ export default function Navbar() {
<nav className="navbar">
<div className="navbar-container">
<Link to="/" className="navbar-logo">
<span className="logo-icon">👟</span> Brand Master
<span className="logo-icon">BM</span>
<span>
<small>BRAND MASTER</small>
<strong>Luxury Sneakers</strong>
</span>
</Link>
<div className="navbar-center">
@ -45,18 +49,18 @@ export default function Navbar() {
<div className="navbar-icons">
{token ? (
<>
<Link to="/wishlist" className="icon-btn" title="Wishlist">
<Link to="/wishlist" className="icon-btn" title="Wishlist" aria-label="Wishlist">
</Link>
<Link to="/cart" className="icon-btn cart-btn" title="Cart">
<Link to="/cart" className="icon-btn cart-btn" title="Cart" aria-label="Cart">
🛒
{cart.length > 0 && <span className="cart-count">{cart.length}</span>}
</Link>
<Link to="/my-messages" className="icon-btn" title="My Messages">
💬
<Link to="/my-messages" className="icon-btn" title="My Messages" aria-label="Messages">
</Link>
<Link to="/profile" className="icon-btn" title="Profile">
👤
<Link to="/profile" className="icon-btn" title="Profile" aria-label="Profile">
</Link>
<button onClick={handleLogout} className="btn btn-small">
Logout
@ -64,10 +68,16 @@ export default function Navbar() {
</>
) : (
<>
<Link to="/cart" className="icon-btn cart-btn" title="Cart">
<Link to="/wishlist" className="icon-btn" title="Wishlist" aria-label="Wishlist">
</Link>
<Link to="/cart" className="icon-btn cart-btn" title="Cart" aria-label="Cart">
🛒
{cart.length > 0 && <span className="cart-count">{cart.length}</span>}
</Link>
<Link to="/profile" className="icon-btn" title="Profile" aria-label="Profile">
</Link>
<Link to="/login" className="btn btn-small">
Login
</Link>

View File

@ -30,6 +30,7 @@ export default function ProductCard({ product }) {
alt={product.name}
onError={() => setImageError(true)}
/>
<span className="product-wishlist-icon" aria-hidden="true"></span>
{product.is_on_sale && discount > 0 && (
<div className="discount-badge">{discount}% OFF</div>
)}

View File

@ -144,13 +144,12 @@ export default function ProductFilters({ onFilter }) {
<div className="filter-group">
<label>Price Range</label>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
<div className="price-range-inputs">
<input
type="number"
placeholder="Min"
value={filters.min_price}
onChange={(e) => handleFilterChange('min_price', e.target.value)}
style={{ width: '80px', padding: '0.5rem' }}
/>
<span>-</span>
<input
@ -158,7 +157,6 @@ export default function ProductFilters({ onFilter }) {
placeholder="Max"
value={filters.max_price}
onChange={(e) => handleFilterChange('max_price', e.target.value)}
style={{ width: '80px', padding: '0.5rem' }}
/>
</div>
</div>

View File

@ -1,5 +1,5 @@
import React, { useState, useContext } from 'react'
import { AuthContext } from '../context/AuthContext'
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import api from '../api'
import '../styles/global.css'
@ -38,10 +38,15 @@ export default function SearchBar() {
{showResults && results.length > 0 && (
<div className="search-results">
{results.map((product) => (
<a key={product.id} href={`/product/${product.id}`} className="search-result-item">
<Link
key={product.id}
to={`/product/${product.id}`}
className="search-result-item"
onClick={() => setShowResults(false)}
>
<span>{product.name}</span>
<span>{product.price.toFixed(2)}</span>
</a>
</Link>
))}
</div>
)}

View File

@ -35,51 +35,36 @@ export default function Cart() {
) : (
<div className="cart-container">
<div className="cart-items">
<table className="cart-table">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{cart.map((item, index) => (
<tr key={index}>
<td>
<div className="cart-item-product">
<article key={index} className="cart-item">
<img src={item.product.images[0]} alt={item.product.name} />
<div>
<p className="product-name">{item.product.name}</p>
{item.size && <p>Size: {item.size}</p>}
<p className="brand">{item.product.brand}</p>
{item.size && <p className="text-muted">Size: {item.size}</p>}
<p className="price">
<span className="current">{(item.product.discount_price || item.product.price).toFixed(2)}</span>
</p>
</div>
</div>
</td>
<td>{(item.product.discount_price || item.product.price).toFixed(2)}</td>
<td>
<div>
<div className="quantity-control">
<button onClick={() => updateQuantity(index, item.quantity - 1)}></button>
<span>{item.quantity}</span>
<button onClick={() => updateQuantity(index, item.quantity + 1)}>+</button>
</div>
</td>
<td>
<p style={{ marginTop: '0.5rem', textAlign: 'right' }}>
{((item.product.discount_price || item.product.price) * item.quantity).toFixed(2)}
</td>
<td>
</p>
<button
className="btn btn-small btn-danger"
style={{ marginTop: '0.5rem' }}
onClick={() => removeFromCart(index)}
>
Remove
</button>
</td>
</tr>
</div>
</article>
))}
</tbody>
</table>
</div>
<div className="cart-summary">
@ -91,7 +76,7 @@ export default function Cart() {
</div>
<div className="summary-row">
<span>Shipping:</span>
<span>$10.00</span>
<span>10.00</span>
</div>
<div className="summary-row">
<span>Tax:</span>

View File

@ -150,7 +150,7 @@ export default function Checkout() {
<div className="checkout-container">
<form onSubmit={handleSubmit} className="checkout-form">
<div className="form-section">
<h2>Contact Information</h2>
<h2>Shipping Information</h2>
<div className="form-group">
<label>
@ -201,7 +201,7 @@ export default function Checkout() {
</div>
<div className="form-section">
<h2>Shipping Address</h2>
<h2>Address Details</h2>
<div className="form-group">
<label>

View File

@ -97,12 +97,12 @@ export default function Contact() {
<h2>Get in Touch</h2>
<div className="info-item">
<h3>📞 Phone</h3>
<h3>Phone</h3>
<p>+972 53-244-1361</p>
</div>
<div className="info-item">
<h3> Email</h3>
<h3>Email</h3>
<p>info@brandmaster.com</p>
</div>

View File

@ -43,32 +43,56 @@ export default function Home() {
if (loading) return <div className="loading">Loading...</div>
const brands = Array.from(
new Set([...featured, ...newArrivals, ...onSale].map((item) => item.brand).filter(Boolean))
).slice(0, 8)
return (
<div className="home">
{/* Hero Section */}
<section className="hero">
<div className="hero-content">
<h1>Welcome to Brand Master</h1>
<p>Discover the latest in fashion and footwear</p>
<Link to="/products" className="btn btn-large">
Shop Now
</Link>
<span className="kicker">Luxury Sneaker House</span>
<h1>Curated Premium Sneakers. Built for Statement.</h1>
<p>
Discover exclusive releases, iconic silhouettes, and elevated essentials in a modern black-and-gold retail experience.
</p>
<div className="hero-cta-row">
<Link to="/products" className="btn btn-large">Shop Now</Link>
<Link to="/sales" className="btn btn-secondary btn-large">Explore Sales</Link>
</div>
</div>
<div className="hero-media">
<img
src="https://images.unsplash.com/photo-1543508282-6319a3e2621f?auto=format&fit=crop&w=1400&q=80"
alt="Luxury sneaker collection"
/>
</div>
</section>
{/* Category Highlights */}
<section className="section">
<h2>Shop by Category</h2>
<div className="grid">
{categories.map((cat) => (
<CategoryCard key={cat.id} category={cat} />
))}
<section className="feature-strip">
<div className="item">
<strong>100% Authentic</strong>
<span>Verified premium stock</span>
</div>
<div className="item">
<strong>Secure Payment</strong>
<span>Safe and encrypted checkout</span>
</div>
<div className="item">
<strong>Free Shipping</strong>
<span>Orders over 299</span>
</div>
<div className="item">
<strong>Easy Returns</strong>
<span>14-day return policy</span>
</div>
</section>
{/* Featured Products */}
<section className="section">
<div className="section-header">
<h2>Featured Products</h2>
<p>Hand-picked from this week's premium drops</p>
</div>
<div className="grid">
{featured.map((product) => (
<ProductCard key={product.id} product={product} />
@ -76,39 +100,70 @@ export default function Home() {
</div>
</section>
{/* New Arrivals */}
<section className="section">
<div className="section-header">
<h2>New Arrivals</h2>
<p>Fresh releases from top designer brands</p>
</div>
<div className="grid">
{newArrivals.slice(0, 4).map((product) => (
{newArrivals.slice(0, 8).map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
</section>
{/* On Sale */}
<section className="section sale-banner">
<h2>🔥 Limited Time Offers</h2>
<p>Up to 50% off on selected items</p>
<Link to="/sales" className="btn btn-large">
View All Sales
</Link>
<h2>Private Sale Collection</h2>
<p>Limited-time markdowns across selected statement pieces.</p>
<Link to="/sales" className="btn btn-large">View All Sales</Link>
</section>
{/* Best Sellers */}
<section className="section">
<div className="section-header">
<h2>Best Sellers</h2>
<p>The silhouettes our community keeps coming back for</p>
</div>
<div className="grid">
{onSale.slice(0, 4).map((product) => (
{onSale.slice(0, 8).map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
</section>
{/* Promo Banner */}
<section className="section">
<div className="section-header">
<h2>Shop by Category</h2>
<p>Build your fit by category</p>
</div>
<div className="grid">
{categories.map((cat) => (
<CategoryCard key={cat.id} category={cat} />
))}
</div>
</section>
{brands.length > 0 && (
<section className="section">
<div className="section-header">
<h2>Brands</h2>
<p>Curated premium houses</p>
</div>
<div className="grid">
{brands.map((brand) => (
<div key={brand} className="category-card">
<div style={{ padding: '1.2rem' }}>
<h3>{brand}</h3>
<p>Explore selected {brand} silhouettes in the Brand Master collection.</p>
</div>
</div>
))}
</div>
</section>
)}
<section className="promo-banner">
<h3>Subscribe to Our Newsletter</h3>
<p>Get exclusive deals and updates</p>
<h3>Join the Private Client List</h3>
<p>Get priority access to drops, restocks, and members-only pricing.</p>
<input type="email" placeholder="Enter your email" />
<button className="btn">Subscribe</button>
</section>

View File

@ -21,6 +21,7 @@ export default function Login() {
const [resetEmail, setResetEmail] = useState('')
const [resetPin, setResetPin] = useState('')
const [newPassword, setNewPassword] = useState('')
const [rememberMe, setRememberMe] = useState(true)
const [resetLoading, setResetLoading] = useState(false)
const [currentUserData, setCurrentUserData] = useState(null)
@ -138,6 +139,18 @@ export default function Login() {
return (
<div className="auth-page">
<div className="auth-container">
<div className="auth-visual">
<img
src="https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?auto=format&fit=crop&w=1200&q=80"
alt="Premium sneaker"
/>
<div className="auth-visual-copy">
<h3>Welcome Back</h3>
<p>Log in to your account and continue your premium shopping experience.</p>
</div>
</div>
<div className="auth-panel">
<h1>Login</h1>
<form onSubmit={handleSubmit}>
@ -164,7 +177,16 @@ export default function Login() {
/>
</div>
<div className="forgot-password-link">
<div className="auth-meta">
<label>
<input
type="checkbox"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
/>
Remember Me
</label>
<button
type="button"
className="link-button"
@ -183,6 +205,7 @@ export default function Login() {
Don't have an account? <Link to="/register">Sign up here</Link>
</p>
</div>
</div>
{/* Forgot Password Modal */}
<Modal

View File

@ -1,291 +1,125 @@
.messages-page {
min-height: 100vh;
background-color: #f5f5f5;
padding: 2rem 0;
padding-top: 1.2rem;
}
.messages-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
border: 1px solid rgba(212, 175, 55, 0.2);
background: linear-gradient(135deg, rgba(18, 18, 18, 0.95), rgba(9, 9, 9, 0.95));
border-radius: 16px;
padding: 1rem;
}
.messages-header {
margin-bottom: 2rem;
}
.messages-header h1 {
font-size: 2.5rem;
font-weight: bold;
color: #333;
margin-bottom: 0.5rem;
}
.messages-header p {
color: #666;
font-size: 1.1rem;
}
.error-message {
background-color: #fee;
border: 1px solid #fcc;
color: #c33;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1.5rem;
}
.no-messages {
background: white;
border-radius: 12px;
padding: 3rem;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.no-messages-icon {
font-size: 4rem;
margin-bottom: 1rem;
}
.no-messages h3 {
font-size: 1.5rem;
color: #333;
margin-bottom: 0.5rem;
.messages-header h1 {
font-size: 2rem;
}
.no-messages p {
color: #666;
margin-bottom: 1.5rem;
.messages-header p {
color: var(--text-muted);
}
.messages-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
display: grid;
gap: 0.8rem;
}
.message-card {
background: white;
border: 1px solid rgba(212, 175, 55, 0.18);
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: box-shadow 0.3s ease;
}
.message-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
background: rgba(255, 255, 255, 0.02);
padding: 0.95rem;
}
.message-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid #e5e5e5;
}
.message-title-section {
flex: 1;
gap: 0.6rem;
margin-bottom: 0.7rem;
}
.message-title-section h3 {
font-size: 1.4rem;
font-weight: 600;
color: #333;
margin: 0 0 0.5rem 0;
margin-bottom: 0.2rem;
}
.message-date {
font-size: 0.9rem;
color: #888;
margin: 0;
}
.status-badge {
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.message-content {
margin-bottom: 1.5rem;
}
.message-content h4 {
font-size: 1rem;
font-weight: 600;
color: #555;
margin-bottom: 0.75rem;
}
.message-box {
background: #f9f9f9;
border-radius: 8px;
padding: 1.25rem;
border-left: 4px solid #007bff;
}
.message-box p {
margin: 0;
color: #333;
line-height: 1.6;
white-space: pre-wrap;
}
.admin-response {
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 2px solid #e5e5e5;
color: var(--text-soft);
font-size: 0.85rem;
}
.message-content h4,
.admin-response h4 {
font-size: 1rem;
font-weight: 600;
color: #10b981;
margin-bottom: 0.75rem;
display: flex;
align-items: center;
margin-bottom: 0.35rem;
color: var(--gold-bright);
}
.response-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background: #10b981;
color: white;
border-radius: 50%;
margin-right: 0.5rem;
font-size: 0.75rem;
font-weight: bold;
}
.response-box {
background: #f0fdf4;
border: 1px solid #86efac;
border-radius: 8px;
padding: 1.25rem;
border-left: 4px solid #10b981;
.message-box,
.response-box,
.message-details {
border: 1px solid rgba(212, 175, 55, 0.15);
background: rgba(0, 0, 0, 0.35);
border-radius: 10px;
padding: 0.75rem;
}
.message-box p,
.response-box p {
margin: 0;
color: #333;
line-height: 1.6;
white-space: pre-wrap;
}
.waiting-response {
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 2px solid #e5e5e5;
color: var(--text-muted);
}
.waiting-response p {
color: #888;
color: var(--text-soft);
font-style: italic;
margin: 0;
}
.message-details-section {
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 1px solid #e5e5e5;
}
.details-toggle {
background: none;
border: none;
color: #007bff;
font-size: 0.9rem;
cursor: pointer;
padding: 0.5rem 0;
display: flex;
align-items: center;
gap: 0.5rem;
transition: color 0.2s ease;
}
.details-toggle:hover {
color: #0056b3;
}
.message-details {
margin-top: 1rem;
padding: 1rem;
background: #f9f9f9;
border-radius: 8px;
color: var(--gold-bright);
margin-top: 0.75rem;
}
.details-grid {
margin-top: 0.6rem;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.detail-item {
display: flex;
flex-direction: column;
gap: 0.25rem;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.detail-item strong {
font-weight: 600;
color: #555;
font-size: 0.9rem;
color: var(--text-main);
font-size: 0.86rem;
}
.detail-item span {
color: #666;
font-size: 0.95rem;
color: var(--text-muted);
font-size: 0.86rem;
}
.messages-actions {
margin-top: 2rem;
margin-top: 0.8rem;
}
.no-messages {
text-align: center;
border: 1px solid rgba(212, 175, 55, 0.2);
border-radius: 12px;
padding: 1.6rem;
background: rgba(255, 255, 255, 0.02);
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #5a6268;
}
/* Loading state */
.loading {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: #666;
}
/* Responsive design */
@media (max-width: 768px) {
.messages-header h1 {
.no-messages-icon {
font-size: 2rem;
margin-bottom: 0.4rem;
}
@media (max-width: 720px) {
.details-grid {
grid-template-columns: 1fr;
}
.message-card-header {
flex-direction: column;
gap: 1rem;
}
.status-badge {
align-self: flex-start;
}
.details-grid {
grid-template-columns: 1fr;
align-items: flex-start;
}
}

View File

@ -137,7 +137,7 @@ export default function ProductDetail() {
<p className="brand">{product.brand}</p>
<div className="rating">
<span> (42 reviews)</span>
<span> (42 reviews)</span>
</div>
<div className="price">
@ -151,6 +151,8 @@ export default function ProductDetail() {
)}
</div>
<p className="model-code">Model Code: {product.sku || product.id}</p>
<p className="description">{product.description}</p>
{product.sizes.length > 0 && (
@ -198,10 +200,11 @@ export default function ProductDetail() {
Add to Cart
</button>
<button
className={`btn btn-icon ${inWishlist ? 'active' : ''}`}
className={`btn-icon ${inWishlist ? 'active' : ''}`}
onClick={handleToggleWishlist}
aria-label="Add to wishlist"
>
{inWishlist ? '❤️' : '🤍'}
{inWishlist ? '♥' : '♡'}
</button>
</div>

View File

@ -110,7 +110,7 @@ export default function Products() {
</span>
<button
onClick={() => { setShowAll(s => !s); setCurrentPage(1) }}
style={{ marginLeft: '1rem', padding: '0.3rem 0.8rem', borderRadius: '4px', border: '1px solid #ccc', cursor: 'pointer', fontSize: '0.85rem' }}
className="page-btn"
>
{showAll ? 'Paginate' : 'Show All'}
</button>
@ -128,11 +128,11 @@ export default function Products() {
{/* Pagination controls (hidden when Show All is active) */}
{!showAll && totalPages > 1 && (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '0.5rem', marginTop: '2rem', flexWrap: 'wrap' }}>
<div className="pagination">
<button
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
disabled={currentPage <= 1}
style={{ padding: '0.5rem 1rem', borderRadius: '4px', border: '1px solid #ccc', cursor: currentPage <= 1 ? 'not-allowed' : 'pointer', opacity: currentPage <= 1 ? 0.5 : 1 }}
className="page-btn"
>
Prev
</button>
@ -143,7 +143,7 @@ export default function Products() {
<button
key={page}
onClick={() => setCurrentPage(page)}
style={{ padding: '0.5rem 1rem', borderRadius: '4px', border: '1px solid #ccc', cursor: 'pointer', backgroundColor: page === currentPage ? '#333' : 'white', color: page === currentPage ? 'white' : 'inherit' }}
className={`page-btn ${page === currentPage ? 'active' : ''}`}
>
{page}
</button>
@ -152,7 +152,7 @@ export default function Products() {
<button
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
disabled={currentPage >= totalPages}
style={{ padding: '0.5rem 1rem', borderRadius: '4px', border: '1px solid #ccc', cursor: currentPage >= totalPages ? 'not-allowed' : 'pointer', opacity: currentPage >= totalPages ? 0.5 : 1 }}
className="page-btn"
>
Next
</button>

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { Link, useNavigate } from 'react-router-dom'
import api from '../api'
import { AuthContext } from '../context/AuthContext'
import Toast from '../components/Toast'
@ -26,6 +26,12 @@ export default function Profile() {
const [saving, setSaving] = useState(false)
const [changingPassword, setChangingPassword] = useState(false)
const [toast, setToast] = useState(null)
const [activeSection, setActiveSection] = useState('overview')
const [stats, setStats] = useState({
orders: 0,
wishlist: 0,
messages: 0,
})
useEffect(() => {
if (!token) {
@ -37,9 +43,20 @@ export default function Profile() {
const fetchProfile = async () => {
try {
const response = await api.get('/users/me')
setFormData(response.data)
setUser(response.data)
const [profileRes, ordersRes, wishlistRes, messagesRes] = await Promise.all([
api.get('/users/me'),
api.get('/orders').catch(() => ({ data: [] })),
api.get('/wishlist').catch(() => ({ data: [] })),
api.get('/my-messages').catch(() => ({ data: [] })),
])
setFormData(profileRes.data)
setUser(profileRes.data)
setStats({
orders: ordersRes.data.length || 0,
wishlist: wishlistRes.data.length || 0,
messages: messagesRes.data.length || 0,
})
} catch (error) {
console.error('Error fetching profile:', error)
} finally {
@ -103,25 +120,57 @@ export default function Profile() {
return (
<div className="profile-page">
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '1rem' }}>
<h1>My Profile</h1>
{user?.is_admin && (
<span style={{
backgroundColor: '#ff6b6b',
color: 'white',
padding: '0.25rem 0.75rem',
borderRadius: '4px',
fontSize: '0.875rem',
fontWeight: 'bold'
}}>
ADMIN
</span>
)}
<h1>
My Profile
{user?.is_admin && <span className="admin-pill">ADMIN</span>}
</h1>
<div className="profile-shell">
<nav className="profile-nav">
<button
className={activeSection === 'overview' ? 'active' : ''}
onClick={() => setActiveSection('overview')}
type="button"
>
Overview
</button>
<Link to="/orders">Orders</Link>
<Link to="/wishlist">Wishlist</Link>
<Link to="/my-messages">Messages</Link>
<button
className={activeSection === 'addresses' ? 'active' : ''}
onClick={() => setActiveSection('addresses')}
type="button"
>
Addresses
</button>
<button
className={activeSection === 'settings' ? 'active' : ''}
onClick={() => setActiveSection('settings')}
type="button"
>
Account Settings
</button>
</nav>
<div className="profile-forms">
<div className="profile-metrics">
<div className="profile-metric">
<span>Total Orders</span>
<strong>{stats.orders}</strong>
</div>
<div className="profile-metric">
<span>Wishlist Count</span>
<strong>{stats.wishlist}</strong>
</div>
<div className="profile-metric">
<span>Messages Count</span>
<strong>{stats.messages}</strong>
</div>
</div>
<div className="profile-container">
<form onSubmit={handleSubmit} className="profile-form">
<h2>Personal Information</h2>
<h2>{activeSection === 'addresses' ? 'Addresses' : 'Personal Information'}</h2>
<div className="form-group">
<label>Full Name</label>
@ -203,8 +252,8 @@ export default function Profile() {
</button>
</form>
<form onSubmit={handlePasswordChange} className="profile-form" style={{ marginTop: '2rem' }}>
<h2>Change Password</h2>
<form onSubmit={handlePasswordChange} className="profile-form">
<h2>Account Settings</h2>
<div className="form-group">
<label>Current Password</label>
@ -243,6 +292,7 @@ export default function Profile() {
</button>
</form>
</div>
</div>
{toast && (
<Toast

View File

@ -60,6 +60,18 @@ export default function Register() {
return (
<div className="auth-page">
<div className="auth-container">
<div className="auth-visual">
<img
src="https://images.unsplash.com/photo-1515955656352-a1fa3ffcd111?auto=format&fit=crop&w=1200&q=80"
alt="Luxury sneaker"
/>
<div className="auth-visual-copy">
<h3>Create Account</h3>
<p>Join Brand Master and access exclusive collections and member-only drops.</p>
</div>
</div>
<div className="auth-panel">
<h1>Create Account</h1>
<form onSubmit={handleSubmit}>
@ -128,6 +140,7 @@ export default function Register() {
Already have an account? <Link to="/login">Login here</Link>
</p>
</div>
</div>
{toast && (
<Toast

View File

@ -30,8 +30,8 @@ export default function Sales() {
return (
<div className="sales-page">
<div className="sales-header">
<h1>🔥 Limited Time Offers</h1>
<p>Huge discounts on selected items - Limited time only!</p>
<h1>Limited Time Offers</h1>
<p>Luxury selections with exclusive markdowns. Ends soon.</p>
</div>
{loading ? (

File diff suppressed because it is too large Load Diff