feat: build Step 6 Products form with upload grid, all form fields, and action buttons
This commit is contained in:
parent
da6ff22d61
commit
7dd650e9ba
1 changed files with 410 additions and 11 deletions
|
|
@ -28,7 +28,10 @@ import {
|
|||
Gem,
|
||||
Paintbrush,
|
||||
Leaf,
|
||||
Scissors
|
||||
Scissors,
|
||||
Plus,
|
||||
Play,
|
||||
IndianRupee
|
||||
} from 'lucide-react';
|
||||
|
||||
export const OnboardingPage: React.FC = () => {
|
||||
|
|
@ -110,6 +113,36 @@ export const OnboardingPage: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
// Step 6 Specific State — Products form
|
||||
const [step6ProductName, setStep6ProductName] = useState('');
|
||||
const [step6Category, setStep6Category] = useState('Handicrafts');
|
||||
const [step6SubCategory, setStep6SubCategory] = useState('');
|
||||
const [step6About, setStep6About] = useState('');
|
||||
const [step6Color, setStep6Color] = useState('');
|
||||
const [step6Material, setStep6Material] = useState('');
|
||||
const [step6Brand, setStep6Brand] = useState('');
|
||||
const [step6Warranty, setStep6Warranty] = useState('');
|
||||
const [step6ManufacturerInfo, setStep6ManufacturerInfo] = useState('');
|
||||
const [step6Specification, setStep6Specification] = useState('');
|
||||
const [step6Showcase, setStep6Showcase] = useState('');
|
||||
const [step6Price, setStep6Price] = useState('');
|
||||
const [step6Stock, setStep6Stock] = useState('');
|
||||
const [step6Sku] = useState('TRDX-' + Math.random().toString(36).substring(2, 8).toUpperCase());
|
||||
const [step6Weight, setStep6Weight] = useState('');
|
||||
const [step6MadeToOrder, setStep6MadeToOrder] = useState(false);
|
||||
const step6SubCategoryMap: Record<string, string[]> = {
|
||||
'Handicrafts': ['Wall Hangings', 'Decorative Figurines', 'Gift Sets', 'Handmade Toys'],
|
||||
'Home & decor': ['Table Decor', 'Cushion Covers', 'Curtains', 'Storage Baskets'],
|
||||
'Handloom & Textiles': ['Sarees', 'Dupattas', 'Stoles', 'Yardage Fabric'],
|
||||
'Pottery & Ceramics': ['Mugs & Cups', 'Bowls', 'Vases', 'Plates'],
|
||||
'Brass & Metal Craft': ['Idols & Statues', 'Lamps & Diyas', 'Cookware', 'Wall Art'],
|
||||
'Woodcraft & Carvings': ['Furniture', 'Photo Frames', 'Kitchen Accessories', 'Sculptures'],
|
||||
'Jewellery & Ornaments': ['Necklaces', 'Earrings', 'Bangles', 'Anklets'],
|
||||
'Paintings & Folk Art': ['Canvas Paintings', 'Madhubani', 'Warli', 'Miniature Art'],
|
||||
'Jute & Eco-Fibers': ['Bags & Totes', 'Baskets', 'Mats & Rugs', 'Plant Holders'],
|
||||
'Zari & Embroidery': ['Embroidered Tops', 'Lehengas', 'Bed Covers', 'Table Runners'],
|
||||
};
|
||||
|
||||
// Step 7 Specific State matching stitch wireframe
|
||||
const [step7StoreUrl, setStep7StoreUrl] = useState(onboarding.storeSlug ? `tradhox.com/store/${onboarding.storeSlug}` : 'tradhox.com/store/heritage-crafts');
|
||||
const [step7Tagline, setStep7Tagline] = useState('Authentic Handcrafted Treasures from Master Artisans');
|
||||
|
|
@ -2630,16 +2663,382 @@ export const OnboardingPage: React.FC = () => {
|
|||
{/* STEP 6: Products Wireframe matching stitch reference */}
|
||||
{/* =================================================================== */}
|
||||
{onboardingStep === 6 && (
|
||||
<div
|
||||
className="mx-auto mb-6"
|
||||
style={{
|
||||
maxWidth: '820px',
|
||||
width: '100%',
|
||||
minHeight: '480px',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
{/* Clean wireframe canvas matching stitch reference */}
|
||||
<div className="mx-auto mb-6" style={{ maxWidth: '820px', width: '100%' }}>
|
||||
<div
|
||||
className="p-5 p-6-tablet"
|
||||
style={{
|
||||
borderRadius: '24px',
|
||||
border: '1px solid #E5E7EB',
|
||||
backgroundColor: '#FFFFFF',
|
||||
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
{/* Form header */}
|
||||
<div className="mb-4">
|
||||
<p style={{ fontSize: '0.72rem', fontWeight: 700, letterSpacing: '0.08em', color: '#9CA3AF', textTransform: 'uppercase', marginBottom: '4px' }}>
|
||||
STEP 6 OF 7 · ADD YOUR FIRST PRODUCT
|
||||
</p>
|
||||
<p style={{ fontSize: '0.82rem', color: '#6B7280' }}>
|
||||
add your first product · you can add the rest after you go live
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* ── Photo / Video Upload Grid ── */}
|
||||
<div className="mb-1">
|
||||
<p style={{ fontSize: '0.75rem', fontWeight: 600, color: '#374151', letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: '10px' }}>Product photos & video</p>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: '10px' }}>
|
||||
{/* Box 1 — Cover photo */}
|
||||
<div
|
||||
style={{
|
||||
height: '100px',
|
||||
border: '2px dashed #DBDBDB',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: '#FBF8F4',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<Plus size={18} color="#9CA3AF" strokeWidth={2} />
|
||||
<span style={{ fontSize: '0.66rem', color: '#9CA3AF', fontWeight: 600, textAlign: 'center', lineHeight: 1.2 }}>Add cover</span>
|
||||
</div>
|
||||
{/* Boxes 2–4 — Extra photos */}
|
||||
{[2, 3, 4].map(n => (
|
||||
<div
|
||||
key={n}
|
||||
style={{
|
||||
height: '100px',
|
||||
border: '2px dashed #DBDBDB',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: '#FAFAFA',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<Plus size={16} color="#D1D5DB" strokeWidth={2} />
|
||||
</div>
|
||||
))}
|
||||
{/* Box 5 — Video */}
|
||||
<div
|
||||
style={{
|
||||
height: '100px',
|
||||
border: '2px dashed #DBDBDB',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: '#FAFAFA',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<Play size={16} color="#9CA3AF" strokeWidth={2} />
|
||||
<span style={{ fontSize: '0.66rem', color: '#9CA3AF', fontWeight: 600, textAlign: 'center', lineHeight: 1.2 }}>Add video</span>
|
||||
</div>
|
||||
</div>
|
||||
<p style={{ fontSize: '0.72rem', color: '#9CA3AF', marginTop: '6px' }}>
|
||||
up to 6 photos + 1 video (max 10 seconds) · first photo is your cover image
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr style={{ border: 'none', borderTop: '1px solid #F3F4F6', margin: '20px 0' }} />
|
||||
|
||||
{/* ── Form Fields ── */}
|
||||
<div className="columns is-multiline is-variable is-3">
|
||||
|
||||
{/* Product name — full width */}
|
||||
<div className="column is-12">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Product name</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="e.g. Handwoven jute tote bag"
|
||||
value={step6ProductName}
|
||||
onChange={e => setStep6ProductName(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Category */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Category</label>
|
||||
<div className="select is-fullwidth" style={{ borderRadius: '10px' }}>
|
||||
<select
|
||||
value={step6Category}
|
||||
onChange={e => { setStep6Category(e.target.value); setStep6SubCategory(''); }}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
>
|
||||
{masterCraftCategories.map(c => <option key={c.name} value={c.name}>{c.name}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sub-category */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Sub-category</label>
|
||||
<div className="select is-fullwidth">
|
||||
<select
|
||||
value={step6SubCategory}
|
||||
onChange={e => setStep6SubCategory(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
>
|
||||
<option value="">Select sub-category</option>
|
||||
{(step6SubCategoryMap[step6Category] || []).map(sc => <option key={sc} value={sc}>{sc}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* About — full width */}
|
||||
<div className="column is-12">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>About this item</label>
|
||||
<textarea
|
||||
className="textarea"
|
||||
rows={3}
|
||||
placeholder="materials, dimensions, what makes it special..."
|
||||
value={step6About}
|
||||
onChange={e => setStep6About(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', boxShadow: 'none', resize: 'vertical' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Color */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Selected color</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="e.g. Natural beige"
|
||||
value={step6Color}
|
||||
onChange={e => setStep6Color(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Material */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Material</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="e.g. Jute, cotton"
|
||||
value={step6Material}
|
||||
onChange={e => setStep6Material(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Brand */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Brand</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="enter brand name"
|
||||
value={step6Brand}
|
||||
onChange={e => setStep6Brand(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Warranty */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Warranty</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="e.g. No warranty / 6 months"
|
||||
value={step6Warranty}
|
||||
onChange={e => setStep6Warranty(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Manufacturer info — full width */}
|
||||
<div className="column is-12">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Manufacturer info</label>
|
||||
<textarea
|
||||
className="textarea"
|
||||
rows={2}
|
||||
placeholder="name, address & contact of manufacturer/packer"
|
||||
value={step6ManufacturerInfo}
|
||||
onChange={e => setStep6ManufacturerInfo(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', boxShadow: 'none', resize: 'vertical' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Specification — full width */}
|
||||
<div className="column is-12">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Specification</label>
|
||||
<textarea
|
||||
className="textarea"
|
||||
rows={2}
|
||||
placeholder="dimensions, weight, capacity, care instructions..."
|
||||
value={step6Specification}
|
||||
onChange={e => setStep6Specification(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', boxShadow: 'none', resize: 'vertical' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Showcase — full width */}
|
||||
<div className="column is-12">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Showcase</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="short highlight shown on your storefront banner"
|
||||
value={step6Showcase}
|
||||
onChange={e => setStep6Showcase(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Selling price */}
|
||||
<div className="column is-4">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Selling price</label>
|
||||
<div className="control has-icons-left">
|
||||
<input
|
||||
className="input"
|
||||
type="number"
|
||||
placeholder="0"
|
||||
min="0"
|
||||
value={step6Price}
|
||||
onChange={e => setStep6Price(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none', paddingLeft: '36px' }}
|
||||
/>
|
||||
<span className="icon is-left" style={{ height: '42px', width: '36px', pointerEvents: 'none' }}>
|
||||
<IndianRupee size={14} color="#9CA3AF" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stock quantity */}
|
||||
<div className="column is-4">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Stock quantity</label>
|
||||
<input
|
||||
className="input"
|
||||
type="number"
|
||||
placeholder="0"
|
||||
min="0"
|
||||
value={step6Stock}
|
||||
onChange={e => setStep6Stock(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* SKU */}
|
||||
<div className="column is-4">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>SKU</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
value={step6Sku}
|
||||
readOnly
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none', backgroundColor: '#FAFAFA', color: '#6B7280' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Shipping weight */}
|
||||
<div className="column is-6">
|
||||
<label style={{ fontSize: '0.78rem', fontWeight: 600, color: '#374151', display: 'block', marginBottom: '6px' }}>Shipping weight (kg)</label>
|
||||
<input
|
||||
className="input"
|
||||
type="number"
|
||||
placeholder="0.0"
|
||||
min="0"
|
||||
step="0.1"
|
||||
value={step6Weight}
|
||||
onChange={e => setStep6Weight(e.target.value)}
|
||||
style={{ borderRadius: '10px', border: '1px solid #E5E7EB', fontSize: '0.88rem', height: '42px', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Made-to-order checkbox */}
|
||||
<div className="column is-6" style={{ display: 'flex', alignItems: 'center', paddingTop: '26px' }}>
|
||||
<label
|
||||
style={{ display: 'flex', alignItems: 'center', gap: '10px', cursor: 'pointer', fontSize: '0.84rem', color: '#374151', fontWeight: 500, userSelect: 'none' }}
|
||||
>
|
||||
<div
|
||||
onClick={() => setStep6MadeToOrder(!step6MadeToOrder)}
|
||||
style={{
|
||||
width: '18px',
|
||||
height: '18px',
|
||||
borderRadius: '5px',
|
||||
border: step6MadeToOrder ? 'none' : '1.5px solid #D1D5DB',
|
||||
backgroundColor: step6MadeToOrder ? '#1B2A4A' : '#FFFFFF',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.15s ease'
|
||||
}}
|
||||
>
|
||||
{step6MadeToOrder && <Check size={11} color="#FFFFFF" strokeWidth={3} />}
|
||||
</div>
|
||||
this is a made-to-order / handmade item
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ── Action Buttons ── */}
|
||||
<div
|
||||
className="mt-5 is-flex is-align-items-center is-justify-content-space-between"
|
||||
style={{ gap: '12px' }}
|
||||
>
|
||||
<button
|
||||
onClick={handleBack}
|
||||
className="button is-outlined"
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
borderColor: '#D1D5DB',
|
||||
color: '#374151',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.88rem',
|
||||
height: '44px',
|
||||
padding: '0 22px'
|
||||
}}
|
||||
>
|
||||
<ArrowLeft size={15} className="mr-2" />
|
||||
Back
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="button"
|
||||
style={{
|
||||
backgroundColor: '#1B2A4A',
|
||||
color: '#FFFFFF',
|
||||
borderRadius: '10px',
|
||||
fontWeight: 700,
|
||||
fontSize: '0.88rem',
|
||||
height: '44px',
|
||||
padding: '0 28px',
|
||||
border: 'none'
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
<ArrowRight size={15} className="ml-2" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Skip link */}
|
||||
<div className="has-text-centered mt-3">
|
||||
<button
|
||||
onClick={handleNext}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: '0.8rem', color: '#6B7280', textDecoration: 'underline', fontWeight: 500 }}
|
||||
>
|
||||
Skip for now
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue