human hand off bug

This commit is contained in:
debu-2 2026-10-06 19:09:02 +05:30
parent 2855a20140
commit 962f991580
11 changed files with 226 additions and 34 deletions

View file

@ -1,5 +1,6 @@
import { useState } from "react";
import { changePassword } from "../api";
import PasswordField from "./PasswordField";
function validateForm(form) {
const errors = {};
@ -79,8 +80,7 @@ export default function ChangePasswordModal({ account, onComplete }) {
<form className="change-password-form" onSubmit={handleSubmit} noValidate>
<label>
Current password
<input
type="password"
<PasswordField
autoComplete="current-password"
value={form.current_password}
onChange={(event) => updateField("current_password", event.target.value)}
@ -94,8 +94,7 @@ export default function ChangePasswordModal({ account, onComplete }) {
<label>
New password
<input
type="password"
<PasswordField
autoComplete="new-password"
value={form.new_password}
onChange={(event) => updateField("new_password", event.target.value)}
@ -109,8 +108,7 @@ export default function ChangePasswordModal({ account, onComplete }) {
<label>
Confirm new password
<input
type="password"
<PasswordField
autoComplete="new-password"
value={form.confirm_password}
onChange={(event) => updateField("confirm_password", event.target.value)}

View file

@ -0,0 +1,95 @@
import { ArrowRight, Mail } from "lucide-react";
import { useState } from "react";
import { resetPassword } from "../api";
import AuthLayout from "./AuthLayout";
import PasswordField from "./PasswordField";
export default function ForgotPasswordPage() {
const [status, setStatus] = useState({ loading: false, error: "", done: false });
async function handleSubmit(event) {
event.preventDefault();
const form = new FormData(event.currentTarget);
const password = String(form.get("new_password") || "");
const confirm = String(form.get("confirm_password") || "");
if (password !== confirm) {
setStatus({ loading: false, error: "Passwords do not match.", done: false });
return;
}
setStatus({ loading: true, error: "", done: false });
try {
await resetPassword({
email: form.get("email"),
new_password: password,
});
setStatus({ loading: false, error: "", done: true });
} catch (error) {
setStatus({ loading: false, error: error.message, done: false });
}
}
return (
<AuthLayout
eyebrow="Forgot password"
title={<>Set a new password<br /><em>and sign back in.</em></>}
description="Enter your account email and choose a new password. Extra email or phone checks are skipped for now."
>
<>
<div className="card-heading">
<h2>Reset your password</h2>
<p>Use the email you sign in with. No verification code is required yet.</p>
</div>
{status.done ? (
<div className="auth-success">
<p>Your password has been updated. You can sign in with it now.</p>
<a className="button button-coral auth-submit" href="/login">
Back to sign in <ArrowRight size={16} />
</a>
</div>
) : (
<form className="auth-form" onSubmit={handleSubmit}>
<label>
Email address
<div className="input-wrap">
<Mail size={16} />
<input
name="email"
type="email"
placeholder="you@gentic.email"
required
autoComplete="email"
/>
</div>
</label>
<label>
New password
<PasswordField
name="new_password"
placeholder="8+ characters"
minLength={8}
required
autoComplete="new-password"
/>
<small className="field-hint">Use uppercase, lowercase, and a number.</small>
</label>
<label>
Confirm new password
<PasswordField
name="confirm_password"
placeholder="Repeat your password"
minLength={8}
required
autoComplete="new-password"
/>
</label>
{status.error && <p className="form-error" role="alert">{status.error}</p>}
<button className="button button-coral auth-submit" disabled={status.loading}>
{status.loading ? "Updating…" : "Update password"} <ArrowRight size={16} />
</button>
</form>
)}
<p className="auth-switch">Remembered it? <a href="/login">Log in</a></p>
</>
</AuthLayout>
);
}

View file

@ -1,7 +1,8 @@
import { ArrowRight, LockKeyhole } from "lucide-react";
import { ArrowRight } from "lucide-react";
import { useEffect, useState } from "react";
import { acceptInvite, previewInvite } from "../api";
import AuthLayout from "./AuthLayout";
import PasswordField from "./PasswordField";
function inviteTokenFromPath() {
const match = window.location.pathname.match(/^\/invite\/([^/]+)/);
@ -89,31 +90,23 @@ export default function InviteAcceptPage() {
<form className="auth-form" onSubmit={handleSubmit}>
<label>
Password
<div className="input-wrap">
<LockKeyhole size={16} />
<input
name="password"
type="password"
placeholder="Create a password"
required
minLength={8}
autoComplete="new-password"
/>
</div>
<PasswordField
name="password"
placeholder="Create a password"
required
minLength={8}
autoComplete="new-password"
/>
</label>
<label>
Confirm password
<div className="input-wrap">
<LockKeyhole size={16} />
<input
name="confirm_password"
type="password"
placeholder="Repeat your password"
required
minLength={8}
autoComplete="new-password"
/>
</div>
<PasswordField
name="confirm_password"
placeholder="Repeat your password"
required
minLength={8}
autoComplete="new-password"
/>
</label>
<p className="auth-switch" style={{ marginTop: 0 }}>
Must include uppercase, lowercase, and a number.

View file

@ -1,7 +1,8 @@
import { ArrowRight, LockKeyhole, Mail } from "lucide-react";
import { ArrowRight, Mail } from "lucide-react";
import { useState } from "react";
import { login } from "../api";
import AuthLayout from "./AuthLayout";
import PasswordField from "./PasswordField";
export default function LoginPage() {
const [status, setStatus] = useState({ loading: false, error: "" });
@ -33,7 +34,18 @@ export default function LoginPage() {
<div className="card-heading"><h2>Log in to agmail</h2><p>Enter your account details below.</p></div>
<form className="auth-form" onSubmit={handleSubmit}>
<label>Email address<div className="input-wrap"><Mail size={16} /><input name="email" type="email" placeholder="you@gentic.email" required autoComplete="email" /></div></label>
<label>Password<div className="input-wrap"><LockKeyhole size={16} /><input name="password" type="password" placeholder="Your password" required autoComplete="current-password" /></div></label>
<label>
<span className="auth-label-row">
Password
<a className="auth-forgot" href="/forgot-password">Forgot password?</a>
</span>
<PasswordField
name="password"
placeholder="Your password"
required
autoComplete="current-password"
/>
</label>
{status.error && <p className="form-error" role="alert">{status.error}</p>}
<button className="button button-coral auth-submit" disabled={status.loading}>
{status.loading ? "Signing in…" : "Log in"} <ArrowRight size={16} />

View file

@ -0,0 +1,41 @@
import { Eye, EyeOff, LockKeyhole } from "lucide-react";
import { useState } from "react";
export default function PasswordField({
name,
placeholder,
autoComplete,
required,
minLength,
value,
onChange,
showLock = true,
className = "input-wrap",
}) {
const [visible, setVisible] = useState(false);
return (
<div className={className}>
{showLock ? <LockKeyhole size={16} /> : null}
<input
name={name}
type={visible ? "text" : "password"}
placeholder={placeholder}
required={required}
minLength={minLength}
autoComplete={autoComplete}
value={value}
onChange={onChange}
/>
<button
type="button"
className="password-peek"
aria-label={visible ? "Hide password" : "Show password"}
aria-pressed={visible}
onClick={() => setVisible((current) => !current)}
>
{visible ? <EyeOff size={15} /> : <Eye size={15} />}
</button>
</div>
);
}

View file

@ -1,9 +1,10 @@
import {
ArrowRight, Building2, CalendarDays, Eye, LockKeyhole, Mail, Phone, UserRound,
ArrowRight, Building2, CalendarDays, Mail, Phone, UserRound,
} from "lucide-react";
import { useState } from "react";
import { register } from "../api";
import AuthLayout from "./AuthLayout";
import PasswordField from "./PasswordField";
export default function SignupPage() {
const [accountType, setAccountType] = useState("individual");
@ -67,7 +68,7 @@ export default function SignupPage() {
</div>
<label>Date of birth<div className="input-wrap"><CalendarDays size={16} /><input name="date_of_birth" type="date" required /></div></label>
<label>Phone number<div className="input-wrap"><Phone size={16} /><input name="phone_number" type="tel" placeholder="+1 555 123 4567" required /></div></label>
<label>Password<div className="input-wrap"><LockKeyhole size={16} /><input name="password" type="password" placeholder="8+ characters" minLength="8" required autoComplete="new-password" /><Eye size={15} /></div><small className="field-hint">Use uppercase, lowercase, and a number.</small></label>
<label>Password<PasswordField name="password" placeholder="8+ characters" minLength={8} required autoComplete="new-password" /><small className="field-hint">Use uppercase, lowercase, and a number.</small></label>
{status.error && <p className="form-error" role="alert">{status.error}</p>}
<button className="button button-coral auth-submit" disabled={status.loading}>
{status.loading ? "Creating account…" : "Create account"} <ArrowRight size={16} />