/* ============================================================= KASDAP ONE — AUTH SCREEN (customer) ============================================================= */ const { useState: useStateAuth } = React; /* 6-box OTP input — auto-advances focus, handles backspace */ function OtpBoxes({ value, onChange }) { const chars = Array.from({ length: 6 }, (_, i) => (value || '')[i] || ''); const moveFocus = (currentIdx, delta) => { const boxes = document.querySelectorAll('.otp-row .otp-box'); const target = boxes[currentIdx + delta]; if (target) target.focus(); }; return React.createElement('div', { className: 'otp-row' }, ...Array.from({ length: 6 }, (_, i) => React.createElement('input', { key: i, className: 'otp-box', type: 'text', inputMode: 'numeric', maxLength: 1, value: chars[i], autoComplete: 'one-time-code', onChange: e => { const ch = e.target.value.replace(/\D/g, '').slice(-1); const arr = Array.from({ length: 6 }, (_, j) => (value || '')[j] || ''); arr[i] = ch; onChange(arr.join('').trimEnd()); if (ch) moveFocus(i, 1); }, onKeyDown: e => { if (e.key === 'Backspace' && !chars[i]) moveFocus(i, -1); if (e.key === 'ArrowLeft') moveFocus(i, -1); if (e.key === 'ArrowRight') moveFocus(i, 1); }, onFocus: e => e.target.select(), onPaste: e => { e.preventDefault(); const pasted = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, 6); onChange(pasted); const boxes = document.querySelectorAll('.otp-row .otp-box'); if (boxes[Math.min(pasted.length, 5)]) boxes[Math.min(pasted.length, 5)].focus(); }, })) ); } function AuthScreen() { const { login, signup, forgotPassword, resetPassword, toast } = useStore(); const [tab, setTab] = useStateAuth('login'); const [email, setEmail] = useStateAuth(''); const [pass, setPass] = useStateAuth(''); const [err, setErr] = useStateAuth(''); const [name, setName] = useStateAuth(''); const [org, setOrg] = useStateAuth(''); const [gst, setGst] = useStateAuth(''); const [dl, setDl] = useStateAuth(''); const [acc] = useStateAuth('b2b'); const [role, setRole] = useStateAuth('chemist'); /* forgot password flow state */ const [step, setStep] = useStateAuth('main'); // 'main' | 'forgot' | 'otp' | 'newpass' const [resetEmail, setResetEmail] = useStateAuth(''); const [resetCode, setResetCode] = useStateAuth(''); const [newPass, setNewPass] = useStateAuth(''); const [newPass2, setNewPass2] = useStateAuth(''); const [resetErr, setResetErr] = useStateAuth(''); const [resetLoading, setResetLoading] = useStateAuth(false); const [devCode, setDevCode] = useStateAuth(''); const SUBROLES = [ { key: 'chemist', name: 'Chemist / Retailer', icon: 'store' }, { key: 'distributor', name: 'Distributor', icon: 'truck' }, { key: 'hospital', name: 'Hospital / Institution', icon: 'building' }, ]; const doLogin = async () => { const r = await login(email, pass); if (!r.ok) setErr(r.err); }; const doSignup = async () => { if (!name || !email || !pass || !org) { setErr('Please fill all required fields'); return; } if (!gst.trim()) { setErr('GST number is required'); return; } const r = await signup({ name, email, pass, accountType: 'b2b', role, org, gst, drug_license: dl }); if (!r.ok) setErr(r.err); }; const openForgot = () => { setStep('forgot'); setResetEmail(email); setResetErr(''); setDevCode(''); setResetCode(''); setNewPass(''); setNewPass2(''); }; const backToMain = () => { setStep('main'); setResetErr(''); setResetCode(''); setDevCode(''); }; const doSendOtp = async () => { if (!resetEmail.trim()) { setResetErr('Please enter your registered email'); return; } setResetLoading(true); setResetErr(''); const r = await forgotPassword(resetEmail.trim()); setResetLoading(false); if (!r.ok) { setResetErr(r.err); return; } if (r.code) setDevCode(r.code); // dev/offline: surface code on screen setStep('otp'); }; const doVerifyOtp = () => { if ((resetCode || '').length < 6) { setResetErr('Enter the complete 6-digit code'); return; } setResetErr(''); setStep('newpass'); }; const doResetPassword = async () => { if (newPass.length < 6) { setResetErr('Password must be at least 6 characters'); return; } if (newPass !== newPass2) { setResetErr('Passwords do not match'); return; } setResetLoading(true); setResetErr(''); const r = await resetPassword(resetEmail.trim(), resetCode, newPass); setResetLoading(false); if (!r.ok) { setResetErr(r.err); if (r.err && (r.err.toLowerCase().includes('code') || r.err.toLowerCase().includes('otp'))) { setStep('otp'); setResetCode(''); } return; } toast('Password reset successfully — please sign in', 'ok'); setStep('main'); setEmail(resetEmail); setPass(''); setTab('login'); setResetCode(''); setNewPass(''); setNewPass2(''); setDevCode(''); }; /* ----- forgot password step renderers ----- */ const renderForgotFlow = () => { if (step === 'forgot') return React.createElement(React.Fragment, null, React.createElement('button', { className: 'auth-back-btn', onClick: backToMain }, React.createElement(Icon, { name: 'back', size: 14 }), 'Back to sign in'), React.createElement('div', { className: 'auth-step-ic' }, React.createElement(Icon, { name: 'mail', size: 24 })), React.createElement('h2', null, 'Forgot password?'), React.createElement('p', { className: 'sub' }, 'Enter your registered email and we\'ll send a 6-digit reset code.'), resetErr && React.createElement('div', { className: 'auth-err' }, resetErr), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Registered email'), React.createElement('input', { className: 'input', type: 'email', value: resetEmail, onChange: e => setResetEmail(e.target.value), placeholder: 'you@example.com', autoFocus: true, onKeyDown: e => e.key === 'Enter' && doSendOtp(), }) ), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: 6 }, disabled: resetLoading, onClick: doSendOtp, }, resetLoading ? 'Sending…' : React.createElement(React.Fragment, null, React.createElement(Icon, { name: 'mail', size: 16 }), ' Send reset code')) ); if (step === 'otp') return React.createElement(React.Fragment, null, React.createElement('button', { className: 'auth-back-btn', onClick: () => { setStep('forgot'); setResetCode(''); setResetErr(''); } }, React.createElement(Icon, { name: 'back', size: 14 }), 'Back'), React.createElement('div', { className: 'auth-step-ic' }, React.createElement(Icon, { name: 'shieldCheck', size: 24 })), React.createElement('h2', null, 'Enter reset code'), React.createElement('p', { className: 'sub' }, 'Enter the 6-digit code sent to ', React.createElement('b', null, resetEmail)), resetErr && React.createElement('div', { className: 'auth-err' }, resetErr), React.createElement(OtpBoxes, { value: resetCode, onChange: setResetCode }), devCode && React.createElement('div', { className: 'dev-code-hint' }, 'Dev mode code: ', React.createElement('b', null, devCode)), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: 18 }, disabled: (resetCode || '').length < 6, onClick: doVerifyOtp, }, React.createElement(Icon, { name: 'shieldCheck', size: 16 }), ' Continue'), React.createElement('div', { className: 'resend-link' }, React.createElement('button', { onClick: () => { setStep('forgot'); setResetCode(''); setResetErr(''); setDevCode(''); }, }, 'Didn\'t receive it? Resend code')) ); if (step === 'newpass') return React.createElement(React.Fragment, null, React.createElement('button', { className: 'auth-back-btn', onClick: () => { setStep('otp'); setResetErr(''); } }, React.createElement(Icon, { name: 'back', size: 14 }), 'Back'), React.createElement('div', { className: 'auth-step-ic' }, React.createElement(Icon, { name: 'lock', size: 24 })), React.createElement('h2', null, 'Set new password'), React.createElement('p', { className: 'sub' }, 'Choose a strong password for your account.'), resetErr && React.createElement('div', { className: 'auth-err' }, resetErr), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'New password'), React.createElement('input', { className: 'input', type: 'password', value: newPass, autoFocus: true, onChange: e => setNewPass(e.target.value), placeholder: '••••••••', }) ), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Confirm password'), React.createElement('input', { className: 'input', type: 'password', value: newPass2, onChange: e => setNewPass2(e.target.value), placeholder: '••••••••', onKeyDown: e => e.key === 'Enter' && doResetPassword(), }) ), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: 6 }, disabled: resetLoading, onClick: doResetPassword, }, resetLoading ? 'Resetting…' : React.createElement(React.Fragment, null, React.createElement(Icon, { name: 'lock', size: 16 }), ' Reset password')) ); }; const needsTrade = true; return React.createElement('div', { className: 'auth' }, /* ---- left: brand panel ---- */ React.createElement('div', { className: 'auth-brand' }, React.createElement('div', { className: 'auth-logo' }, React.createElement('div', { className: 'brand-mark' }, React.createElement('img', { src: 'app/icons/kasdap.png', alt: 'Kasdap' })), React.createElement('div', { className: 'brand-txt' }, React.createElement('div', { className: 'brand-name' }, React.createElement('b', null, 'Kasdap')), React.createElement('div', { className: 'brand-sub' }, 'B2B Trade')) ), React.createElement('div', { className: 'auth-hero' }, React.createElement('div', { className: 'auth-kicker' }, React.createElement(Icon, { name: 'sparkles', size: 13 }), 'B2B Pharma Trade Platform'), React.createElement('h1', { className: 'auth-h1' }, 'Wholesale pharma,', React.createElement('br'), 'at your ', React.createElement('span', { className: 'g-in' }, 'fingertips.')), React.createElement('p', { className: 'auth-sub' }, 'Kasdap connects distributors, chemists, and hospitals to 700+ specialty generics at partner pricing. Tier-based margins, quantity slabs, and RFQ quotes — all in one platform.'), React.createElement('div', { className: 'auth-features' }, [ { icon: 'tag', title: 'Tier-based pricing', desc: 'Distributor, chemist & hospital rates with quantity slabs' }, { icon: 'receipt', title: 'RFQ & bulk quotes', desc: 'Raise quote requests for large orders, get negotiated pricing' }, { icon: 'box', title: '700+ Specialty SKUs', desc: 'GMP-certified generics across 9 therapeutic areas' }, ].map((f, i) => React.createElement('div', { key: i, className: 'auth-feat' }, React.createElement('div', { className: 'auth-feat-ic' }, React.createElement(Icon, { name: f.icon, size: 16 })), React.createElement('div', null, React.createElement('div', { className: 'auth-feat-t' }, f.title), React.createElement('div', { className: 'auth-feat-d' }, f.desc)))) ), React.createElement('div', { className: 'auth-trust' }, React.createElement('div', null, React.createElement(Icon, { name: 'shieldCheck', size: 15 }), 'GMP & WHO-GMP Certified'), React.createElement('div', null, React.createElement(Icon, { name: 'globe', size: 15 }), 'PAN India delivery'), React.createElement('div', null, React.createElement(Icon, { name: 'star', size: 15 }), 'ISO 9001:2015') ) ) ), /* ---- right: form panel ---- */ React.createElement('div', { className: 'auth-form-wrap' }, React.createElement('div', { className: 'auth-form' }, /* mobile brand strip */ React.createElement('div', { className: 'auth-mob-brand' }, React.createElement('div', { className: 'auth-mb-mark' }, React.createElement('img', { src: 'app/icons/kasdap.png', alt: 'Kasdap' })), React.createElement('div', null, React.createElement('div', { className: 'auth-mb-name' }, React.createElement('b', null, 'Kasdap')), React.createElement('div', { className: 'auth-mb-sub' }, 'B2B Pharma Trade Platform'))), /* forgot flow OR normal login/signup */ step !== 'main' ? renderForgotFlow() : React.createElement(React.Fragment, null, React.createElement('h2', null, tab === 'login' ? 'Sign in to your account' : 'Create trade account'), React.createElement('p', { className: 'sub' }, tab === 'login' ? 'Access your B2B trade dashboard' : 'Register as a B2B trade partner'), React.createElement('div', { className: 'auth-tabs' }, React.createElement('button', { className: tab==='login'?'on':'', onClick: () => { setTab('login'); setErr(''); } }, 'Sign in'), React.createElement('button', { className: tab==='signup'?'on':'', onClick: () => { setTab('signup'); setErr(''); } }, 'Sign up') ), err && React.createElement('div', { className: 'auth-err' }, err), tab === 'signup' && React.createElement(React.Fragment, null, needsTrade && React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Business type'), React.createElement('div', { className: 'role-grid', style: { gridTemplateColumns: '1fr 1fr 1fr' } }, SUBROLES.map(r => React.createElement('div', { key: r.key, className: 'role-opt' + (role===r.key?' on':''), onClick: () => setRole(r.key) }, React.createElement('div', { className: 'rn', style: { fontSize: '.72rem' } }, React.createElement(Icon, { name: r.icon, size: 14 }), r.name.split(' ')[0]) )) ) ), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Full name'), React.createElement('input', { className: 'input', value: name, onChange: e => setName(e.target.value), placeholder: 'Your name' })), needsTrade && React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Business / organisation'), React.createElement('input', { className: 'input', value: org, onChange: e => setOrg(e.target.value), placeholder: 'e.g. Apollo Medical Store' })), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'GST number ', React.createElement('span', { className: 'req-star' }, '*')), React.createElement('input', { className: 'input mono', value: gst, onChange: e => setGst(e.target.value.toUpperCase()), placeholder: '27AAACR1234B1Z5', maxLength: 15 }), React.createElement('div', { className: 'field-hint' }, '15-digit GSTIN — required for B2B registration')), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Drug license no. ', React.createElement('span', { className: 'opt-tag' }, 'optional')), React.createElement('input', { className: 'input mono', value: dl, onChange: e => setDl(e.target.value), placeholder: 'e.g. DL-20B-123456' })) ), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Email'), React.createElement('input', { className: 'input', type: 'email', value: email, onChange: e => setEmail(e.target.value), placeholder: 'you@example.com', onKeyDown: e => e.key==='Enter' && (tab==='login'?doLogin():doSignup()) })), React.createElement('div', { className: 'field' }, React.createElement('label', null, 'Password'), React.createElement('input', { className: 'input', type: 'password', value: pass, onChange: e => setPass(e.target.value), placeholder: '••••••••', onKeyDown: e => e.key==='Enter' && (tab==='login'?doLogin():doSignup()) })), tab === 'login' && React.createElement('div', { className: 'forgot-link' }, React.createElement('button', { onClick: openForgot }, 'Forgot password?')), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: tab==='login'?2:6 }, onClick: tab==='login'?doLogin:doSignup }, React.createElement(Icon, { name: 'lock', size: 16 }), tab==='login' ? ' Sign in securely' : ' Create account'), React.createElement('div', { className: 'auth-tagline' }, React.createElement(Icon, { name: 'shieldCheck', size: 13 }), 'Quality medicines. Partner pricing. Pan India.') ) ) ) ); } Object.assign(window, { AuthScreen });