"use client"; import { PlusIcon, RotateCcwIcon, Trash2Icon } from "lucide-react"; import { useMemo } from "react"; import * as z from "zod"; import { CharacterSelect, WeaponSelect, type AdminCatalogCharacter, type AdminCatalogWeapon, } from "@/components/admin/ui/catalog-select"; import { useImageGeneratorDraft } from "@/components/admin/use-image-generator-draft"; import { GuideImageExport } from "@/components/public/guide-image-export"; import { WeaponComparisonImage, type DamageMetric, type WeaponExportGuide, type WeaponGroup, } from "@/components/public/weapon-image-export"; import { Button } from "@/components/ui/button"; import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, } from "@/components/ui/empty"; import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { supportsWeaponType } from "@/lib/catalog/lunaris"; const rowSchema = z.object({ id: z.string(), weaponKey: z.string(), refinement: z.enum(["1", "2", "3", "4", "5", "1-5"]), overallPercent: z.string(), personalPercent: z.string(), note: z.string(), }); const draftSchema = z.object({ characterKey: z.string(), conditionLabel: z.string(), note: z.string(), metric: z.enum(["overallPercent", "personalPercent"]), rows: z.array(rowSchema).max(100), }); type WeaponDraft = z.infer; type WeaponRowDraft = WeaponDraft["rows"][number]; let nextRowId = 1; const emptyRow = (): WeaponRowDraft => ({ id: `weapon-image-${nextRowId++}`, weaponKey: "", refinement: "1", overallPercent: "100", personalPercent: "", note: "", }); const INITIAL_WEAPON_DRAFT: WeaponDraft = { characterKey: "", conditionLabel: "", note: "", metric: "overallPercent", rows: [], }; const parseWeaponDraft = (value: unknown): WeaponDraft | null => { const parsed = draftSchema.safeParse(value); return parsed.success ? parsed.data : null; }; function validPercent(value: string): boolean { if (!value.trim()) return false; const number = Number(value); return Number.isFinite(number) && number >= -9999 && number <= 9999; } export function WeaponImageGenerator({ characters, weapons, }: { characters: AdminCatalogCharacter[]; weapons: AdminCatalogWeapon[]; }) { const [draft, setDraft, resetDraft] = useImageGeneratorDraft( "buzz-sheet:admin-image:weapon", INITIAL_WEAPON_DRAFT, parseWeaponDraft, ); const character = characters.find((item) => item.key === draft.characterKey); const compatibleWeapons = weapons.filter((weapon) => supportsWeaponType(character?.weaponType, weapon.weaponType), ); const valid = Boolean( character && draft.rows.every((row) => compatibleWeapons.some((weapon) => weapon.key === row.weaponKey) && (validPercent(row.overallPercent) || validPercent(row.personalPercent)), ) && draft.rows.some((row) => validPercent(row[draft.metric])), ); const guide = useMemo(() => ({ name: character?.name ?? "Character", coverUrl: character?.imageUrl ?? "", character: { name: character?.name ?? "Character", splashImageUrl: character?.splashImageUrl ?? character?.imageUrl ?? null, }, }), [character]); const group = useMemo(() => ({ name: draft.conditionLabel.trim() || null, note: draft.note.trim() || null, rows: draft.rows.flatMap((row) => { const weapon = compatibleWeapons.find((item) => item.key === row.weaponKey); if (!weapon) return []; return [{ id: row.id, refinement: row.refinement, overallPercent: validPercent(row.overallPercent) ? row.overallPercent : null, personalPercent: validPercent(row.personalPercent) ? row.personalPercent : null, note: row.note.trim() || null, weapon, }]; }), }), [compatibleWeapons, draft]); const updateRow = (id: string, update: Partial) => { setDraft((current) => ({ ...current, rows: current.rows.map((row) => row.id === id ? { ...row, ...update } : row), })); }; return (
ข้อมูลเปรียบเทียบอาวุธ เลือกตัวละครและกรอกเปอร์เซ็นต์จากการคำนวณ {!draft.rows.length ? ( ยังไม่มีรายการอาวุธ เพิ่มอาวุธรายการแรกเพื่อเริ่มสร้างภาพเปรียบเทียบ ) : ( <> ตัวละคร setDraft((current) => ({ ...current, characterKey, rows: current.rows.map((row) => ({ ...row, weaponKey: "" })), }))} /> ชื่อเงื่อนไข (ถ้ามี) setDraft((current) => ({ ...current, conditionLabel: event.target.value }))} /> โน้ตท้ายภาพ (ถ้ามี)