"use client"; import { useState } from "react"; import { apiFetch, ApiError, toFormData } from "@/lib/api"; import { useList } from "@/lib/useResource"; import { useToast } from "@/components/toast"; import { DataTable, type Column } from "@/components/DataTable"; import { Button, ConfirmDialog, Field, Input, Modal, PageHeader, Select, Textarea, } from "@/components/ui"; import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons"; import { ImagePicker } from "@/components/ImagePicker"; import { MediaPreview } from "@/components/MediaPreview"; import { pickUrl, IMAGE_KEYS } from "@/lib/media"; import { toFa } from "@/lib/utils"; interface SliderAction { path?: string; type?: string; } interface Slider { id: number; title?: string; description?: string; url?: string; action?: SliderAction; image_id?: number | null; image?: unknown; } const ACTION_TYPES = [ { value: "navigation", label: "صفحه (navigation)" }, { value: "link", label: "لینک (link)" }, ]; export default function SlidersPage() { const { data, loading, error, reload } = useList("/slider"); const toast = useToast(); const [editing, setEditing] = useState(null); const [open, setOpen] = useState(false); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [url, setUrl] = useState(""); const [actionPath, setActionPath] = useState(""); const [actionType, setActionType] = useState("navigation"); const [imageId, setImageId] = useState(null); const [imageFile, setImageFile] = useState(null); const [saving, setSaving] = useState(false); const [deleting, setDeleting] = useState(null); const [removing, setRemoving] = useState(false); function openCreate() { setEditing(null); setTitle(""); setDescription(""); setUrl(""); setActionPath(""); setActionType("navigation"); setImageId(null); setImageFile(null); setOpen(true); } function openEdit(row: Slider) { setEditing(row); setTitle(row.title ?? ""); setDescription(row.description ?? ""); setUrl(row.url ?? ""); setActionPath(row.action?.path ?? ""); setActionType(row.action?.type ?? "navigation"); setImageId(row.image_id ?? null); setImageFile(null); setOpen(true); } async function save(e: React.FormEvent) { e.preventDefault(); setSaving(true); try { // Multipart for both (so an image file can be uploaded). Bracket keys // build the nested action object; update uses POST /slider/:id. const body = toFormData({ title, description, url, "action[path]": actionPath, "action[type]": actionType, image_id: imageId, image: imageFile, }); if (editing) { await apiFetch(`/slider/${editing.id}`, { method: "POST", body }); toast.success("اسلایدر ویرایش شد."); } else { await apiFetch("/slider", { method: "POST", body }); await apiFetch("/slider", { method: "POST", body }); toast.success("اسلایدر افزوده شد."); } setOpen(false); reload(); } catch (err) { toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی"); } finally { setSaving(false); } } async function confirmDelete() { if (!deleting) return; setRemoving(true); try { await apiFetch(`/slider/${deleting.id}`, { method: "DELETE" }); toast.success("اسلایدر حذف شد."); setDeleting(null); reload(); } catch (err) { toast.error(err instanceof ApiError ? err.message : "خطا در حذف"); } finally { setRemoving(false); } } const columns: Column[] = [ { key: "id", header: "شناسه", render: (r) => toFa(r.id), className: "w-24" }, { key: "image", header: "تصویر", className: "w-20", render: (r) => ( ), }, { key: "title", header: "عنوان", render: (r) => r.title ?? "—" }, { key: "description", header: "توضیحات", render: (r) => r.description ?? "—", }, { key: "url", header: "آدرس", render: (r) => r.url ? ( {r.url} ) : ( "—" ), }, { key: "action_type", header: "نوع اکشن", render: (r) => r.action?.type ?? "—", className: "w-32", }, ]; return (
} onClick={openCreate}> اسلایدر جدید } /> } onClick={openCreate}> اسلایدر جدید } actions={(row) => ( <> )} /> setOpen(false)} title={editing ? "ویرایش اسلایدر" : "اسلایدر جدید"} footer={ <> } >
setTitle(e.target.value)} placeholder="مثلاً مدیتیشن صبحگاهی" required autoFocus />