feat: build Step 6 Products form with upload grid, all form fields, and action buttons
Some checks failed
Beta CI/CD Pipeline / build-and-test (push) Failing after 27s
Beta CI/CD Pipeline / deploy-beta (push) Has been skipped

This commit is contained in:
vickytechkey 2026-09-17 22:22:20 +05:30
parent da6ff22d61
commit 7dd650e9ba

View file

@ -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 &amp; 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 &amp; 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>
)}