"use client"; import { ImagePlusIcon, UploadCloudIcon } from "lucide-react"; import { useId, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"; import { Spinner } from "@/components/ui/spinner"; import { IMAGE_MIME_TYPES, MAX_MEDIA_BYTES } from "@/lib/media/validation"; export interface UploadedMedia { id: string; url: string; fileName: string; } export function MediaUploader({ onReady, }: { onReady: (media: UploadedMedia) => void; }) { const inputId = useId(); const [state, setState] = useState<"idle" | "uploading">("idle"); const busy = state !== "idle"; async function upload(file: File) { if (!IMAGE_MIME_TYPES.includes(file.type as (typeof IMAGE_MIME_TYPES)[number])) { toast.error("รองรับเฉพาะ PNG, JPEG, WebP และ GIF"); return; } if (file.size <= 0 || file.size > MAX_MEDIA_BYTES) { toast.error("ไฟล์ต้องมีขนาดไม่เกิน 20 MB"); return; } try { setState("uploading"); const body = new FormData(); body.set("file", file); const response = await fetch("/api/admin/media", { method: "POST", body, }); const result = await response.json() as UploadedMedia & { error?: string }; if (!response.ok) throw new Error(result.error || "upload"); onReady(result); toast.success("อัปโหลดรูปภาพแล้ว"); } catch (cause) { toast.error(cause instanceof Error ? cause.message : "อัปโหลดไม่สำเร็จ"); } finally { setState("idle"); } } return ( คลังสื่อ { const file = event.target.files?.[0]; event.target.value = ""; if (file) void upload(file); }} /> PNG, JPEG, WebP หรือ GIF ขนาดไม่เกิน 20 MB ); }