From 7c76c2a2a0116de8418b0438a3859fc1add419e3 Mon Sep 17 00:00:00 2001
From: Siddharth Kumar Sah
Date: Sat, 28 Mar 2026 14:09:02 +0800
Subject: [PATCH] feat: add password generator and browser save prompt on
change-password page
Add a "Generate strong password" button that creates a random 16-char
password meeting all requirements (uppercase, lowercase, digit).
Generated passwords are shown in plain text so users can copy them.
Add autocomplete attributes (current-password, new-password, username)
so browsers prompt to save the new credentials after submission.
---
apps/web/src/pages/change-password-page.tsx | 75 +++++++++++++++++----
1 file changed, 63 insertions(+), 12 deletions(-)
diff --git a/apps/web/src/pages/change-password-page.tsx b/apps/web/src/pages/change-password-page.tsx
index 6f912747..98023226 100644
--- a/apps/web/src/pages/change-password-page.tsx
+++ b/apps/web/src/pages/change-password-page.tsx
@@ -1,11 +1,40 @@
import { type FormEvent, useState } from "react";
+function generatePassword(): string {
+ const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const lower = "abcdefghijklmnopqrstuvwxyz";
+ const digits = "0123456789";
+ const all = upper + lower + digits;
+ // Guarantee at least one of each required character class
+ const required = [
+ upper[Math.floor(Math.random() * upper.length)],
+ lower[Math.floor(Math.random() * lower.length)],
+ digits[Math.floor(Math.random() * digits.length)],
+ ];
+ const rest = Array.from({ length: 13 }, () => all[Math.floor(Math.random() * all.length)]);
+ // Shuffle so the required chars aren't always at the start
+ const chars = [...required, ...rest];
+ for (let i = chars.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [chars[i], chars[j]] = [chars[j], chars[i]];
+ }
+ return chars.join("");
+}
+
export function ChangePasswordPage() {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
+ const [showGenerated, setShowGenerated] = useState(false);
+
+ const handleGenerate = () => {
+ const pw = generatePassword();
+ setNewPassword(pw);
+ setConfirmPassword(pw);
+ setShowGenerated(true);
+ };
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
@@ -58,6 +87,13 @@ export function ChangePasswordPage() {