92 lines
5.5 KiB
TypeScript
92 lines
5.5 KiB
TypeScript
import { ArrowLeft, ArrowRight, Check, Eye, EyeOff, LockKeyhole, Mail, User } from 'lucide-react'
|
||
import { useState } from 'react'
|
||
import type { FormEvent } from 'react'
|
||
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
||
import { authApi } from '../../lib/api'
|
||
import { useAuth } from './auth-context'
|
||
|
||
export function AuthPage({ initialMode }: { initialMode: 'login' | 'register' }) {
|
||
const [mode, setMode] = useState(initialMode)
|
||
const [name, setName] = useState('')
|
||
const [email, setEmail] = useState('')
|
||
const [password, setPassword] = useState('')
|
||
const [showPassword, setShowPassword] = useState(false)
|
||
const [error, setError] = useState('')
|
||
const [submitting, setSubmitting] = useState(false)
|
||
const { setUser } = useAuth()
|
||
const navigate = useNavigate()
|
||
const location = useLocation()
|
||
|
||
async function submit(event: FormEvent) {
|
||
event.preventDefault()
|
||
setError('')
|
||
setSubmitting(true)
|
||
try {
|
||
const user = mode === 'login'
|
||
? await authApi.login(email, password)
|
||
: await authApi.register(name, email, password)
|
||
setUser(user)
|
||
const destination = (location.state as { from?: string } | null)?.from ?? '/console'
|
||
navigate(destination, { replace: true })
|
||
} catch (reason) {
|
||
setError(reason instanceof Error ? reason.message : 'Unable to continue')
|
||
} finally {
|
||
setSubmitting(false)
|
||
}
|
||
}
|
||
|
||
function switchMode(nextMode: 'login' | 'register') {
|
||
setMode(nextMode)
|
||
setError('')
|
||
navigate(nextMode === 'login' ? '/login' : '/register', { replace: true })
|
||
}
|
||
|
||
return (
|
||
<div className="auth-page">
|
||
<div className="auth-visual">
|
||
<Link to="/" className="auth-brand"><img src="/urmi-logo.png" alt="Urmi" /></Link>
|
||
<div className="auth-message">
|
||
<span>CUSTOMER MESSAGING</span>
|
||
<h1>Messages your customers actually receive.</h1>
|
||
<p>Text, WhatsApp, verification codes, and calls in one workspace, with the approvals Indian businesses need.</p>
|
||
<div><span><Check size={15} /> SMS, WhatsApp, and phone</span><span><Check size={15} /> KYC and DLT in setup</span><span><Check size={15} /> Delivery you can check</span></div>
|
||
</div>
|
||
<small>Set up · Approve · Send · Review</small>
|
||
</div>
|
||
|
||
<main className="auth-main">
|
||
<Link to="/" className="back-home"><ArrowLeft size={15} /> Back to Urmi</Link>
|
||
<section className="auth-card">
|
||
<div className="auth-tabs">
|
||
<button className={mode === 'login' ? 'active' : ''} onClick={() => switchMode('login')}>Log in</button>
|
||
<button className={mode === 'register' ? 'active' : ''} onClick={() => switchMode('register')}>Create account</button>
|
||
</div>
|
||
<div className="auth-heading">
|
||
<h2>{mode === 'login' ? 'Welcome back' : 'Create your workspace'}</h2>
|
||
<p>{mode === 'login' ? 'Sign in to messages, calls, and your account.' : 'Set up Urmi and send your first message.'}</p>
|
||
</div>
|
||
|
||
<a className="google-button" href={authApi.googleUrl}>
|
||
<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#4285F4" d="M21.6 12.23c0-.71-.06-1.39-.18-2.05H12v3.87h5.38a4.6 4.6 0 0 1-2 3.02v2.51h3.24c1.9-1.75 2.98-4.33 2.98-7.35Z"/><path fill="#34A853" d="M12 22c2.7 0 4.98-.9 6.63-2.42l-3.24-2.51c-.9.6-2.05.96-3.39.96-2.61 0-4.82-1.76-5.61-4.13H3.04v2.59A10 10 0 0 0 12 22Z"/><path fill="#FBBC05" d="M6.39 13.9A6.01 6.01 0 0 1 6.08 12c0-.66.11-1.3.31-1.9V7.51H3.04A10 10 0 0 0 2 12c0 1.61.38 3.14 1.04 4.49l3.35-2.59Z"/><path fill="#EA4335" d="M12 5.97c1.47 0 2.79.51 3.83 1.5l2.87-2.88A9.64 9.64 0 0 0 12 2a10 10 0 0 0-8.96 5.51l3.35 2.59C7.18 7.73 9.39 5.97 12 5.97Z"/></svg>
|
||
Continue with Google
|
||
</a>
|
||
|
||
<div className="auth-divider"><span>or continue with email</span></div>
|
||
|
||
<form onSubmit={submit}>
|
||
{mode === 'register' && <label><span>Name</span><div><User size={17} /><input required minLength={2} autoComplete="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="Your name" /></div></label>}
|
||
<label><span>Email address</span><div><Mail size={17} /><input required type="email" autoComplete="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@company.com" /></div></label>
|
||
<label><span>Password</span><div><LockKeyhole size={17} /><input required minLength={mode === 'register' ? 10 : 1} type={showPassword ? 'text' : 'password'} autoComplete={mode === 'login' ? 'current-password' : 'new-password'} value={password} onChange={(e) => setPassword(e.target.value)} placeholder={mode === 'register' ? 'At least 10 characters' : 'Your password'} /><button type="button" aria-label="Toggle password visibility" onClick={() => setShowPassword(!showPassword)}>{showPassword ? <EyeOff size={17} /> : <Eye size={17} />}</button></div></label>
|
||
{mode === 'login' && <div className="forgot-row"><span>Secure, encrypted sign in</span><button type="button">Forgot password?</button></div>}
|
||
{error && <p className="auth-error">{error}</p>}
|
||
<button className="auth-submit" disabled={submitting}>{submitting ? 'Please wait…' : mode === 'login' ? 'Log in to Urmi' : 'Create my account'} {!submitting && <ArrowRight size={17} />}</button>
|
||
</form>
|
||
<p className="auth-terms">
|
||
By continuing, you agree to Urmi’s Terms of Service and{' '}
|
||
<Link to="/privacy">Privacy Policy</Link>.
|
||
</p>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
)
|
||
}
|