feat: add modal for bulk product and document uploads to ProductsTab
All checks were successful
Beta CI/CD Pipeline / build-and-test (push) Successful in 1m6s
Beta CI/CD Pipeline / deploy-beta (push) Successful in 9s

This commit is contained in:
vickytechkey 2026-08-27 21:47:52 +05:30
parent 524038cf2b
commit af2f309e00
4 changed files with 352 additions and 165 deletions

View file

@ -10,6 +10,15 @@ export default function SettingsTab() {
supportPhone, setSupportPhone, supportPhone, setSupportPhone,
saveProfileBackend, saveProfileBackend,
uploadDocument, uploadDocument,
// Verification
email, phone,
emailVerified, phoneVerified,
// Business Details
gstin, setGstin, isGstinVerified, handleVerifyGstin,
aadharFile, aadharS3Key,
panFile, panS3Key,
// Location
address, setAddress
} = useSeller(); } = useSeller();
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
@ -34,7 +43,7 @@ export default function SettingsTab() {
return ( return (
<div className="columns is-centered"> <div className="columns is-centered">
<div className="column is-8"> <div className="column is-10">
<h1 className="title is-3 has-text-dark mb-5" style={{ fontFamily: 'Libre Caslon Text, serif' }}>Settings</h1> <h1 className="title is-3 has-text-dark mb-5" style={{ fontFamily: 'Libre Caslon Text, serif' }}>Settings</h1>
{saveSuccess && ( {saveSuccess && (
@ -51,9 +60,47 @@ export default function SettingsTab() {
)} )}
<form onSubmit={handleSave}> <form onSubmit={handleSave}>
{/* Verification Section */}
<div className="box mb-5"> <div className="box mb-5">
<h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Store Profile</h2> <h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Verification</h2>
<div className="columns">
<div className="column is-half">
<div className="field">
<label className="label">Registered Email</label>
<div className="control has-icons-right">
<input className="input" type="email" value={email} readOnly />
{emailVerified && (
<span className="icon is-small is-right has-text-success">
<span className="material-symbols-outlined">check_circle</span>
</span>
)}
</div>
{!emailVerified && <p className="help has-text-danger">Email not verified</p>}
</div>
</div>
<div className="column is-half">
<div className="field">
<label className="label">Registered Phone</label>
<div className="control has-icons-right">
<input className="input" type="tel" value={phone} readOnly />
{phoneVerified && (
<span className="icon is-small is-right has-text-success">
<span className="material-symbols-outlined">check_circle</span>
</span>
)}
</div>
{!phoneVerified && <p className="help has-text-danger">Phone not verified</p>}
</div>
</div>
</div>
</div>
{/* Store Profile Section */}
<div className="box mb-5">
<h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Store Profile & Location</h2>
<div className="columns">
<div className="column is-half">
<div className="field"> <div className="field">
<label className="label">Store Name</label> <label className="label">Store Name</label>
<div className="control"> <div className="control">
@ -66,7 +113,8 @@ export default function SettingsTab() {
/> />
</div> </div>
</div> </div>
</div>
<div className="column is-half">
<div className="field"> <div className="field">
<label className="label">Store URL Slug</label> <label className="label">Store URL Slug</label>
<div className="control"> <div className="control">
@ -74,6 +122,8 @@ export default function SettingsTab() {
</div> </div>
<p className="help">Contact support to change your store URL.</p> <p className="help">Contact support to change your store URL.</p>
</div> </div>
</div>
</div>
<div className="field"> <div className="field">
<label className="label">Store Description</label> <label className="label">Store Description</label>
@ -86,10 +136,69 @@ export default function SettingsTab() {
/> />
</div> </div>
</div> </div>
<div className="columns mt-2">
<div className="column is-half">
<div className="field">
<label className="label">Street Address</label>
<div className="control">
<input
className="input"
type="text"
value={address.street}
onChange={e => setAddress({...address, street: e.target.value})}
/>
</div>
</div>
</div>
<div className="column is-half">
<div className="field">
<label className="label">City</label>
<div className="control">
<input
className="input"
type="text"
value={address.city}
onChange={e => setAddress({...address, city: e.target.value})}
/>
</div>
</div>
</div>
</div> </div>
<div className="columns">
<div className="column is-half">
<div className="field">
<label className="label">State</label>
<div className="control">
<input
className="input"
type="text"
value={address.state}
onChange={e => setAddress({...address, state: e.target.value})}
/>
</div>
</div>
</div>
<div className="column is-half">
<div className="field">
<label className="label">Pincode</label>
<div className="control">
<input
className="input"
type="text"
value={address.pincode}
onChange={e => setAddress({...address, pincode: e.target.value})}
/>
</div>
</div>
</div>
</div>
</div>
{/* Contact Section */}
<div className="box mb-5"> <div className="box mb-5">
<h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Contact Information</h2> <h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Public Contact Information</h2>
<div className="columns"> <div className="columns">
<div className="column is-half"> <div className="column is-half">
@ -123,46 +232,81 @@ export default function SettingsTab() {
</div> </div>
</div> </div>
{/* Business Details / Legal */}
<div className="box mb-5"> <div className="box mb-5">
<h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Business Documents</h2> <h2 className="title is-5 has-text-primary pb-2" style={{ borderBottom: '1px solid #eee' }}>Business Documents (Legal)</h2>
<p className="has-text-grey-dark mb-4">Upload any additional documents (like business licenses, identity proof, or craft certifications).</p> <p className="has-text-grey-dark mb-4">Required for marketplace verification.</p>
<div className="field"> <div className="field">
<div className="control"> <label className="label">GSTIN</label>
<div className="file is-boxed"> <div className="field has-addons">
<label className="file-label is-flex-direction-column is-align-items-center"> <div className="control is-expanded">
<input <input
className="file-input" className="input"
type="file" type="text"
name="business_doc" value={gstin}
accept=".pdf,.jpg,.jpeg,.png" onChange={e => setGstin(e.target.value)}
onChange={e => { placeholder="Enter 15-digit GSTIN"
if (e.target.files?.[0]) {
uploadDocument(e.target.files[0], 'document');
}
}}
/> />
<span className="file-cta is-flex is-flex-direction-column is-align-items-center py-4 px-6 has-background-white" style={{ border: '1px solid var(--bulma-primary)' }}> </div>
<span className="file-icon mb-2 has-text-primary"> <div className="control">
<span className="material-symbols-outlined is-size-3">upload_file</span> <button type="button" className="button is-info" onClick={handleVerifyGstin}>
</span> Verify
<span className="file-label has-text-primary"> </button>
Choose a document </div>
</span> </div>
{isGstinVerified && <p className="help has-text-success">GSTIN Verified </p>}
</div>
<div className="columns mt-4">
<div className="column is-half">
<div className="field">
<label className="label">Aadhar Document</label>
<div className="control">
<div className="file has-name is-fullwidth">
<label className="file-label">
<input className="file-input" type="file" onChange={e => {
if (e.target.files?.[0]) uploadDocument(e.target.files[0], 'aadhar');
}} />
<span className="file-cta">
<span className="file-icon"><span className="material-symbols-outlined">upload</span></span>
<span className="file-label">Choose Aadhar...</span>
</span> </span>
<span className="file-name">{aadharFile || aadharS3Key || 'No file uploaded'}</span>
</label> </label>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="column is-half">
<div className="field">
<label className="label">PAN Document</label>
<div className="control">
<div className="file has-name is-fullwidth">
<label className="file-label">
<input className="file-input" type="file" onChange={e => {
if (e.target.files?.[0]) uploadDocument(e.target.files[0], 'pan');
}} />
<span className="file-cta">
<span className="file-icon"><span className="material-symbols-outlined">upload</span></span>
<span className="file-label">Choose PAN...</span>
</span>
<span className="file-name">{panFile || panS3Key || 'No file uploaded'}</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="is-flex is-justify-content-flex-end"> <div className="is-flex is-justify-content-flex-end">
<button <button
type="submit" type="submit"
className={`button is-primary is-outlined ${isSaving ? 'is-loading' : ''}`} className={`button is-primary is-outlined is-medium ${isSaving ? 'is-loading' : ''}`}
disabled={isSaving} disabled={isSaving}
> >
Save Changes Save Settings
</button> </button>
</div> </div>
</form> </form>

View file

@ -1,115 +1,165 @@
import React from 'react'; import React from 'react';
import { useSeller } from '../../context/SellerContext'; import { useSeller } from '../../context/SellerContext';
const CRAFT_CATEGORIES = [
'Apparel',
'Home Decor',
'Jewelry',
'Textiles',
'Pottery & Ceramics',
'Woodwork',
'Art & Collectibles',
'Bath & Beauty',
];
export default function OnboardingWizard() { export default function OnboardingWizard() {
const { const {
saveProfileBackend, handleProfileSubmit,
setIsProfileComplete, businessType, setBusinessType,
setCurrentPage storeSlug, setStoreSlug,
supportEmail, setSupportEmail,
supportPhone, setSupportPhone,
selectedCategories, setSelectedCategories
} = useSeller(); } = useSeller();
const handleNext = () => { const handleCategoryToggle = (category: string) => {
saveProfileBackend(true) if (selectedCategories.includes(category)) {
.then(() => { setSelectedCategories(selectedCategories.filter((c: string) => c !== category));
setIsProfileComplete(true); } else {
setCurrentPage('dashboard'); setSelectedCategories([...selectedCategories, category]);
}) }
.catch((err: Error) => {
alert("Failed to save progress: " + err.message);
});
}; };
const renderStep1 = () => (
<div className="columns is-vcentered" style={{ minHeight: 'calc(100vh - 4rem)' }}>
{/* Left Column (Text) */}
<div className="column is-5 is-flex is-flex-direction-column is-justify-content-center p-6">
<p className="has-text-primary mb-4 is-size-7 has-text-weight-bold is-uppercase tracking-wide" style={{ letterSpacing: '0.1em' }}>
Welcome to Tradhox
</p>
<h1 className="title is-1 has-text-dark mb-5" style={{ fontFamily: 'Libre Caslon Text, serif', lineHeight: '1.2' }}>
Every Piece You List Keeps a Craft Alive
</h1>
<p className="subtitle is-5 has-text-grey-dark mb-6">
Join a global marketplace dedicated to cultural preservation. Your craftsmanship tells a story. Let's build your store to share it with the world.
</p>
<div className="mb-6">
<div className="is-flex is-align-items-flex-start mb-5">
<span className="icon is-large has-text-primary mr-4" style={{ backgroundColor: 'rgba(226, 223, 219, 0.2)', borderRadius: '50%', padding: '24px', border: '1px solid #d7c3b0' }}>
<span className="material-symbols-outlined is-size-4">handshake</span>
</span>
<div>
<h3 className="title is-5 mb-2 has-text-dark">Fair Trade Certified</h3>
<p className="has-text-grey-dark is-size-6">Directly connect with buyers seeking authentic, ethically sourced goods.</p>
</div>
</div>
<div className="is-flex is-align-items-flex-start mb-5">
<span className="icon is-large has-text-primary mr-4" style={{ backgroundColor: 'rgba(226, 223, 219, 0.2)', borderRadius: '50%', padding: '24px', border: '1px solid #d7c3b0' }}>
<span className="material-symbols-outlined is-size-4">storefront</span>
</span>
<div>
<h3 className="title is-5 mb-2 has-text-dark">Your Brand, Your Way</h3>
<p className="has-text-grey-dark is-size-6">Customize your storefront to reflect your unique heritage and style.</p>
</div>
</div>
</div>
<div>
<button className="button is-primary is-medium is-rounded is-outlined" onClick={handleNext}>
<span>Go to Dashboard</span>
<span className="icon is-small ml-2"><span className="material-symbols-outlined">arrow_forward</span></span>
</button>
</div>
</div>
{/* Right Column (Image) */}
<div className="column is-7 is-hidden-mobile" style={{ height: 'calc(100vh - 4rem)' }}>
<div style={{ position: 'relative', height: '100%', padding: '2rem' }}>
<div style={{
position: 'relative',
width: '100%',
height: '100%',
borderRadius: '1rem',
overflow: 'hidden',
boxShadow: '0 4px 20px rgba(107,26,44,0.05)',
border: '1px solid #d7c3b0'
}}>
<img
src="https://lh3.googleusercontent.com/aida-public/AB6AXuB4W-NVA2QTeIF_XSyCokGOQf4RVLTiMmxLi69rYdK7uVQ5yINgHSBzGIeC1WJSEtTjXGBp3hx_OrKdiiV7_hcwN9oQdLnuoABA1XYYFf-RrQbgv9khd1zVujiaAjlPvBaj8WKCD83RjZqHUmuGM_-vKmmKWiijoqaOdoPAuWJdZu-QkASeowWzfwCljpwZTeVD2VaLxc5y1PzIKEmnTfy6O8jqTsZhOo-k6HrhZggm1lMF9kondr_oQg"
alt="Artisan at work"
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }}
/>
{/* Global Reach Badge */}
<div style={{
position: 'absolute',
bottom: '24px',
left: '24px',
backgroundColor: 'rgba(255, 255, 255, 0.9)',
backdropFilter: 'blur(4px)',
border: '1px solid #d7c3b0',
borderRadius: '8px',
padding: '16px',
display: 'flex',
alignItems: 'center',
gap: '12px',
boxShadow: '0 2px 8px rgba(0,0,0,0.05)'
}}>
<span className="material-symbols-outlined has-text-primary is-size-3">public</span>
<div>
<p className="has-text-weight-bold has-text-dark is-size-6 mb-0">Global Reach</p>
<p className="has-text-grey-dark is-size-7 mb-0">Buyers in 50+ countries</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
return ( return (
<section className="has-background-white" style={{ minHeight: 'calc(100vh - 4rem)' }}> <section className="has-background-white" style={{ minHeight: 'calc(100vh - 4rem)' }}>
<div className="container is-fluid px-0"> <div className="container is-max-desktop py-6">
{renderStep1()} <h1 className="title is-2 has-text-dark mb-4" style={{ fontFamily: 'Libre Caslon Text, serif' }}>
Welcome to Tradhox
</h1>
<p className="subtitle is-5 has-text-grey-dark mb-6">
Let's get to know your business. Tell us about what you do so we can help you reach the right audience.
</p>
<form onSubmit={handleProfileSubmit} className="box p-5" style={{ border: '1px solid #d7c3b0', boxShadow: '0 4px 20px rgba(107,26,44,0.05)' }}>
<div className="field mb-5">
<label className="label has-text-dark">Business Type</label>
<div className="control">
<label className="radio mr-4">
<input
type="radio"
name="businessType"
value="registered_company"
checked={businessType === 'registered_company'}
onChange={(e) => setBusinessType(e.target.value as any)}
className="mr-2"
/>
Registered Company
</label>
<label className="radio mr-4">
<input
type="radio"
name="businessType"
value="self_help_group"
checked={businessType === 'self_help_group'}
onChange={(e) => setBusinessType(e.target.value as any)}
className="mr-2"
/>
Self Help Group
</label>
<label className="radio">
<input
type="radio"
name="businessType"
value="individual_maker"
checked={businessType === 'individual_maker'}
onChange={(e) => setBusinessType(e.target.value as any)}
className="mr-2"
/>
Individual Maker
</label>
</div>
</div>
<div className="field mb-5">
<label className="label has-text-dark">Store URL Slug</label>
<div className="control">
<input
className="input"
type="text"
placeholder="e.g. my-artisan-store"
value={storeSlug}
onChange={(e) => setStoreSlug(e.target.value)}
required
/>
</div>
<p className="help">This will be your unique Tradhox web address (e.g., tradhox.com/store/your-slug).</p>
</div>
<div className="columns mb-5">
<div className="column is-half">
<div className="field">
<label className="label has-text-dark">Support Email</label>
<div className="control">
<input
className="input"
type="email"
placeholder="support@example.com"
value={supportEmail}
onChange={(e) => setSupportEmail(e.target.value)}
required
/>
</div>
</div>
</div>
<div className="column is-half">
<div className="field">
<label className="label has-text-dark">Support Phone</label>
<div className="control">
<input
className="input"
type="tel"
placeholder="+91 XXXXX XXXXX"
value={supportPhone}
onChange={(e) => setSupportPhone(e.target.value)}
required
/>
</div>
</div>
</div>
</div>
<div className="field mb-6">
<label className="label has-text-dark">Categories</label>
<p className="help mb-3">Select the categories that best describe your crafts.</p>
<div className="columns is-multiline">
{CRAFT_CATEGORIES.map(category => (
<div key={category} className="column is-4 pb-2 pt-2">
<label className="checkbox">
<input
type="checkbox"
className="mr-2"
checked={selectedCategories.includes(category)}
onChange={() => handleCategoryToggle(category)}
/>
{category}
</label>
</div>
))}
</div>
</div>
<div className="field mt-5">
<div className="control has-text-right">
<button type="submit" className="button is-primary is-medium is-rounded">
<span>Complete Profile</span>
<span className="icon is-small ml-2">
<span className="material-symbols-outlined">arrow_forward</span>
</span>
</button>
</div>
</div>
</form>
</div> </div>
</section> </section>
); );

View file

@ -1,4 +1,7 @@
const getApiBaseUrl = () => { const getApiBaseUrl = () => {
if (import.meta.env.DEV) {
return 'http://127.0.0.1:8000';
}
return 'https://ec2-16-113-57-127.ap-south-2.compute.amazonaws.com'; return 'https://ec2-16-113-57-127.ap-south-2.compute.amazonaws.com';
}; };

View file

@ -51,7 +51,6 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
// Onboarding Status // Onboarding Status
const [isProfileComplete, setIsProfileComplete] = useState(false) const [isProfileComplete, setIsProfileComplete] = useState(false)
const [profileStep, setProfileStep] = useState(1)
// Registration / Onboarding Form States // Registration / Onboarding Form States
const [email, setEmail] = useState('') const [email, setEmail] = useState('')
@ -217,11 +216,11 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
} }
const step = profile.onboarding_step; const step = profile.onboarding_step;
if (step >= 4) { // The onboarding flow is now just 1 step, so anything >= 2 (or 4 if we keep old backend state) means complete
if (step >= 4 || profile.is_profile_complete) {
setIsProfileComplete(true); setIsProfileComplete(true);
setCurrentPage('dashboard'); setCurrentPage('dashboard');
} else { } else {
setProfileStep(step);
setIsProfileComplete(false); setIsProfileComplete(false);
setCurrentPage('profile-completion'); setCurrentPage('profile-completion');
} }
@ -393,7 +392,6 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
localStorage.removeItem('refresh_token') localStorage.removeItem('refresh_token')
// Reset all onboarding & profile states to their defaults // Reset all onboarding & profile states to their defaults
setIsProfileComplete(false) setIsProfileComplete(false)
setProfileStep(1)
setEmail('') setEmail('')
setPhone('') setPhone('')
setPassword('') setPassword('')
@ -549,11 +547,10 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
} }
const step = profile.onboarding_step; const step = profile.onboarding_step;
if (step >= 4) { if (step >= 4 || profile.is_profile_complete) {
setIsProfileComplete(true); setIsProfileComplete(true);
navigateTo('dashboard', true); navigateTo('dashboard', true);
} else { } else {
setProfileStep(step);
setIsProfileComplete(false); setIsProfileComplete(false);
navigateTo('profile-completion'); navigateTo('profile-completion');
} }
@ -576,7 +573,7 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
phone_verified: phoneVerified, phone_verified: phoneVerified,
email_verified: emailVerified, email_verified: emailVerified,
gstin: gstin, gstin: gstin,
is_gstin_verified: profileStep === 2 ? true : isGstinVerified, is_gstin_verified: isGstinVerified,
business_type: businessType, business_type: businessType,
store_slug: storeSlug, store_slug: storeSlug,
support_email: supportEmail, support_email: supportEmail,
@ -607,17 +604,10 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const handleProfileSubmit = (e: React.FormEvent) => { const handleProfileSubmit = (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
if (profileStep === 2) { saveProfileBackend(true)
setIsGstinVerified(true)
}
const isLastStep = profileStep === 3;
saveProfileBackend(isLastStep)
.then(() => { .then(() => {
if (!isLastStep) {
setProfileStep(prev => prev + 1)
} else {
setIsProfileComplete(true); setIsProfileComplete(true);
} setCurrentPage('dashboard');
}) })
.catch(err => { .catch(err => {
alert(err.message); alert(err.message);
@ -815,7 +805,7 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const contextValue = { const contextValue = {
setBusinessBio, email, resetPassword, setLogoS3Key, setStoreName, setShowLoginPass, storeName, otpLoginSent, setOtpLoginSent, aadharS3Key, logoS3Key, customDates, setProductFormDetails, handleBulkUploadSubmit, setMapCoordinates, setAadharFile, gstin, mapCoordinates, setIsGstinVerified, enteredPhoneOtp, address, setEmailVerified, dashTab, selectedOrderDetail, setShowSignupConfirmPass, handleRegisterSubmit, setBulkCsvFile, confirmPassword, navigateTo, setResetPassword, orderNotes, setOrders, handleRejectOrder, barcodeProductSku, setEnteredEmailOtp, setIsEditingProduct, setBulkLog, isMobileMenuOpen, resetOtp, productWizardStep, setCustomDates, setConfirmPassword, isGstinVerified, bulkCsvFile, setAddress, storeLogo, handleProfileSubmit, setPhoneOtpSent, setOrderNotes, handleDeleteProduct, setWallet, policyAccepted, emailOtpSent, setResetOtpSent, setGstin, phoneOtpSent, showLoginPass, showSignupConfirmPass, setPhoneVerified, aadharFile, setDateFilter, activeTab, computeRealtimeMetrics, setIsParsingBulk, handleLogout, panS3Key, setCurrentPage, selectedCategories, setEmailOtpSent, showSignupPass, resetEmail, handleLogoChange, dateFilter, setShowSignupPass, businessBio, setWithdrawAmount, phoneVerified, currentPage, setResetOtp, enteredEmailOtp, setEnteredPhoneOtp, setPanFile, setIsSidebarOpen, setSelectedOrderDetail, handleAcceptOrder, saveProfileBackend, supportPhone, handleEditClick, setStoreLogo, setEmail, password, setOtpLoginPhone, bulkLog, businessType, setPanS3Key, setProducts, setSupportEmail, setOtpLoginCode, withdrawAmount, handleSaveProduct, setStoreSlug, setBarcodeProductSku, setProductForm, setBulkZipFile, productFormDetails, setIsProfileComplete, otpLoginPhone, orders, setActiveTab, bulkZipFile, isSidebarOpen, setBarcodeGenerated, setBusinessType, handleReturnAction, setSupportPhone, barcodeGenerated, products, productForm, setProductWizardStep, resetOtpSent, emailVerified, panFile, isParsingBulk, setDashTab, setReturns, setPassword, handleWithdrawRequest, uploadDocument, setPolicyAccepted, isEditingProduct, setIsMobileMenuOpen, profileStep, isProfileComplete, setSelectedCategories, storeSlug, phone, setPhone, setAadharS3Key, handleVerifyGstin, setProfileStep, returns, handleLoginSubmit, setResetEmail, wallet, otpLoginCode, supportEmail setBusinessBio, email, resetPassword, setLogoS3Key, setStoreName, setShowLoginPass, storeName, otpLoginSent, setOtpLoginSent, aadharS3Key, logoS3Key, customDates, setProductFormDetails, handleBulkUploadSubmit, setMapCoordinates, setAadharFile, gstin, mapCoordinates, setIsGstinVerified, enteredPhoneOtp, address, setEmailVerified, dashTab, selectedOrderDetail, setShowSignupConfirmPass, handleRegisterSubmit, setBulkCsvFile, confirmPassword, navigateTo, setResetPassword, orderNotes, setOrders, handleRejectOrder, barcodeProductSku, setEnteredEmailOtp, setIsEditingProduct, setBulkLog, isMobileMenuOpen, resetOtp, productWizardStep, setCustomDates, setConfirmPassword, isGstinVerified, bulkCsvFile, setAddress, storeLogo, handleProfileSubmit, setPhoneOtpSent, setOrderNotes, handleDeleteProduct, setWallet, policyAccepted, emailOtpSent, setResetOtpSent, setGstin, phoneOtpSent, showLoginPass, showSignupConfirmPass, setPhoneVerified, aadharFile, setDateFilter, activeTab, computeRealtimeMetrics, setIsParsingBulk, handleLogout, panS3Key, setCurrentPage, selectedCategories, setEmailOtpSent, showSignupPass, resetEmail, handleLogoChange, dateFilter, setShowSignupPass, businessBio, setWithdrawAmount, phoneVerified, currentPage, setResetOtp, enteredEmailOtp, setEnteredPhoneOtp, setPanFile, setIsSidebarOpen, setSelectedOrderDetail, handleAcceptOrder, saveProfileBackend, supportPhone, handleEditClick, setStoreLogo, setEmail, password, setOtpLoginPhone, bulkLog, businessType, setPanS3Key, setProducts, setSupportEmail, setOtpLoginCode, withdrawAmount, handleSaveProduct, setStoreSlug, setBarcodeProductSku, setProductForm, setBulkZipFile, productFormDetails, setIsProfileComplete, otpLoginPhone, orders, setActiveTab, bulkZipFile, isSidebarOpen, setBarcodeGenerated, setBusinessType, handleReturnAction, setSupportPhone, barcodeGenerated, products, productForm, setProductWizardStep, resetOtpSent, emailVerified, panFile, isParsingBulk, setDashTab, setReturns, setPassword, handleWithdrawRequest, uploadDocument, setPolicyAccepted, isEditingProduct, setIsMobileMenuOpen, isProfileComplete, setSelectedCategories, storeSlug, phone, setPhone, setAadharS3Key, handleVerifyGstin, returns, handleLoginSubmit, setResetEmail, wallet, otpLoginCode, supportEmail
}; };
return ( return (