From d2ed1b1c7678db18a8b7750a705fc55317f648c7 Mon Sep 17 00:00:00 2001 From: aramesh-site deploy Date: Wed, 30 Sep 2026 10:20:34 +0000 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=D8=AC=D8=B3=D8=AA=D8=AC=D9=88?= =?UTF-8?q?=DB=8C=20=D8=AA=D8=B9=D8=B1=DB=8C=D9=81=20=D9=85=D9=88=D8=AC?= =?UTF-8?q?=D9=88=D8=AF=DB=8C=D8=AA=20=D8=A8=D8=B1=20=D8=A7=D8=B3=D8=A7?= =?UTF-8?q?=D8=B3=20resource=20=E2=80=94=20=D9=88=DB=8C=D8=B1=D8=A7=DB=8C?= =?UTF-8?q?=D8=B4=20=DA=86=D8=B1=D8=A7=20=D8=A2=D8=B1=D8=A7=D9=85=D8=B4/?= =?UTF-8?q?=D9=81=D8=B1=D9=85=20=D8=AA=D9=85=D8=A7=D8=B3=20=D8=B1=D9=88?= =?UTF-8?q?=DB=8C=20/en=20=D9=87=D9=85=20=D8=B3=D8=AA=D9=88=D9=86=20=D9=81?= =?UTF-8?q?=D8=A7=D8=B1=D8=B3=DB=8C=20=D8=B1=D8=A7=20=D9=85=DB=8C=E2=80=8C?= =?UTF-8?q?=D9=86=D9=88=D8=B4=D8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit کلید فهرست ENTITIES برای چند موجودیت snake_case است (why_us، contact_section، seo_meta، …) ولی resource همان‌ها کباب‌کامل؛ isTranslatable و سایر جستجوها با ENTITIES[resource] پیدا نمی‌شدند و نتیجه دو بود: - ویرایش درجای «چرا آرامش» و متن‌های فرم تماس روی صفحهٔ انگلیسی به‌جای ستون‌های _en ستون فارسی را بازنویسی می‌کرد (حتی با زبان ویرایش انگلیسی)؛ - قرص سئوی صفحهٔ اصلی (SingletonPill resource="seo-meta") اصلاً رندر نمی‌شد. حالا همهٔ جستجوها با entityConfig بر اساس resource انجام می‌شود. --- frontend/src/admin/AdminContext.tsx | 4 ++-- frontend/src/admin/Editable.tsx | 10 +++++----- frontend/src/admin/entities.ts | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/frontend/src/admin/AdminContext.tsx b/frontend/src/admin/AdminContext.tsx index e732eff..1034455 100644 --- a/frontend/src/admin/AdminContext.tsx +++ b/frontend/src/admin/AdminContext.tsx @@ -4,7 +4,7 @@ import Swal from 'sweetalert2' import type { SiteData } from '../api' import { useSiteData } from '../api' import { adminApi, getToken, HttpError, setToken, AUTH_CHANGE_EVENT } from './adminClient' -import { ENTITIES, isTranslatable } from './entities' +import { entityConfig, isTranslatable } from './entities' export type SaveStatus = 'idle' | 'saving' | 'error' /** زبان ویرایش محتوا — رابط مدیریتی فارسی می‌ماند؛ این فقط تعیین می‌کند کدام ستون زبان ذخیره شود */ @@ -246,7 +246,7 @@ export function useFieldSaver() { } await adminApi.patch(resource, id, changes) updateSite((d) => { - const config = ENTITIES[resource] + const config = entityConfig(resource) let node: Record | undefined if (config) { const target = d[config.dataKey as keyof SiteData] as unknown diff --git a/frontend/src/admin/Editable.tsx b/frontend/src/admin/Editable.tsx index 73abc97..1dad767 100644 --- a/frontend/src/admin/Editable.tsx +++ b/frontend/src/admin/Editable.tsx @@ -8,14 +8,14 @@ import { useSiteData } from '../api' import type { SiteData } from '../api' import { useAdmin } from './AdminContext' import { adminApi } from './adminClient' -import { ENTITIES } from './entities' +import { entityConfig } from './entities' import { EntityDrawer } from './EntityDrawer' type ItemWithId = Record & { id: number } function useEntityList(resource: string): ItemWithId[] { const { data } = useSiteData() - const config = ENTITIES[resource] + const config = entityConfig(resource) if (!config) throw new Error(`منبع ناشناخته: ${resource}`) return (data?.[config.dataKey as keyof NonNullable] ?? []) as ItemWithId[] } @@ -72,7 +72,7 @@ export function EditableItem({ }) { const { isAuthenticated, isEditMode, runSave, canManageSite } = useAdmin() const { reload } = useSiteData() - const config = ENTITIES[resource] + const config = entityConfig(resource) const list = useEntityList(resource) const [drawerOpen, setDrawerOpen] = useState(false) @@ -175,7 +175,7 @@ export function AddItemButton({ const { isAuthenticated, isEditMode, runSave, canManageSite } = useAdmin() const navigate = useNavigate() const { updateSite } = useSiteData() - const config = ENTITIES[resource] + const config = entityConfig(resource) const [newItem, setNewItem] = useState(null) if (!config || !isAuthenticated || !isEditMode || !canManageSite) return null @@ -250,7 +250,7 @@ export function SingletonPill({ createDefaults?: Record | (() => Record) }) { const { isAuthenticated, isEditMode, runSave, canManageSite } = useAdmin() - const config = ENTITIES[resource] + const config = entityConfig(resource) const { data, updateSite } = useSiteData() const [drawerOpen, setDrawerOpen] = useState(false) const [created, setCreated] = useState(null) diff --git a/frontend/src/admin/entities.ts b/frontend/src/admin/entities.ts index d709638..c83b34f 100644 --- a/frontend/src/admin/entities.ts +++ b/frontend/src/admin/entities.ts @@ -270,10 +270,16 @@ export const ENTITIES: Record = { }, } +/** تعریف موجودیت بر اساس resource (نشانی API) — کلید فهرست همیشه با resource یکی نیست + * (why_us/contact_section/seo_meta/… کلید snake_case دارند ولی resource کباب‌کامل است) */ +export function entityConfig(resource: string): EntityConfig | undefined { + return Object.values(ENTITIES).find((c) => c.resource === resource) +} + /** آیا فیلد در منبع داده قابل ترجمه است؟ (فیلدهای مشترک و پسوندهای انگلیسی قبلی خیر) */ export function isTranslatable(resource: string, name: string): boolean { if (name.endsWith('_en')) return false - const config = ENTITIES[resource] + const config = entityConfig(resource) return !!config?.fields.some((f) => f.name === name && !f.shared) }