feat : update
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
+2
-2
@@ -20,8 +20,8 @@ const geistMono = Geist_Mono({
|
|||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
default: "Buzz Sheet — คู่มือเกม",
|
default: "Buzz Guide",
|
||||||
template: "%s | Buzz Sheet",
|
template: "%s",
|
||||||
},
|
},
|
||||||
description: "คู่มือตัวละคร บิลด์ ทีม และโรเทชันที่อ่านง่ายในทุกหน้าจอ",
|
description: "คู่มือตัวละคร บิลด์ ทีม และโรเทชันที่อ่านง่ายในทุกหน้าจอ",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ export function CreateGuideFlow({ characters, existingKeys }: { characters: Char
|
|||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
return (
|
return (
|
||||||
<Card className="mx-auto max-w-2xl">
|
<Card className="mx-auto w-full max-w-4xl">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>ตั้งค่า Guide ของ {selected.name}</CardTitle>
|
<CardTitle>ตั้งค่า Guide ของ {selected.name}</CardTitle>
|
||||||
<CardDescription>เพิ่มภาพหน้าปกและ Overview ก่อนสร้าง Guide สาธารณะ</CardDescription>
|
<CardDescription>เพิ่มภาพหน้าปก และใส่ Overview ได้หากต้องการ</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<FieldGroup>
|
<FieldGroup>
|
||||||
@@ -47,7 +47,7 @@ export function CreateGuideFlow({ characters, existingKeys }: { characters: Char
|
|||||||
<MediaUploader onReady={setCover} />
|
<MediaUploader onReady={setCover} />
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel htmlFor="overview">Overview</FieldLabel>
|
<FieldLabel htmlFor="overview">Overview (optional)</FieldLabel>
|
||||||
<Textarea id="overview" value={overview} maxLength={500} onChange={(event) => setOverview(event.target.value)} placeholder="สรุปแนวทางเล่น จุดเด่น และสิ่งที่ผู้ชมจะพบใน Guide นี้" />
|
<Textarea id="overview" value={overview} maxLength={500} onChange={(event) => setOverview(event.target.value)} placeholder="สรุปแนวทางเล่น จุดเด่น และสิ่งที่ผู้ชมจะพบใน Guide นี้" />
|
||||||
<FieldDescription>{overview.length}/500 ตัวอักษร</FieldDescription>
|
<FieldDescription>{overview.length}/500 ตัวอักษร</FieldDescription>
|
||||||
</Field>
|
</Field>
|
||||||
@@ -55,7 +55,7 @@ export function CreateGuideFlow({ characters, existingKeys }: { characters: Char
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter className="justify-between">
|
<CardFooter className="justify-between">
|
||||||
<Button type="button" variant="outline" onClick={() => setSelected(null)}><ArrowLeftIcon data-icon="inline-start" />เลือกใหม่</Button>
|
<Button type="button" variant="outline" onClick={() => setSelected(null)}><ArrowLeftIcon data-icon="inline-start" />เลือกใหม่</Button>
|
||||||
<Button disabled={pending || !cover || !overview.trim()} onClick={() => startTransition(async () => {
|
<Button disabled={pending || !cover} onClick={() => startTransition(async () => {
|
||||||
const result = await createStructuredGuide({ characterKey: selected.key, coverMediaId: cover?.id, overview });
|
const result = await createStructuredGuide({ characterKey: selected.key, coverMediaId: cover?.id, overview });
|
||||||
if (result.status === "error") { toast.error(result.message); return; }
|
if (result.status === "error") { toast.error(result.message); return; }
|
||||||
toast.success("สร้าง Guide แล้ว");
|
toast.success("สร้าง Guide แล้ว");
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { calculateTeamMetrics } from "@/lib/guides/calculations";
|
import { calculateTeamMetrics } from "@/lib/guides/calculations";
|
||||||
import { artifactSectionSchema, teamSectionSchema, weaponSectionSchema } from "@/lib/guides/schemas";
|
import { artifactSectionSchema, createGuideSchema, teamSectionSchema, weaponSectionSchema } from "@/lib/guides/schemas";
|
||||||
|
|
||||||
describe("structured guide validation", () => {
|
describe("structured guide validation", () => {
|
||||||
|
it("allows creating a guide without an overview", () => {
|
||||||
|
expect(createGuideSchema.safeParse({ characterKey: "1", coverMediaId: "550e8400-e29b-41d4-a716-446655440000", overview: "" }).success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("requires at least one weapon percentage", () => {
|
it("requires at least one weapon percentage", () => {
|
||||||
expect(weaponSectionSchema.safeParse({ expectedVersion: 1, rows: [{ weaponKey: "1", refinement: 5, overallPercent: null, personalPercent: null }] }).success).toBe(false);
|
expect(weaponSectionSchema.safeParse({ expectedVersion: 1, rows: [{ weaponKey: "1", refinement: 5, overallPercent: null, personalPercent: null }] }).success).toBe(false);
|
||||||
expect(weaponSectionSchema.safeParse({ expectedVersion: 1, rows: [{ weaponKey: "1", refinement: 5, overallPercent: 104, personalPercent: null }] }).success).toBe(true);
|
expect(weaponSectionSchema.safeParse({ expectedVersion: 1, rows: [{ weaponKey: "1", refinement: 5, overallPercent: 104, personalPercent: null }] }).success).toBe(true);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const catalogKey = z.string().trim().min(1).max(64);
|
|||||||
export const createGuideSchema = z.strictObject({
|
export const createGuideSchema = z.strictObject({
|
||||||
characterKey: catalogKey,
|
characterKey: catalogKey,
|
||||||
coverMediaId: z.string().uuid(),
|
coverMediaId: z.string().uuid(),
|
||||||
overview: z.string().trim().min(1).max(500),
|
overview: z.string().trim().max(500),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const updateGuideSchema = z.strictObject({
|
export const updateGuideSchema = z.strictObject({
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Reference in New Issue
Block a user