feat : use guide login only [no ci]
This commit is contained in:
@@ -10,7 +10,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
import { sudlohStartErrorMessage } from "@/lib/auth/sudloh-redirect";
|
||||
import { ProfileImageInput } from "./profile-image-input";
|
||||
|
||||
declare global {
|
||||
@@ -33,18 +32,12 @@ export function AccountForm({
|
||||
nextPath,
|
||||
verified,
|
||||
verificationError,
|
||||
oidcEnabled,
|
||||
oidcOnly,
|
||||
oidcError,
|
||||
}: {
|
||||
mode: "login" | "register";
|
||||
siteKey: string;
|
||||
nextPath: string;
|
||||
verified?: boolean;
|
||||
verificationError?: boolean;
|
||||
oidcEnabled?: boolean;
|
||||
oidcOnly?: boolean;
|
||||
oidcError?: string;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const register = mode === "register";
|
||||
@@ -59,7 +52,7 @@ export function AccountForm({
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
const widget = useRef<string | null>(null);
|
||||
const captcha = !oidcOnly && process.env.NODE_ENV !== "development";
|
||||
const captcha = process.env.NODE_ENV !== "development";
|
||||
useEffect(() => () => {
|
||||
if (profilePreview) URL.revokeObjectURL(profilePreview);
|
||||
}, [profilePreview]);
|
||||
@@ -179,44 +172,12 @@ export function AccountForm({
|
||||
} finally { setBusy(false); }
|
||||
}
|
||||
|
||||
async function signInWithSudloh() {
|
||||
if (busy) return;
|
||||
setBusy(true);
|
||||
setError("");
|
||||
try {
|
||||
const errorCallbackURL = `/auth/login?next=${encodeURIComponent(nextPath)}&sudloh=1`;
|
||||
const result = await authClient.signIn.social({
|
||||
provider: "sudloh", callbackURL: nextPath, errorCallbackURL,
|
||||
});
|
||||
if (result.error) {
|
||||
setError(sudlohStartErrorMessage(result.error.status));
|
||||
setBusy(false);
|
||||
}
|
||||
} catch {
|
||||
setError("เริ่มเข้าสู่ระบบด้วย Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง");
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>{register ? "สมัครสมาชิก" : "เข้าสู่ระบบ"}</CardTitle>
|
||||
{oidcEnabled && <p className="text-sm text-muted-foreground">
|
||||
{oidcOnly ? "ใช้ Sudloh Account แล้วกลับมายัง Buzz Guide หลังเข้าสู่ระบบ" : "ใช้ Sudloh Account หรือบัญชี Buzz Guide ของคุณ"}
|
||||
</p>}
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{oidcEnabled && <Button type="button" variant="outline" disabled={busy} onClick={() => void signInWithSudloh()}>
|
||||
ดำเนินการต่อด้วย Sudloh
|
||||
</Button>}
|
||||
{oidcError && <Alert variant="destructive"><AlertDescription>
|
||||
{oidcError === "account_not_linked"
|
||||
? oidcOnly ? "บัญชีนี้ยังไม่เชื่อมต่อกับ Buzz Guide กรุณาติดต่อผู้ดูแลเพื่อยืนยันตัวตน"
|
||||
: "มีบัญชี Buzz Guide ที่ใช้อีเมลนี้แล้ว กรุณาเข้าสู่ระบบด้วยอีเมลและเชื่อมต่อ Sudloh จากหน้าโปรไฟล์"
|
||||
: "เข้าสู่ระบบด้วย Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง"}
|
||||
</AlertDescription></Alert>}
|
||||
{!oidcOnly && <>
|
||||
{verified && <Alert><AlertDescription>ยืนยันอีเมลแล้ว กรุณาเข้าสู่ระบบ</AlertDescription></Alert>}
|
||||
{verificationError && <Alert variant="destructive"><AlertDescription>ลิงก์ยืนยันไม่ถูกต้องหรือหมดอายุ กรุณาขอลิงก์ใหม่</AlertDescription></Alert>}
|
||||
{notice && <Alert><AlertDescription>{notice}</AlertDescription></Alert>}
|
||||
@@ -318,7 +279,6 @@ export function AccountForm({
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
</>}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { SiteHeader } from "@/components/public/site-header";
|
||||
import { isAuthorizedAdmin } from "@/lib/auth/authorization";
|
||||
import { getCustomerSession, isSudlohOidcEnabled } from "@/lib/auth/server";
|
||||
import { getCustomerSession } from "@/lib/auth/server";
|
||||
import { safeAuthReturnPath } from "@/lib/auth/return-path";
|
||||
import { AccountForm } from "./account-form";
|
||||
import { SudlohSignInRedirect } from "./sudloh-sign-in-redirect";
|
||||
|
||||
export async function AccountPage({ mode, next, verified, verificationError, oidcError }: {
|
||||
export async function AccountPage({ mode, next, verified, verificationError }: {
|
||||
mode: "login" | "register"; next: unknown; verified?: boolean; verificationError?: boolean;
|
||||
oidcError?: string;
|
||||
}) {
|
||||
const nextPath = safeAuthReturnPath(next);
|
||||
const session = await getCustomerSession();
|
||||
@@ -17,15 +15,9 @@ export async function AccountPage({ mode, next, verified, verificationError, oid
|
||||
redirect(nextPath);
|
||||
}
|
||||
const siteKey = process.env.TURNSTILE_SITE_KEY ?? "";
|
||||
const oidcEnabled = isSudlohOidcEnabled();
|
||||
const oidcOnly = oidcEnabled && process.env.SUDLOH_OIDC_ONLY === "true";
|
||||
if (mode === "login" && oidcEnabled && !oidcError) {
|
||||
return <div className="min-h-svh"><SiteHeader /><SudlohSignInRedirect nextPath={nextPath} /></div>;
|
||||
}
|
||||
if (!oidcOnly && process.env.NODE_ENV !== "development" && !siteKey) throw new Error("TURNSTILE_SITE_KEY is required");
|
||||
if (process.env.NODE_ENV !== "development" && !siteKey) throw new Error("TURNSTILE_SITE_KEY is required");
|
||||
return <div className="min-h-svh"><SiteHeader /><main className="grid min-h-[calc(100svh-4rem)] place-items-center p-4">
|
||||
<AccountForm mode={mode} siteKey={siteKey} nextPath={nextPath}
|
||||
oidcEnabled={oidcEnabled} oidcOnly={oidcOnly}
|
||||
verified={verified} verificationError={verificationError} oidcError={oidcError} />
|
||||
verified={verified} verificationError={verificationError} />
|
||||
</main></div>;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import { authClient } from "@/lib/auth/client";
|
||||
|
||||
type Mode = "forgot" | "reset";
|
||||
|
||||
export function EmailActionForm({ mode, token = "", invalidToken = false, nextPath = "/", oidcEnabled = false, oidcOnly = false }: {
|
||||
mode: Mode; token?: string; invalidToken?: boolean; nextPath?: string; oidcEnabled?: boolean; oidcOnly?: boolean;
|
||||
export function EmailActionForm({ mode, token = "", invalidToken = false, nextPath = "/" }: {
|
||||
mode: Mode; token?: string; invalidToken?: boolean; nextPath?: string;
|
||||
}) {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
@@ -53,16 +53,6 @@ export function EmailActionForm({ mode, token = "", invalidToken = false, nextPa
|
||||
return <Card className="w-full max-w-sm">
|
||||
<CardHeader><CardTitle>{title}</CardTitle></CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{oidcOnly ? <>
|
||||
<p className="text-sm text-muted-foreground">Buzz Guide ใช้ Sudloh Account สำหรับเข้าสู่ระบบ กรุณาตั้งรหัสผ่านใหม่ที่ Sudloh Account</p>
|
||||
<Button nativeButton={false} render={<a href="https://account.sudloh.com/reset-password" target="_blank" rel="noreferrer" />}>
|
||||
ไปหน้าตั้งรหัสผ่าน Sudloh
|
||||
</Button>
|
||||
</> : null}
|
||||
{oidcEnabled && !oidcOnly && mode === "forgot" ? <p className="text-sm text-muted-foreground">
|
||||
หากเข้าสู่ระบบด้วย Sudloh Account ให้ <a href="https://account.sudloh.com/reset-password" target="_blank" rel="noreferrer" className="underline underline-offset-4">ตั้งรหัสผ่านที่ Sudloh</a> ส่วนแบบฟอร์มด้านล่างสำหรับบัญชี Buzz Guide ที่ใช้อีเมลและรหัสผ่าน
|
||||
</p> : null}
|
||||
{!oidcOnly && <>
|
||||
{sent && <Alert><AlertDescription>{mode === "reset"
|
||||
? "ตั้งรหัสผ่านใหม่แล้ว กรุณาเข้าสู่ระบบ"
|
||||
: "หากอีเมลนี้มีบัญชีอยู่ โปรดตรวจสอบกล่องจดหมายและโฟลเดอร์สแปม"}</AlertDescription></Alert>}
|
||||
@@ -90,7 +80,6 @@ export function EmailActionForm({ mode, token = "", invalidToken = false, nextPa
|
||||
{mode === "reset" && !canReset && !sent && <Button variant="link" nativeButton={false} render={<Link href={`/auth/forgot-password${nextPath === "/" ? "" : `?next=${encodeURIComponent(nextPath)}`}`} />}>
|
||||
ขอลิงก์รีเซ็ตใหม่
|
||||
</Button>}
|
||||
</>}
|
||||
<Button variant="link" nativeButton={false} render={<Link href={loginHref} />}>กลับไปเข้าสู่ระบบ</Button>
|
||||
</CardContent>
|
||||
</Card>;
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useRouter } from "next/navigation";
|
||||
import { LogOutIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
import { markSudlohSignInAttempt } from "@/lib/auth/sudloh-redirect";
|
||||
import { unsubscribeCommissionPush } from "@/components/commission/push-client";
|
||||
|
||||
export function SignOutButton({ admin = false }: { admin?: boolean }) {
|
||||
@@ -15,7 +14,6 @@ export function SignOutButton({ admin = false }: { admin?: boolean }) {
|
||||
async function signOut() {
|
||||
await unsubscribeCommissionPush().catch(() => undefined);
|
||||
await authClient.signOut();
|
||||
markSudlohSignInAttempt();
|
||||
router.push(admin ? "/auth/login?next=%2Fadmin" : "/commission");
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
|
||||
export function SudlohConnection({ linked, callbackError }: {
|
||||
linked: boolean;
|
||||
callbackError?: string;
|
||||
}) {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
async function connect() {
|
||||
if (busy) return;
|
||||
setBusy(true);
|
||||
setError("");
|
||||
try {
|
||||
const result = await authClient.linkSocial({
|
||||
provider: "sudloh",
|
||||
callbackURL: "/profile?sudloh=linked",
|
||||
errorCallbackURL: "/profile?sudloh=error",
|
||||
});
|
||||
if (result.error) throw new Error();
|
||||
} catch {
|
||||
setError("เชื่อมต่อ Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง");
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
const callbackMessage = callbackError === "email_does_not_match"
|
||||
? "อีเมล Sudloh ต้องตรงกับอีเมล Buzz Guide ก่อนเชื่อมต่อบัญชี"
|
||||
: callbackError === "account_already_linked_to_different_user"
|
||||
? "บัญชี Sudloh นี้เชื่อมต่อกับบัญชี Buzz Guide อื่นแล้ว"
|
||||
: callbackError ? "เชื่อมต่อ Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง" : "";
|
||||
|
||||
return <Card>
|
||||
<CardHeader><CardTitle>Sudloh Account</CardTitle></CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{linked ? "เชื่อมต่อแล้ว คุณสามารถใช้ Sudloh เพื่อเข้าสู่ระบบ Buzz Guide"
|
||||
: "เชื่อมต่อบัญชี Sudloh เพื่อใช้เข้าสู่ระบบ Buzz Guide ในครั้งถัดไป"}
|
||||
</p>
|
||||
{!linked && <Button type="button" variant="outline" disabled={busy} onClick={() => void connect()}>
|
||||
{busy ? "กำลังเชื่อมต่อ..." : "เชื่อมต่อ Sudloh"}
|
||||
</Button>}
|
||||
{(callbackMessage || error) && <Alert variant="destructive"><AlertDescription>
|
||||
{callbackMessage || error}
|
||||
</AlertDescription></Alert>}
|
||||
</CardContent>
|
||||
</Card>;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
|
||||
export function SudlohProfile({ name, email, image, accountUrl, callbackError }: {
|
||||
name: string; email: string; image: string | null; accountUrl: string; callbackError: boolean;
|
||||
}) {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
async function refresh() {
|
||||
setBusy(true);
|
||||
setError("");
|
||||
try {
|
||||
const response = await fetch("/api/profile/sync", { method: "POST" });
|
||||
if (response.status === 401) {
|
||||
const result = await authClient.signIn.social({ provider: "sudloh", callbackURL: "/profile",
|
||||
errorCallbackURL: "/profile?sudloh=error" });
|
||||
if (result.error) throw new Error("เข้าสู่ระบบ Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง");
|
||||
return;
|
||||
}
|
||||
if (response.status === 409) throw new Error("อีเมลนี้ถูกใช้โดยบัญชี Buzz Guide อื่น กรุณาติดต่อผู้ดูแล");
|
||||
if (!response.ok) throw new Error("อัปเดตข้อมูลจาก Sudloh ไม่สำเร็จ กรุณาเข้าสู่ระบบใหม่แล้วลองอีกครั้ง");
|
||||
window.location.reload();
|
||||
} catch (cause) {
|
||||
setError(cause instanceof Error ? cause.message : "อัปเดตข้อมูลจาก Sudloh ไม่สำเร็จ");
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return <Card>
|
||||
<CardHeader><CardTitle>ข้อมูลบัญชี</CardTitle>
|
||||
<CardDescription>จัดการชื่อ รูปโปรไฟล์ และอีเมลที่ Sudloh Account</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex items-center gap-4">
|
||||
<Avatar size="lg" className="size-16">
|
||||
{image && <AvatarImage src={image} alt="รูปโปรไฟล์" />}
|
||||
<AvatarFallback>{name.trim().charAt(0).toUpperCase() || "?"}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0"><p className="font-medium">{name}</p>
|
||||
<p className="truncate text-sm text-muted-foreground">{email}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-wrap gap-2">
|
||||
<Button render={<a href={accountUrl} />}>จัดการบัญชีที่ Sudloh</Button>
|
||||
<Button type="button" variant="outline" disabled={busy} onClick={() => void refresh()}>
|
||||
{busy ? "กำลังอัปเดต..." : "อัปเดตข้อมูลจาก Sudloh"}
|
||||
</Button>
|
||||
{(error || callbackError) && <Alert variant="destructive"><AlertDescription>
|
||||
{error || "เข้าสู่ระบบ Sudloh ไม่สำเร็จ กรุณาลองอีกครั้ง"}
|
||||
</AlertDescription></Alert>}
|
||||
</CardFooter>
|
||||
</Card>;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
import { claimAutomaticSudlohSignIn, markSudlohSignInAttempt, sudlohStartErrorMessage } from "@/lib/auth/sudloh-redirect";
|
||||
|
||||
export function SudlohSignInRedirect({ nextPath }: { nextPath: string }) {
|
||||
const started = useRef(false);
|
||||
const [message, setMessage] = useState("กำลังไปที่ Sudloh Account…");
|
||||
const [showRetry, setShowRetry] = useState(false);
|
||||
|
||||
const start = useCallback(async () => {
|
||||
markSudlohSignInAttempt();
|
||||
setShowRetry(false);
|
||||
setMessage("กำลังไปที่ Sudloh Account…");
|
||||
try {
|
||||
const result = await authClient.signIn.social({
|
||||
provider: "sudloh",
|
||||
callbackURL: nextPath,
|
||||
errorCallbackURL: `/auth/login?next=${encodeURIComponent(nextPath)}&sudloh=1`,
|
||||
});
|
||||
if (result.error) {
|
||||
setMessage(sudlohStartErrorMessage(result.error.status));
|
||||
setShowRetry(true);
|
||||
}
|
||||
} catch {
|
||||
setMessage(sudlohStartErrorMessage());
|
||||
setShowRetry(true);
|
||||
}
|
||||
}, [nextPath]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = window.setTimeout(() => {
|
||||
if (started.current) return;
|
||||
started.current = true;
|
||||
if (claimAutomaticSudlohSignIn()) void start();
|
||||
else {
|
||||
setMessage("การเข้าสู่ระบบยังไม่เสร็จ กรุณาลองอีกครั้ง");
|
||||
setShowRetry(true);
|
||||
}
|
||||
}, 0);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [start]);
|
||||
|
||||
return <div className="grid min-h-[calc(100svh-4rem)] place-items-center p-4">
|
||||
<div className="flex flex-col items-center gap-4 text-center">
|
||||
<p>{message}</p>
|
||||
<p className="max-w-sm text-sm text-muted-foreground">เข้าสู่ระบบหรือสมัครสมาชิกที่ Sudloh Account แล้วระบบจะพาคุณกลับมายัง Buzz Guide</p>
|
||||
{showRetry && <Button onClick={() => void start()}>ลองอีกครั้ง</Button>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
Reference in New Issue
Block a user