Demo site #2

Merged
vignesh merged 4 commits from beta into main 2026-09-10 13:13:23 +00:00
30 changed files with 3709 additions and 378 deletions

View file

@ -20,27 +20,19 @@ export class BetaSupplierSiteStack extends cdk.Stack {
encryption: s3.BucketEncryption.S3_MANAGED, encryption: s3.BucketEncryption.S3_MANAGED,
}); });
const ec2Origin = new origins.HttpOrigin('api.tipro.in', { const ec2Origin = new origins.HttpOrigin('api.tradhox.com', {
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY, protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY,
httpPort: 8080, httpPort: 8080,
}); });
// Look up the tipro.in hosted zone // Look up the tradhox.com hosted zone
const zone = route53.HostedZone.fromLookup(this, 'TiproZone', { const zone = route53.HostedZone.fromLookup(this, 'TradhoxZone', {
domainName: 'tipro.in', domainName: 'tradhox.com',
});
// Create Route53 A Record for the EC2 API server
// This allows us to use an IP address indirectly, by mapping api.tipro.in to it.
new route53.ARecord(this, 'ApiRecord', {
recordName: 'api.tipro.in',
target: route53.RecordTarget.fromIpAddresses('16.113.57.127'),
zone
}); });
// Create a certificate in us-east-1 for CloudFront // Create a certificate in us-east-1 for CloudFront
const certificate = new acm.DnsValidatedCertificate(this, 'SiteCertificate', { const certificate = new acm.DnsValidatedCertificate(this, 'SiteCertificate', {
domainName: 'partners.tipro.in', domainName: 'betapartners.tradhox.com',
hostedZone: zone, hostedZone: zone,
region: 'us-east-1', // CloudFront requires certificates to be in us-east-1 region: 'us-east-1', // CloudFront requires certificates to be in us-east-1
}); });
@ -49,7 +41,7 @@ export class BetaSupplierSiteStack extends cdk.Stack {
// origins.S3BucketOrigin.withOriginAccessControl will automatically create an Origin Access Control (OAC) // origins.S3BucketOrigin.withOriginAccessControl will automatically create an Origin Access Control (OAC)
// and update the S3 bucket policy to allow access only from this CloudFront distribution. // and update the S3 bucket policy to allow access only from this CloudFront distribution.
const distribution = new cloudfront.Distribution(this, 'BetaSupplierSiteDistribution', { const distribution = new cloudfront.Distribution(this, 'BetaSupplierSiteDistribution', {
domainNames: ['partners.tipro.in'], domainNames: ['betapartners.tradhox.com'],
certificate: certificate, certificate: certificate,
defaultRootObject: 'index.html', defaultRootObject: 'index.html',
defaultBehavior: { defaultBehavior: {
@ -97,7 +89,7 @@ export class BetaSupplierSiteStack extends cdk.Stack {
// 3. Create Route53 A Record to point to the CloudFront Distribution // 3. Create Route53 A Record to point to the CloudFront Distribution
new route53.ARecord(this, 'SiteAliasRecord', { new route53.ARecord(this, 'SiteAliasRecord', {
recordName: 'partners.tipro.in', recordName: 'betapartners.tradhox.com',
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)), target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
zone zone
}); });

View file

@ -8,8 +8,34 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital,wght@0,400;0,700;1,400&family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<script>
tailwind = {
config: {
theme: {
extend: {
colors: {
brand: {
maroon: '#671B26',
maroonHover: '#52141e',
footerWine: '#791B2C',
cream: '#fbf9f5',
creamDark: '#f2eee6',
navy: '#1B2667',
border: '#e6e1d8'
}
},
fontFamily: {
sans: ['Inter', 'system-ui', '-apple-system', 'Segoe UI', 'Roboto', 'sans-serif']
}
}
}
}
};
</script>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -55,10 +55,9 @@ describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
it('renders landing page with correct primary titles', () => { it('renders landing page with correct primary titles', () => {
render(<App />) render(<App />)
expect(screen.getByText(/The Winter Weaves/i)).toBeInTheDocument() expect(screen.getByText(/Sell Authentic Handcrafted Products Across India & Worldwide/i)).toBeInTheDocument()
expect(screen.getByRole('heading', { name: /^Featured Seller Categories$/i })).toBeInTheDocument()
expect(screen.getByRole('heading', { name: /^Explore by Craft$/i })).toBeInTheDocument()
}) })
it('navigates to Support page and handles contact form submission', () => { it('navigates to Support page and handles contact form submission', () => {
@ -154,4 +153,119 @@ describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
expect(screen.getByText(/Available for Payout/i)).toBeInTheDocument() expect(screen.getByText(/Available for Payout/i)).toBeInTheDocument()
expect(screen.getByText(/Transaction History/i)).toBeInTheDocument() expect(screen.getByText(/Transaction History/i)).toBeInTheDocument()
}) })
it('navigates to How It Works page from landing nav and renders 6-step journey', () => {
render(<App />)
const howItWorksBtn = screen.getAllByRole('button', { name: /^How it works$/i })[0]
fireEvent.click(howItWorksBtn)
expect(screen.getByText(/How it works — The Seller Journey/i)).toBeInTheDocument()
expect(screen.getByText(/The 6-Step Journey/i)).toBeInTheDocument()
expect(screen.getByText(/Guaranteed 7-Day Payouts/i)).toBeInTheDocument()
})
it('navigates to Pricing page and calculates artisan net payout correctly', () => {
render(<App />)
const pricingBtn = screen.getAllByRole('button', { name: /^Pricing$/i })[0]
fireEvent.click(pricingBtn)
expect(screen.getByText(/Transparent Pricing Built Solely for Maker Prosperity/i)).toBeInTheDocument()
expect(screen.getByText(/Estimate Your Net Take-Home Earnings/i)).toBeInTheDocument()
expect(screen.getByText(/Net Bank Payout/i)).toBeInTheDocument()
})
it('navigates to Grow Your Business page and renders growth initiatives', () => {
render(<App />)
const growBtn = screen.getAllByRole('button', { name: /^Grow your business$/i })[0]
fireEvent.click(growBtn)
expect(screen.getByText(/Scale Your Authentic Artisan Brand With Tradhox/i)).toBeInTheDocument()
expect(screen.getByText(/Early Maker Initiative/i)).toBeInTheDocument()
expect(screen.getByText(/Curated Artisan Showcases/i)).toBeInTheDocument()
})
it('progresses through the full 7-step onboarding wizard to Application Submitted', async () => {
render(<App />)
// Sign up to enter wizard
const getStartedBtn = screen.getByText(/^Get started$/i)
fireEvent.click(getStartedBtn)
fireEvent.change(screen.getByPlaceholderText(/Enter your email/i), { target: { value: 'artisan@tradhox.com' } })
fireEvent.change(screen.getByPlaceholderText(/9876543210/i), { target: { value: '9876543210' } })
fireEvent.change(screen.getByPlaceholderText(/Create a password/i), { target: { value: 'artisanPass123' } })
fireEvent.change(screen.getByPlaceholderText(/Repeat your password/i), { target: { value: 'artisanPass123' } })
fireEvent.click(screen.getByLabelText(/I agree to the/i))
const alertMock = vi.spyOn(window, 'alert').mockImplementation(() => {})
fireEvent.click(screen.getByRole('button', { name: /Create Account/i }))
// Now in Step 1 of Onboarding Wizard
expect(await screen.findByText(/Welcome to Tradhox/i)).toBeInTheDocument()
expect(screen.getByText(/Step 1: Account/i)).toBeInTheDocument()
// Step 1 -> Step 2
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 2: Business & GST/i)).toBeInTheDocument()
// Step 2 -> Step 3
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 3: Pickup Address/i)).toBeInTheDocument()
// Step 3 -> Step 4
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 4: Bank Details/i)).toBeInTheDocument()
// Step 4 -> Step 5
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 5: Categories/i)).toBeInTheDocument()
// Select category in Step 5
const categoryCard = screen.getByText(/Handloom & Textiles/i)
fireEvent.click(categoryCard)
// Step 5 -> Step 6
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 6: Products/i)).toBeInTheDocument()
// Step 6 -> Step 7
fireEvent.click(screen.getByRole('button', { name: /Save & Continue/i }))
expect(screen.getByText(/Step 7: Store Profile/i)).toBeInTheDocument()
// Step 7 Submit Application -> Application Submitted confirmation screen
const submitAppBtn = screen.getByRole('button', { name: /Submit Application/i })
fireEvent.click(submitAppBtn)
expect(screen.getByText(/Application submitted!/i)).toBeInTheDocument()
expect(screen.getByText(/What happens next:/i)).toBeInTheDocument()
alertMock.mockRestore()
})
it('allows demo login with any custom email and password without server session', async () => {
const originalFetch = globalThis.fetch
globalThis.fetch = vi.fn().mockRejectedValue(new Error('Server offline'))
render(<App />)
const loginBtn = screen.getByText(/^Login$/i)
fireEvent.click(loginBtn)
const emailInput = screen.getByPlaceholderText(/you@example.com/i)
const passInput = screen.getByPlaceholderText(/••••••••/)
fireEvent.change(emailInput, { target: { value: 'random_artisan_demo@craft.org' } })
fireEvent.change(passInput, { target: { value: 'any_password_123' } })
const submitBtn = screen.getByRole('button', { name: /Sign In/i })
fireEvent.click(submitBtn)
expect(await screen.findByText(/Total Sales/i)).toBeInTheDocument()
globalThis.fetch = originalFetch
})
}) })

View file

