feat: remove backend link and support passwordless login and registration
All checks were successful
Beta CI/CD Pipeline / build-and-test (push) Successful in 1m21s
Beta CI/CD Pipeline / deploy-beta (push) Successful in 25s

This commit is contained in:
vickytechkey 2026-09-10 20:05:12 +05:30
parent b3557d0698
commit 2a8f575e1c
6 changed files with 59 additions and 37 deletions

View file

@ -267,5 +267,34 @@ describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
globalThis.fetch = originalFetch globalThis.fetch = originalFetch
}) })
it('allows login directly without entering any password', async () => {
render(<App />)
const loginBtn = screen.getByText(/^Login$/i)
fireEvent.click(loginBtn)
const submitBtn = screen.getByRole('button', { name: /Sign In/i })
fireEvent.click(submitBtn)
expect(await screen.findByText(/Total Sales/i)).toBeInTheDocument()
})
it('allows signup without entering any password', async () => {
render(<App />)
const getStartedBtn = screen.getByText(/^Get started$/i)
fireEvent.click(getStartedBtn)
fireEvent.change(screen.getByPlaceholderText(/Enter your email/i), { target: { value: 'artisan_nopass@tradhox.com' } })
fireEvent.change(screen.getByPlaceholderText(/9876543210/i), { target: { value: '9876543210' } })
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 }))
expect(await screen.findByText(/Welcome to Tradhox/i)).toBeInTheDocument()
alertMock.mockRestore()
})
}) })

View file

@ -150,10 +150,9 @@ export default function AuthForms() {
<input <input
id="r-pass" id="r-pass"
type={showSignupPass ? 'text' : 'password'} type={showSignupPass ? 'text' : 'password'}
placeholder="Create a password" placeholder="Create a password (optional)"
value={password} value={password}
onChange={e => setPassword(e.target.value)} onChange={e => setPassword(e.target.value)}
required
style={{ width: '100%', border: '1px solid #D1CAC7', borderRadius: '8px', height: '42px', padding: '0 40px 0 14px', fontSize: '0.9rem', outline: 'none' }} style={{ width: '100%', border: '1px solid #D1CAC7', borderRadius: '8px', height: '42px', padding: '0 40px 0 14px', fontSize: '0.9rem', outline: 'none' }}
/> />
<button <button
@ -174,10 +173,9 @@ export default function AuthForms() {
<input <input
id="r-confirm" id="r-confirm"
type="password" type="password"
placeholder="Repeat your password" placeholder="Repeat your password (optional)"
value={confirmPassword} value={confirmPassword}
onChange={e => setConfirmPassword(e.target.value)} onChange={e => setConfirmPassword(e.target.value)}
required
style={{ width: '100%', border: '1px solid #D1CAC7', borderRadius: '8px', height: '42px', padding: '0 14px', fontSize: '0.9rem', outline: 'none' }} style={{ width: '100%', border: '1px solid #D1CAC7', borderRadius: '8px', height: '42px', padding: '0 14px', fontSize: '0.9rem', outline: 'none' }}
/> />
</div> </div>

View file

@ -211,7 +211,6 @@ export default function LoginPage() {
placeholder="you@example.com" placeholder="you@example.com"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
required
style={{ borderColor: '#D1CAC7', borderRadius: '8px', height: '42px', fontSize: '0.9rem' }} style={{ borderColor: '#D1CAC7', borderRadius: '8px', height: '42px', fontSize: '0.9rem' }}
/> />
<span className="icon is-left has-text-grey"> <span className="icon is-left has-text-grey">
@ -237,7 +236,6 @@ export default function LoginPage() {
placeholder="••••••••" placeholder="••••••••"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
required
style={{ borderColor: '#D1CAC7', borderRadius: '8px', height: '42px', fontSize: '0.9rem' }} style={{ borderColor: '#D1CAC7', borderRadius: '8px', height: '42px', fontSize: '0.9rem' }}
/> />
<span className="icon is-left has-text-grey"> <span className="icon is-left has-text-grey">

View file

@ -1,9 +1,4 @@
const getApiBaseUrl = () => { const getApiBaseUrl = () => {
if (import.meta.env.DEV) {
return 'http://127.0.0.1:8000'; // Or your local backend port
}
// Use relative path in production.
// CloudFront will proxy /api/* requests to the EC2 backend automatically!
return ''; return '';
}; };

View file

@ -479,26 +479,22 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
const handleRegisterSubmit = (e: React.FormEvent) => { const handleRegisterSubmit = (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
// Email Validation // Email Validation (if provided)
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) { if (email.trim() && !emailRegex.test(email)) {
alert('Please enter a valid email address.'); alert('Please enter a valid email address.');
return; return;
} }
// Phone Validation // Phone Validation (if provided)
const phoneRegex = /^[6-9]\d{9}$/; const phoneRegex = /^[6-9]\d{9}$/;
if (!phoneRegex.test(phone)) { if (phone.trim() && !phoneRegex.test(phone)) {
alert('Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9.'); alert('Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9.');
return; return;
} }
// Password Validation // Password Validation: If password is provided and confirm password doesn't match
if (password.length < 8) { if (password && confirmPassword && password !== confirmPassword) {
alert('Password must be at least 8 characters long.');
return;
}
if (password !== confirmPassword) {
alert('Passwords do not match.'); alert('Passwords do not match.');
return; return;
} }
@ -509,15 +505,26 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
return; return;
} }
const completeRegistration = () => {
localStorage.setItem('access_token', 'demo_access_token');
navigateTo('profile-completion');
};
// If no password is provided, proceed directly to onboarding
if (!password) {
completeRegistration();
return;
}
apiFetch(`${CONFIG.apiBaseUrl}/api/auth/register/`, { apiFetch(`${CONFIG.apiBaseUrl}/api/auth/register/`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
username: email, username: email || 'demo_artisan@tradhox.com',
email: email, email: email || 'demo_artisan@tradhox.com',
phone: phone, phone: phone || '9876543210',
password: password, password: password,
confirm_password: confirmPassword, confirm_password: confirmPassword || password,
policy_accepted: policyAccepted policy_accepted: policyAccepted
}) })
}) })
@ -530,7 +537,7 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
apiFetch(`${CONFIG.apiBaseUrl}/api/auth/login/`, { apiFetch(`${CONFIG.apiBaseUrl}/api/auth/login/`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: email, password: password }) body: JSON.stringify({ username: email || 'demo_artisan@tradhox.com', password: password })
}) })
.then(res => { .then(res => {
if (!res.ok) throw new Error('Auto-login failed.'); if (!res.ok) throw new Error('Auto-login failed.');
@ -541,11 +548,13 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
if (data.refresh_token) localStorage.setItem('refresh_token', data.refresh_token); if (data.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);
navigateTo('profile-completion') navigateTo('profile-completion')
}) })
.catch(() => {
completeRegistration();
})
}) })
.catch(() => { .catch(() => {
// Offline / demo fallback // Offline / demo fallback
localStorage.setItem('access_token', 'demo_access_token'); completeRegistration();
navigateTo('profile-completion');
}); });
} }
@ -562,7 +571,8 @@ export const SellerProvider: React.FC<{children: React.ReactNode}> = ({ children
navigateTo('dashboard', true); navigateTo('dashboard', true);
}; };
if (!email.trim()) { // Allow login without password directly
if (!password) {
fallbackDemoLogin(); fallbackDemoLogin();
return; return;
} }

View file

@ -6,12 +6,4 @@ export default defineConfig({
plugins: [ plugins: [
react(), react(),
], ],
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
},
},
},
}) })