import { useState, useEffect } from 'react' import { CONFIG, apiFetch } from './config' type Page = 'home' | 'about' | 'contact' | 'login' | 'signup' | 'profile-completion' | 'confirmation' | 'dashboard' | 'forgot-password' | 'login-otp' | 'welcome-tour' type DashboardTab = 'overview' | 'products' | 'orders' | 'returns' | 'wallet' | 'settings' | 'barcode-generator' | 'analytics' type DateFilter = 'year' | 'week' | 'day' | 'custom' interface Product { id: string title: string category: string price: number stock: number sku: string image: string } interface Order { id: string date: string item: string quantity: number customer: string total: number status: 'Ready to Ship test' | 'Ready to Ship' | 'Shipped' | 'Delivered' | 'Cancelled' | 'Pending Acceptance' | 'Rejected' carrier: string tracking: string eta: string } interface ReturnRequest { id: string orderId: string customer: string item: string reason: string status: 'Pending Approval' | 'Approved' | 'Rejected' | 'In Transit' image: string returningTracking: string } export default function App() { const [currentPage, setCurrentPage] = useState('home') const [isSidebarOpen, setIsSidebarOpen] = useState(false) const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) const [activeTab, setActiveTab] = useState<'login' | 'register'>('login') // Onboarding Status const [isProfileComplete, setIsProfileComplete] = useState(false) const [profileStep, setProfileStep] = useState(1) // Registration / Onboarding Form States const [email, setEmail] = useState('') const [phone, setPhone] = useState('') const [password, setPassword] = useState('') // Step 1: Verification const [phoneVerified, setPhoneVerified] = useState(false) const [emailVerified, setEmailVerified] = useState(false) const [phoneOtpSent, setPhoneOtpSent] = useState(false) const [emailOtpSent, setEmailOtpSent] = useState(false) const [enteredPhoneOtp, setEnteredPhoneOtp] = useState('') const [enteredEmailOtp, setEnteredEmailOtp] = useState('') // Step 2: Business details (moved GSTIN here) const [gstin, setGstin] = useState('29AAAAA1111A1Z1') const [isGstinVerified, setIsGstinVerified] = useState(false) const [aadharFile, setAadharFile] = useState(null) const [panFile, setPanFile] = useState(null) const [aadharS3Key, setAadharS3Key] = useState(null) const [panS3Key, setPanS3Key] = useState(null) // New onboarding customization states const [businessType, setBusinessType] = useState<'registered_company' | 'self_help_group' | 'individual_maker'>('registered_company') const [storeSlug, setStoreSlug] = useState('') const [supportEmail, setSupportEmail] = useState('') const [supportPhone, setSupportPhone] = useState('') const [selectedCategories, setSelectedCategories] = useState([]) // Step 3: Store and Location details const [storeName, setStoreName] = useState('My Artisan Handloom') const [storeLogo, setStoreLogo] = useState(null) const [logoS3Key, setLogoS3Key] = useState(null) const [businessBio, setBusinessBio] = useState('Traditional weaving and local sustainable designs.') const [address, setAddress] = useState({ street: '123 Handloom Lane', city: 'Textile Town', state: 'Karnataka', pincode: '560001' }) const [mapCoordinates, setMapCoordinates] = useState({ lat: 12.9716, lng: 77.5946 }) // --- Password visibility, confirm password and policy states --- const [showLoginPass, setShowLoginPass] = useState(false) const [showSignupPass, setShowSignupPass] = useState(false) const [showSignupConfirmPass, setShowSignupConfirmPass] = useState(false) const [confirmPassword, setConfirmPassword] = useState('') const [policyAccepted, setPolicyAccepted] = useState(false) // --- Password Reset Page States --- const [resetEmail, setResetEmail] = useState('') const [resetOtpSent, setResetOtpSent] = useState(false) const [resetOtp, setResetOtp] = useState('') const [resetPassword, setResetPassword] = useState('') // --- OTP Login States --- const [otpLoginPhone, setOtpLoginPhone] = useState('') const [otpLoginSent, setOtpLoginSent] = useState(false) const [otpLoginCode, setOtpLoginCode] = useState('') // --- Barcode Generator States --- const [barcodeProductSku, setBarcodeProductSku] = useState('') const [barcodeGenerated, setBarcodeGenerated] = useState(false) // --- Active Dashboard States --- const [dashTab, setDashTab] = useState('overview') const [dateFilter, setDateFilter] = useState('year') const [customDates, setCustomDates] = useState({ start: '2026-06-01', end: '2026-06-15' }) // Lists const [products, setProducts] = useState([]) const [orders, setOrders] = useState([]) const [returns, setReturns] = useState([]) // Forms & Editing const [productForm, setProductForm] = useState({ id: '', title: '', category: 'Apparel', price: 0, stock: 0, sku: '', image: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?auto=format&fit=crop&q=80&w=100' }) const [isEditingProduct, setIsEditingProduct] = useState(false) // New Heritage UI wizard states const [productWizardStep, setProductWizardStep] = useState(0) // 0: Catalog list, 1-5: Product upload wizard steps const [productFormDetails, setProductFormDetails] = useState({ id: '', name: '', category: 'Textiles & Apparel', description: '', isGiTagged: false, primaryImage: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?auto=format&fit=crop&q=80&w=300', additionalViews: [] as string[], videoUrl: '', view360Url: '', basePrice: '', compareAtPrice: '', trackInventory: true, sku: '', initialStock: '', shippingProfile: 'Standard Fragile', processingDays: 3, packageWeight: 1.0 }) const [selectedOrderDetail, setSelectedOrderDetail] = useState(null) const [orderNotes, setOrderNotes] = useState('') // Payout outstanding states const [wallet, setWallet] = useState({ outstanding: 850.00, withdrawn: 1250.00, history: [ { id: 'TX-9031', date: '2026-08-01', amount: 500.00, status: 'Transferred' }, { id: 'TX-9022', date: '2026-07-15', amount: 750.00, status: 'Transferred' } ] }) const [withdrawAmount, setWithdrawAmount] = useState('') // Load data from backend on mount or when profile is complete / logged in useEffect(() => { const token = localStorage.getItem('access_token'); if (token) { apiFetch(`${CONFIG.apiBaseUrl}/api/profile/`) .then(res => { if (res.ok) return res.json(); throw new Error('Session expired'); }) .then(user => { if (user && user.profile) { const profile = user.profile; setPhone(profile.phone || ''); setPhoneVerified(profile.phone_verified || false); setEmail(user.email || ''); setEmailVerified(profile.email_verified || false); setGstin(profile.gstin || '29AAAAA1111A1Z1'); setIsGstinVerified(profile.is_gstin_verified || false); setAadharFile(profile.aadhar_file || null); setPanFile(profile.pan_file || null); setAadharS3Key(profile.aadhar_s3_key || null); setPanS3Key(profile.pan_s3_key || null); setBusinessType(profile.business_type || 'registered_company'); setStoreSlug(profile.store_slug || ''); setSupportEmail(profile.support_email || ''); setSupportPhone(profile.support_phone || ''); setSelectedCategories(profile.categories || []); setStoreName(profile.store_name || 'My Artisan Handloom'); setStoreLogo(profile.store_logo || null); setLogoS3Key(profile.logo_s3_key || null); setBusinessBio(profile.business_bio || 'Traditional weaving and local sustainable designs.'); setAddress({ street: profile.street || '123 Handloom Lane', city: profile.city || 'Textile Town', state: profile.state || 'Karnataka', pincode: profile.pincode || '560001' }); if (profile.latitude && profile.longitude) { setMapCoordinates({ lat: Number(profile.latitude), lng: Number(profile.longitude) }); } const step = profile.onboarding_step; if (step >= 7) { setIsProfileComplete(true); setCurrentPage('dashboard'); } else { setProfileStep(step); setIsProfileComplete(false); setCurrentPage('profile-completion'); } } }) .catch(err => { console.error('Session restore failed:', err); localStorage.removeItem('access_token'); }); } }, []); useEffect(() => { if (isProfileComplete || currentPage === 'dashboard') { // Fetch Products apiFetch(`${CONFIG.apiBaseUrl}/api/products/`) .then(res => res.json()) .then(data => { if (Array.isArray(data)) setProducts(data); else if (data && Array.isArray(data.results)) setProducts(data.results); }) .catch(err => console.error('Error fetching products:', err)); // Fetch Orders apiFetch(`${CONFIG.apiBaseUrl}/api/orders/`) .then(res => res.json()) .then(data => { if (Array.isArray(data)) setOrders(data); else if (data && Array.isArray(data.results)) setOrders(data.results); }) .catch(err => console.error('Error fetching orders:', err)); // Fetch Returns apiFetch(`${CONFIG.apiBaseUrl}/api/returns/`) .then(res => res.json()) .then(data => { if (Array.isArray(data)) setReturns(data); else if (data && Array.isArray(data.results)) setReturns(data.results); }) .catch(err => console.error('Error fetching returns:', err)); // Fetch Wallet apiFetch(`${CONFIG.apiBaseUrl}/api/wallet/`) .then(res => res.json()) .then(data => { if (data) setWallet(data); }) .catch(err => console.error('Error fetching wallet:', err)); } }, [isProfileComplete, currentPage]); const uploadDocument = async (file: File, fileType: string) => { try { const response = await apiFetch(`${CONFIG.apiBaseUrl}/api/profile/presigned-url/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file_type: fileType, content_type: file.type }) }); if (!response.ok) throw new Error('Failed to get presigned URL'); const data = await response.json(); // Simulate file upload PUT to mock presigned_url await fetch(data.presigned_url, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } }).catch(err => console.log('Mock S3 upload:', err)); return data.s3_key; } catch (err) { console.error(err); return `suppliers/default/${fileType}.jpg`; } }; const handleAcceptOrder = (id: string) => { apiFetch(`${CONFIG.apiBaseUrl}/api/orders/${id}/accept/`, { method: 'POST' }) .then(res => res.json()) .then(updatedOrder => { setOrders(orders.map(o => o.id === updatedOrder.id ? updatedOrder : o)) alert(`Order accepted successfully!`) }) .catch(err => console.error(err)) } const handleRejectOrder = (id: string) => { apiFetch(`${CONFIG.apiBaseUrl}/api/orders/${id}/reject/`, { method: 'POST' }) .then(res => res.json()) .then(updatedOrder => { setOrders(orders.map(o => o.id === updatedOrder.id ? updatedOrder : o)) alert(`Order rejected.`) }) .catch(err => console.error(err)) } // Bulk Upload const [bulkLog, setBulkLog] = useState([]) const [isParsingBulk, setIsParsingBulk] = useState(false) const [bulkCsvFile, setBulkCsvFile] = useState(null) const [bulkZipFile, setBulkZipFile] = useState(null) // GSTIN verification simulator const handleVerifyGstin = () => { if (!gstin.trim() || gstin.length !== 15) { alert('Invalid GSTIN length. Must be 15 chars.'); return; } apiFetch(`${CONFIG.apiBaseUrl}/api/profile/submit-gstin/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ gstin }) }) .then(res => { if (!res.ok) throw new Error('Failed to verify GSTIN.'); return res.json(); }) .then(data => { if (data.verified) { setIsGstinVerified(true); } }) .catch(err => { alert(err.message); }); } // Handle Logo Upload simulation const handleLogoChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { const reader = new FileReader() reader.onloadend = () => { setStoreLogo(reader.result as string) } reader.readAsDataURL(file) const s3Key = await uploadDocument(file, 'logo'); setLogoS3Key(s3Key); } } // Route/Navigation Guard: If profile is not complete, redirect to profile-completion const navigateTo = (page: Page, forceComplete: boolean = false) => { const publicPages: Page[] = ['home', 'about', 'contact', 'login', 'signup', 'forgot-password', 'login-otp'] const complete = isProfileComplete || forceComplete if (!complete && !publicPages.includes(page) && page !== 'profile-completion') { alert('Access Denied: Please complete your supplier profile first!') setCurrentPage('profile-completion') } else { setCurrentPage(page) } window.scrollTo({ top: 0, behavior: 'smooth' }) } const handleLogout = () => { apiFetch(`${CONFIG.apiBaseUrl}/api/auth/logout/`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }) .catch(err => console.error('Error logging out:', err)) .finally(() => { localStorage.removeItem('access_token') // Reset all onboarding & profile states to their defaults setIsProfileComplete(false) setProfileStep(1) setEmail('') setPhone('') setPassword('') setConfirmPassword('') setPolicyAccepted(false) setPhoneVerified(false) setEmailVerified(false) setPhoneOtpSent(false) setEmailOtpSent(false) setEnteredPhoneOtp('') setEnteredEmailOtp('') setGstin('29AAAAA1111A1Z1') setIsGstinVerified(false) setAadharFile(null) setPanFile(null) setAadharS3Key(null) setPanS3Key(null) setStoreName('My Artisan Handloom') setStoreLogo(null) setLogoS3Key(null) setBusinessBio('Traditional weaving and local sustainable designs.') setAddress({ street: '123 Handloom Lane', city: 'Textile Town', state: 'Karnataka', pincode: '560001' }) setMapCoordinates({ lat: 12.9716, lng: 77.5946 }) navigateTo('home', true) }) } const handleRegisterSubmit = (e: React.FormEvent) => { e.preventDefault() // Email Validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { alert('Please enter a valid email address.'); return; } // Phone Validation const phoneRegex = /^[6-9]\d{9}$/; if (!phoneRegex.test(phone)) { alert('Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9.'); return; } // Password Validation if (password.length < 8) { alert('Password must be at least 8 characters long.'); return; } if (password !== confirmPassword) { alert('Passwords do not match.'); return; } // Policy Validation if (!policyAccepted) { alert('You must accept the Terms of Service and Privacy Policy.'); return; } apiFetch(`${CONFIG.apiBaseUrl}/api/auth/register/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: email, email: email, phone: phone, password: password, confirm_password: confirmPassword, policy_accepted: policyAccepted }) }) .then(res => { if (!res.ok) throw new Error('Registration failed. Username/email might already be taken.'); return res.json(); }) .then(() => { // Auto login after signup apiFetch(`${CONFIG.apiBaseUrl}/api/auth/login/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: email, password: password }) }) .then(res => { if (!res.ok) throw new Error('Auto-login failed.'); return res.json(); }) .then(data => { localStorage.setItem('access_token', data.access_token); navigateTo('profile-completion') }) }) .catch(err => { alert(err.message); }); } const handleLoginSubmit = (e: React.FormEvent) => { e.preventDefault() if (!email.trim()) { alert('Please enter your email or phone number.'); return; } apiFetch(`${CONFIG.apiBaseUrl}/api/auth/login/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: email, password: password }) }) .then(res => { if (!res.ok) throw new Error('Invalid credentials.'); return res.json(); }) .then(data => { localStorage.setItem('access_token', data.access_token); if (data.user && data.user.profile) { const profile = data.user.profile; setPhone(profile.phone || ''); setPhoneVerified(profile.phone_verified || false); setEmail(data.user.email || ''); setEmailVerified(profile.email_verified || false); setGstin(profile.gstin || '29AAAAA1111A1Z1'); setIsGstinVerified(profile.is_gstin_verified || false); setAadharFile(profile.aadhar_file || null); setPanFile(profile.pan_file || null); setAadharS3Key(profile.aadhar_s3_key || null); setPanS3Key(profile.pan_s3_key || null); setStoreName(profile.store_name || 'My Artisan Handloom'); setStoreLogo(profile.store_logo || null); setLogoS3Key(profile.logo_s3_key || null); setBusinessBio(profile.business_bio || 'Traditional weaving and local sustainable designs.'); setAddress({ street: profile.street || '123 Handloom Lane', city: profile.city || 'Textile Town', state: profile.state || 'Karnataka', pincode: profile.pincode || '560001' }); if (profile.latitude && profile.longitude) { setMapCoordinates({ lat: Number(profile.latitude), lng: Number(profile.longitude) }); } const step = profile.onboarding_step; if (step >= 4) { setIsProfileComplete(true); navigateTo('dashboard', true); } else { setProfileStep(step); setIsProfileComplete(false); navigateTo('profile-completion'); } } else { setIsProfileComplete(false); navigateTo('profile-completion'); } }) .catch(err => { alert(err.message); }); } const saveProfileBackend = (isComplete: boolean) => { return apiFetch(`${CONFIG.apiBaseUrl}/api/profile/`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: phone, phone_verified: phoneVerified, email_verified: emailVerified, gstin: gstin, is_gstin_verified: isGstinVerified, business_type: businessType, store_slug: storeSlug, support_email: supportEmail, support_phone: supportPhone, categories: selectedCategories, aadhar_file: aadharFile, pan_file: panFile, aadhar_s3_key: aadharS3Key || 'suppliers/default/aadhar.pdf', pan_s3_key: panS3Key || 'suppliers/default/pan.pdf', store_name: storeName, store_logo: storeLogo || 'https://images.unsplash.com/photo-1513519245088-0e12902e5a38?auto=format&fit=crop&q=80&w=800', logo_s3_key: logoS3Key || 'suppliers/default/logo.jpg', business_bio: businessBio, street: address.street, city: address.city, state: address.state, pincode: address.pincode, latitude: mapCoordinates.lat, longitude: mapCoordinates.lng, is_profile_complete: isComplete }) }) .then(res => { if (!res.ok) throw new Error('Failed to update profile.'); return res.json(); }); }; const handleProfileSubmit = (e: React.FormEvent) => { e.preventDefault() if (profileStep === 2) { setIsGstinVerified(true) } const isLastStep = profileStep === 6; saveProfileBackend(isLastStep) .then(() => { if (!isLastStep) { setProfileStep(prev => prev + 1) } else { setProfileStep(7); } }) .catch(err => { alert(err.message); }); } // --- Dashboard Logic Actions --- // Product creation/modification const handleSaveProduct = (e: React.FormEvent) => { e.preventDefault() const url = isEditingProduct ? `${CONFIG.apiBaseUrl}/api/products/${productForm.id}/` : `${CONFIG.apiBaseUrl}/api/products/` const method = isEditingProduct ? 'PUT' : 'POST' apiFetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: productForm.title, category: productForm.category, price: String(productForm.price), stock: Number(productForm.stock), sku: productForm.sku || `PROD-${Date.now().toString().slice(-6)}`, image: productForm.image }) }) .then(res => res.json()) .then(() => { // Refresh products from backend apiFetch(`${CONFIG.apiBaseUrl}/api/products/`) .then(r => r.json()) .then(prods => { if (Array.isArray(prods)) setProducts(prods); else if (prods && Array.isArray(prods.results)) setProducts(prods.results); }) setIsEditingProduct(false) alert(isEditingProduct ? 'Product modified successfully!' : 'Product uploaded successfully!') }) .catch(err => console.error(err)) // reset form setProductForm({ id: '', title: '', category: 'Apparel', price: 0, stock: 0, sku: '', image: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?auto=format&fit=crop&q=80&w=100' }) } const handleEditClick = (p: Product) => { setProductForm(p) setIsEditingProduct(true) } const handleDeleteProduct = (id: string) => { if (confirm('Are you sure you want to delete this listing?')) { apiFetch(`${CONFIG.apiBaseUrl}/api/products/${id}/`, { method: 'DELETE' }) .then(() => { setProducts(products.filter(p => p.id !== id)) }) .catch(err => console.error(err)) } } const handleBulkUploadSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!bulkCsvFile) { alert("Please select a CSV file to upload."); return; } setIsParsingBulk(true); setBulkLog(['Uploading files to server...', 'Parsing CSV data and extracting ZIP images...']); const formData = new FormData(); formData.append('csv_file', bulkCsvFile); if (bulkZipFile) { formData.append('zip_file', bulkZipFile); } try { const token = localStorage.getItem('access_token'); const response = await fetch(`${CONFIG.apiBaseUrl}/api/products/bulk-upload/`, { method: 'POST', headers: { ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }, body: formData }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Failed to complete bulk upload.'); } setBulkLog([ 'CSV file parsed successfully.', `Extracted and matched images for SKUs from ZIP file.`, `Successfully added ${data.products?.length || 0} product listings!`, ]); // Refresh product list const prodRes = await apiFetch(`${CONFIG.apiBaseUrl}/api/products/`); const prods = await prodRes.json(); if (Array.isArray(prods)) { setProducts(prods); } else if (prods && Array.isArray(prods.results)) { setProducts(prods.results); } setBulkCsvFile(null); setBulkZipFile(null); } catch (err: any) { setBulkLog(prev => [...prev, `Error: ${err.message}`]); } finally { setIsParsingBulk(false); } }; // Wallet outstanding requests const handleWithdrawRequest = (e: React.FormEvent) => { e.preventDefault() const amount = Number(withdrawAmount) if (isNaN(amount) || amount <= 0) { alert('Please enter a valid amount') return } apiFetch(`${CONFIG.apiBaseUrl}/api/wallet/withdraw/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: String(amount) }) }) .then(res => { if (!res.ok) throw new Error('Insufficient funds or invalid request'); return res.json(); }) .then(updatedWallet => { setWallet(updatedWallet) setWithdrawAmount('') alert(`Payout of $${amount} successfully transferred!`) }) .catch(err => { alert(err.message) }) } // Returns actions const handleReturnAction = (id: string, action: 'Approved' | 'Rejected') => { apiFetch(`${CONFIG.apiBaseUrl}/api/returns/${id}/action/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: action }) }) .then(res => res.json()) .then(updatedReturn => { setReturns(returns.map(ret => ret.id === id ? updatedReturn : ret)) alert(`Return request ${action.toLowerCase()}!`) }) .catch(err => console.error(err)) } // Compute realtime metrics based on state loaded from backend const computeRealtimeMetrics = () => { const totalSales = orders .filter(o => o.status !== 'Cancelled' && o.status !== 'Rejected') .reduce((sum, o) => sum + Number(o.total), 0) const totalEarned = Number(wallet.outstanding) + Number(wallet.withdrawn) const totalStock = products.reduce((sum, p) => sum + Number(p.stock), 0) const totalReturns = returns.length const isLoggedIn = currentPage === 'dashboard' || currentPage === 'profile-completion' || currentPage === 'welcome-tour' || isProfileComplete if (isLoggedIn) { return { totalSales, totalEarned, stockDetails: totalStock, returnedItems: totalReturns, chartValues: orders.length > 0 ? orders.map(o => Number(o.total)) : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } } return { totalSales: 45280.00, totalEarned: 38488.00, stockDetails: 342, returnedItems: 12, chartValues: CONFIG.dashboardData.filters[dateFilter]?.chartValues || [30, 45, 35, 60, 50, 75, 65, 80, 70, 95, 90, 110] } } const selectedMetrics = computeRealtimeMetrics() return ( <> {/* Dynamic Header */} {currentPage !== 'dashboard' && ( )} {/* Main Content Area */} {currentPage !== 'dashboard' ? (
{/* HOMEPAGE VIEW */} {currentPage === 'home' && (
{/* Hero Section */}

Sell Globally. Celebrate Craft.

Discover authentic Indian craftsmanship, preserved for generations and handcrafted for you.

{/* Discover Heritage Cards */}

Discover Heritage

{/* Category 1 */}

Hand-Thrown Pottery

Explore Collection

{/* Category 2 */}

Traditional Textiles

Explore Collection

{/* Category 3 */}

Metallic Arts

Explore Collection

{/* Category 4 */}

Wooden Heritage

Explore Collection

{/* The Tradhox Promise */}
verified

Expand Your Reach

Every piece is verified for its origin and traditional crafting methods, ensuring you receive true heritage art.

handshake

Easy Inventory Tools

We empower creators directly, bypassing intermediaries to foster sustainable livelihoods for artisanal communities.

eco

Secure Payments

Committed to eco-friendly materials and ethical production processes that respect both people and the planet.

)} {/* ABOUT US VIEW */} {currentPage === 'about' && (

{CONFIG.about.missionTitle}

{CONFIG.about.missionDescription}

Meet Our Leaders

{CONFIG.about.team.map((member, i) => (
{member.name}

{member.name}

{member.role}

))}
)} {/* CONTACT US VIEW */} {currentPage === 'contact' && (

Get in Touch

{ e.preventDefault(); alert('Thank you for contacting us! We will get back to you shortly.'); navigateTo('home'); }}>

Address

') }}>

Support Email

{CONFIG.supportEmail}

Partner Hotline

{CONFIG.supportPhone}

📍 Interactive Map Preview
)} {/* AUTHENTICATION VIEW (LOGIN & SIGNUP) */} {(currentPage === 'login' || currentPage === 'signup') && (
{activeTab === 'login' ? (

Supplier Portal Access

setEmail(e.target.value)} required />
setPassword(e.target.value)} required style={{ paddingRight: '45px' }} />
) : (

Create Your Supplier Account

setEmail(e.target.value)} required />
setPhone(e.target.value)} required />
setPassword(e.target.value)} required style={{ paddingRight: '45px' }} />
setConfirmPassword(e.target.value)} required style={{ paddingRight: '45px' }} />
setPolicyAccepted(e.target.checked)} required />
)}
)} {/* FORGOT PASSWORD PAGE */} {currentPage === 'forgot-password' && (

Reset Your Password

Enter your registered business email or mobile number to receive a secure password reset link / OTP.

{!resetOtpSent ? (
{ e.preventDefault(); if (resetEmail.trim()) { setResetOtpSent(true); alert('Simulated Reset Code (123456) sent successfully!'); } }}>
setResetEmail(e.target.value)} required />
) : (
{ e.preventDefault(); if (resetOtp === '123456') { setPassword(resetPassword); alert('Password updated successfully! Please login with your new password.'); setResetOtpSent(false); setResetEmail(''); setResetOtp(''); setResetPassword(''); navigateTo('login'); } else { alert('Invalid OTP. Please enter 123456'); } }}>
setResetOtp(e.target.value)} required />
setResetPassword(e.target.value)} required />
)}
)} {/* LOGIN WITH OTP PAGE */} {currentPage === 'login-otp' && (

Login with OTP

Access your seller portal using a temporary verification code sent to your mobile.

{!otpLoginSent ? (
{ e.preventDefault(); if (otpLoginPhone.trim()) { setOtpLoginSent(true); alert('Simulated Login Code (123456) sent to mobile!'); } }}>
setOtpLoginPhone(e.target.value)} required />
) : (
{ e.preventDefault(); if (otpLoginCode === '123456') { setOtpLoginSent(false); setOtpLoginPhone(''); setOtpLoginCode(''); if (!isProfileComplete) { navigateTo('profile-completion'); } else { navigateTo('dashboard'); } } else { alert('Invalid OTP. Please enter 123456'); } }}>
setOtpLoginCode(e.target.value)} required />
)}
)} {currentPage === 'profile-completion' && (
Step {profileStep} of 7: { profileStep === 1 ? 'Welcome' : profileStep === 2 ? 'Business Details' : profileStep === 3 ? 'Identity Verification' : profileStep === 4 ? 'Contact Verification' : profileStep === 5 ? 'Choose Categories' : profileStep === 6 ? 'Store Setup' : 'Verification' }

Complete Your Supplier Profile

{profileStep === 1 && (
👋

Welcome to Tradhox Onboarding

We bridge the gap between traditional Indian artistry and a global marketplace. Let's set up your supplier profile in a few simple steps.

)} {profileStep === 2 && (

Step 2: Business Details

setGstin(e.target.value)} required />
{isGstinVerified && (

✓ GSTIN verification will be completed within the next 24 hrs

)}
)} {profileStep === 3 && (

Step 3: Identity Verification

{/* Aadhaar Upload */}
{ if (e.target.files?.[0]) { const file = e.target.files[0]; setAadharFile(file.name); alert(`Aadhaar card selected: ${file.name}. Uploading...`); const s3Key = await uploadDocument(file, 'aadhar'); setAadharS3Key(s3Key); alert(`Aadhaar card uploaded successfully!`); } }} style={{ display: 'none' }} /> {aadharFile ? `Selected: ${aadharFile}` : 'No file uploaded yet'}
{/* PAN Upload */}
{ if (e.target.files?.[0]) { const file = e.target.files[0]; setPanFile(file.name); alert(`PAN card selected: ${file.name}. Uploading...`); const s3Key = await uploadDocument(file, 'pan'); setPanS3Key(s3Key); alert(`PAN card uploaded successfully!`); } }} style={{ display: 'none' }} /> {panFile ? `Selected: ${panFile}` : 'No file uploaded yet'}
)} {profileStep === 4 && (

Step 4: Verify Contacts

{/* Phone/WhatsApp Verification */}
setPhone(e.target.value)} disabled={phoneVerified} />
{phoneOtpSent && !phoneVerified && (
setEnteredPhoneOtp(e.target.value)} style={{ maxWidth: '150px' }} />
)} {phoneVerified && (
✓ Mobile & WhatsApp Verified
)}
{/* Email Verification */}
setEmail(e.target.value)} disabled={emailVerified} />
{emailOtpSent && !emailVerified && (
setEnteredEmailOtp(e.target.value)} style={{ maxWidth: '150px' }} />
)} {emailVerified && (
✓ Email Verified
)}
)} {profileStep === 5 && (

Step 5: Choose Product Categories

Select the categories that apply to your artisanal goods.

{['Sustainable Products', 'Home Decor', 'Eco-Friendly', 'OPOD Products', 'GI Tagged', 'Textiles & Apparel'].map(cat => { const isSelected = selectedCategories.includes(cat); return (
{ if (isSelected) { setSelectedCategories(selectedCategories.filter(c => c !== cat)); } else { setSelectedCategories([...selectedCategories, cat]); } }} style={{ padding: '1rem', border: isSelected ? '2px solid var(--primary)' : '1px solid var(--border)', backgroundColor: isSelected ? 'rgba(107, 26, 44, 0.05)' : 'transparent', borderRadius: '8px', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: isSelected ? '600' : 'normal', transition: 'all 0.2s ease', textAlign: 'center' }} > {cat}
); })}
)} {profileStep === 6 && (

Step 6: Store Details & Pickup Location

setStoreName(e.target.value)} required />
setStoreSlug(e.target.value.toLowerCase().replace(/[^a-z0-9\-]/g, ''))} required />
setSupportEmail(e.target.value)} required />
setSupportPhone(e.target.value)} required />
{ const rect = e.currentTarget.getBoundingClientRect(); const x = Math.round(e.clientX - rect.left); const y = Math.round(e.clientY - rect.top); setMapCoordinates({ lat: Number((12.9 + y * 0.001).toFixed(4)), lng: Number((77.5 + x * 0.001).toFixed(4)) }); setAddress(prev => ({ ...prev, street: `Plot ${x}, Sector ${Math.round(y/10)}, Handicraft Park` })); }} >
📍
Click map to pin location
setAddress({ ...address, street: e.target.value })} required />
setAddress({ ...address, city: e.target.value })} required />
setAddress({ ...address, state: e.target.value })} required />
setAddress({ ...address, pincode: e.target.value })} required />
)} {profileStep === 7 && (
🎉

Setup Complete!

Your supplier profile has been successfully submitted and is under review. You can now access your preview dashboard.

)}
)} {/* WELCOME PAGE & SETUP TOUR FOR NEW SELLERS */} {currentPage === 'welcome-tour' && ( navigateTo('dashboard')} /> )}
) : ( /* --- FULL SERVICE SUPPLIER ACTIVE DASHBOARD PAGE --- */
{/* Sidebar */} <> {isSidebarOpen &&
setIsSidebarOpen(false)}>
} {/* Main Workspace Frame */}
{/* Top Workspace Header */}
search
{CONFIG.logoLetter}
{/* Inner Dashboard Tabs Area */}
{/* OVERVIEW PANEL / HOME TAB */} {dashTab === 'overview' && !selectedOrderDetail && (

Welcome back, Artisan!

Your store is looking great. Here is what's happening today.

{/* Left Column (Metrics + Orders) */}
{/* Metric Cards */}
{/* Card 1 */}
Total Sales (₹)

₹ 42,500

{/* Card 2 */}
Active Orders

14

{/* Card 3 */}
Store Views

1,204

{/* Recent Orders Queue Card */}

Recent Orders

{orders.slice(0, 5).map(o => ( ))}
Order ID Date Product Name Status
{o.date} {o.item} {o.status === 'Pending Acceptance' ? 'Pending' : o.status}
{/* Right Column (Live Preview) */}

Live Preview

{/* Store Preview Mockup */}

{storeName || 'Tradhox Artisan Co.'}

Your store is currently live and looking great.

)} {/* PRODUCTS TAB */} {dashTab === 'products' && (
{productWizardStep === 0 ? (

Products

Manage your listings, catalog collections, and stock values.

{/* Filters */}
{/* Products Cards Grid */}
{products.map(p => { const isOut = p.stock === 0; const isLow = p.stock > 0 && p.stock <= 5; return (
{p.image ? ( ) : (
🖼️ No Image
)} {isOut ? 'Out of Stock' : isLow ? `Low Stock (${p.stock})` : `In Stock (${p.stock})`}
{p.category} {(p as any).is_gi_tagged && ( GI Tagged )}

{p.title}

₹ {Number(p.price).toFixed(2)}

); })}
) : ( /* Multi-Step Wizard */

{productFormDetails.id ? 'Edit Product Details' : 'Add New Product'}

Fill out the heritage marketplace listing form.

{/* Step lines progress */}
{['General', 'Media', 'Pricing', 'Shipping', 'Review'].map((tabLabel, idx) => { const sNum = idx + 1; const active = productWizardStep === sNum; const done = productWizardStep > sNum; return (
{done ? '✓' : sNum}
{tabLabel}
); })}
{ e.preventDefault(); if (productWizardStep < 5) { setProductWizardStep(prev => prev + 1); } else { const url = productFormDetails.id ? `${CONFIG.apiBaseUrl}/api/products/${productFormDetails.id}/` : `${CONFIG.apiBaseUrl}/api/products/`; const method = productFormDetails.id ? 'PUT' : 'POST'; apiFetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: productFormDetails.name, category: productFormDetails.category, price: String(productFormDetails.basePrice), stock: Number(productFormDetails.initialStock), sku: productFormDetails.sku || `PROD-${Date.now().toString().slice(-6)}`, image: productFormDetails.primaryImage || '/kanchipuram_silk.jpg', description: productFormDetails.description, is_gi_tagged: productFormDetails.isGiTagged, additional_images: productFormDetails.additionalViews, video_url: productFormDetails.videoUrl, view_360_url: productFormDetails.view360Url, compare_at_price: productFormDetails.compareAtPrice ? String(productFormDetails.compareAtPrice) : null, track_inventory: productFormDetails.trackInventory, shipping_profile: productFormDetails.shippingProfile, processing_days: Number(productFormDetails.processingDays), package_weight: Number(productFormDetails.packageWeight) }) }) .then(res => res.json()) .then(() => { apiFetch(`${CONFIG.apiBaseUrl}/api/products/`) .then(r => r.json()) .then(prods => { if (Array.isArray(prods)) setProducts(prods); else if (prods && Array.isArray(prods.results)) setProducts(prods.results); }); setProductWizardStep(0); alert('Product details successfully processed!'); }) .catch(err => alert(err.message)); } }} className="space-y-6"> {/* Step 1 */} {productWizardStep === 1 && (
setProductFormDetails({ ...productFormDetails, name: e.target.value })} required />