feat(auth) : let Google-only users add a password

This commit is contained in:
2026-10-12 00:34:43 +07:00 Unverified
parent 839f98aab7
commit e2af59292c
3 changed files with 76 additions and 25 deletions
+41 -20
View File
@@ -1,6 +1,7 @@
"use client";
import { useRef, useState, type FormEvent } from "react";
import { useRouter } from "next/navigation";
import { KeyRoundIcon } from "lucide-react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
@@ -9,11 +10,13 @@ import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { authClient } from "@/lib/auth/client";
export function PasswordForm() {
export function PasswordForm({ hasPassword: initialHasPassword }: { hasPassword: boolean }) {
const router = useRouter();
const formRef = useRef<HTMLFormElement>(null);
const [hasPassword, setHasPassword] = useState(initialHasPassword);
const [busy, setBusy] = useState(false);
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
const [success, setSuccess] = useState("");
async function changePassword(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
@@ -23,24 +26,38 @@ export function PasswordForm() {
const newPassword = String(form.get("newPassword") ?? "");
const confirmPassword = String(form.get("confirmPassword") ?? "");
setError("");
setSuccess(false);
setSuccess("");
if (newPassword !== confirmPassword) {
setError("รหัสผ่านใหม่ไม่ตรงกัน");
setError(hasPassword ? "รหัสผ่านใหม่ไม่ตรงกัน" : "รหัสผ่านไม่ตรงกัน");
return;
}
setBusy(true);
try {
const result = await authClient.changePassword({ currentPassword, newPassword });
if (result.error) {
setError(result.error.code === "INVALID_PASSWORD"
? "รหัสผ่านปัจจุบันไม่ถูกต้อง"
: "เปลี่ยนรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง");
return;
if (hasPassword) {
const result = await authClient.changePassword({ currentPassword, newPassword });
if (result.error) {
setError(result.error.code === "INVALID_PASSWORD"
? "รหัสผ่านปัจจุบันไม่ถูกต้อง"
: "เปลี่ยนรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง");
return;
}
} else {
const response = await fetch("/api/profile/password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ newPassword }),
});
if (!response.ok) {
setError("เพิ่มรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง");
return;
}
setHasPassword(true);
router.refresh();
}
formRef.current?.reset();
setSuccess(true);
setSuccess(hasPassword ? "เปลี่ยนรหัสผ่านเรียบร้อยแล้ว" : "เพิ่มรหัสผ่านเรียบร้อยแล้ว");
} catch {
setError("เปลี่ยนรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง");
setError(hasPassword ? "เปลี่ยนรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง" : "เพิ่มรหัสผ่านไม่สำเร็จ กรุณาลองอีกครั้ง");
} finally {
setBusy(false);
}
@@ -50,36 +67,40 @@ export function PasswordForm() {
<CardHeader>
<CardTitle className="flex items-center gap-2">
<KeyRoundIcon aria-hidden="true" className="size-4 shrink-0" />
เปลี่ยนรหัสผ่าน
{hasPassword ? "เปลี่ยนรหัสผ่าน" : "เพิ่มรหัสผ่าน"}
</CardTitle>
<CardDescription>กรอกรหัสผ่านปัจจุบันและรหัสผ่านใหม่</CardDescription>
<CardDescription>{hasPassword
? "กรอกรหัสผ่านปัจจุบันและรหัสผ่านใหม่"
: "บัญชีนี้ยังไม่มีรหัสผ่าน เพิ่มรหัสผ่านเพื่อเข้าสู่ระบบด้วยอีเมลได้ด้วย"}</CardDescription>
</CardHeader>
<CardContent>
<form id="password-form" ref={formRef} onSubmit={changePassword}>
<FieldGroup>
<Field>
{hasPassword && <Field>
<FieldLabel htmlFor="current-password">รหัสผ่านปัจจุบัน</FieldLabel>
<Input id="current-password" name="currentPassword" type="password"
autoComplete="current-password" required disabled={busy} />
</Field>
</Field>}
<Field>
<FieldLabel htmlFor="new-password">รหัสผ่านใหม่</FieldLabel>
<FieldLabel htmlFor="new-password">{hasPassword ? "รหัสผ่านใหม่" : "รหัสผ่าน"}</FieldLabel>
<Input id="new-password" name="newPassword" type="password"
autoComplete="new-password" minLength={6} maxLength={128} required disabled={busy} />
</Field>
<Field>
<FieldLabel htmlFor="confirm-password">ยืนยันรหัสผ่านใหม่</FieldLabel>
<FieldLabel htmlFor="confirm-password">{hasPassword ? "ยืนยันรหัสผ่านใหม่" : "ยืนยันรหัสผ่าน"}</FieldLabel>
<Input id="confirm-password" name="confirmPassword" type="password"
autoComplete="new-password" minLength={6} maxLength={128} required disabled={busy} />
</Field>
{error && <Alert variant="destructive"><AlertDescription>{error}</AlertDescription></Alert>}
{success && <Alert><AlertDescription>เปลี่ยนรหัสผ่านเรียบร้อยแล้ว</AlertDescription></Alert>}
{success && <Alert role="status"><AlertDescription>{success}</AlertDescription></Alert>}
</FieldGroup>
</form>
</CardContent>
<CardFooter>
<Button type="submit" form="password-form" disabled={busy}>
{busy ? "กำลังเปลี่ยนรหัสผ่าน..." : "เปลี่ยนรหัสผ่าน"}
{busy
? hasPassword ? "กำลังเปลี่ยนรหัสผ่าน..." : "กำลังเพิ่มรหัสผ่าน..."
: hasPassword ? "เปลี่ยนรหัสผ่าน" : "เพิ่มรหัสผ่าน"}
</Button>
</CardFooter>
</Card>;