feat : update
CI / Verify (push) Successful in 3m8s
CI / Build immutable images and deploy (push) Successful in 3m11s

This commit is contained in:
2026-10-05 22:40:59 +07:00 Unverified
parent 7729068219
commit d6153be50d
19 changed files with 304 additions and 84 deletions
@@ -0,0 +1,76 @@
import Image from "next/image";
import { UserRoundIcon } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
const steps = [
{ title: "1. เลือกรายการ", description: "เลือกทีม อาวุธ หรือกลุ่มดาวที่ต้องการคำนวณ" },
{ title: "2. ชำระเงิน", description: "ตรวจสอบยอด สแกน PromptPay และส่งสลิป" },
{ title: "3. รับผลใน Ticket", description: "ติดตามคำขอและพูดคุยเรื่องผลลัพธ์ใน Ticket ของคุณ" },
];
const sampleMembers = [
{ name: "ตัวละคร A", damage: "40,000", share: "40.00%" },
{ name: "ตัวละคร B", damage: "30,000", share: "30.00%" },
{ name: "ตัวละคร C", damage: "20,000", share: "20.00%" },
{ name: "ตัวละคร D", damage: "10,000", share: "10.00%" },
];
function CommissionTeamPreview() {
return <Card>
<CardHeader>
<CardTitle>ตัวอย่างทีม 4 ตัวละคร</CardTitle>
<CardDescription>โรเทชั่น 20 วิ · ข้อมูลสมมติสำหรับดูรูปแบบผลลัพธ์</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<div className="grid grid-cols-4 gap-1 sm:gap-3">
{sampleMembers.map((member) => <div key={member.name} className="min-w-0 rounded-lg bg-muted/50 p-1 text-center sm:p-2">
<div className="flex flex-col gap-2 sm:grid sm:grid-cols-3">
<div className="flex aspect-square items-center justify-center rounded-lg bg-accent sm:col-span-2 sm:row-span-2"><UserRoundIcon className="size-8 text-muted-foreground" aria-hidden="true" /></div>
<div className="grid grid-cols-2 gap-1 sm:col-span-1 sm:row-span-2 sm:grid-cols-1">
<div className="flex aspect-square items-center justify-center rounded-md border bg-card"><Image src="/icon/nav/Weapon.png" alt="" width={24} height={24} className="size-5 object-contain opacity-60 sm:size-6" /></div>
<div className="flex aspect-square items-center justify-center rounded-md border bg-card"><Image src="/icon/nav/Artifact.webp" alt="" width={24} height={24} className="size-5 object-contain opacity-60 sm:size-6" /></div>
</div>
</div>
<div className="mt-2 flex items-center justify-center gap-1"><Badge variant="secondary">C0</Badge><Badge variant="secondary">R1</Badge></div>
<p className="mt-1 truncate text-xs font-medium sm:text-sm">{member.name}</p>
<p className="text-xs font-semibold sm:text-sm">{member.damage}</p>
<p className="text-xs text-muted-foreground">{member.share}</p>
</div>)}
</div>
<Separator />
<div className="flex items-end justify-between">
<div><p className="text-sm text-muted-foreground">ดาเมจรวม</p><p className="font-semibold">100,000</p></div>
<div className="text-right"><p className="text-sm text-muted-foreground">DPS</p><p className="text-3xl font-semibold text-primary">5,000</p></div>
</div>
<p className="rounded-lg bg-muted p-3 text-sm leading-6">ตัวอย่างลำดับการใช้สกิลและคำอธิบายทีม</p>
</CardContent>
</Card>;
}
export function CommissionIntro() {
return <section className="flex flex-col gap-6" aria-labelledby="commission-how-it-works">
<div>
<h2 id="commission-how-it-works" className="font-heading text-2xl font-semibold">ขอคำนวณแบบที่ต้องการ</h2>
<p className="mt-2 text-muted-foreground">เลือกได้ทั้งจัดทีม เปรียบเทียบอาวุธ และเปรียบเทียบกลุ่มดาว โดยเห็นยอดก่อนชำระเงิน</p>
</div>
<div className="grid gap-3 sm:grid-cols-3">
{steps.map((step) => <Card key={step.title} size="sm">
<CardHeader><CardTitle>{step.title}</CardTitle><CardDescription>{step.description}</CardDescription></CardHeader>
</Card>)}
</div>
<div className="grid gap-4 lg:grid-cols-2">
<Card>
<CardHeader><CardTitle>ราคาเริ่มต้น</CardTitle><CardDescription>ระบบคำนวณยอดรวมจากรายการที่เลือก</CardDescription></CardHeader>
<CardContent className="flex flex-col gap-3 text-sm">
<p className="flex justify-between gap-3"><span>จัดทีม 4 ตัวละคร</span><strong>฿100 ต่อทีม</strong></p>
<p className="flex justify-between gap-3"><span>เปรียบเทียบอาวุธ</span><strong>฿20 ต่ออาวุธ</strong></p>
<p className="flex justify-between gap-3"><span>เปรียบเทียบกลุ่มดาว</span><strong>฿20 ต่อระดับ</strong></p>
<p className="border-t pt-3 text-muted-foreground">หากไม่เลือกทีม จะมีค่าบริการพื้นฐาน ฿100</p>
</CardContent>
</Card>
<CommissionTeamPreview />
</div>
</section>;
}
+7 -1
View File
@@ -2,7 +2,8 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import { XIcon } from "lucide-react";
import Image from "next/image";
import { UserRoundIcon, XIcon } from "lucide-react";
import { toast } from "sonner";
import { ArtifactSelect, CharacterSelect, WeaponSelect } from "@/components/admin/ui/catalog-select";
import { ConstellationSelect, RefinementSelect } from "@/components/admin/ui/option-select";
@@ -95,18 +96,21 @@ export function CommissionRequestForm({ catalog }: { catalog: Catalog }) {
<div className="grid grid-cols-[2fr_1fr] gap-1">
<CharacterSelect presentation="slot" items={catalog.characters} value={member.characterKey}
label={`เลือกตัวละครตำแหน่ง ${memberIndex + 1}`} placeholder="ค้นหาชื่อตัวละคร…"
placeholderIcon={<UserRoundIcon className="size-10" aria-hidden="true" />}
className="border-0 [&>img]:object-cover [&>img]:p-0" onValueChange={(characterKey) => {
const teams = structuredClone(request.teams); teams[teamIndex].members[memberIndex] = { ...blankMember(), characterKey }; patch({ teams });
}} />
<div className="grid min-w-0 grid-rows-2 gap-1">
<WeaponSelect presentation="slot" items={compatibleWeapons(member.characterKey)} value={member.weaponKey}
label={`เลือกอาวุธของตัวละครตำแหน่ง ${memberIndex + 1}`} placeholder="ค้นหาอาวุธที่รองรับ…"
placeholderIcon={<Image src="/icon/nav/Weapon.png" alt="" width={32} height={32} className="size-8 object-contain opacity-60" />}
emptyLabel={character ? "ไม่พบอาวุธ" : "เลือกตัวละครก่อน"} onValueChange={(weaponKey) => {
const teams = structuredClone(request.teams); teams[teamIndex].members[memberIndex].weaponKey = weaponKey;
teams[teamIndex].members[memberIndex].refinement = "1"; patch({ teams });
}} />
<ArtifactSelect presentation="slot" items={catalog.artifacts} value={member.artifactKey}
label={`เลือกอาร์ติแฟกต์ของตัวละครตำแหน่ง ${memberIndex + 1}`} placeholder="ค้นหาชุดอาร์ติแฟกต์…"
placeholderIcon={<Image src="/icon/nav/Artifact.webp" alt="" width={32} height={32} className="size-8 object-contain opacity-60" />}
onValueChange={(artifactKey) => {
const teams = structuredClone(request.teams); teams[teamIndex].members[memberIndex].artifactKey = artifactKey; patch({ teams });
}} />
@@ -177,6 +181,7 @@ export function CommissionRequestForm({ catalog }: { catalog: Catalog }) {
<div className="relative w-20 sm:w-24">
<CharacterSelect presentation="slot" items={catalog.characters} value={set.characterKey}
label={`เลือกตัวละครเปรียบเทียบอาวุธชุดที่ ${index + 1}`} placeholder="ค้นหาชื่อตัวละคร…"
placeholderIcon={<UserRoundIcon className="size-9" aria-hidden="true" />}
className="border-0 [&>img]:object-cover [&>img]:p-0" onValueChange={(characterKey) => {
const weapons = structuredClone(request.weapons); weapons[index] = { characterKey, weaponKeys: [""], refinements: {} }; patch({ weapons });
}} />
@@ -209,6 +214,7 @@ export function CommissionRequestForm({ catalog }: { catalog: Catalog }) {
<div className="w-20 sm:w-24">
<CharacterSelect presentation="slot" items={catalog.characters} value={set.characterKey}
label={`เลือกตัวละครเปรียบเทียบกลุ่มดาวชุดที่ ${index + 1}`} placeholder="ค้นหาชื่อตัวละคร…"
placeholderIcon={<UserRoundIcon className="size-9" aria-hidden="true" />}
className="border-0 [&>img]:object-cover [&>img]:p-0" onValueChange={(characterKey) => {
const constellations = structuredClone(request.constellations); constellations[index] = { characterKey, levels: [] }; patch({ constellations });
}} />