import { A, useNavigate } from '@solidjs/router'; import { createMemo, createSignal, For, Show } from 'solid-js'; import PublicBackground from '~/components/PublicBackground'; import PublicHeader from '~/components/PublicHeader'; import CaptchaCanvas from '~/components/CaptchaCanvas'; import { isValidEmail } from '~/lib/form-validation'; type RoleKey = 'company' | 'job_seeker' | 'professional' | 'customer'; function makeCaptcha() { const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; return Array.from({ length: 6 }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); } function PasswordVisibilityIcon(props: { visible: boolean }) { if (props.visible) { return ( ); } return ( ); } export default function LoginRoute() { const navigate = useNavigate(); const [email, setEmail] = createSignal(''); const [password, setPassword] = createSignal(''); const [otp, setOtp] = createSignal(['', '', '', '', '', '']); const [showVerify, setShowVerify] = createSignal(false); const [showPassword, setShowPassword] = createSignal(false); const [captcha, setCaptcha] = createSignal(makeCaptcha()); const [captchaInput, setCaptchaInput] = createSignal(''); const [error, setError] = createSignal(''); const [submitting, setSubmitting] = createSignal(false); const [roleGuess, setRoleGuess] = createSignal('job_seeker'); const otpCode = createMemo(() => otp().join('')); const setOtpDigit = (index: number, value: string) => { const clean = value.replace(/\D/g, '').slice(0, 1); setOtp((prev) => { const next = prev.slice(); next[index] = clean; return next; }); if (clean) { const nextEl = document.querySelector(`#login-otp-${index + 1}`); if (nextEl) nextEl.focus(); } }; const saveUser = (user: any) => { const fullName = String(user?.full_name || user?.fullName || '').trim(); const [firstName, ...rest] = fullName.split(' '); const lastName = rest.join(' '); const normalizedRole = String(user?.active_role || user?.role || roleGuess() || '') .trim() .toUpperCase() .replace(/\s+/g, '_'); const storedRole = normalizedRole ? normalizedRole.toLowerCase() : roleGuess(); const payload = { firstName: firstName || '', lastName: lastName || '', fullName: fullName || '', name: fullName || '', displayName: fullName || '', email: String(user?.email || email()).trim().toLowerCase(), roleKey: storedRole, role: storedRole, active_role: normalizedRole || 'JOB_SEEKER', user, }; if (typeof window !== 'undefined') { window.localStorage.setItem('nxtgauge_auth_user', JSON.stringify(payload)); window.localStorage.setItem('nxtgauge_user', JSON.stringify(payload)); window.localStorage.setItem('nxtgauge_signup_profile_v1', JSON.stringify(payload)); } }; const login = async () => { setError(''); if (email().trim().toLowerCase() === 'demo@nxtgauge.com' && password() === 'Demo@1234') { dummyLogin(); return; } if (!isValidEmail(email())) { setError('Enter a valid email address.'); return; } if (!password().trim()) { setError('Password is required.'); return; } if (!captchaInput().trim() || captchaInput().trim().toUpperCase() !== captcha().toUpperCase()) { setError('Captcha does not match. Please try again.'); setCaptcha(makeCaptcha()); setCaptchaInput(''); return; } setSubmitting(true); try { const res = await fetch('/api/gateway/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email().trim().toLowerCase(), password: password(), }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { const code = String(data?.code || '').toUpperCase(); if (code === 'EMAIL_NOT_VERIFIED') { setShowVerify(true); setError('Email not verified. Enter OTP sent to your inbox.'); return; } setError(String(data?.error || data?.message || 'Invalid login credentials.')); return; } const accessToken = String(data?.access_token || '').trim(); if (typeof window !== 'undefined' && accessToken) { window.sessionStorage.setItem('nxtgauge_access_token', accessToken); window.sessionStorage.setItem('nxtgauge_frontend_access_token', accessToken); window.localStorage.setItem('nxtgauge_access_token', accessToken); } saveUser(data?.user || {}); navigate('/dashboard', { replace: true }); } finally { setSubmitting(false); } }; const resendOtp = async () => { setError(''); setSubmitting(true); try { const res = await fetch('/api/gateway/api/auth/resend-otp', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email().trim().toLowerCase() }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { setError(String(data?.error || data?.message || 'Unable to resend OTP.')); } } finally { setSubmitting(false); } }; const verifyThenLogin = async () => { setError(''); if (otpCode().length !== 6) { setError('Enter a valid 6-digit OTP.'); return; } setSubmitting(true); try { const verifyRes = await fetch('/api/gateway/api/auth/verify-email', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, credentials: 'include', body: JSON.stringify({ otp: otpCode() }), }); const verifyData = await verifyRes.json().catch(() => ({})); if (!verifyRes.ok) { setError(String(verifyData?.error || verifyData?.message || 'OTP verification failed.')); return; } await login(); } finally { setSubmitting(false); } }; const dummyLogin = () => { const demoUser = { id: 'demo-user-001', email: 'demo@nxtgauge.com', full_name: 'Demo User', email_verified: true, active_role: 'JOB_SEEKER', roles: ['JOB_SEEKER'], }; const payload = { firstName: 'Demo', lastName: 'User', fullName: 'Demo User', name: 'Demo User', displayName: 'Demo User', email: 'demo@nxtgauge.com', roleKey: 'job_seeker', role: 'job_seeker', user: demoUser, }; if (typeof window !== 'undefined') { window.sessionStorage.setItem('nxtgauge_access_token', 'dummy-access-token'); window.sessionStorage.setItem('nxtgauge_frontend_access_token', 'dummy-access-token'); window.localStorage.setItem('nxtgauge_access_token', 'dummy-access-token'); window.localStorage.setItem('nxtgauge_auth_user', JSON.stringify(payload)); window.localStorage.setItem('nxtgauge_user', JSON.stringify(payload)); window.localStorage.setItem('nxtgauge_signup_profile_v1', JSON.stringify(payload)); } setRoleGuess('job_seeker'); navigate('/dashboard', { replace: true }); }; return (
Public Workspace

Public Workspace

Welcome Back To Nxtgauge

Sign in to manage your profile, portfolio, and verification in one place.

Sign In

setEmail(e.currentTarget.value)} placeholder="Enter your email" />

{email().trim() && isValidEmail(email()) ? '✓ Valid email format' : '• Enter a valid email format'}

setPassword(e.currentTarget.value)} placeholder="Enter your password" />
setCaptchaInput(e.currentTarget.value)} placeholder="Enter captcha" />
index)}> {(index) => ( setOtpDigit(index, e.currentTarget.value)} /> )}

{error()}

); }