fix(admin): جستجوی تعریف موجودیت بر اساس resource — ویرایش چرا آرامش/فرم تماس روی /en هم ستون فارسی را می‌نوشت

کلید فهرست ENTITIES برای چند موجودیت snake_case است (why_us، contact_section،
seo_meta، …) ولی resource همان‌ها کباب‌کامل؛ isTranslatable و سایر جستجوها با
ENTITIES[resource] پیدا نمی‌شدند و نتیجه دو بود:
- ویرایش درجای «چرا آرامش» و متن‌های فرم تماس روی صفحهٔ انگلیسی به‌جای ستون‌های
  _en ستون فارسی را بازنویسی می‌کرد (حتی با زبان ویرایش انگلیسی)؛
- قرص سئوی صفحهٔ اصلی (SingletonPill resource="seo-meta") اصلاً رندر نمی‌شد.
حالا همهٔ جستجوها با entityConfig بر اساس resource انجام می‌شود.
This commit is contained in:
aramesh-site deploy
2026-09-30 10:20:34 +00:00
parent 5530c141a2
commit d2ed1b1c76
3 changed files with 14 additions and 8 deletions
+2 -2
View File
@@ -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<string, unknown> | undefined
if (config) {
const target = d[config.dataKey as keyof SiteData] as unknown
+5 -5
View File
@@ -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<string, unknown> & { 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<typeof data>] ?? []) 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<ItemWithId | null>(null)
if (!config || !isAuthenticated || !isEditMode || !canManageSite) return null
@@ -250,7 +250,7 @@ export function SingletonPill({
createDefaults?: Record<string, unknown> | (() => Record<string, unknown>)
}) {
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<ItemWithId | null>(null)
+7 -1
View File
@@ -270,10 +270,16 @@ export const ENTITIES: Record<string, EntityConfig> = {
},
}
/** تعریف موجودیت بر اساس 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)
}