feat: implement responsive auth card layout, password reset page, and update navigation and footer styles
This commit is contained in:
parent
d23ae61c57
commit
208eede1aa
11 changed files with 1039 additions and 157 deletions
BIN
card_inputs_enhanced.png
Normal file
BIN
card_inputs_enhanced.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
card_middle_debug.png
Normal file
BIN
card_middle_debug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
card_step1_debug.png
Normal file
BIN
card_step1_debug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 35 KiB |
|
|
@ -12,6 +12,7 @@ import { HowItWorksPage } from './pages/HowItWorksPage';
|
|||
import { PricingPage } from './pages/PricingPage';
|
||||
import { GrowBusinessPage } from './pages/GrowBusinessPage';
|
||||
import { LoginPage } from './pages/LoginPage';
|
||||
import { ResetPasswordPage } from './pages/ResetPasswordPage';
|
||||
import { OnboardingPage } from './pages/OnboardingPage';
|
||||
|
||||
// Authenticated Seller Central Pages
|
||||
|
|
@ -36,7 +37,7 @@ export const App: React.FC = () => {
|
|||
<Route path="/pricing" element={<PricingPage />} />
|
||||
<Route path="/why-sell" element={<GrowBusinessPage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/reset-password" element={<LoginPage initialMode="reset-password" />} />
|
||||
<Route path="/reset-password" element={<ResetPasswordPage />} />
|
||||
<Route path="/onboarding" element={<OnboardingPage />} />
|
||||
</Route>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,79 +3,79 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
export const Footer: React.FC = () => {
|
||||
return (
|
||||
<footer className="footer pt-6 pb-6" style={{ backgroundColor: '#791B2C', color: '#ffffff' }}>
|
||||
<footer className="footer pt-6 pb-6" style={{ backgroundColor: '#671B26', color: '#ffffff' }}>
|
||||
<div className="container is-widescreen px-4">
|
||||
<div className="columns is-multiline pb-6" style={{ borderBottom: '1px solid rgba(255, 255, 255, 0.2)' }}>
|
||||
<div className="columns is-multiline pb-5">
|
||||
{/* Brand Info */}
|
||||
<div className="column is-6-desktop is-12-tablet mb-4">
|
||||
<div className="is-flex is-align-items-center mb-3">
|
||||
<span className="has-text-weight-black is-size-4 has-text-white" style={{ letterSpacing: '0.05em' }}>
|
||||
<span className="has-text-weight-black is-size-4 has-text-white" style={{ letterSpacing: '0.02em' }}>
|
||||
TRADHOX
|
||||
</span>
|
||||
</div>
|
||||
<p className="is-size-7 font-weight-bold has-text-weight-bold has-text-white-ter mb-2" style={{ letterSpacing: '0.12em', textTransform: 'uppercase' }}>
|
||||
FROM MAKERS TO THE WORLD.
|
||||
<p className="is-size-7 font-weight-bold has-text-weight-bold mb-2" style={{ letterSpacing: '0.12em', textTransform: 'uppercase', color: '#E2BDC4' }}>
|
||||
FROM MAKERS TO THE WORLD
|
||||
</p>
|
||||
<p className="is-size-6" style={{ color: '#EED5D9', maxWidth: '380px', lineHeight: 1.6 }}>
|
||||
Empowering verified Indian craftsmanship and creative makers with seamless nationwide commerce, transparent payouts, and cultural storytelling.
|
||||
<p className="is-size-7" style={{ color: '#E5C3C8', maxWidth: '380px', lineHeight: 1.6 }}>
|
||||
The sovereign digital trade bridge linking India's verified hereditary master artisans directly to ethical world markets.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="column is-2-desktop is-4-tablet is-6-mobile">
|
||||
<div className="column is-2-desktop is-4-tablet is-4-mobile">
|
||||
<h4 className="is-size-7 has-text-weight-bold has-text-white mb-3" style={{ letterSpacing: '0.1em', textTransform: 'uppercase' }}>
|
||||
COMPANY
|
||||
</h4>
|
||||
<ul className="is-size-6" style={{ lineHeight: 2.2 }}>
|
||||
<ul className="is-size-7" style={{ lineHeight: 2.2 }}>
|
||||
<li>
|
||||
<Link to="/how-it-works" style={{ color: '#E5C3C8' }}>About</Link>
|
||||
<Link to="/how-it-works" style={{ color: '#E5C3C8', textDecoration: 'none' }}>About</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/pricing" style={{ color: '#E5C3C8' }}>Contact</Link>
|
||||
<Link to="/pricing" style={{ color: '#E5C3C8', textDecoration: 'none' }}>Contact</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/why-sell" style={{ color: '#E5C3C8' }}>Grow your business</Link>
|
||||
<Link to="/why-sell" style={{ color: '#E5C3C8', textDecoration: 'none' }}>Grow your business</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Policies Links */}
|
||||
<div className="column is-2-desktop is-4-tablet is-6-mobile">
|
||||
<div className="column is-2-desktop is-4-tablet is-4-mobile">
|
||||
<h4 className="is-size-7 has-text-weight-bold has-text-white mb-3" style={{ letterSpacing: '0.1em', textTransform: 'uppercase' }}>
|
||||
POLICIES
|
||||
</h4>
|
||||
<ul className="is-size-6" style={{ lineHeight: 2.2 }}>
|
||||
<ul className="is-size-7" style={{ lineHeight: 2.2 }}>
|
||||
<li>
|
||||
<a href="#privacy" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8' }}>Privacy policy</a>
|
||||
<a href="#privacy" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8', textDecoration: 'none' }}>Privacy policy</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#terms" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8' }}>Terms of service</a>
|
||||
<a href="#terms" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8', textDecoration: 'none' }}>Terms of service</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#seller-agreement" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8' }}>Seller agreement</a>
|
||||
<a href="#seller-agreement" onClick={(e) => e.preventDefault()} style={{ color: '#E5C3C8', textDecoration: 'none' }}>Seller agreement</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Social Handlers */}
|
||||
<div className="column is-2-desktop is-4-tablet is-12-mobile">
|
||||
{/* Social Handlers / Connect */}
|
||||
<div className="column is-2-desktop is-4-tablet is-4-mobile">
|
||||
<h4 className="is-size-7 has-text-weight-bold has-text-white mb-3" style={{ letterSpacing: '0.1em', textTransform: 'uppercase' }}>
|
||||
SOCIAL HANDLERS
|
||||
CONNECT
|
||||
</h4>
|
||||
<ul className="is-size-6" style={{ lineHeight: 2.2 }}>
|
||||
<ul className="is-size-7" style={{ lineHeight: 2.2 }}>
|
||||
<li>
|
||||
<a href="https://instagram.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8' }}>
|
||||
<i className="fa-brands fa-instagram mr-2"></i> Instagram
|
||||
<a href="https://instagram.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8', textDecoration: 'none' }}>
|
||||
Instagram
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://facebook.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8' }}>
|
||||
<i className="fa-brands fa-facebook mr-2"></i> Facebook
|
||||
<a href="https://facebook.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8', textDecoration: 'none' }}>
|
||||
Facebook
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://youtube.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8' }}>
|
||||
<i className="fa-brands fa-youtube mr-2"></i> YouTube
|
||||
<a href="https://youtube.com" target="_blank" rel="noreferrer" style={{ color: '#E5C3C8', textDecoration: 'none' }}>
|
||||
YouTube
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -49,11 +49,14 @@ export const Navbar: React.FC = () => {
|
|||
onClick={closeMenu}
|
||||
style={{ textDecoration: 'none' }}
|
||||
>
|
||||
<span className="has-text-weight-bold is-size-4" style={{ color: 'var(--trad-maroon)', letterSpacing: '-0.03em' }}>
|
||||
<span className="has-text-weight-bold is-size-4" style={{ color: 'var(--trad-maroon)', letterSpacing: '-0.02em', lineHeight: 1 }}>
|
||||
TRADHOX
|
||||
</span>
|
||||
<span className="tag is-trad-wine is-rounded ml-2 is-size-7 is-hidden-touch is-hidden-desktop-only">
|
||||
SELLER CENTRAL
|
||||
<span className="is-hidden-touch is-align-items-center ml-2.5" style={{ display: 'inline-flex', gap: '0.45rem' }}>
|
||||
<span style={{ color: 'var(--trad-maroon)', fontSize: '0.9rem', lineHeight: 1 }}>•</span>
|
||||
<span style={{ color: '#4A5568', fontSize: '0.75rem', fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
|
||||
SELLER CENTRAL
|
||||
</span>
|
||||
</span>
|
||||
</Link>
|
||||
|
||||
|
|
@ -107,9 +110,19 @@ export const Navbar: React.FC = () => {
|
|||
|
||||
<Link
|
||||
to="/onboarding"
|
||||
className="button is-trad-primary px-4"
|
||||
className={`button px-4 ${location.pathname === '/onboarding' ? 'is-outlined' : 'is-trad-primary'}`}
|
||||
onClick={closeMenu}
|
||||
style={{ whiteSpace: 'nowrap', borderRadius: '9999px', fontSize: '0.875rem', fontWeight: 600 }}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
borderRadius: '9999px',
|
||||
fontSize: '0.875rem',
|
||||
fontWeight: 600,
|
||||
...(location.pathname === '/onboarding' ? {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderColor: 'var(--trad-maroon)',
|
||||
color: 'var(--trad-maroon)'
|
||||
} : {})
|
||||
}}
|
||||
>
|
||||
<span>Become a seller</span>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -138,20 +138,12 @@ export const LoginPage: React.FC<LoginPageProps> = ({ initialMode }) => {
|
|||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<div className="is-flex is-flex-direction-column is-flex-direction-row-desktop" style={{ width: '100%' }}>
|
||||
<div className="auth-card-layout">
|
||||
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
{/* LEFT COLUMN: Artisan Story, Image & Guarantee Highlights */}
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
<div
|
||||
className="is-hidden-touch"
|
||||
style={{
|
||||
flex: '0 0 42%',
|
||||
borderRight: '1px solid #EAE5DD',
|
||||
backgroundColor: '#FAF9F6',
|
||||
padding: '2.5rem'
|
||||
}}
|
||||
>
|
||||
<div className="auth-card-left">
|
||||
{mode === 'login' ? (
|
||||
<div>
|
||||
{/* Badge */}
|
||||
|
|
@ -356,14 +348,7 @@ export const LoginPage: React.FC<LoginPageProps> = ({ initialMode }) => {
|
|||
</div>
|
||||
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 auto',
|
||||
padding: 'clamp(1.25rem, 4vw, 3rem)',
|
||||
minWidth: 0,
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<div className="auth-card-right">
|
||||
|
||||
{/* ================================================================ */}
|
||||
{/* VIEW A: LOGIN FORM */}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate, Link } from 'react-router-dom';
|
||||
import { useSeller } from '../context/SellerContext';
|
||||
import {
|
||||
Check,
|
||||
|
|
@ -31,15 +31,37 @@ export const OnboardingPage: React.FC = () => {
|
|||
const navigate = useNavigate();
|
||||
|
||||
const stepLabels = [
|
||||
'Account',
|
||||
'GST & Tax',
|
||||
'Pickup Address',
|
||||
'Bank Account',
|
||||
'Mobile',
|
||||
'Business & GST',
|
||||
'Pickup address',
|
||||
'Bank details',
|
||||
'Categories',
|
||||
'Sample Craft',
|
||||
'Store Profile'
|
||||
'Products',
|
||||
'Store profile'
|
||||
];
|
||||
|
||||
// Step 1 Specific State matching stitch wireframe
|
||||
const [step1Phone, setStep1Phone] = useState(onboarding.phone || '9845012345');
|
||||
const [step1Otp, setStep1Otp] = useState<string[]>(['4', '8', '2', '9', '', '']);
|
||||
const [termsAgreed, setTermsAgreed] = useState(true);
|
||||
const [isPhoneFocused, setIsPhoneFocused] = useState(false);
|
||||
|
||||
const handleStep1OtpChange = (index: number, val: string) => {
|
||||
const clean = val.replace(/[^0-9]/g, '').slice(-1);
|
||||
const newOtp = [...step1Otp];
|
||||
newOtp[index] = clean;
|
||||
setStep1Otp(newOtp);
|
||||
if (clean && index < 5) {
|
||||
document.getElementById(`step1-otp-${index + 1}`)?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleStep1OtpKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Backspace' && !step1Otp[index] && index > 0) {
|
||||
document.getElementById(`step1-otp-${index - 1}`)?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const craftCategoryOptions = [
|
||||
'Handloom & Textiles',
|
||||
'Handmade Pottery & Ceramics',
|
||||
|
|
@ -340,22 +362,63 @@ export const OnboardingPage: React.FC = () => {
|
|||
);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------
|
||||
Render Onboarding Wizard (Steps 1 to 7)
|
||||
---------------------------------------------------- */
|
||||
/* ----------------------------------------------------
|
||||
Render Onboarding Wizard (Steps 1 to 7)
|
||||
---------------------------------------------------- */
|
||||
return (
|
||||
<div className="section py-4 py-6-tablet">
|
||||
<div className="section py-5 py-6-tablet" style={{ backgroundColor: '#FCF9F8', minHeight: 'calc(100vh - 80px)' }}>
|
||||
<div className="container is-widescreen px-3 px-4-tablet">
|
||||
{/* Wizard Header */}
|
||||
<div className="has-text-centered mb-4 mb-5-tablet">
|
||||
<span className="tag is-trad-wine is-rounded mb-2">Seller Registration Wizard</span>
|
||||
<h1 className="title is-size-4-mobile is-size-3-tablet is-size-2-desktop mb-2">Setup Your Artisan Workshop</h1>
|
||||
<p className="subtitle is-size-7-mobile is-size-6-tablet has-text-grey">Step {onboardingStep} of 7: {stepLabels[onboardingStep - 1]}</p>
|
||||
|
||||
{/* Page Hero Header matching stitch screen */}
|
||||
<div className="mb-5 mb-6-tablet" style={{ maxWidth: '820px', margin: '0 auto 2.25rem auto' }}>
|
||||
<h1
|
||||
className="title mb-2"
|
||||
style={{
|
||||
fontSize: 'clamp(1.75rem, 3.5vw, 2.35rem)',
|
||||
fontWeight: 800,
|
||||
color: '#111827',
|
||||
letterSpacing: '-0.025em',
|
||||
lineHeight: 1.2
|
||||
}}
|
||||
>
|
||||
Join India’s Dedicated Artisan Marketplace
|
||||
</h1>
|
||||
<p
|
||||
className="subtitle mb-3"
|
||||
style={{
|
||||
color: '#4B5563',
|
||||
fontSize: '0.92rem',
|
||||
lineHeight: 1.55,
|
||||
maxWidth: '650px'
|
||||
}}
|
||||
>
|
||||
Connect your generational craft with conscious patrons across 15,000+ pin codes. Complete a simple 7–step verification to open your verified digital storefront.
|
||||
</p>
|
||||
<div
|
||||
className="is-flex is-align-items-center is-flex-wrap-wrap"
|
||||
style={{ gap: '0.45rem', color: '#9C381E', fontSize: '0.85rem', fontWeight: 600 }}
|
||||
>
|
||||
<span>no listing fee</span>
|
||||
<span style={{ color: '#D1D5DB' }}>•</span>
|
||||
<span>no registration fee</span>
|
||||
<span style={{ color: '#D1D5DB' }}>•</span>
|
||||
<span>get live in minutes</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Responsive Step Progress Bar */}
|
||||
<div className="card p-3 p-4-desktop mb-5" style={{ borderRadius: '16px', border: '1px solid var(--trad-border)' }}>
|
||||
<div className="is-flex is-align-items-center is-justify-content-space-between px-1 px-3-desktop">
|
||||
{/* Responsive 7-Step Stepper matching stitch screen */}
|
||||
<div className="mb-5 mb-6-tablet" style={{ maxWidth: '820px', margin: '0 auto 2.75rem auto', width: '100%' }}>
|
||||
<div
|
||||
className="is-flex is-align-items-flex-start is-justify-content-space-between"
|
||||
style={{
|
||||
width: '100%',
|
||||
overflowX: 'auto',
|
||||
paddingBottom: '0.5rem'
|
||||
}}
|
||||
>
|
||||
{stepLabels.map((lbl, idx) => {
|
||||
const stepNum = idx + 1;
|
||||
const isDone = stepNum < onboardingStep;
|
||||
|
|
@ -363,47 +426,56 @@ export const OnboardingPage: React.FC = () => {
|
|||
|
||||
return (
|
||||
<React.Fragment key={idx}>
|
||||
{/* Step Node */}
|
||||
<div
|
||||
onClick={() => stepNum <= onboardingStep && setOnboardingStep(stepNum)}
|
||||
className="is-flex is-align-items-center"
|
||||
style={{ cursor: stepNum <= onboardingStep ? 'pointer' : 'default', flexShrink: 0 }}
|
||||
title={`Step ${stepNum}: ${lbl}`}
|
||||
className="is-flex is-flex-direction-column is-align-items-center"
|
||||
style={{
|
||||
cursor: stepNum <= onboardingStep ? 'pointer' : 'default',
|
||||
flex: '0 0 auto',
|
||||
width: '84px',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="is-flex is-align-items-center is-justify-content-center"
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
width: '34px',
|
||||
height: '34px',
|
||||
borderRadius: '50%',
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: isActive ? 'var(--trad-maroon)' : isDone ? 'var(--trad-forest)' : '#ffffff',
|
||||
color: isActive || isDone ? '#ffffff' : 'var(--trad-text-secondary)',
|
||||
border: isActive ? '2px solid var(--trad-maroon)' : isDone ? '2px solid var(--trad-forest)' : '2px solid var(--trad-border)',
|
||||
boxShadow: isActive ? '0 0 0 3px rgba(121, 27, 44, 0.18)' : 'none',
|
||||
fontSize: '0.88rem',
|
||||
fontWeight: 700,
|
||||
backgroundColor: (isActive || isDone) ? '#1B2A4A' : '#FFFFFF',
|
||||
color: (isActive || isDone) ? '#FFFFFF' : '#6B7280',
|
||||
border: (isActive || isDone) ? '2px solid #1B2A4A' : '1.5px solid #D1D5DB',
|
||||
boxShadow: isActive ? '0 0 0 3px rgba(27, 42, 74, 0.15)' : 'none',
|
||||
transition: 'all 0.2s ease'
|
||||
}}
|
||||
>
|
||||
{isDone ? <Check size={16} /> : stepNum}
|
||||
{stepNum}
|
||||
</div>
|
||||
<span
|
||||
className="is-size-7 is-hidden-touch ml-2"
|
||||
className="mt-1.5"
|
||||
style={{
|
||||
fontWeight: isActive ? 700 : 500,
|
||||
color: isActive ? 'var(--trad-maroon)' : isDone ? 'var(--trad-text-primary)' : 'var(--trad-text-secondary)',
|
||||
whiteSpace: 'nowrap'
|
||||
color: isActive ? '#111827' : '#6B7280',
|
||||
lineHeight: 1.25,
|
||||
fontSize: '0.76rem'
|
||||
}}
|
||||
>
|
||||
{lbl}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Connecting Line */}
|
||||
{idx !== stepLabels.length - 1 && (
|
||||
<div
|
||||
className="is-flex-grow-1 mx-1 mx-3-desktop"
|
||||
className="is-flex-grow-1"
|
||||
style={{
|
||||
height: '2px',
|
||||
minWidth: '8px',
|
||||
backgroundColor: isDone ? 'var(--trad-forest)' : 'var(--trad-border)',
|
||||
height: '1.5px',
|
||||
minWidth: '14px',
|
||||
backgroundColor: isDone ? '#1B2A4A' : '#E5E7EB',
|
||||
marginTop: '16px',
|
||||
transition: 'background-color 0.25s ease'
|
||||
}}
|
||||
/>
|
||||
|
|
@ -412,81 +484,193 @@ export const OnboardingPage: React.FC = () => {
|
|||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Mobile Current Step Banner */}
|
||||
<div className="is-hidden-desktop has-text-centered mt-2 pt-2" style={{ borderTop: '1px dashed var(--trad-border)' }}>
|
||||
<span className="is-size-7 has-text-weight-bold" style={{ color: 'var(--trad-maroon)' }}>
|
||||
Step {onboardingStep} of 7: {stepLabels[onboardingStep - 1]}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Step Content Container */}
|
||||
<div className="columns is-centered">
|
||||
<div className="column is-8-desktop is-10-tablet is-12-mobile">
|
||||
<div className="card p-4 p-5-tablet p-6-desktop" style={{ borderRadius: '20px', border: '1.5px solid var(--trad-border)' }}>
|
||||
{/* =================================================================== */}
|
||||
{/* STEP 1: Create Your Seller Account (Centered 480px Card) */}
|
||||
{/* =================================================================== */}
|
||||
{onboardingStep === 1 && (
|
||||
<div className="mx-auto mb-6" style={{ maxWidth: '480px', width: '100%' }}>
|
||||
<div
|
||||
className="card p-5 p-6-tablet"
|
||||
style={{
|
||||
borderRadius: '24px',
|
||||
border: '1px solid #E5E7EB',
|
||||
backgroundColor: '#FFFFFF',
|
||||
boxShadow: '0 8px 30px rgba(0, 0, 0, 0.04)'
|
||||
}}
|
||||
>
|
||||
<div className="has-text-centered mb-5">
|
||||
<h2
|
||||
className="title mb-1.5"
|
||||
style={{
|
||||
fontSize: 'clamp(1.35rem, 3vw, 1.55rem)',
|
||||
fontWeight: 800,
|
||||
color: '#111827',
|
||||
letterSpacing: '-0.02em'
|
||||
}}
|
||||
>
|
||||
Create your seller account
|
||||
</h2>
|
||||
<p className="subtitle is-size-7 mb-0" style={{ color: '#6B7280' }}>
|
||||
step 1 of 7 · takes about 2 minutes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* STEP 1: Account Creation */}
|
||||
{onboardingStep === 1 && (
|
||||
<div>
|
||||
<h2 className="title is-size-4 mb-2">Step 1: Create Your Seller Account</h2>
|
||||
<p className="subtitle is-size-7 has-text-grey mb-5">Basic contact information for order alerts and dashboard login</p>
|
||||
|
||||
<div className="field mb-4">
|
||||
<label className="label is-size-7 has-text-grey">Master Artisan / Contact Person Full Name</label>
|
||||
<div className="control">
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
placeholder="e.g. Raghavendra Sharma"
|
||||
value={onboarding.fullName}
|
||||
onChange={(e) => updateOnboarding({ fullName: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="columns mb-2">
|
||||
<div className="column is-6">
|
||||
<div className="field">
|
||||
<label className="label is-size-7 has-text-grey">Official Email Address</label>
|
||||
<div className="control">
|
||||
<input
|
||||
className="input"
|
||||
type="email"
|
||||
placeholder="artisan@guild.com"
|
||||
value={onboarding.email}
|
||||
onChange={(e) => updateOnboarding({ email: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="column is-6">
|
||||
<div className="field">
|
||||
<label className="label is-size-7 has-text-grey">10-Digit Mobile Number</label>
|
||||
<div className="field has-addons">
|
||||
<p className="control"><span className="button is-static">+91</span></p>
|
||||
<div className="control is-expanded">
|
||||
<input
|
||||
className="input"
|
||||
type="tel"
|
||||
maxLength={10}
|
||||
value={onboarding.phone}
|
||||
onChange={(e) => updateOnboarding({ phone: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="notification is-success is-light p-3 is-size-7 mb-4">
|
||||
<span className="is-flex is-align-items-center font-weight-bold">
|
||||
<CheckCircle2 size={16} className="mr-2" />
|
||||
Mobile number pre-verified via simulated OTP (4829)
|
||||
</span>
|
||||
<form onSubmit={(e) => { e.preventDefault(); handleNext(); }}>
|
||||
{/* Phone Input */}
|
||||
<div className="field mb-4">
|
||||
<div
|
||||
className="is-flex is-align-items-center"
|
||||
style={{
|
||||
border: isPhoneFocused ? '1.5px solid #1B2A4A' : '1.5px solid #CBD5E0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#FFFFFF',
|
||||
height: '46px',
|
||||
padding: '0 12px',
|
||||
boxShadow: isPhoneFocused ? '0 0 0 3px rgba(27, 42, 74, 0.12)' : 'none',
|
||||
transition: 'all 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: 700, color: '#111827', fontSize: '0.88rem' }}>IN</span>
|
||||
<span style={{ color: '#4B5563', fontSize: '0.88rem', marginLeft: '4px' }}>+91</span>
|
||||
<div style={{ width: '1px', height: '20px', backgroundColor: '#E2E8F0', margin: '0 10px' }} />
|
||||
<input
|
||||
type="tel"
|
||||
maxLength={10}
|
||||
value={step1Phone}
|
||||
onChange={(e) => {
|
||||
setStep1Phone(e.target.value);
|
||||
updateOnboarding({ phone: e.target.value });
|
||||
}}
|
||||
onFocus={() => setIsPhoneFocused(true)}
|
||||
onBlur={() => setIsPhoneFocused(false)}
|
||||
placeholder="9845012345"
|
||||
style={{
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
height: '100%',
|
||||
fontSize: '0.9rem',
|
||||
color: '#111827',
|
||||
fontWeight: 600,
|
||||
flex: 1,
|
||||
minWidth: 0
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* OTP code prompt and 6 boxes */}
|
||||
<div className="field mb-4">
|
||||
<div className="mb-2">
|
||||
<span style={{ color: '#4B5563', fontSize: '0.85rem' }}>
|
||||
enter the 6–digit code sent to your phone
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="is-flex is-align-items-center is-justify-content-space-between mb-2" style={{ gap: '8px' }}>
|
||||
{step1Otp.map((digit, idx) => (
|
||||
<input
|
||||
key={idx}
|
||||
id={`step1-otp-${idx}`}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
maxLength={1}
|
||||
value={digit}
|
||||
placeholder="•"
|
||||
onChange={(e) => handleStep1OtpChange(idx, e.target.value)}
|
||||
onKeyDown={(e) => handleStep1OtpKeyDown(idx, e)}
|
||||
className="has-text-centered has-text-weight-bold"
|
||||
style={{
|
||||
width: '46px',
|
||||
height: '46px',
|
||||
borderRadius: '10px',
|
||||
border: '1.5px solid #CBD5E0',
|
||||
fontSize: digit ? '1.15rem' : '1.4rem',
|
||||
color: '#111827',
|
||||
outline: 'none',
|
||||
backgroundColor: '#FFFFFF',
|
||||
flex: '1 1 0',
|
||||
minWidth: '36px',
|
||||
maxWidth: '48px',
|
||||
padding: 0,
|
||||
transition: 'border-color 0.15s ease, box-shadow 0.15s ease'
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderColor = '#1B2A4A';
|
||||
e.target.style.boxShadow = '0 0 0 3px rgba(27, 42, 74, 0.12)';
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderColor = '#CBD5E0';
|
||||
e.target.style.boxShadow = 'none';
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Terms & Policies Checkbox */}
|
||||
<div className="field mb-5">
|
||||
<label className="checkbox is-flex is-align-items-center" style={{ fontSize: '0.85rem', color: '#4B5563', cursor: 'pointer' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={termsAgreed}
|
||||
onChange={(e) => setTermsAgreed(e.target.checked)}
|
||||
className="mr-2.5"
|
||||
style={{ accentColor: '#1B2A4A', width: '16px', height: '16px' }}
|
||||
/>
|
||||
<span>I agree to the seller terms & policies</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Continue Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!termsAgreed}
|
||||
className="button is-fullwidth"
|
||||
style={{
|
||||
backgroundColor: '#1B2A4A',
|
||||
color: '#FFFFFF',
|
||||
borderRadius: '9999px',
|
||||
height: '48px',
|
||||
fontSize: '0.95rem',
|
||||
fontWeight: 700,
|
||||
border: 'none',
|
||||
boxShadow: '0 4px 14px rgba(27, 42, 74, 0.25)',
|
||||
transition: 'all 0.2s ease',
|
||||
cursor: termsAgreed ? 'pointer' : 'not-allowed',
|
||||
opacity: termsAgreed ? 1 : 0.6
|
||||
}}
|
||||
>
|
||||
<span>Continue</span>
|
||||
</button>
|
||||
|
||||
{/* Already registered? Log in */}
|
||||
<div className="has-text-centered mt-4 pt-1">
|
||||
<span style={{ color: '#4B5563', fontSize: '0.85rem' }}>Already registered? </span>
|
||||
<Link to="/login" style={{ color: '#791B2C', fontWeight: 700, textDecoration: 'none' }}>Log in</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* =================================================================== */}
|
||||
{/* STEPS 2 TO 7: Business, Pickup, Bank, Categories, Products, Profile */}
|
||||
{/* =================================================================== */}
|
||||
{onboardingStep > 1 && (
|
||||
<div className="columns is-centered">
|
||||
<div className="column is-8-desktop is-10-tablet is-12-mobile">
|
||||
<div
|
||||
className="card p-4 p-5-tablet p-6-desktop mb-6"
|
||||
style={{
|
||||
borderRadius: '24px',
|
||||
border: '1px solid #E5E7EB',
|
||||
backgroundColor: '#FFFFFF',
|
||||
boxShadow: '0 8px 30px rgba(0, 0, 0, 0.04)'
|
||||
}}
|
||||
>
|
||||
|
||||
{/* STEP 2: Business & GST / Enrolment ID */}
|
||||
{onboardingStep === 2 && (
|
||||
|
|
@ -940,6 +1124,78 @@ export const OnboardingPage: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Trust Badges Strip matching stitch screen */}
|
||||
<div className="mt-6 mb-4">
|
||||
<div className="container" style={{ maxWidth: '720px' }}>
|
||||
<div className="columns is-mobile has-text-centered">
|
||||
<div className="column is-4">
|
||||
<div className="is-flex is-flex-direction-column is-align-items-center">
|
||||
<div
|
||||
className="mb-2 is-flex is-align-items-center is-justify-content-center"
|
||||
style={{
|
||||
width: '42px',
|
||||
height: '42px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#FFFFFF',
|
||||
border: '1px solid #E5E7EB',
|
||||
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
<Lock size={16} color="#4B5563" />
|
||||
</div>
|
||||
<span style={{ color: '#374151', fontSize: '0.82rem', fontWeight: 600 }}>
|
||||
Secure & encrypted
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="column is-4">
|
||||
<div className="is-flex is-flex-direction-column is-align-items-center">
|
||||
<div
|
||||
className="mb-2 is-flex is-align-items-center is-justify-content-center"
|
||||
style={{
|
||||
width: '42px',
|
||||
height: '42px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#FFFFFF',
|
||||
border: '1px solid #E5E7EB',
|
||||
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: '1.1rem', fontWeight: 700, color: '#4B5563', lineHeight: 1 }}>₹</span>
|
||||
</div>
|
||||
<span style={{ color: '#374151', fontSize: '0.82rem', fontWeight: 600 }}>
|
||||
No registration fee
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="column is-4">
|
||||
<div className="is-flex is-flex-direction-column is-align-items-center">
|
||||
<div
|
||||
className="mb-2 is-flex is-align-items-center is-justify-content-center"
|
||||
style={{
|
||||
width: '42px',
|
||||
height: '42px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#FFFFFF',
|
||||
border: '1px solid #E5E7EB',
|
||||
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
<Headphones size={16} color="#4B5563" />
|
||||
</div>
|
||||
<span style={{ color: '#374151', fontSize: '0.82rem', fontWeight: 600 }}>
|
||||
Dedicated onboarding support
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
589
src/pages/ResetPasswordPage.tsx
Normal file
589
src/pages/ResetPasswordPage.tsx
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useSeller } from '../context/SellerContext';
|
||||
import {
|
||||
Star,
|
||||
Check,
|
||||
ArrowRight,
|
||||
ArrowLeft,
|
||||
Smartphone,
|
||||
Mail,
|
||||
Eye,
|
||||
EyeOff,
|
||||
PhoneCall
|
||||
} from 'lucide-react';
|
||||
|
||||
const SolidGreenCheck: React.FC<{ size?: number }> = ({ size = 16 }) => (
|
||||
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className="is-flex-shrink-0">
|
||||
<circle cx="8" cy="8" r="8" fill="#1E8E3E" />
|
||||
<path d="M4.8 8.2L7 10.4L11.4 5.8" stroke="white" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ResetPasswordPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { login } = useSeller();
|
||||
|
||||
// Reset tab: 'email' or 'mobile' (matches screenshot: default is 'email')
|
||||
const [resetTab, setResetTab] = useState<'email' | 'mobile'>('email');
|
||||
const [resetEmail, setResetEmail] = useState('artisan.weaver@craftguild.in');
|
||||
const [resetMobile, setResetMobile] = useState('9845012345');
|
||||
|
||||
// OTP Digits matching screenshot: 7, 3, 9, 4, and empty for 5 and 6
|
||||
const [otpDigits, setOtpDigits] = useState<string[]>(['7', '3', '9', '4', '', '']);
|
||||
const [newPassword, setNewPassword] = useState('craftatelier2026');
|
||||
const [confirmPassword, setConfirmPassword] = useState('craftatelier2026');
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const [resendTimer, setResendTimer] = useState(28);
|
||||
|
||||
const [isEmailFocused, setIsEmailFocused] = useState(false);
|
||||
const [isNewPassFocused, setIsNewPassFocused] = useState(false);
|
||||
const [isConfirmPassFocused, setIsConfirmPassFocused] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (resendTimer > 0) {
|
||||
const timer = setTimeout(() => setResendTimer(resendTimer - 1), 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [resendTimer]);
|
||||
|
||||
const handleOtpDigitChange = (index: number, value: string) => {
|
||||
// Only accept numeric or clean char
|
||||
const cleanValue = value.replace(/[^0-9]/g, '').slice(-1);
|
||||
const newDigits = [...otpDigits];
|
||||
newDigits[index] = cleanValue;
|
||||
setOtpDigits(newDigits);
|
||||
|
||||
// Auto focus next input
|
||||
if (cleanValue && index < 5) {
|
||||
const nextInput = document.getElementById(`otp-digit-${index + 1}`);
|
||||
nextInput?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleOtpKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Backspace') {
|
||||
if (!otpDigits[index] && index > 0) {
|
||||
const prevInput = document.getElementById(`otp-digit-${index - 1}`);
|
||||
prevInput?.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
login(resetEmail || 'artisan.weaver@craftguild.in');
|
||||
navigate('/dashboard');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="section py-5 py-6-desktop" style={{ minHeight: 'calc(100vh - 80px)', display: 'flex', alignItems: 'center' }}>
|
||||
<div className="container is-widescreen px-3 px-4-desktop">
|
||||
<div className="columns is-centered">
|
||||
<div className="column is-11-widescreen is-12-desktop is-9-tablet is-12-mobile">
|
||||
|
||||
{/* 2-Column Authentication Card */}
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
borderRadius: '24px',
|
||||
border: '1px solid #EAE5DD',
|
||||
boxShadow: '0 12px 40px rgba(0, 0, 0, 0.04)',
|
||||
backgroundColor: '#FFFFFF',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<div className="auth-card-layout">
|
||||
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
{/* LEFT COLUMN: Artisan Security, Guarantee Highlights & Helpline */}
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
<div className="auth-card-left">
|
||||
<div>
|
||||
{/* Badge */}
|
||||
<div className="mb-3">
|
||||
<span
|
||||
className="is-inline-flex is-align-items-center px-3 py-1"
|
||||
style={{
|
||||
backgroundColor: '#FDF2F4',
|
||||
border: '1px solid rgba(103, 27, 38, 0.15)',
|
||||
borderRadius: '9999px',
|
||||
color: 'var(--trad-maroon)',
|
||||
fontSize: '0.72rem',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '0.08em',
|
||||
textTransform: 'uppercase'
|
||||
}}
|
||||
>
|
||||
<Star size={11} className="mr-1.5" fill="var(--trad-maroon)" color="var(--trad-maroon)" />
|
||||
<span>ARTISAN SECURITY</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Headline */}
|
||||
<h2
|
||||
className="title mb-2"
|
||||
style={{
|
||||
fontSize: '1.6rem',
|
||||
fontWeight: 800,
|
||||
color: '#1A202C',
|
||||
lineHeight: 1.3,
|
||||
letterSpacing: '-0.02em'
|
||||
}}
|
||||
>
|
||||
Protecting your craft atelier & earnings.
|
||||
</h2>
|
||||
|
||||
{/* Subtitle */}
|
||||
<p className="subtitle mb-4 is-size-7" style={{ color: '#4A5568', lineHeight: 1.55 }}>
|
||||
Ensure seamless recovery to your master workshop ledger, scheduled bank settlements, and global artisan trade orders.
|
||||
</p>
|
||||
|
||||
{/* Artisan Image */}
|
||||
<div className="mb-5">
|
||||
<img
|
||||
src="/images/login-potter.jpg"
|
||||
alt="Authentic Indian Artisan Potter"
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '215px',
|
||||
objectFit: 'cover',
|
||||
borderRadius: '16px',
|
||||
display: 'block',
|
||||
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.06)'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Checklist */}
|
||||
<div className="is-flex is-flex-direction-column" style={{ gap: '0.85rem' }}>
|
||||
<div className="is-flex is-align-items-center">
|
||||
<div
|
||||
className="mr-2.5 is-flex is-align-items-center is-justify-content-center is-flex-shrink-0"
|
||||
style={{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: '#E6F4EA' }}
|
||||
>
|
||||
<Check size={13} color="#137333" strokeWidth={3} />
|
||||
</div>
|
||||
<span className="is-size-7" style={{ color: '#2D3748', fontWeight: 500 }}>
|
||||
Quick OTP recovery via registered email or mobile SIM
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="is-flex is-align-items-center">
|
||||
<div
|
||||
className="mr-2.5 is-flex is-align-items-center is-justify-content-center is-flex-shrink-0"
|
||||
style={{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: '#E6F4EA' }}
|
||||
>
|
||||
<Check size={13} color="#137333" strokeWidth={3} />
|
||||
</div>
|
||||
<span className="is-size-7" style={{ color: '#2D3748', fontWeight: 500 }}>
|
||||
Zero interruption to your ongoing orders and payouts
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="is-flex is-align-items-center">
|
||||
<div
|
||||
className="mr-2.5 is-flex is-align-items-center is-justify-content-center is-flex-shrink-0"
|
||||
style={{ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: '#E6F4EA' }}
|
||||
>
|
||||
<Check size={13} color="#137333" strokeWidth={3} />
|
||||
</div>
|
||||
<span className="is-size-7" style={{ color: '#2D3748', fontWeight: 500 }}>
|
||||
Dedicated 24/7 maker helpline in 7 regional languages
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Toll Free Callout */}
|
||||
<div
|
||||
className="mt-5 pt-4 is-flex is-align-items-center is-size-7"
|
||||
style={{ borderTop: '1px solid #EAE5DD', color: '#4A5568' }}
|
||||
>
|
||||
<PhoneCall size={15} className="mr-2 has-text-grey" />
|
||||
<span>
|
||||
Kala Setu Support:{' '}
|
||||
<strong style={{ color: '#1A202C' }}>1800–419–8723</strong>{' '}
|
||||
<span className="has-text-grey">(Toll Free)</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
{/* RIGHT COLUMN: Reset Password Form */}
|
||||
{/* ------------------------------------------------------------------ */}
|
||||
<div className="auth-card-right">
|
||||
<div>
|
||||
{/* Back to login button */}
|
||||
<div className="mb-3">
|
||||
<Link
|
||||
to="/login"
|
||||
className="is-inline-flex is-align-items-center"
|
||||
style={{
|
||||
color: 'var(--trad-maroon)',
|
||||
fontSize: '0.85rem',
|
||||
fontWeight: 600,
|
||||
textDecoration: 'none'
|
||||
}}
|
||||
>
|
||||
<ArrowLeft size={16} className="mr-1.5" />
|
||||
<span>Back to login</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<h1
|
||||
className="title mb-1.5"
|
||||
style={{
|
||||
fontSize: 'clamp(1.45rem, 4vw, 1.85rem)',
|
||||
fontWeight: 800,
|
||||
color: '#1A202C',
|
||||
letterSpacing: '-0.02em',
|
||||
lineHeight: 1.25
|
||||
}}
|
||||
>
|
||||
Reset your password
|
||||
</h1>
|
||||
|
||||
<p className="subtitle is-size-7 mb-4" style={{ color: '#718096', lineHeight: 1.5 }}>
|
||||
Enter your registered email address to receive a verification code and create a new password.
|
||||
</p>
|
||||
|
||||
{/* Segmented Toggle Tabs */}
|
||||
<div
|
||||
className="mb-5 p-1 is-flex"
|
||||
style={{
|
||||
backgroundColor: '#F1F3F5',
|
||||
borderRadius: '9999px',
|
||||
width: '100%',
|
||||
maxWidth: '280px'
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResetTab('mobile')}
|
||||
className="button is-small is-flex-grow-1"
|
||||
style={{
|
||||
backgroundColor: resetTab === 'mobile' ? '#FFFFFF' : 'transparent',
|
||||
color: resetTab === 'mobile' ? '#1A202C' : '#718096',
|
||||
fontWeight: resetTab === 'mobile' ? 700 : 500,
|
||||
border: 'none',
|
||||
borderRadius: '9999px',
|
||||
boxShadow: resetTab === 'mobile' ? '0 2px 6px rgba(0, 0, 0, 0.08)' : 'none',
|
||||
height: '34px',
|
||||
fontSize: '0.8rem',
|
||||
transition: 'all 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<span>Mobile Number</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResetTab('email')}
|
||||
className="button is-small is-flex-grow-1"
|
||||
style={{
|
||||
backgroundColor: resetTab === 'email' ? '#FFFFFF' : 'transparent',
|
||||
color: resetTab === 'email' ? '#1A202C' : '#718096',
|
||||
fontWeight: resetTab === 'email' ? 700 : 500,
|
||||
border: 'none',
|
||||
borderRadius: '9999px',
|
||||
boxShadow: resetTab === 'email' ? '0 2px 6px rgba(0, 0, 0, 0.08)' : 'none',
|
||||
height: '34px',
|
||||
fontSize: '0.8rem',
|
||||
transition: 'all 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<span>Email ID</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleResetSubmit}>
|
||||
{/* Registered Email / Mobile Field */}
|
||||
<div className="field mb-4">
|
||||
<label
|
||||
className="label mb-1.5"
|
||||
style={{
|
||||
fontSize: '0.68rem',
|
||||
fontWeight: 700,
|
||||
color: '#718096',
|
||||
letterSpacing: '0.06em',
|
||||
textTransform: 'uppercase'
|
||||
}}
|
||||
>
|
||||
{resetTab === 'email' ? 'REGISTERED EMAIL ADDRESS' : 'REGISTERED MOBILE NUMBER'}
|
||||
</label>
|
||||
|
||||
<div
|
||||
className="is-flex is-align-items-center"
|
||||
style={{
|
||||
border: isEmailFocused ? '1.5px solid var(--trad-maroon)' : '1.5px solid #CBD5E0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#FFFFFF',
|
||||
height: '46px',
|
||||
padding: '0 12px',
|
||||
boxShadow: isEmailFocused ? '0 0 0 3px rgba(103, 27, 38, 0.12)' : 'none',
|
||||
transition: 'border-color 0.15s ease, box-shadow 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<span className="mr-2.5 is-flex is-align-items-center is-flex-shrink-0" style={{ color: '#718096' }}>
|
||||
{resetTab === 'email' ? <Mail size={16} /> : <Smartphone size={16} />}
|
||||
</span>
|
||||
<input
|
||||
type={resetTab === 'email' ? 'email' : 'tel'}
|
||||
value={resetTab === 'email' ? resetEmail : resetMobile}
|
||||
onChange={(e) => resetTab === 'email' ? setResetEmail(e.target.value) : setResetMobile(e.target.value)}
|
||||
onFocus={() => setIsEmailFocused(true)}
|
||||
onBlur={() => setIsEmailFocused(false)}
|
||||
style={{
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
boxShadow: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
height: '100%',
|
||||
fontSize: '0.88rem',
|
||||
color: '#1A202C',
|
||||
flex: 1,
|
||||
minWidth: 0
|
||||
}}
|
||||
/>
|
||||
<SolidGreenCheck size={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 6-Digit OTP Verification Field */}
|
||||
<div className="field mb-4">
|
||||
<div className="is-flex is-justify-content-space-between is-align-items-center mb-1.5">
|
||||
<label
|
||||
className="label mb-0"
|
||||
style={{
|
||||
fontSize: '0.68rem',
|
||||
fontWeight: 700,
|
||||
color: '#718096',
|
||||
letterSpacing: '0.06em',
|
||||
textTransform: 'uppercase'
|
||||
}}
|
||||
>
|
||||
VERIFICATION CODE ({resetTab === 'email' ? 'EMAIL OTP' : 'SMS OTP'})
|
||||
</label>
|
||||
<span
|
||||
className="is-size-7"
|
||||
style={{
|
||||
color: 'var(--trad-maroon)',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.75rem',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Resend code in {resendTimer}s
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 6 Distinct OTP Boxes */}
|
||||
<div className="is-flex is-align-items-center" style={{ gap: '8px', maxWidth: '340px' }}>
|
||||
{otpDigits.map((digit, idx) => (
|
||||
<input
|
||||
key={idx}
|
||||
id={`otp-digit-${idx}`}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
maxLength={1}
|
||||
value={digit}
|
||||
placeholder="•"
|
||||
onChange={(e) => handleOtpDigitChange(idx, e.target.value)}
|
||||
onKeyDown={(e) => handleOtpKeyDown(idx, e)}
|
||||
className="has-text-centered has-text-weight-bold"
|
||||
style={{
|
||||
width: '46px',
|
||||
height: '48px',
|
||||
borderRadius: '10px',
|
||||
border: '1.5px solid #CBD5E0',
|
||||
fontSize: digit ? '1.15rem' : '1.4rem',
|
||||
color: '#1A202C',
|
||||
outline: 'none',
|
||||
backgroundColor: '#FFFFFF',
|
||||
flex: '1 1 0',
|
||||
minWidth: '36px',
|
||||
maxWidth: '48px',
|
||||
padding: 0,
|
||||
transition: 'border-color 0.15s ease, box-shadow 0.15s ease'
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderColor = 'var(--trad-maroon)';
|
||||
e.target.style.boxShadow = '0 0 0 3px rgba(103, 27, 38, 0.12)';
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderColor = '#CBD5E0';
|
||||
e.target.style.boxShadow = 'none';
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="help mt-1.5 is-flex is-align-items-center" style={{ color: '#1E8E3E', fontSize: '0.75rem' }}>
|
||||
<SolidGreenCheck size={13} />
|
||||
<span className="ml-1.5">Code sent to artisa*****@craftguild.in</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Create New Password */}
|
||||
<div className="field mb-3">
|
||||
<label
|
||||
className="label mb-1.5"
|
||||
style={{
|
||||
fontSize: '0.68rem',
|
||||
fontWeight: 700,
|
||||
color: '#718096',
|
||||
letterSpacing: '0.06em',
|
||||
textTransform: 'uppercase'
|
||||
}}
|
||||
>
|
||||
CREATE NEW PASSWORD
|
||||
</label>
|
||||
<div
|
||||
className="is-flex is-align-items-center"
|
||||
style={{
|
||||
border: isNewPassFocused ? '1.5px solid var(--trad-maroon)' : '1.5px solid #CBD5E0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#FFFFFF',
|
||||
height: '46px',
|
||||
padding: '0 12px',
|
||||
boxShadow: isNewPassFocused ? '0 0 0 3px rgba(103, 27, 38, 0.12)' : 'none',
|
||||
transition: 'border-color 0.15s ease, box-shadow 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type={showNewPassword ? 'text' : 'password'}
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
onFocus={() => setIsNewPassFocused(true)}
|
||||
onBlur={() => setIsNewPassFocused(false)}
|
||||
style={{
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
boxShadow: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
height: '100%',
|
||||
fontSize: '0.88rem',
|
||||
color: '#1A202C',
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
letterSpacing: showNewPassword ? 'normal' : '0.12em'
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="is-clickable ml-2 is-flex is-align-items-center"
|
||||
style={{ cursor: 'pointer', color: '#718096' }}
|
||||
onClick={() => setShowNewPassword(!showNewPassword)}
|
||||
>
|
||||
{showNewPassword ? <EyeOff size={16} /> : <Eye size={16} />}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Password Strength Meter (3 green segments, 1 gray, Strong (8+ chars)) */}
|
||||
<div className="is-flex is-align-items-center mt-2">
|
||||
<div className="is-flex is-flex-grow-1 mr-3" style={{ gap: '4px' }}>
|
||||
<div style={{ flex: 1, height: '4px', backgroundColor: '#1E6548', borderRadius: '2px' }} />
|
||||
<div style={{ flex: 1, height: '4px', backgroundColor: '#1E6548', borderRadius: '2px' }} />
|
||||
<div style={{ flex: 1, height: '4px', backgroundColor: '#1E6548', borderRadius: '2px' }} />
|
||||
<div style={{ flex: 1, height: '4px', backgroundColor: '#E2E8F0', borderRadius: '2px' }} />
|
||||
</div>
|
||||
<span style={{ color: '#1E6548', fontWeight: 600, fontSize: '0.72rem', whiteSpace: 'nowrap' }}>
|
||||
Strong (8+ chars)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Confirm New Password */}
|
||||
<div className="field mb-5">
|
||||
<label
|
||||
className="label mb-1.5"
|
||||
style={{
|
||||
fontSize: '0.68rem',
|
||||
fontWeight: 700,
|
||||
color: '#718096',
|
||||
letterSpacing: '0.06em',
|
||||
textTransform: 'uppercase'
|
||||
}}
|
||||
>
|
||||
CONFIRM NEW PASSWORD
|
||||
</label>
|
||||
<div
|
||||
className="is-flex is-align-items-center"
|
||||
style={{
|
||||
border: isConfirmPassFocused ? '1.5px solid var(--trad-maroon)' : '1.5px solid #CBD5E0',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: '#FFFFFF',
|
||||
height: '46px',
|
||||
padding: '0 12px',
|
||||
boxShadow: isConfirmPassFocused ? '0 0 0 3px rgba(103, 27, 38, 0.12)' : 'none',
|
||||
transition: 'border-color 0.15s ease, box-shadow 0.15s ease'
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
onFocus={() => setIsConfirmPassFocused(true)}
|
||||
onBlur={() => setIsConfirmPassFocused(false)}
|
||||
style={{
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
boxShadow: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
height: '100%',
|
||||
fontSize: '0.88rem',
|
||||
color: '#1A202C',
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
letterSpacing: '0.12em'
|
||||
}}
|
||||
/>
|
||||
<SolidGreenCheck size={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Reset Password & Log In Button */}
|
||||
<button
|
||||
type="submit"
|
||||
className="button is-fullwidth"
|
||||
style={{
|
||||
backgroundColor: 'var(--trad-maroon)',
|
||||
color: '#FFFFFF',
|
||||
borderRadius: '9999px',
|
||||
height: '48px',
|
||||
fontSize: '0.95rem',
|
||||
fontWeight: 700,
|
||||
border: 'none',
|
||||
boxShadow: '0 4px 12px rgba(103, 27, 38, 0.25)',
|
||||
transition: 'all 0.2s ease'
|
||||
}}
|
||||
>
|
||||
<span>Reset Password & Log In</span>
|
||||
<ArrowRight size={17} className="ml-2" />
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* Footer Support Desk Link */}
|
||||
<div className="has-text-centered mt-4 pt-2">
|
||||
<span className="is-size-7" style={{ color: '#718096' }}>
|
||||
Having trouble?{' '}
|
||||
<a
|
||||
href="#support"
|
||||
onClick={(e) => { e.preventDefault(); alert('Kala Setu Support Helpline: 1800-419-8723'); }}
|
||||
style={{ color: 'var(--trad-maroon)', fontWeight: 600, textDecoration: 'none' }}
|
||||
>
|
||||
Request assistance from our Onboarding Desk
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -621,3 +621,41 @@ h1, h2, h3, h4, h5, h6, .title {
|
|||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Responsive Auth Two-Column Layout (.auth-card-layout)
|
||||
========================================================================== */
|
||||
.auth-card-layout {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
.auth-card-layout {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-card-left {
|
||||
flex: 0 0 42% !important;
|
||||
max-width: 42% !important;
|
||||
border-right: 1px solid #EAE5DD !important;
|
||||
background-color: #FAF9F6 !important;
|
||||
padding: 2.5rem !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1023px) {
|
||||
.auth-card-left {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-card-right {
|
||||
flex: 1 1 auto !important;
|
||||
min-width: 0 !important;
|
||||
width: 100% !important;
|
||||
padding: clamp(1.25rem, 4vw, 3rem) !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue