This commit is contained in:
2026-09-02 12:06:20 +03:30
parent e248943f4c
commit 87aee8c46b
5 changed files with 46 additions and 39 deletions
+10 -7
View File
@@ -14,7 +14,6 @@ import {
Textarea, Textarea,
Modal, Modal,
PageHeader, PageHeader,
Switch,
} from "@/components/ui"; } from "@/components/ui";
import { EditIcon, EyeIcon, PlusIcon, TrashIcon } from "@/components/icons"; import { EditIcon, EyeIcon, PlusIcon, TrashIcon } from "@/components/icons";
import { MediaPreview } from "@/components/MediaPreview"; import { MediaPreview } from "@/components/MediaPreview";
@@ -148,7 +147,7 @@ export default function CategoriesPage() {
}); });
toast.success( toast.success(
row.is_deeplink_only row.is_deeplink_only
? "به فهرست عادی بازگشت." ? "به فهرست عادی بازگردانده شد."
: "به لینک مستقیم تبدیل شد.", : "به لینک مستقیم تبدیل شد.",
); );
reload(); reload();
@@ -237,11 +236,15 @@ export default function CategoriesPage() {
subtitle="مدیریت دسته‌بندی‌های عمومی رسانه، پلی‌لیست و قالب تنفس" subtitle="مدیریت دسته‌بندی‌های عمومی رسانه، پلی‌لیست و قالب تنفس"
action={ action={
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch <Select
checked={showDeepLinks} value={showDeepLinks ? "deeplink" : "normal"}
onChange={setShowDeepLinks} onChange={(e) => setShowDeepLinks(e.target.value === "deeplink")}
label="فقط لینک‌های مستقیم" aria-label="نمایش"
/> className="w-44"
>
<option value="normal">دسته‌بندی‌های عادی</option>
<option value="deeplink">لینک‌های مستقیم</option>
</Select>
<Select <Select
value={typeFilter} value={typeFilter}
onChange={(e) => setTypeFilter(e.target.value as CategoryType)} onChange={(e) => setTypeFilter(e.target.value as CategoryType)}
+11 -11
View File
@@ -117,7 +117,7 @@ export default function CategoryDeepLinksPage() {
method: "POST", method: "POST",
body: toFormData({ is_deeplink_only: 0 }), body: toFormData({ is_deeplink_only: 0 }),
}); });
toast.success("از لینک مستقیم خارج شد."); toast.success("به فهرست عادی بازگردانده شد.");
reload(); reload();
} catch (err) { } catch (err) {
toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی"); toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی");
@@ -134,10 +134,10 @@ export default function CategoryDeepLinksPage() {
method: "POST", method: "POST",
body: toFormData({ name, type, order, description, icon }), body: toFormData({ name, type, order, description, icon }),
}); });
toast.success("لینک مستقیم بهروزرسانی شد."); toast.success("لینک مستقیم به‌روزرسانی شد.");
} else if (source === "existing") { } else if (source === "existing") {
if (!existingId) { if (!existingId) {
toast.error("دسته‌بندی را انتخاب کنید."); toast.error("یک دسته‌بندی انتخاب کنید.");
return; return;
} }
await apiFetch(`/categories/${existingId}`, { await apiFetch(`/categories/${existingId}`, {
@@ -233,8 +233,8 @@ export default function CategoryDeepLinksPage() {
return ( return (
<div> <div>
<PageHeader <PageHeader
title="لینکهای مستقیم دسته‌بندی" title="لینک‌های مستقیم دسته‌بندی"
subtitle="دسته‌بندیهایی که در فهرست نمایش داده نمیشوند اما از طریق لینک مستقیم قابل دسترسیاند" subtitle="دسته‌بندی‌هایی که در فهرست نمایش داده نمی‌شوند اما از طریق لینک مستقیم قابل دسترسی هستند"
action={ action={
<Button icon={<PlusIcon className="h-4 w-4" />} onClick={openCreate}> <Button icon={<PlusIcon className="h-4 w-4" />} onClick={openCreate}>
لینک مستقیم جدید لینک مستقیم جدید
@@ -262,8 +262,8 @@ export default function CategoryDeepLinksPage() {
<Button <Button
variant="ghost" variant="ghost"
onClick={() => unhide(row)} onClick={() => unhide(row)}
aria-label="نمایش در فهرست" aria-label="بازگرداندن به فهرست"
title="نمایش در فهرست" title="بازگرداندن به فهرست"
> >
<EyeIcon className="h-4 w-4" /> <EyeIcon className="h-4 w-4" />
</Button> </Button>
@@ -329,7 +329,7 @@ export default function CategoryDeepLinksPage() {
</Select> </Select>
) : ( ) : (
<p className="text-xs text-muted"> <p className="text-xs text-muted">
{allLoading ? "در حال بارگذاری..." : "دسته‌بندی‌ای موجود نیست."} {allLoading ? "در حال بارگذاری..." : "دسته‌بندی‌ای وجود ندارد."}
</p> </p>
)} )}
</Field> </Field>
@@ -387,13 +387,13 @@ export default function CategoryDeepLinksPage() {
<p className="rounded-xl border border-border bg-surface-muted p-3 text-xs text-muted"> <p className="rounded-xl border border-border bg-surface-muted p-3 text-xs text-muted">
{editing ? ( {editing ? (
<> <>
این دسته‌بندی در فهرست نمایش داده نمیشود و فقط با لینک مستقیم قابل این دسته‌بندی در فهرست نمایش داده نمی‌شود و فقط با لینک مستقیم قابل
دسترسی است. برای بازگرداندن آن به فهرست، از دکمه «نمایش در فهرست» دسترسی است. برای بازگرداندن آن به فهرست، از دکمه «بازگرداندن به فهرست»
استفاده کنید. استفاده کنید.
</> </>
) : ( ) : (
<> <>
پس از ذخیره، این دسته‌بندی در فهرست نمایش داده نمیشود و فقط با لینک پس از ذخیره، این دسته‌بندی در فهرست نمایش داده نمی‌شود و فقط با لینک
مستقیم قابل دسترسی است. مستقیم قابل دسترسی است.
</> </>
)} )}
+12 -12
View File
@@ -151,7 +151,7 @@ export default function MediaDeepLinksPage() {
method: "POST", method: "POST",
body: toFormData({ is_deeplink_only: 0 }), body: toFormData({ is_deeplink_only: 0 }),
}); });
toast.success("از لینک مستقیم خارج شد."); toast.success("به فهرست عادی بازگردانده شد.");
reload(); reload();
} catch (err) { } catch (err) {
toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی"); toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی");
@@ -175,11 +175,11 @@ export default function MediaDeepLinksPage() {
image: imageFile, image: imageFile,
}); });
await apiFetch(`/media/${editing.id}`, { method: "POST", body }); await apiFetch(`/media/${editing.id}`, { method: "POST", body });
toast.success("لینک مستقیم بهروزرسانی شد."); toast.success("لینک مستقیم به‌روزرسانی شد.");
} else if (source === "existing") { } else if (source === "existing") {
// Toggle the chosen existing media to deeplink-only. // Toggle the chosen existing media to deeplink-only.
if (!existingId) { if (!existingId) {
toast.error("رسانهای را انتخاب کنید."); toast.error("یک رسانه انتخاب کنید.");
return; return;
} }
await apiFetch(`/media/${existingId}`, { await apiFetch(`/media/${existingId}`, {
@@ -263,8 +263,8 @@ export default function MediaDeepLinksPage() {
return ( return (
<div> <div>
<PageHeader <PageHeader
title="لینکهای مستقیم رسانه" title="لینک‌های مستقیم رسانه"
subtitle="رسانههایی که در فهرست نمایش داده نمیشوند اما از طریق لینک مستقیم (دیپلینک) قابل دسترسیاند" subtitle="رسانه‌هایی که در فهرست نمایش داده نمی‌شوند اما از طریق لینک مستقیم قابل دسترسی هستند"
action={ action={
<Button icon={<PlusIcon className="h-4 w-4" />} onClick={openCreate}> <Button icon={<PlusIcon className="h-4 w-4" />} onClick={openCreate}>
لینک مستقیم جدید لینک مستقیم جدید
@@ -292,8 +292,8 @@ export default function MediaDeepLinksPage() {
<Button <Button
variant="ghost" variant="ghost"
onClick={() => unhide(row)} onClick={() => unhide(row)}
aria-label="نمایش در فهرست" aria-label="بازگرداندن به فهرست"
title="نمایش در فهرست" title="بازگرداندن به فهرست"
> >
<EyeIcon className="h-4 w-4" /> <EyeIcon className="h-4 w-4" />
</Button> </Button>
@@ -354,7 +354,7 @@ export default function MediaDeepLinksPage() {
</Select> </Select>
) : ( ) : (
<p className="text-xs text-muted"> <p className="text-xs text-muted">
{allLoading ? "در حال بارگذاری..." : "رسانهای موجود نیست."} {allLoading ? "در حال بارگذاری..." : "رسانه‌ای وجود ندارد."}
</p> </p>
)} )}
</Field> </Field>
@@ -410,7 +410,7 @@ export default function MediaDeepLinksPage() {
/> />
</Field> </Field>
<Field label="لینک خارجی" hint="اگر فایل آپلود نمیکنید، آدرس مستقیم فایل."> <Field label="لینک خارجی" hint="اگر فایلی بارگذاری نمی‌کنید، نشانی مستقیم فایل را وارد کنید.">
<Input <Input
dir="ltr" dir="ltr"
value={externalUrl} value={externalUrl}
@@ -434,13 +434,13 @@ export default function MediaDeepLinksPage() {
<p className="rounded-xl border border-border bg-surface-muted p-3 text-xs text-muted"> <p className="rounded-xl border border-border bg-surface-muted p-3 text-xs text-muted">
{editing ? ( {editing ? (
<> <>
این رسانه در فهرست «رسانهها» نمایش داده نمیشود و فقط با لینک مستقیم این رسانه در فهرست «رسانه‌ها» نمایش داده نمی‌شود و فقط با لینک مستقیم
قابل دسترسی است. برای بازگرداندن آن به فهرست، از دکمه «نمایش در فهرست» قابل دسترسی است. برای بازگرداندن آن به فهرست، از دکمه «بازگرداندن به فهرست»
استفاده کنید. استفاده کنید.
</> </>
) : ( ) : (
<> <>
پس از ذخیره، این رسانه در فهرست «رسانهها» نمایش داده نمیشود و فقط با پس از ذخیره، این رسانه در فهرست «رسانه‌ها» نمایش داده نمی‌شود و فقط با
لینک مستقیم قابل دسترسی است. لینک مستقیم قابل دسترسی است.
</> </>
)} )}
+11 -7
View File
@@ -220,7 +220,7 @@ export default function MediaPage() {
}); });
toast.success( toast.success(
row.is_deeplink_only row.is_deeplink_only
? "به فهرست عادی بازگشت." ? "به فهرست عادی بازگردانده شد."
: "به لینک مستقیم تبدیل شد.", : "به لینک مستقیم تبدیل شد.",
); );
reload(); reload();
@@ -327,7 +327,7 @@ export default function MediaPage() {
} }
/> />
<div className="mb-4 flex items-center gap-4"> <div className="mb-4 flex items-center gap-3">
<div className="max-w-sm flex-1"> <div className="max-w-sm flex-1">
<Input <Input
value={search} value={search}
@@ -336,11 +336,15 @@ export default function MediaPage() {
disabled={showDeepLinks} disabled={showDeepLinks}
/> />
</div> </div>
<Switch <Select
checked={showDeepLinks} value={showDeepLinks ? "deeplink" : "normal"}
onChange={setShowDeepLinks} onChange={(e) => setShowDeepLinks(e.target.value === "deeplink")}
label="فقط لینک‌های مستقیم" aria-label="نمایش"
/> className="w-44"
>
<option value="normal">رسانه‌های عادی</option>
<option value="deeplink">لینک‌های مستقیم</option>
</Select>
</div> </div>
<DataTable <DataTable
+2 -2
View File
@@ -83,10 +83,10 @@ export const NAV: NavSection[] = [
items: [{ href: "/dashboard/sliders", label: "اسلایدرها" }], items: [{ href: "/dashboard/sliders", label: "اسلایدرها" }],
}, },
{ {
label: "لینکهای مستقیم", label: "لینک‌های مستقیم",
icon: EyeIcon, icon: EyeIcon,
items: [ items: [
{ href: "/dashboard/deep-links/media", label: "رسانهها" }, { href: "/dashboard/deep-links/media", label: "رسانه‌ها" },
{ href: "/dashboard/deep-links/categories", label: "دستهبندیها" }, { href: "/dashboard/deep-links/categories", label: "دستهبندیها" },
], ],
}, },