/** biome-ignore-all lint/a11y/noStaticElementInteractions: Span is needed for double triggering */ /** biome-ignore-all lint/a11y/useKeyWithClickEvents: Not needed */ "use client"; import { ArrowBigUp, BookAlert, CircleX, Loader2, Search, UserSearch, Wrench, } from "lucide-react"; import Image from "next/image"; import { use, useEffect, useState } from "react"; import { toast } from "sonner"; import GuideImage1 from "#/guide/1.png"; import GuideImage2 from "#/guide/2.png"; import Avatar from "@/components/avatar"; import { Blocker } from "@/components/blocker"; import { ComboBox } from "@/components/combobox"; import { HorizontalDiv } from "@/components/horizontal"; import { SimpleTooltip } from "@/components/tooltip"; import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { ScrollBar } from "@/components/ui/scroll-area"; import { Spinner } from "@/components/ui/spinner"; import { getCharacters } from "@/lib/api"; import { IccContext, shared } from "@/lib/comms"; import { uidRegex } from "@/lib/const"; import type { characters } from "@/lib/db/schema"; import { cn } from "@/lib/utils"; import type { EnkaNetworkUser } from "@/types/enka"; import { Countdown } from "../rubgram/client"; import { RulesDialog } from "./rules"; export function CharacterChooser({ clist, uid: defaultUid = "", char: defaultChar, }: { clist: { value: string; label: string; }[]; uid?: string; char?: string; }) { const [uid, setUid] = useState(defaultUid); const [chars, setChars] = useState<(typeof characters.$inferSelect)[]>([]); const [selected, setSelected] = useState(defaultChar); const [isError, setIsError] = useState(false); const [isLoading, setIsLoading] = useState(false); const [manual, setManual] = useState(false); const [, setWarningUid] = shared.state("warning.uid"); const [, setWarningSrc] = shared.state("warning.src"); const [, setWarning] = shared.state("warning"); useEffect(() => { if (defaultUid) setUid(defaultUid); }, [defaultUid]); useEffect(() => { setIsLoading(true); setIsError(false); async function fetchChars() { try { if (!uidRegex.test(uid)) return setChars([]); const res = await fetch(`/api/enka/${uid}`); const data: | (EnkaNetworkUser & { message: undefined }) | { message: string; playerInfo: undefined } = await res .json() .catch(() => ({ message: "not json" })); if (data.message === "This player does not exist.") return setIsError("ไม่พบผู้เล่นที่มี UID นี้"); if (!res.ok) return setIsError(true); if (!data.playerInfo) return setIsError(true); if (!data.playerInfo.showAvatarInfoList) return setIsError("UID นี้ไม่มีตัวละครที่จัดแสดงเป็นสาธารณะ"); const charIds = data.playerInfo.showAvatarInfoList.map((c) => c.avatarId.toString(), ); const chars = await getCharacters(charIds); const userChars = charIds .map((e) => chars.find((c) => c.amber === e)!) .filter(Boolean); setChars(userChars); setSelected( userChars.some((c) => c.name === defaultChar) ? defaultChar : undefined, ); } catch (e) { console.error(e); setIsError("ข้อผิดพลาดภายในระบบ"); } } fetchChars() .catch(() => setIsError(true)) .finally(() => setIsLoading(false)); }, [uid, defaultChar]); return ( <>
setUid(ev.target.value)} defaultValue={defaultUid} />
{manual ? ( ) : ( {isError ? (
{" "} {typeof isError === "string" ? isError : "เกิดข้อผิดพลาดในการดึงข้อมูล"}
) : isLoading ? ( กำลังโหลดตัวละคร... ) : !chars.length ? (
) : (
setManual(true)} > {chars.map((c) => ( ))}
)}
)} ); } function Placeholder({ className, ...props }: React.ComponentProps<"div">) { return (
); } export function Disclaimer() { const [agreed, setAgreed] = useState(false); const [updated] = shared.state("updated"); if (agreed || updated) return; return ( !set && setAgreed(true)}> ); } export function ClearCookie() { // biome-ignore lint/suspicious/noTsIgnore: typescript issue // @ts-ignore try { cookieStore.delete("sid"); } catch { // not in browser(im too lazy to check) } return ""; } export function WarningDialog() { const [warning, setWarning] = shared.state("warning"); const [uid] = shared.state("warning.uid"); const [open, setOpen] = useState(false); const [isRefreshing, setRefreshing] = useState(false); const [cacheTtl, setCacheTtl] = useState(new Date()); const icc = use(IccContext); // 👀 open when warning === "guide" useEffect(() => { setOpen(warning === "guide"); }, [warning]); async function refreshChars() { if (!uid) return; setRefreshing(true); try { const res = await fetch(`/api/enka/${uid}`); const data: | (EnkaNetworkUser & { message: undefined }) | { message: string; playerInfo: undefined } = await res .json() .catch(() => ({ message: "not json" })); if (data.message === "This player does not exist.") return toast.error("ไม่พบผู้เล่นที่มี UID นี้"); if (!res.ok || !data.playerInfo) return toast.error("เกิดข้อผิดพลาดในการดึงข้อมูล"); setCacheTtl(new Date(Date.now() + data.ttl * 1000)); if (!data.playerInfo.showAvatarInfoList) return toast.error("ยังไม่พบตัวละคร ลองใหม่อีกครั้ง"); const charIds = data.playerInfo.showAvatarInfoList.map((c) => c.avatarId.toString(), ); await getCharacters(charIds); // warm cache / ensure available // ✅ success → close dialog + notify setWarning(undefined); icc.emit("warningSolved"); setOpen(false); } catch (e) { console.error(e); toast.error("ข้อผิดพลาดภายในระบบ"); } finally { setRefreshing(false); } } if (warning === "nf") return ( setWarning(undefined)} open> เดี๋ยวนะ UID นี้ไม่มีอยู่จริง แน่เหรอว่าจะส่ง? ยกเลิก ); if (warning === "showcase") return ( setWarning(undefined)} open> เดี๋ยวนะ ตัวละครที่เลือกไม่ได้อยู่ในตั้งโชว์
ถ้าส่งก่อนใส่มันจะไม่ขึ้นนะ ไปแก้ก่อนมั้ย ยกเลิก
); if (warning === "private") return ( setWarning(undefined)} open> เดี๋ยวนะ ใน UID นี้ไม่มีตัวละครอะไรตั้งโชว์อยู่เลย
ถ้าส่งก่อนใส่มันจะไม่ขึ้นนะ ไปแก้ก่อนมั้ย ยกเลิก
); if (!warning) return null; return ( { setOpen(o); if (!o) setWarning(undefined); }} > วิธีแก้ไขตัวละครไม่ขึ้น
ในเกม เปิดเมนูเกมแล้วไปที่ แก้ไขข้อมูลส่วนตัว
Guide Image 1
ใส่ตัวละครที่ต้องการ แล้วเปิด "แสดงรายละเอียดตัวละคร"
Guide Image 2 อย่าลืมเปิด
ออกจากเกมเพื่อให้ข้อมูลอัพเดท แล้วกดรีโหลด
ปิดหน้าต่าง ( )} />
); }