@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import { SellerProvider, useSeller } from './context/SellerContext'; import { SellerProvider, useSeller } from './context/SellerContext';
import Header from './components/layout/Header'; import Header from './components/layout/Header';
import Footer from './components/layout/Footer'; import Footer from './components/layout/Footer';
import LandingPage from './components/pages/LandingPage'; import LandingPage from './components/pages/LandingPage';
import HowItWorksPage from './components/pages/HowItWorksPage';
import PricingPage from './components/pages/PricingPage';
import GrowBusinessPage from './components/pages/GrowBusinessPage';
import AboutPage from './components/pages/AboutPage'; import AboutPage from './components/pages/AboutPage';
import ContactPage from './components/pages/ContactPage'; import ContactPage from './components/pages/ContactPage';
import AuthForms from './components/pages/AuthForms'; import AuthForms from './components/pages/AuthForms';
@ -17,12 +19,18 @@ function AppRouter() {
return <DashboardLayout />; return <DashboardLayout />;
} }
if (currentPage === 'home') {
return <LandingPage />;
}
return ( return (
<div className="is-flex is-flex-direction-column" style={{ minHeight: '100vh' }}> <div className="is-flex is-flex-direction-column" style={{ minHeight: '100vh', backgroundColor: 'var(--trad-bg)' }}>
<Header /> <Header />
<main className="is-flex-grow-1"> <main className="is-flex-grow-1">
{currentPage === 'how-it-works' && <HowItWorksPage />}
{currentPage === 'pricing' && <PricingPage />}
{currentPage === 'grow-business' && <GrowBusinessPage />}
{currentPage === 'profile-completion' && <OnboardingWizard />} {currentPage === 'profile-completion' && <OnboardingWizard />}
{currentPage === 'home' && <LandingPage />}
{currentPage === 'about' && <AboutPage />} {currentPage === 'about' && <AboutPage />}
{currentPage === 'contact' && <ContactPage />} {currentPage === 'contact' && <ContactPage />}
{(currentPage === 'login' || currentPage === 'signup') && <AuthForms />} {(currentPage === 'login' || currentPage === 'signup') && <AuthForms />}

View file

@ -1,37 +1,130 @@
import React from 'react'; import React from 'react';
import { useSeller } from '../../context/SellerContext';
export default function Footer() { export default function Footer() {
const { setCurrentPage } = useSeller();
const handleNav = (page: any) => {
setCurrentPage(page);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return ( return (
<footer className="footer has-background-white-bis" style={{ borderTop: '1px solid #dac0c2' }}> <footer className="trad-footer py-6 px-4" style={{ backgroundColor: 'var(--trad-footer-bg)', color: '#ffffff', borderTop: '1px solid #5a1420' }}>
<div className="container" style={{ maxWidth: '1120px' }}> <div className="container is-max-widescreen">
<div className="columns"> <div className="columns is-variable is-6">
{/* Brand & Copyright */} {/* Brand & Mission */}
<div className="column is-4"> <div className="column is-4 trad-footer-brand">
<h2 className="title is-4 has-text-primary mb-3" style={{ fontFamily: 'Libre Caslon Text, serif' }}>Tradhox</h2> <h4 className="font-serif-trad" style={{ color: '#ffffff', fontSize: '1.65rem', fontWeight: 800, letterSpacing: '0.04em', marginBottom: '0.35rem' }}>
<p className="has-text-grey-dark"> TRADHOX
© 2026 Tradhox. Honoring Human Craftsmanship. </h4>
<p style={{ color: '#f5d5d8', fontSize: '0.75rem', textTransform: 'uppercase', letterSpacing: '0.14em', fontWeight: 700, marginBottom: '1rem' }}>
FROM MAKERS TO THE WORLD.
</p>
<p style={{ color: '#e5e2e1', fontSize: '0.9rem', lineHeight: 1.65, maxWidth: '340px' }}>
Empowering verified Indian craftsmanship and creative makers with seamless nationwide commerce, transparent weekly payouts, and cultural storytelling.
</p>
<div className="is-flex is-align-items-center mt-4" style={{ gap: '1rem' }}>
<span className="tag is-dark is-rounded" style={{ backgroundColor: '#57131e', color: '#ffdee2', fontSize: '0.75rem' }}>
<i className="fa-solid fa-shield-halved mr-1"></i> AEO &amp; GI Verified
</span>
<span className="tag is-dark is-rounded" style={{ backgroundColor: '#57131e', color: '#ffdee2', fontSize: '0.75rem' }}>
<i className="fa-solid fa-truck-fast mr-1"></i> 15,000+ Pincodes
</span>
</div>
</div>
{/* Quick Links */}
<div className="column is-2 is-offset-1">
<h5 style={{ color: '#ffffff', fontSize: '0.8rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '1.25rem' }}>
Quick Links
</h5>
<ul style={{ listStyle: 'none', paddingLeft: 0, margin: 0 }}>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('home')}>Home</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('how-it-works')}>How it works</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('pricing')}>Pricing &amp; Fees</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('grow-business')}>Grow your business</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('signup')}>Register as Seller</a>
</li>
</ul>
</div>
{/* Seller Support */}
<div className="column is-2">
<h5 style={{ color: '#ffffff', fontSize: '0.8rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '1.25rem' }}>
Support &amp; Trust
</h5>
<ul style={{ listStyle: 'none', paddingLeft: 0, margin: 0 }}>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('contact')}>Artisan Help Desk</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('about')}>About TRADHOX</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" href="#logistics">Logistics Guidelines</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" href="#gi-tag">GI Craft Certification</a>
</li>
<li className="mb-2">
<a className="trad-footer-link" onClick={() => handleNav('login')}>Seller Login</a>
</li>
</ul>
</div>
{/* Contact & Hours */}
<div className="column is-3">
<h5 style={{ color: '#ffffff', fontSize: '0.8rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '1.25rem' }}>
Artisan Helpline
</h5>
<p style={{ color: '#e5e2e1', fontSize: '0.875rem', marginBottom: '0.5rem' }}>
<i className="fa-solid fa-phone mr-2" style={{ color: '#d8aa76' }}></i> 1800-TRADHOX (Toll-Free)
</p>
<p style={{ color: '#e5e2e1', fontSize: '0.875rem', marginBottom: '0.5rem' }}>
<i className="fa-solid fa-envelope mr-2" style={{ color: '#d8aa76' }}></i> sellers@tradhox.com
</p>
<p style={{ color: '#b9a5a7', fontSize: '0.75rem', marginTop: '0.75rem' }}>
Dedicated support available Mon - Sat: 9:00 AM - 7:00 PM IST
</p> </p>
</div> </div>
</div>
{/* Links 1 */} <hr style={{ backgroundColor: 'rgba(255,255,255,0.12)', margin: '2rem 0 1.5rem 0' }} />
<div className="column is-4">
<ul style={{ listStyle: 'none', marginLeft: 0 }}>
<li className="mb-2"><a href="#" className="has-text-grey-dark hover-text-primary" style={{ transition: 'color 0.2s' }}>Privacy Policy</a></li>
<li><a href="#" className="has-text-grey-dark hover-text-primary" style={{ transition: 'color 0.2s' }}>Terms of Service</a></li>
</ul>
</div>
{/* Links 2 */} <div className="is-flex is-justify-content-between is-align-items-center is-flex-wrap-wrap" style={{ gap: '1rem' }}>
<div className="column is-4"> <p style={{ color: '#c5b7b9', fontSize: '0.82rem', margin: 0 }}>
<ul style={{ listStyle: 'none', marginLeft: 0 }}> © 2026 TRADHOX Central. All rights reserved. Celebrating authentic heritage craft across India.
<li className="mb-2"><a href="#" className="has-text-grey-dark hover-text-primary" style={{ transition: 'color 0.2s' }}>Sustainability Report</a></li> </p>
<li><a href="#" className="has-text-grey-dark hover-text-primary" style={{ transition: 'color 0.2s' }}>Shipping Info</a></li> <div className="is-flex" style={{ gap: '1.5rem' }}>
</ul> <a href="#" className="trad-footer-link" style={{ fontSize: '0.82rem' }}>Privacy Policy</a>
<a href="#" className="trad-footer-link" style={{ fontSize: '0.82rem' }}>Terms of Service</a>
<a href="#" className="trad-footer-link" style={{ fontSize: '0.82rem' }}>Seller Agreement</a>
</div> </div>
</div> </div>
</div> </div>
<style>{` <style>{`
.hover-text-primary:hover { color: var(--bulma-primary) !important; } .trad-footer-link {
color: #e7dcd9 !important;
text-decoration: none;
cursor: pointer;
font-size: 0.875rem;
transition: color 0.15s ease;
}
.trad-footer-link:hover {
color: #ffffff !important;
text-decoration: underline;
}
`}</style> `}</style>
</footer> </footer>
); );

View file

@ -2,87 +2,141 @@ import React from 'react';
import { useSeller } from '../../context/SellerContext'; import { useSeller } from '../../context/SellerContext';
export default function Header() { export default function Header() {
const { currentPage, setCurrentPage, isMobileMenuOpen, setIsMobileMenuOpen } = useSeller(); const { currentPage, setCurrentPage, isMobileMenuOpen, setIsMobileMenuOpen, isProfileComplete } = useSeller();
const handleNav = (page: any) => {
setCurrentPage(page);
setIsMobileMenuOpen(false);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return ( return (
<nav className="navbar has-background-white-bis" style={{ borderBottom: '1px solid #dac0c2' }} role="navigation" aria-label="main navigation"> <header className="trad-header-wrapper" style={{ borderBottom: '1px solid #e7ded9', background: '#ffffff', position: 'sticky', top: 0, zIndex: 90 }}>
<div className="container" style={{ maxWidth: '1120px' }}> <div className="container is-max-widescreen px-4">
<div className="navbar-brand"> <nav className="navbar" role="navigation" aria-label="main navigation" style={{ background: 'transparent', minHeight: '4.25rem' }}>
<a className="navbar-item is-size-4 has-text-primary" style={{ fontFamily: 'Libre Caslon Text, serif', letterSpacing: '-0.02em', fontWeight: 700 }} onClick={() => setCurrentPage('home')}> <div className="navbar-brand is-flex is-align-items-center">
Tradhox
</a>
<a role="button" className={`navbar-burger ${isMobileMenuOpen ? 'is-active' : ''}`} aria-label="menu" aria-expanded="false" onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} style={{ color: 'var(--bulma-primary)' }}>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div className={`navbar-menu ${isMobileMenuOpen ? 'is-active' : ''}`} style={{ backgroundColor: 'transparent' }}>
<div className="navbar-start" style={{ margin: '0 auto', gap: '2rem' }}>
<a <a
className="navbar-item has-text-weight-medium custom-nav-link" className="navbar-item is-clickable is-flex is-align-items-center p-0 mr-5"
onClick={() => setCurrentPage('home')} onClick={() => handleNav('home')}
style={{ color: currentPage === 'home' ? 'var(--bulma-primary)' : '#5f5e5b' }} style={{ textDecoration: 'none' }}
> >
Shop <span className="font-serif-trad has-text-weight-bold" style={{ fontSize: '1.65rem', color: 'var(--trad-maroon)', letterSpacing: '-0.02em' }}>
TRADHOX
</span>
<span className="tag is-rounded ml-2 is-hidden-mobile" style={{ fontSize: '0.65rem', fontWeight: 700, letterSpacing: '0.08em', backgroundColor: '#f5e8e8', color: 'var(--trad-maroon)' }}>
SELLER HUB
</span>
</a> </a>
<a <a
className="navbar-item has-text-weight-medium custom-nav-link" role="button"
onClick={() => setCurrentPage('about')} className={`navbar-burger ${isMobileMenuOpen ? 'is-active' : ''}`}
style={{ color: currentPage === 'about' ? 'var(--bulma-primary)' : '#5f5e5b' }} aria-label="menu"
aria-expanded={isMobileMenuOpen}
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
style={{ color: 'var(--trad-maroon)', marginLeft: 'auto' }}
> >
Our Story <span aria-hidden="true"></span>
</a> <span aria-hidden="true"></span>
<a <span aria-hidden="true"></span>
className="navbar-item has-text-weight-medium custom-nav-link"
onClick={() => setCurrentPage('contact')}
style={{ color: currentPage === 'contact' ? 'var(--bulma-primary)' : '#5f5e5b' }}
>
Contact Us
</a> </a>
</div> </div>
<div className="navbar-end"> <div className={`navbar-menu ${isMobileMenuOpen ? 'is-active' : ''}`} style={{ backgroundColor: isMobileMenuOpen ? '#ffffff' : 'transparent', boxShadow: isMobileMenuOpen ? '0 8px 16px rgba(0,0,0,0.1)' : 'none' }}>
<div className="navbar-item"> <div className="navbar-start is-flex-grow-1 is-justify-content-center" style={{ gap: '1.75rem' }}>
<div className="buttons"> <a
<a className="button is-ghost has-text-weight-semibold" style={{ color: '#5f5e5b' }} onClick={() => setCurrentPage('login')}> className={`navbar-item is-size-6 has-text-weight-semibold trad-nav-item ${currentPage === 'home' ? 'is-active-nav' : ''}`}
Login onClick={() => handleNav('home')}
</a> >
<a className="button is-primary is-outlined has-text-weight-semibold" onClick={() => setCurrentPage('signup')}> Home
Get started </a>
</a> <a
className={`navbar-item is-size-6 has-text-weight-semibold trad-nav-item ${currentPage === 'how-it-works' ? 'is-active-nav' : ''}`}
onClick={() => handleNav('how-it-works')}
>
How it works
</a>
<a
className={`navbar-item is-size-6 has-text-weight-semibold trad-nav-item ${currentPage === 'pricing' ? 'is-active-nav' : ''}`}
onClick={() => handleNav('pricing')}
>
Pricing
</a>
<a
className={`navbar-item is-size-6 has-text-weight-semibold trad-nav-item ${currentPage === 'grow-business' ? 'is-active-nav' : ''}`}
onClick={() => handleNav('grow-business')}
>
Grow your business
</a>
<a
className={`navbar-item is-size-6 has-text-weight-semibold trad-nav-item ${currentPage === 'contact' ? 'is-active-nav' : ''}`}
onClick={() => handleNav('contact')}
>
Contact Us
</a>
</div>
<div className="navbar-end is-flex is-align-items-center">
<div className="navbar-item">
<div className="buttons is-align-items-center mb-0">
{isProfileComplete ? (
<button
className="button is-rounded is-small has-text-weight-bold"
onClick={() => handleNav('dashboard')}
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff' }}
>
<i className="fa-solid fa-gauge-high mr-2"></i> Seller Dashboard
</button>
) : (
<>
<a
className="button is-ghost has-text-weight-bold mr-2"
onClick={() => handleNav('login')}
style={{ color: 'var(--trad-text-main)', textDecoration: 'none' }}
>
Login
</a>
<a
className="button is-rounded has-text-weight-bold px-5"
onClick={() => handleNav('signup')}
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', border: 'none', transition: 'all 0.2s' }}
>
Start Selling
</a>
</>
)}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </nav>
</div> </div>
<style>{` <style>{`
.custom-nav-link { .trad-nav-item {
position: relative; color: #4b4746 !important;
background-color: transparent !important; transition: color 0.15s ease;
background: transparent !important;
} }
.custom-nav-link:hover { .trad-nav-item:hover, .trad-nav-item.is-active-nav {
color: var(--bulma-primary) !important; color: var(--trad-maroon) !important;
} }
.custom-nav-link::after { @media screen and (min-width: 1024px) {
content: ''; .trad-nav-item {
position: absolute; position: relative;
bottom: 0px; padding: 0.5rem 0.25rem;
left: 50%; }
transform: translateX(-50%); .trad-nav-item.is-active-nav::after {
width: 0; content: '';
height: 2px; position: absolute;
background-color: var(--bulma-primary); bottom: 0px;
transition: width 0.3s ease; left: 0;
} right: 0;
.custom-nav-link:hover::after { height: 2px;
width: 80%; background-color: var(--trad-maroon);
}
} }
`}</style> `}</style>
</nav> </header>
); );
} }

View file

@ -0,0 +1,188 @@
import React from 'react';
import { useSeller } from '../../context/SellerContext';
export default function GrowBusinessPage() {
const { setCurrentPage } = useSeller();
const initiatives = [
{
title: 'Curated Artisan Showcases',
tag: 'Marketing',
icon: 'fa-bullhorn',
desc: 'Get featured on festive curation pages (Diwali, Pongal, Handloom Day), thematic catalogs, and heritage story reels distributed to verified buyers.'
},
{
title: 'Craft Analytics & Trends',
tag: 'Intelligence',
icon: 'fa-chart-line',
desc: 'Understand which designs, materials, and colors are trending across metro cities. Optimize your inventory with data-backed demand forecasts.'
},
{
title: '1-on-1 Cluster Mentorship',
tag: 'Support',
icon: 'fa-user-group',
desc: 'Work directly with dedicated craft managers who assist with professional product photography tips, SKU descriptions, and GI certifications.'
},
{
title: 'Safe Storage & Fast Dispatch',
tag: 'Logistics',
icon: 'fa-warehouse',
desc: 'Store inventory in secure regional facilities or dispatch straight from your workshop. Enjoy seamless doorstep pickups covering 15,000+ pin codes.'
},
{
title: 'Global Export Facilitation',
tag: 'Export Ready',
icon: 'fa-earth-americas',
desc: 'Expand your reach to international art lovers and Indian diaspora with simplified customs paperwork and discounted international air freight.'
},
{
title: 'Direct Patron Relationships',
tag: 'Community',
icon: 'fa-comments',
desc: 'Connect your personal story with connoisseurs. Share weaving traditions, generational techniques, and receive custom bespoke craft commissions.'
}
];
return (
<div className="grow-business-page has-background-white-ter" style={{ minHeight: '100vh' }}>
{/* Hero */}
<section className="py-6 px-4" style={{ background: 'linear-gradient(180deg, #f7eeee 0%, #fcf9f8 100%)', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop has-text-centered py-5">
<span className="tag is-rounded is-small mb-3" style={{ backgroundColor: '#f2dede', color: 'var(--trad-maroon)', fontWeight: 700, letterSpacing: '0.08em' }}>
ACCELERATOR &amp; SCALE PROGRAMMES
</span>
<h1 className="title is-1 font-serif-trad mb-4" style={{ color: 'var(--trad-maroon)', fontSize: '2.75rem' }}>
Scale Your Authentic Artisan Brand With Tradhox
</h1>
<p className="subtitle is-5 has-text-grey-dark mx-auto mb-6" style={{ maxWidth: '750px', lineHeight: 1.6 }}>
Unlock tailored marketing campaigns, comprehensive analytics, dedicated maker account mentorship, and streamlined logistics designed specifically for heritage craftsmen, GI-tagged clusters, and regional creators.
</p>
<div className="is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap mb-5" style={{ gap: '1.25rem' }}>
<span className="tag is-light is-rounded has-text-weight-bold" style={{ color: 'var(--trad-maroon)', backgroundColor: '#faeef0' }}>
Zero listing fee · Guaranteed direct payouts
</span>
<span className="tag is-light is-rounded has-text-weight-bold" style={{ color: 'var(--trad-navy)', backgroundColor: '#edf0fb' }}>
Dedicated Maker Mentorship
</span>
<span className="tag is-light is-rounded has-text-weight-bold" style={{ color: 'var(--trad-teal)', backgroundColor: '#edf7f5' }}>
GI &amp; Cluster Certification Support
</span>
</div>
<button
className="button is-large is-rounded has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', border: 'none', boxShadow: '0 8px 24px rgba(103,27,38,0.2)' }}
>
Start Growing Today <i className="fa-solid fa-arrow-right ml-3"></i>
</button>
</div>
</section>
{/* Impact Stats Banner */}
<section className="py-5 px-4" style={{ backgroundColor: '#ffffff', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-widescreen">
<div className="columns is-mobile is-multiline has-text-centered">
<div className="column is-3-desktop is-6-mobile">
<p className="title is-2 mb-1" style={{ color: 'var(--trad-maroon)', fontWeight: 800 }}>Day 1</p>
<p className="has-text-grey is-size-6">Direct Storefront Setup</p>
</div>
<div className="column is-3-desktop is-6-mobile">
<p className="title is-2 mb-1" style={{ color: 'var(--trad-teal)', fontWeight: 800 }}>1-on-1</p>
<p className="has-text-grey is-size-6">Dedicated Craft Mentorship</p>
</div>
<div className="column is-3-desktop is-6-mobile">
<p className="title is-2 mb-1" style={{ color: 'var(--trad-navy)', fontWeight: 800 }}>100%</p>
<p className="has-text-grey is-size-6">Direct Artisan Bank Payouts</p>
</div>
<div className="column is-3-desktop is-6-mobile">
<p className="title is-2 mb-1" style={{ color: 'var(--trad-bronze)', fontWeight: 800 }}>0</p>
<p className="has-text-grey is-size-6">Upfront Setup &amp; Joining Cost</p>
</div>
</div>
</div>
</section>
{/* Growth Initiatives Grid */}
<section className="py-6 px-4">
<div className="container is-max-widescreen">
<div className="has-text-centered mb-6">
<span className="has-text-weight-bold is-uppercase" style={{ color: 'var(--trad-bronze)', letterSpacing: '0.1em', fontSize: '0.85rem' }}>
Specialized Initiatives
</span>
<h2 className="title is-2 font-serif-trad mt-2" style={{ color: 'var(--trad-maroon)' }}>
Every Advantage Built Into Your Storefront
</h2>
<p className="has-text-grey-dark">
From catalog digitisation to global shipping, we provide the infrastructure so authentic traditions thrive.
</p>
</div>
<div className="columns is-multiline">
{initiatives.map((item, i) => (
<div key={i} className="column is-4-desktop is-6-tablet">
<div className="box p-5 is-flex is-flex-direction-column" style={{ height: '100%', borderRadius: '12px', border: '1px solid #e7ded9' }}>
<div className="is-flex is-justify-content-between is-align-items-center mb-3">
<div style={{ width: '40px', height: '40px', borderRadius: '8px', backgroundColor: '#faeef0', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--trad-maroon)', fontSize: '1.15rem' }}>
<i className={`fa-solid ${item.icon}`}></i>
</div>
<span className="tag is-light is-rounded has-text-weight-semibold" style={{ color: 'var(--trad-navy)', backgroundColor: '#edf0fb', fontSize: '0.75rem' }}>
{item.tag}
</span>
</div>
<h3 className="title is-5 mb-2" style={{ color: '#2b2523' }}>
{item.title}
</h3>
<p className="has-text-grey-dark is-size-6" style={{ lineHeight: 1.6 }}>
{item.desc}
</p>
</div>
</div>
))}
</div>
</div>
</section>
{/* Artisan Spotlight Quote */}
<section className="py-6 px-4" style={{ backgroundColor: '#ffffff', borderTop: '1px solid #e7ded9', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop">
<div className="box p-6" style={{ backgroundColor: '#fdf9f7', border: '1px solid #dacfc9', borderRadius: '16px', position: 'relative' }}>
<div className="is-flex is-align-items-center mb-4">
<span className="tag is-rounded is-medium has-text-weight-bold" style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff' }}>
EARLY MAKER INITIATIVE
</span>
</div>
<p className="font-serif-trad is-size-4 mb-4" style={{ color: '#2b2523', fontStyle: 'italic', lineHeight: 1.6 }}>
Be among the first heritage artisan clusters and master makers to launch on Tradhox. Get priority catalog placement, professional storytelling assistance, and zero upfront platform charges from day one.
</p>
<p className="has-text-weight-bold" style={{ color: 'var(--trad-bronze)' }}>
Tradhox Maker Onboarding &amp; Cultural Council
</p>
</div>
</div>
</section>
{/* Bottom CTA */}
<section className="py-6 px-4">
<div className="container is-max-desktop">
<div className="box has-text-centered py-6 px-4" style={{ background: 'linear-gradient(135deg, var(--trad-maroon) 0%, var(--trad-burgundy) 100%)', color: '#ffffff', borderRadius: '16px' }}>
<h2 className="title is-2 font-serif-trad mb-3" style={{ color: '#ffffff' }}>
Take your craft brand to patrons across India and beyond
</h2>
<p className="subtitle is-5 mb-5" style={{ color: '#fad4d8', maxWidth: '600px', margin: '0 auto' }}>
Simple registration. Dedicated onboarding support. Zero upfront fees.
</p>
<button
className="button is-rounded is-large has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: '#ffffff', color: 'var(--trad-maroon)', border: 'none' }}
>
Register as a Maker
</button>
</div>
</div>
</section>
</div>
);
}

View file

@ -0,0 +1,252 @@
import React, { useState } from 'react';
import { useSeller } from '../../context/SellerContext';
export default function HowItWorksPage() {
const { setCurrentPage } = useSeller();
const [activeFaq, setActiveFaq] = useState<number | null>(null);
const steps = [
{
num: 1,
title: 'Create Your Profile',
badge: 'Step 1: Setup',
icon: 'fa-user-check',
desc: 'Register with your mobile number, PAN, and GSTIN (or artisan registration). Set up your unique craft store URL and artisan bio in minutes.'
},
{
num: 2,
title: 'List Your Craft Catalog',
badge: 'Step 2: Showcase',
icon: 'fa-boxes-stacked',
desc: 'Upload high-resolution images, highlight GI tags, artisan technique details, and fair-pricing tiers with zero upfront listing fees.'
},
{
num: 3,
title: 'Receive Customer Orders',
badge: 'Step 3: Alert',
icon: 'fa-bell',
desc: 'Get immediate notifications via SMS, WhatsApp, and your dashboard whenever a customer falls in love with your creation.'
},
{
num: 4,
title: 'Craft Safe Packaging',
badge: 'Step 4: Protect',
icon: 'fa-box-open',
desc: 'Pack your authentic creations securely using standard or eco-friendly materials. Generate and stick the pre-printed courier dispatch label.'
},
{
num: 5,
title: 'Doorstep Courier Pickup',
badge: 'Step 5: Transit',
icon: 'fa-truck-ramp-box',
desc: 'Our certified logistics partners collect the parcels directly from your workshop or home across 15,000+ pin codes in India.'
},
{
num: 6,
title: 'Guaranteed 7-Day Payouts',
badge: 'Step 6: Payout',
icon: 'fa-indian-rupee-sign',
desc: 'Receive 100% direct bank deposits for every delivered order within 7 days. Full transparency, zero hidden commission deductions.'
}
];
const faqs = [
{
q: 'Do I need a GST number to sell on Tradhox?',
a: 'If you sell within the state (intra-state) under current government threshold exemptions for small artisans and handicraft makers, enrollment IDs may qualify. For pan-India shipping, a GST number is recommended and our team assists with quick registration.'
},
{
q: 'How does pickup work from remote artisan villages?',
a: 'We partner with Indias leading logistics providers reaching over 15,000 pin codes. If your village has courier accessibility, pickups are scheduled at your doorstep.'
},
{
q: 'When and how do I receive money for my sales?',
a: 'Payouts are transferred directly into your verified bank account via NEFT/IMPS within 7 business days after customer delivery is confirmed.'
},
{
q: 'Are there any registration or listing fees?',
a: 'None! Tradhox has zero registration fees and zero listing fees. You only pay a transparent marketplace fee when your product actually sells.'
}
];
return (
<div className="how-it-works-page has-background-white-ter" style={{ minHeight: '100vh' }}>
{/* Hero Section */}
<section className="py-6 px-4" style={{ background: 'linear-gradient(180deg, #f7eeee 0%, #fcf9f8 100%)', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop has-text-centered py-5">
<span className="tag is-rounded is-small mb-3" style={{ backgroundColor: '#f2dede', color: 'var(--trad-maroon)', fontWeight: 700, letterSpacing: '0.08em' }}>
EMPOWERING INDIAN ARTISANS
</span>
<h1 className="title is-1 font-serif-trad mb-4" style={{ color: 'var(--trad-maroon)', fontSize: '2.75rem' }}>
How it works The Seller Journey
</h1>
<p className="subtitle is-5 has-text-grey-dark mx-auto mb-6" style={{ maxWidth: '720px', lineHeight: 1.6 }}>
A transparent, step-by-step pathway empowering verified Indian craftsmen and creative masters to showcase heritage artistry, fulfill orders effortlessly, and reach patrons nationwide.
</p>
<div className="is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap mb-5" style={{ gap: '1.5rem' }}>
<span className="has-text-weight-semibold" style={{ color: '#4a4543' }}>
<i className="fa-solid fa-circle-check mr-2" style={{ color: 'var(--trad-teal)' }}></i> Zero Listing Fees
</span>
<span className="has-text-grey-light"></span>
<span className="has-text-weight-semibold" style={{ color: '#4a4543' }}>
<i className="fa-solid fa-circle-check mr-2" style={{ color: 'var(--trad-teal)' }}></i> 7-Day Direct Payouts
</span>
<span className="has-text-grey-light"></span>
<span className="has-text-weight-semibold" style={{ color: '#4a4543' }}>
<i className="fa-solid fa-circle-check mr-2" style={{ color: 'var(--trad-teal)' }}></i> 15,000+ Pin Codes Pickup
</span>
</div>
<div>
<button
className="button is-large is-rounded has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', border: 'none', boxShadow: '0 8px 24px rgba(103,27,38,0.2)' }}
>
Register as a seller <i className="fa-solid fa-arrow-right ml-3"></i>
</button>
</div>
</div>
</section>
{/* 6-Step Journey Grid */}
<section className="py-6 px-4">
<div className="container is-max-widescreen">
<div className="has-text-centered mb-6">
<span className="has-text-weight-bold is-uppercase" style={{ color: 'var(--trad-bronze)', letterSpacing: '0.1em', fontSize: '0.85rem' }}>
The 6-Step Journey
</span>
<h2 className="title is-2 font-serif-trad mt-2" style={{ color: 'var(--trad-maroon)' }}>
From artisan workshop to nationwide doorstep delivery
</h2>
</div>
<div className="columns is-multiline">
{steps.map((step) => (
<div key={step.num} className="column is-4-desktop is-6-tablet">
<div className="box p-5 is-flex is-flex-direction-column" style={{ height: '100%', borderRadius: '12px', border: '1px solid #e7ded9', boxShadow: '0 4px 14px rgba(0,0,0,0.03)' }}>
<div className="is-flex is-justify-content-between is-align-items-center mb-4">
<span className="trad-badge-step is-active" style={{ fontSize: '1.1rem' }}>
{step.num}
</span>
<span className="tag is-light is-rounded has-text-weight-semibold" style={{ color: 'var(--trad-maroon)', backgroundColor: '#faeef0' }}>
{step.badge}
</span>
</div>
<h3 className="title is-4 mb-3" style={{ color: '#2b2523' }}>
{step.title}
</h3>
<p className="has-text-grey-dark is-size-6" style={{ lineHeight: 1.6 }}>
{step.desc}
</p>
</div>
</div>
))}
</div>
</div>
</section>
{/* Logistics & Support Highlight */}
<section className="py-6 px-4" style={{ backgroundColor: '#ffffff', borderTop: '1px solid #e7ded9', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop">
<div className="columns is-vcentered">
<div className="column is-6">
<span className="tag is-warning is-light is-rounded has-text-weight-bold mb-3">
ARTISAN FIRST LOGISTICS
</span>
<h2 className="title is-2 font-serif-trad mb-4" style={{ color: 'var(--trad-maroon)' }}>
We handle the heavy lifting, so you can focus on your craft.
</h2>
<p className="has-text-grey-dark mb-4" style={{ lineHeight: 1.7 }}>
Traditional handlooms and handicraft items require careful transit. Tradhox works closely with certified regional partners who know how to protect fragile clay, delicate silk, and intricate woodwork.
</p>
<ul style={{ listStyle: 'none', paddingLeft: 0 }}>
<li className="mb-3 is-flex is-align-items-center">
<i className="fa-solid fa-circle-check mr-3" style={{ color: 'var(--trad-teal)' }}></i>
<span>Automated tracking links sent to your patrons</span>
</li>
<li className="mb-3 is-flex is-align-items-center">
<i className="fa-solid fa-circle-check mr-3" style={{ color: 'var(--trad-teal)' }}></i>
<span>Zero fines for delayed dispatches due to seasonal weather</span>
</li>
<li className="mb-3 is-flex is-align-items-center">
<i className="fa-solid fa-circle-check mr-3" style={{ color: 'var(--trad-teal)' }}></i>
<span>Free doorstep return inspection to protect maker goods</span>
</li>
</ul>
</div>
<div className="column is-6">
<div className="box p-5" style={{ backgroundColor: '#fdf9f7', border: '1px solid #dacfc9', borderRadius: '12px' }}>
<h4 className="title is-4 mb-4" style={{ color: 'var(--trad-navy)' }}>
<i className="fa-solid fa-hand-holding-heart mr-2" style={{ color: 'var(--trad-maroon)' }}></i>
Maker Support Pledge
</h4>
<p className="is-size-6 mb-4 has-text-grey-dark">
Need help taking catalog photos or writing your story? Our regional field coordinators visit artisan clusters across Rajasthan, Bengal, Tamil Nadu, and UP to help you digitize.
</p>
<div className="notification is-light p-3" style={{ backgroundColor: '#ffffff', border: '1px solid #e7ded9' }}>
<p className="is-size-7 has-text-weight-semibold" style={{ color: 'var(--trad-maroon)' }}>
<i className="fa-solid fa-phone mr-1"></i> Dedicated Maker Helpline: 1800-TRADHOX
</p>
</div>
</div>
</div>
</div>
</div>
</section>
{/* FAQ Section */}
<section className="py-6 px-4">
<div className="container is-max-desktop">
<div className="has-text-centered mb-6">
<span className="has-text-weight-bold is-uppercase" style={{ color: 'var(--trad-bronze)', letterSpacing: '0.1em', fontSize: '0.85rem' }}>
Got Questions?
</span>
<h2 className="title is-2 font-serif-trad mt-2" style={{ color: 'var(--trad-maroon)' }}>
Frequently Asked Questions
</h2>
</div>
<div className="faq-list">
{faqs.map((faq, i) => (
<div key={i} className="box mb-4 p-5" style={{ border: '1px solid #e7ded9', borderRadius: '8px' }}>
<div
className="is-flex is-justify-content-between is-align-items-center is-clickable"
onClick={() => setActiveFaq(activeFaq === i ? null : i)}
>
<h4 className="title is-5 mb-0" style={{ color: '#2b2523' }}>
{faq.q}
</h4>
<i className={`fa-solid ${activeFaq === i ? 'fa-chevron-up' : 'fa-chevron-down'}`} style={{ color: 'var(--trad-maroon)' }}></i>
</div>
{activeFaq === i && (
<p className="mt-4 has-text-grey-dark is-size-6" style={{ lineHeight: 1.6 }}>
{faq.a}
</p>
)}
</div>
))}
</div>
{/* CTA Banner */}
<div className="box has-text-centered py-6 px-4 mt-6" style={{ background: 'linear-gradient(135deg, var(--trad-maroon) 0%, var(--trad-burgundy) 100%)', color: '#ffffff', borderRadius: '16px' }}>
<h2 className="title is-2 font-serif-trad mb-3" style={{ color: '#ffffff' }}>
Ready to introduce your craft to the world?
</h2>
<p className="subtitle is-5 mb-5" style={{ color: '#fad4d8', maxWidth: '600px', margin: '0 auto' }}>
Join thousands of Indian artisans and heritage makers expanding their livelihood through Tradhox.
</p>
<button
className="button is-rounded is-large has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: '#ffffff', color: 'var(--trad-maroon)', border: 'none' }}
>
Start Selling Today
</button>
</div>
</div>
</section>
</div>
);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,296 @@
import React, { useState } from 'react';
import { useSeller } from '../../context/SellerContext';
export default function LoginPage() {
const {
email, setEmail,
password, setPassword,
phone, setPhone,
handleLoginSubmit,
showLoginPass, setShowLoginPass,
setCurrentPage,
} = useSeller();
const [activeTab, setActiveTab] = useState<'email' | 'otp'>('email');
const [otpSent, setOtpSent] = useState(false);
const [enteredOtp, setEnteredOtp] = useState('');
const [rememberMe, setRememberMe] = useState(true);
const handleSendOtp = () => {
if (!phone || phone.length < 10) {
alert('Please enter a valid 10-digit mobile number');
return;
}
setOtpSent(true);
alert(`OTP 123456 sent to +91 ${phone}`);
};
const handleOtpLogin = (e: React.FormEvent) => {
e.preventDefault();
if (!enteredOtp) {
alert('Please enter the OTP');
return;
}
// Simulate login
handleLoginSubmit(e);
};
return (
<div className="seller-login-page py-6 px-4" style={{ minHeight: 'calc(100vh - 120px)', backgroundColor: 'var(--trad-bg)', display: 'flex', alignItems: 'center' }}>
<div className="container is-max-desktop">
<div className="box p-0 overflow-hidden" style={{ borderRadius: '16px', border: '1px solid #e7ded9', boxShadow: '0 8px 30px rgba(103,27,38,0.08)' }}>
<div className="columns is-gapless mb-0">
{/* Left Column: Artisan Branding Panel */}
<div className="column is-5 is-hidden-touch p-6 is-flex is-flex-direction-column is-justify-content-between" style={{ background: 'linear-gradient(135deg, var(--trad-maroon) 0%, var(--trad-burgundy) 100%)', color: '#ffffff' }}>
<div>
<span className="tag is-rounded is-small mb-4" style={{ backgroundColor: 'rgba(255,255,255,0.15)', color: '#ffffff', fontWeight: 700, letterSpacing: '0.08em' }}>
SELLER HUB
</span>
<h2 className="title is-2 font-serif-trad mb-4" style={{ color: '#ffffff', lineHeight: 1.3 }}>
Beginning our journey to connect authentic Indian artisans with the world.
</h2>
<p className="subtitle is-6 mb-6" style={{ color: '#fed7db', lineHeight: 1.6 }}>
Direct access to manage orders, inventory, weekly settlements, and cultural storytelling from one verified portal.
</p>
<div className="value-props mt-4">
<div className="is-flex is-align-items-center mb-4">
<div style={{ width: '28px', height: '28px', borderRadius: '50%', backgroundColor: 'rgba(255,255,255,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginRight: '12px' }}>
<i className="fa-solid fa-check" style={{ color: '#ffffff', fontSize: '0.8rem' }}></i>
</div>
<span className="is-size-6 has-text-weight-medium">Zero registration &amp; zero listing fees</span>
</div>
<div className="is-flex is-align-items-center mb-4">
<div style={{ width: '28px', height: '28px', borderRadius: '50%', backgroundColor: 'rgba(255,255,255,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginRight: '12px' }}>
<i className="fa-solid fa-check" style={{ color: '#ffffff', fontSize: '0.8rem' }}></i>
</div>
<span className="is-size-6 has-text-weight-medium">100% direct bank payouts on schedule</span>
</div>
<div className="is-flex is-align-items-center mb-4">
<div style={{ width: '28px', height: '28px', borderRadius: '50%', backgroundColor: 'rgba(255,255,255,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginRight: '12px' }}>
<i className="fa-solid fa-check" style={{ color: '#ffffff', fontSize: '0.8rem' }}></i>
</div>
<span className="is-size-6 has-text-weight-medium">Pan-India delivery covering 15,000+ pin codes</span>
</div>
</div>
</div>
<div className="mt-6 pt-4" style={{ borderTop: '1px solid rgba(255,255,255,0.15)' }}>
<p className="is-size-7" style={{ color: 'rgba(255,255,255,0.7)' }}>
Protected by 256-bit SSL encryption &amp; AEO certification standards.
</p>
</div>
</div>
{/* Right Column: Login Forms */}
<div className="column is-7 p-6 has-background-white is-flex is-flex-direction-column is-justify-content-center">
<div className="mb-5">
<span className="has-text-weight-bold is-uppercase" style={{ color: 'var(--trad-bronze)', letterSpacing: '0.1em', fontSize: '0.75rem' }}>
Seller ID Portal
</span>
<h1 className="title is-3 font-serif-trad mt-1 mb-2" style={{ color: 'var(--trad-maroon)' }}>
Welcome back, Maker
</h1>
<p className="has-text-grey is-size-6">
Access your dashboard, manage orders, and grow your authentic craft brand.
</p>
</div>
{/* Login Method Tabs */}
<div className="tabs is-boxed mb-5">
<ul style={{ borderBottomColor: '#e7ded9' }}>
<li className={activeTab === 'email' ? 'is-active' : ''}>
<a onClick={() => setActiveTab('email')} className="has-text-weight-semibold">
<i className="fa-solid fa-envelope mr-2"></i> Email &amp; Password
</a>
</li>
<li className={activeTab === 'otp' ? 'is-active' : ''}>
<a onClick={() => setActiveTab('otp')} className="has-text-weight-semibold">
<i className="fa-solid fa-mobile-screen mr-2"></i> Mobile OTP Login
</a>
</li>
</ul>
</div>
{/* Tab 1: Email & Password Form */}
{activeTab === 'email' ? (
<form onSubmit={handleLoginSubmit}>
<div className="field mb-4">
<label className="label is-size-7 is-uppercase has-text-grey" htmlFor="seller-email">
Registered Email Address
</label>
<div className="control has-icons-left">
<input
id="seller-email"
type="text"
className="input"
placeholder="you@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
style={{ borderColor: '#e7ded9', borderRadius: '8px' }}
/>
<span className="icon is-left has-text-grey">
<i className="fa-solid fa-envelope"></i>
</span>
</div>
</div>
<div className="field mb-4">
<div className="is-flex is-justify-content-between is-align-items-center mb-1">
<label className="label is-size-7 is-uppercase has-text-grey mb-0" htmlFor="seller-pass">
Password
</label>
<a href="#" className="is-size-7 has-text-weight-semibold" style={{ color: 'var(--trad-maroon)', textDecoration: 'none' }}>
Forgot password?
</a>
</div>
<div className="control has-icons-left has-icons-right">
<input
id="seller-pass"
type={showLoginPass ? 'text' : 'password'}
className="input"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
style={{ borderColor: '#e7ded9', borderRadius: '8px' }}
/>
<span className="icon is-left has-text-grey">
<i className="fa-solid fa-lock"></i>
</span>
<span
className="icon is-right is-clickable"
onClick={() => setShowLoginPass(!showLoginPass)}
style={{ pointerEvents: 'all' }}
>
<i className={`fa-solid ${showLoginPass ? 'fa-eye-slash' : 'fa-eye'}`}></i>
</span>
</div>
</div>
<div className="field mb-5">
<div className="control">
<label className="checkbox is-size-7 has-text-grey is-flex is-align-items-center">
<input
type="checkbox"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="mr-2"
style={{ accentColor: 'var(--trad-maroon)' }}
/>
Remember this device for 30 days
</label>
</div>
</div>
<button
type="submit"
className="button is-fullwidth has-text-weight-bold mb-4"
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', borderRadius: '8px', padding: '0.75rem', height: 'auto' }}
>
Sign In
</button>
</form>
) : (
/* Tab 2: Mobile OTP Form */
<form onSubmit={handleOtpLogin}>
<div className="field mb-4">
<label className="label is-size-7 is-uppercase has-text-grey">
Registered Mobile Number
</label>
<div className="field has-addons">
<p className="control">
<a className="button is-static" style={{ borderColor: '#e7ded9', borderRadius: '8px 0 0 8px' }}>
<span className="has-text-weight-bold mr-1">IN</span> +91
</a>
</p>
<p className="control is-expanded">
<input
type="tel"
className="input"
placeholder="e.g. 9876543210"
maxLength={10}
value={phone}
onChange={(e) => setPhone(e.target.value)}
style={{ borderColor: '#e7ded9' }}
/>
</p>
<p className="control">
<button
type="button"
className="button has-text-weight-semibold"
onClick={handleSendOtp}
style={{ backgroundColor: '#faeef0', color: 'var(--trad-maroon)', borderColor: '#e7ded9', borderRadius: '0 8px 8px 0' }}
>
{otpSent ? 'Resend OTP' : 'Get OTP'}
</button>
</p>
</div>
<p className="help has-text-grey">A 6-digit verification code will be sent via SMS.</p>
</div>
{otpSent && (
<div className="field mb-5">
<label className="label is-size-7 is-uppercase has-text-grey">
Enter 6-digit OTP
</label>
<div className="control has-icons-left">
<input
type="text"
className="input"
placeholder="123456"
maxLength={6}
value={enteredOtp}
onChange={(e) => setEnteredOtp(e.target.value)}
style={{ borderColor: '#e7ded9', borderRadius: '8px' }}
/>
<span className="icon is-left has-text-grey">
<i className="fa-solid fa-key"></i>
</span>
</div>
</div>
)}
<button
type="submit"
className="button is-fullwidth has-text-weight-bold mb-4"
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', borderRadius: '8px', padding: '0.75rem', height: 'auto' }}
>
Log In to Seller Hub
</button>
</form>
)}
<div className="has-text-centered mt-4 pt-4" style={{ borderTop: '1px solid #e7ded9' }}>
<p className="is-size-6 has-text-grey">
Don't have a seller account yet?{' '}
<a
className="has-text-weight-bold is-clickable"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ color: 'var(--trad-maroon)' }}
>
Register as a seller
</a>
</p>
</div>
{/* Trust badges footer */}
<div className="is-flex is-justify-content-center is-align-items-center mt-5 pt-3" style={{ gap: '1.25rem' }}>
<span className="is-size-7 has-text-grey">
<i className="fa-solid fa-lock mr-1" style={{ color: 'var(--trad-teal)' }}></i> SSL Bank Encryption
</span>
<span className="is-size-7 has-text-grey"></span>
<span className="is-size-7 has-text-grey">
<i className="fa-solid fa-certificate mr-1" style={{ color: 'var(--trad-bronze)' }}></i> GI Verified Artisans
</span>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,265 @@
import React, { useState } from 'react';
import { useSeller } from '../../context/SellerContext';
export default function PricingPage() {
const { setCurrentPage } = useSeller();
const [calcPrice, setCalcPrice] = useState<number>(1500);
const [isGiTagged, setIsGiTagged] = useState<boolean>(true);
// Commission is 5% for GI-tagged/artisan heritage, 8% for standard handmade
const commissionRate = isGiTagged ? 0.05 : 0.08;
const commission = Math.round(calcPrice * commissionRate);
const paymentGatewayFee = Math.round(calcPrice * 0.015);
const netEarnings = Math.max(0, calcPrice - commission - paymentGatewayFee);
const pillars = [
{
title: 'No registration fee',
desc: 'Start your digital seller journey completely free. We provide seamless Aadhaar and artisan cluster onboarding without subscription charges.',
badge: '₹0 Upfront Cost',
icon: 'fa-id-card'
},
{
title: 'No listing fee',
desc: 'Publish your full catalog of authentic handmade creations with zero upfront slot or cataloging charges. All verified artisan products receive equal organic discovery.',
badge: 'Unlimited Listings',
icon: 'fa-tags'
},
{
title: 'No hidden deductions',
desc: 'Every rupee earned on your verified craft is safeguarded. We guarantee zero hidden deductions with a 100% transparent split on every order.',
badge: '100% Transparent',
icon: 'fa-file-invoice-dollar'
},
{
title: 'Fast 7-day settlement',
desc: 'Receive accelerated disbursements directly into your registered bank account as soon as your craft reaches the customer, keeping your working capital fluid.',
badge: 'Weekly Direct NEFT',
icon: 'fa-bolt-lightning'
},
{
title: 'No penalization fees',
desc: 'A maker-first community that supports craftsmanship rather than imposing arbitrary SLAs or algorithmic penalty deductions for artisan lead times.',
badge: 'Artisan Protected',
icon: 'fa-heart-circle-check'
}
];
return (
<div className="pricing-page has-background-white-ter" style={{ minHeight: '100vh' }}>
{/* Hero */}
<section className="py-6 px-4" style={{ background: 'linear-gradient(180deg, #f7eeee 0%, #fcf9f8 100%)', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop has-text-centered py-5">
<span className="tag is-rounded is-small mb-3" style={{ backgroundColor: '#f2dede', color: 'var(--trad-maroon)', fontWeight: 700, letterSpacing: '0.08em' }}>
TRANSPARENT ARTISAN COMMERCE
</span>
<h1 className="title is-1 font-serif-trad mb-4" style={{ color: 'var(--trad-maroon)', fontSize: '2.75rem' }}>
Transparent Pricing Built Solely for Maker Prosperity
</h1>
<p className="subtitle is-5 has-text-grey-dark mx-auto mb-6" style={{ maxWidth: '750px', lineHeight: 1.6 }}>
Empowering traditional artisans, GI-tagged clusters, and direct creators across India with 100% transparent fee structures, zero upfront charges, and guaranteed weekly bank payouts.
</p>
<button
className="button is-large is-rounded has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: 'var(--trad-maroon)', color: '#ffffff', border: 'none', boxShadow: '0 8px 24px rgba(103,27,38,0.2)' }}
>
Register as a seller <i className="fa-solid fa-arrow-right ml-3"></i>
</button>
</div>
</section>
{/* 5 Core Pillars */}
<section className="py-6 px-4">
<div className="container is-max-widescreen">
<div className="has-text-centered mb-6">
<h2 className="title is-2 font-serif-trad" style={{ color: 'var(--trad-maroon)' }}>
Zero Upfront Costs. Only Pay When You Sell.
</h2>
<p className="has-text-grey-dark">
Traditional marketplaces charge heavy listing and membership fees. Tradhox changes the rules for India's creators.
</p>
</div>
<div className="columns is-multiline">
{pillars.map((p, i) => (
<div key={i} className="column is-4-desktop is-6-tablet">
<div className="box p-5 is-flex is-flex-direction-column" style={{ height: '100%', borderRadius: '12px', border: '1px solid #e7ded9' }}>
<div className="is-flex is-justify-content-between is-align-items-center mb-4">
<div style={{ width: '42px', height: '42px', borderRadius: '10px', backgroundColor: '#faeef0', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--trad-maroon)', fontSize: '1.25rem' }}>
<i className={`fa-solid ${p.icon}`}></i>
</div>
<span className="tag is-success is-light is-rounded has-text-weight-bold" style={{ fontSize: '0.75rem' }}>
{p.badge}
</span>
</div>
<h3 className="title is-5 mb-2" style={{ color: '#2b2523' }}>
{p.title}
</h3>
<p className="has-text-grey-dark is-size-6" style={{ lineHeight: 1.6 }}>
{p.desc}
</p>
</div>
</div>
))}
</div>
</div>
</section>
{/* Interactive Fee & Payout Calculator */}
<section className="py-6 px-4" style={{ backgroundColor: '#ffffff', borderTop: '1px solid #e7ded9', borderBottom: '1px solid #e7ded9' }}>
<div className="container is-max-desktop">
<div className="has-text-centered mb-5">
<span className="tag is-warning is-light is-rounded has-text-weight-bold mb-2">
ARTISAN PROFIT CALCULATOR
</span>
<h2 className="title is-2 font-serif-trad" style={{ color: 'var(--trad-maroon)' }}>
Estimate Your Net Take-Home Earnings
</h2>
<p className="has-text-grey-dark">
See the exact transparent fee breakdown on any handcrafted item price.
</p>
</div>
<div className="box p-6" style={{ border: '1px solid #e7ded9', borderRadius: '16px', backgroundColor: '#fcf9f8' }}>
<div className="columns is-vcentered">
<div className="column is-6 pr-5">
<div className="field mb-5">
<label className="label has-text-weight-semibold">Your Product Selling Price ()</label>
<div className="control has-icons-left">
<input
type="number"
className="input is-medium has-text-weight-bold"
value={calcPrice}
onChange={(e) => setCalcPrice(Math.max(0, Number(e.target.value)))}
style={{ borderColor: 'var(--trad-border)' }}
/>
<span className="icon is-left has-text-weight-bold" style={{ color: 'var(--trad-maroon)' }}></span>
</div>
</div>
<div className="field mb-4">
<label className="label has-text-weight-semibold mb-2">Heritage Classification</label>
<div className="control">
<label className="checkbox is-flex is-align-items-center">
<input
type="checkbox"
checked={isGiTagged}
onChange={(e) => setIsGiTagged(e.target.checked)}
className="mr-2"
style={{ accentColor: 'var(--trad-maroon)', transform: 'scale(1.2)' }}
/>
<span className="is-size-6">
GI-Tagged / Artisan Certified (Reduced 5% fee tier)
</span>
</label>
</div>
</div>
<p className="is-size-7 has-text-grey mt-4">
*Standard handmade crafts without GI certification have an 8% flat marketplace platform fee. Payment gateway fee is ~1.5%.
</p>
</div>
<div className="column is-6">
<div className="box p-5" style={{ backgroundColor: '#ffffff', border: '1px solid #e7ded9', borderRadius: '12px' }}>
<h4 className="title is-5 mb-4 has-text-grey-dark">Order Payout Breakdown</h4>
<div className="is-flex is-justify-content-between mb-3">
<span className="has-text-grey">Gross Selling Price:</span>
<span className="has-text-weight-semibold">{calcPrice.toLocaleString('en-IN')}</span>
</div>
<div className="is-flex is-justify-content-between mb-3">
<span className="has-text-grey">
Tradhox Fee ({isGiTagged ? '5% GI Rate' : '8% Standard'}):
</span>
<span className="has-text-danger has-text-weight-semibold">- {commission.toLocaleString('en-IN')}</span>
</div>
<div className="is-flex is-justify-content-between mb-4">
<span className="has-text-grey">Payment Gateway (1.5%):</span>
<span className="has-text-danger has-text-weight-semibold">- {paymentGatewayFee.toLocaleString('en-IN')}</span>
</div>
<hr style={{ margin: '1rem 0', backgroundColor: '#e7ded9' }} />
<div className="is-flex is-justify-content-between is-align-items-center">
<div>
<p className="has-text-weight-bold" style={{ color: 'var(--trad-maroon)', fontSize: '1.25rem' }}>Net Bank Payout</p>
<p className="is-size-7 has-text-grey">Credited in 7 days after delivery</p>
</div>
<span className="has-text-weight-bold" style={{ fontSize: '1.75rem', color: 'var(--trad-teal)' }}>
{netEarnings.toLocaleString('en-IN')}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{/* AEO & Customs Compliance Info */}
<section className="py-6 px-4">
<div className="container is-max-desktop">
<div className="has-text-centered mb-6">
<span className="has-text-weight-bold is-uppercase" style={{ color: 'var(--trad-bronze)', letterSpacing: '0.1em', fontSize: '0.85rem' }}>
Frequently Asked · AEO &amp; Export Compliance
</span>
<h2 className="title is-2 font-serif-trad mt-2" style={{ color: 'var(--trad-maroon)' }}>
AEO, Customs &amp; Seller Pricing Questions
</h2>
</div>
<div className="content">
<div className="box p-5 mb-4" style={{ border: '1px solid #e7ded9' }}>
<h4 className="title is-5 mb-2" style={{ color: 'var(--trad-navy)' }}>
What is Tradhox's AEO (Authorised Economic Operator) framework, and how does it benefit sellers?
</h4>
<p className="has-text-grey-dark">
Tradhox operates under AEO-certified customs and export logistics facilitation. This grants verified Indian artisan goods fast-track export customs clearance, prioritized cargo screening, and zero unexpected customs handling charges on outbound international consignments.
</p>
</div>
<div className="box p-5 mb-4" style={{ border: '1px solid #e7ded9' }}>
<h4 className="title is-5 mb-2" style={{ color: 'var(--trad-navy)' }}>
How does the 7-day settlement cycle work?
</h4>
<p className="has-text-grey-dark">
Once courier delivery is confirmed at the customer doorstep, the return buffer period begins. Payouts are computed automatically and credited via NEFT/RTGS into your registered bank account every Tuesday.
</p>
</div>
<div className="box p-5 mb-4" style={{ border: '1px solid #e7ded9' }}>
<h4 className="title is-5 mb-2" style={{ color: 'var(--trad-navy)' }}>
Do I have to pay for marketing or buyer ads?
</h4>
<p className="has-text-grey-dark">
No. Unlike other platforms where sellers must pay for sponsored slots to be seen, Tradhox gives equal organic showcase to all authentic artisan workshops.
</p>
</div>
</div>
{/* Bottom CTA */}
<div className="box has-text-centered py-6 px-4 mt-6" style={{ background: 'linear-gradient(135deg, var(--trad-maroon) 0%, var(--trad-burgundy) 100%)', color: '#ffffff', borderRadius: '16px' }}>
<h2 className="title is-2 font-serif-trad mb-3" style={{ color: '#ffffff' }}>
Ready to start selling your authentic creations?
</h2>
<p className="subtitle is-5 mb-5" style={{ color: '#fad4d8', maxWidth: '600px', margin: '0 auto' }}>
No upfront charges. No hidden contracts. Just fair craft trade.
</p>
<button
className="button is-rounded is-large has-text-weight-bold px-6"
onClick={() => { setCurrentPage('signup'); window.scrollTo(0, 0); }}
style={{ backgroundColor: '#ffffff', color: 'var(--trad-maroon)', border: 'none' }}
>
Join Tradhox Today
</button>
</div>
</div>
</section>
</div>
);
}

View file

@ -1,7 +1,7 @@
import React, { createContext, useContext, useState, useEffect } from 'react'; import React, { createContext, useContext, useState, useEffect } from 'react';
import { CONFIG, apiFetch } from '../config'; import { CONFIG, apiFetch } from '../config';
type Page = 'home' | 'about' | 'contact' | 'login' | 'signup' | 'profile-completion' | 'confirmation' | 'dashboard' | 'forgot-password' | 'login-otp' | 'welcome-tour'; type Page = 'home' | 'about' | 'contact' | 'login' | 'signup' | 'how-it-works' | 'pricing' | 'grow-business' | 'profile-completion' | 'confirmation' | 'dashboard' | 'forgot-password' | 'login-otp' | 'welcome-tour' | 'application-submitted';
type DashboardTab = 'overview' | 'products' | 'orders' | 'returns' | 'wallet' | 'settings' | 'barcode-generator' | 'analytics'; type DashboardTab = 'overview' | 'products' | 'orders' | 'returns' | 'wallet' | 'settings' | 'barcode-generator' | 'analytics';
type DateFilter = 'year' | 'week' | 'day' | 'custom'; type DateFilter = 'year' | 'week' | 'day' | 'custom';
@ -82,7 +82,40 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const [supportPhone, setSupportPhone] = useState('') const [supportPhone, setSupportPhone] = useState('')
const [selectedCategories, setSelectedCategories] = useState<string[]>([]) const [selectedCategories, setSelectedCategories] = useState<string[]>([])
// Step 3: Store and Location details // 7-step onboarding state
const [onboardingStep, setOnboardingStep] = useState<number>(1)
const [applicationId, setApplicationId] = useState<string>('TRD-' + Math.floor(100000 + Math.random() * 900000))
const [bankDetails, setBankDetails] = useState({
accountHolderName: '',
accountNumber: '',
confirmAccountNumber: '',
ifscCode: '',
bankName: '',
branchName: '',
accountType: 'Current'
})
const [pickupAddress, setPickupAddress] = useState({
buildingName: '',
street: '123 Handloom Lane',
landmark: '',
city: 'Textile Town',
state: 'Karnataka',
pincode: '560001',
contactPerson: '',
contactPhone: ''
})
const [initialProduct, setInitialProduct] = useState({
title: '',
category: 'Handloom & Textiles',
price: '',
stock: '',
description: '',
sku: '',
materials: '',
image: ''
})
// Store and Location details
const [storeName, setStoreName] = useState('My Artisan Handloom') const [storeName, setStoreName] = useState('My Artisan Handloom')
const [storeLogo, setStoreLogo] = useState<string | null>(null) const [storeLogo, setStoreLogo] = useState<string | null>(null)
const [logoS3Key, setLogoS3Key] = useState<string | null>(null) const [logoS3Key, setLogoS3Key] = useState<string | null>(null)
@ -122,10 +155,10 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const [dateFilter, setDateFilter] = useState<DateFilter>('year') const [dateFilter, setDateFilter] = useState<DateFilter>('year')
const [customDates, setCustomDates] = useState({ start: '2026-06-01', end: '2026-06-15' }) const [customDates, setCustomDates] = useState({ start: '2026-06-01', end: '2026-06-15' })
// Lists // Lists with rich default mock data for demo mode
const [products, setProducts] = useState<Product[]>([]) const [products, setProducts] = useState<Product[]>(CONFIG.dashboardData.initialProducts || [])
const [orders, setOrders] = useState<Order[]>([]) const [orders, setOrders] = useState<Order[]>((CONFIG.dashboardData.initialOrders as Order[]) || [])
const [returns, setReturns] = useState<ReturnRequest[]>([]) const [returns, setReturns] = useState<ReturnRequest[]>((CONFIG.dashboardData.initialReturns as ReturnRequest[]) || [])
// Forms & Editing // Forms & Editing
const [productForm, setProductForm] = useState({ const [productForm, setProductForm] = useState({
@ -231,9 +264,8 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
} }
}) })
.catch(err => { .catch(err => {
console.error('Session restore failed:', err); console.warn('Session restore fallback to active demo session:', err);
localStorage.removeItem('access_token') setIsProfileComplete(true);
localStorage.removeItem('refresh_token');
}); });
} }
}, []); }, []);
@ -507,16 +539,28 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
navigateTo('profile-completion') navigateTo('profile-completion')
}) })
}) })
.catch(err => { .catch(() => {
alert(err.message); // Offline / demo fallback
localStorage.setItem('access_token', 'demo_access_token');
navigateTo('profile-completion');
}); });
} }
const handleLoginSubmit = (e: React.FormEvent) => { const handleLoginSubmit = (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
const fallbackDemoLogin = () => {
localStorage.setItem('access_token', 'demo_access_token');
setEmail(email.trim() || 'demo_artisan@tradhox.com');
setPhoneVerified(true);
setEmailVerified(true);
setIsGstinVerified(true);
setIsProfileComplete(true);
navigateTo('dashboard', true);
};
if (!email.trim()) { if (!email.trim()) {
alert('Please enter your email or phone number.'); fallbackDemoLogin();
return; return;
} }
@ -526,7 +570,7 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
body: JSON.stringify({ username: email, password: password }) body: JSON.stringify({ username: email, password: password })
}) })
.then(res => { .then(res => {
if (!res.ok) throw new Error('Invalid credentials.'); if (!res.ok) throw new Error('Demo mode activated.');
return res.json(); return res.json();
}) })
.then(data => { .then(data => {
@ -536,7 +580,7 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const profile = data.user.profile; const profile = data.user.profile;
setPhone(profile.phone || ''); setPhone(profile.phone || '');
setPhoneVerified(profile.phone_verified || false); setPhoneVerified(profile.phone_verified || false);
setEmail(data.user.email || ''); setEmail(data.user.email || email);
setEmailVerified(profile.email_verified || false); setEmailVerified(profile.email_verified || false);
setGstin(profile.gstin || '29AAAAA1111A1Z1'); setGstin(profile.gstin || '29AAAAA1111A1Z1');
setIsGstinVerified(profile.is_gstin_verified || false); setIsGstinVerified(profile.is_gstin_verified || false);
@ -578,8 +622,9 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
navigateTo('profile-completion'); navigateTo('profile-completion');
} }
}) })
.catch(err => { .catch(() => {
alert(err.message); // Backend not running or demo credentials -> seamless fallback to demo dashboard
fallbackDemoLogin();
}); });
} }
@ -621,17 +666,15 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
}); });
}; };
const handleProfileSubmit = (e: React.FormEvent) => { const handleProfileSubmit = (e?: React.FormEvent) => {
e.preventDefault() if (e && typeof e.preventDefault === 'function') {
saveProfileBackend(true) e.preventDefault();
.then(() => { }
setIsProfileComplete(true); return saveProfileBackend(true)
setCurrentPage('dashboard');
})
.catch(err => { .catch(err => {
alert(err.message); alert(err.message);
}); })
} };
// --- Dashboard Logic Actions --- // --- Dashboard Logic Actions ---
@ -824,7 +867,8 @@ 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, isProfileComplete, setSelectedCategories, storeSlug, phone, setPhone, setAadharS3Key, handleVerifyGstin, returns, handleLoginSubmit, setResetEmail, wallet, otpLoginCode, supportEmail, aadharUrl, setAadharUrl, panUrl, setPanUrl 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, aadharUrl, setAadharUrl, panUrl, setPanUrl,
onboardingStep, setOnboardingStep, applicationId, setApplicationId, bankDetails, setBankDetails, pickupAddress, setPickupAddress, initialProduct, setInitialProduct
}; };
return ( return (

View file

@ -1,15 +1,84 @@
@import 'bulma/css/bulma.css'; @import 'bulma/css/bulma.css';
:root { :root {
--bulma-primary-h: 342deg; --trad-maroon: #671B26;
--bulma-primary-s: 95%; --trad-maroon-hover: #52141e;
--bulma-primary-l: 15%; --trad-bronze: #675C1B;
--bulma-primary: #4d0218; --trad-teal: #1B675C;
--bulma-link: #4d0218; --trad-navy: #1B2667;
--bulma-body-background-color: #fbf9f8; --trad-burgundy: #791B2C;
--trad-footer-bg: #791B2C;
--trad-bg: #FCF9F8;
--trad-surface: #ffffff;
--trad-border: #e6ded9;
--trad-text-main: #2b2523;
--trad-text-muted: #6e6561;
--bulma-primary: #671B26;
--bulma-primary-h: 351deg;
--bulma-primary-s: 58%;
--bulma-primary-l: 25%;
--bulma-link: #671B26;
--bulma-body-background-color: #fcf9f8;
--bulma-body-family: 'Plus Jakarta Sans', 'Inter', sans-serif;
} }
[data-theme='light'], :root { [data-theme='light'], :root {
color-scheme: light; color-scheme: light;
--bulma-scheme-main: #fbf9f8; --bulma-scheme-main: #fcf9f8;
}
body {
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background-color: var(--trad-bg);
color: var(--trad-text-main);
}
.font-serif-trad {
font-family: 'Libre Caslon Text', Georgia, serif;
}
.trad-badge-step {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
font-weight: 700;
font-size: 0.9rem;
}
.trad-badge-step.is-active {
background-color: var(--trad-maroon);
color: #fff;
}
.trad-badge-step.is-completed {
background-color: var(--trad-teal);
color: #fff;
}
.trad-badge-step.is-pending {
background-color: #e5dfda;
color: #7a706b;
}
.trad-card-interactive {
transition: all 0.2s ease-in-out;
border: 1px solid var(--trad-border);
background: #fff;
cursor: pointer;
}
.trad-card-interactive:hover {
transform: translateY(-2px);
border-color: var(--trad-maroon);
box-shadow: 0 8px 24px rgba(103, 27, 38, 0.08);
}
.trad-card-interactive.is-selected {
border-color: var(--trad-maroon);
background-color: #fdf5f5;
box-shadow: 0 0 0 2px var(--trad-maroon);
} }