From 79ebe69221096743a89cad6357f47b5d13cd66e6 Mon Sep 17 00:00:00 2001 From: aramesh-site deploy Date: Wed, 30 Sep 2026 09:14:34 +0000 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=D8=B2=D8=A8=D8=A7=D9=86=20=D9=88?= =?UTF-8?q?=DB=8C=D8=B1=D8=A7=DB=8C=D8=B4=20=D8=A7=D8=B2=20=D8=B2=D8=A8?= =?UTF-8?q?=D8=A7=D9=86=20=D8=B5=D9=81=D8=AD=D9=87=20=D9=BE=DB=8C=D8=B1?= =?UTF-8?q?=D9=88=DB=8C=20=DA=A9=D9=86=D8=AF=20=E2=80=94=20=D9=88=DB=8C?= =?UTF-8?q?=D8=B1=D8=A7=DB=8C=D8=B4=20=D8=B1=D9=88=DB=8C=20/en=20=D8=AF?= =?UTF-8?q?=DB=8C=DA=AF=D8=B1=20=D9=85=D8=AA=D9=86=20=D9=81=D8=A7=D8=B1?= =?UTF-8?q?=D8=B3=DB=8C=20=D8=B1=D8=A7=20=D8=A8=D8=A7=D8=B2=D9=86=D9=88?= =?UTF-8?q?=DB=8C=D8=B3=DB=8C=20=D9=86=D9=85=DB=8C=E2=80=8C=DA=A9=D9=86?= =?UTF-8?q?=D8=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit قبلاً زبان ویرایش (editLang) کلید جداگانه‌ای در نوار ادمین بود که با زبان صفحهٔ در حال نمایش هیچ ارتباطی نداشت و پیش‌فرضش فارسی می‌ماند؛ نتیجه‌اش این بود که ویرایش درجا روی صفحه‌های /en به ستون‌های فارسی می‌رفت و تغییرها «سمت دیگر» یعنی سایت فارسی ظاهر می‌شدند. - AdminBar: در حالت ویرایش، editLang با زبان URL همگام می‌شود (syncEditLang)؛ کلید دستی فقط برای ویرایش ستون زبان دیگر روی همین صفحه می‌ماند. - entities: تعریف status-labels اضافه شد — نبودش یعنی ویرایش برچسب وضعیت روی صفحهٔ انگلیسی همیشه ستون فارسی را بازنویسی می‌کرد. --- frontend/src/admin/AdminBar.tsx | 16 +++++++++++++--- frontend/src/admin/AdminContext.tsx | 19 ++++++++++++++++--- frontend/src/admin/entities.ts | 8 ++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/frontend/src/admin/AdminBar.tsx b/frontend/src/admin/AdminBar.tsx index 665f434..e3f13b2 100644 --- a/frontend/src/admin/AdminBar.tsx +++ b/frontend/src/admin/AdminBar.tsx @@ -1,9 +1,10 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import Swal from 'sweetalert2' import { Link } from 'react-router-dom' import { KeyRoundIcon, XIcon } from 'lucide-react' import { useAdmin } from './AdminContext' import { adminApi } from './adminClient' +import { useLang } from '../i18n/lang' const STATUS_TEXT: Record = { idle: 'همگام‌سازی شد', @@ -127,9 +128,18 @@ function ChangePasswordModal({ onClose }: { onClose: () => void }) { /** نوار شناور ادمین — فقط برای کاربر واردشده رندر می‌شود */ export function AdminBar() { - const { isEditMode, toggleEditMode, saveStatus, logout, editLang, toggleEditLang, role, canManageSite } = useAdmin() + const { isEditMode, toggleEditMode, saveStatus, logout, editLang, toggleEditLang, syncEditLang, role, canManageSite } = useAdmin() + const { lang } = useLang() const [pwOpen, setPwOpen] = useState(false) + // زبان ویرایش از زبان صفحهٔ در حال نمایش پیروی می‌کند — ویرایش روی /en به ستون‌های + // انگلیسی می‌رود و روی صفحات فارسی به فارسی؛ وگرنه ویرایشِ دیده‌شده در /en ناخواسته + // متن فارسی را بازنویسی می‌کرد. کلید دستی پایین فقط برای ویرایش ستون زبان دیگر + // روی همین صفحه است و با ناوبری بعدی دوباره همگام می‌شود. + useEffect(() => { + if (isEditMode) syncEditLang(lang) + }, [isEditMode, lang, syncEditLang]) + return ( <>
void + /** همگام‌سازی زبان ویرایش با زبان صفحهٔ در حال نمایش — کلید دستی فقط برای + * ویرایش ستون زبان دیگر روی همان صفحه است؛ در ناوبری دوباره از صفحه پیروی می‌کند */ + syncEditLang: (lang: EditLang) => void } const AdminContext = createContext(null) @@ -80,7 +83,7 @@ export function AdminProvider({ children }: { children: ReactNode }) { const [isEditMode, setIsEditMode] = useState( () => sessionStorage.getItem('aramesh_edit_mode') === '1', ) - const [editLang, setEditLang] = useState( + const [editLang, setEditLangState] = useState( () => (sessionStorage.getItem('aramesh_edit_lang') === 'en' ? 'en' : 'fa'), ) const [saveStatus, setSaveStatus] = useState('idle') @@ -94,13 +97,22 @@ export function AdminProvider({ children }: { children: ReactNode }) { }, []) const toggleEditLang = useCallback(() => { - setEditLang((v) => { + setEditLangState((v) => { const next: EditLang = v === 'fa' ? 'en' : 'fa' sessionStorage.setItem('aramesh_edit_lang', next) return next }) }, []) + // بدون بازنویسی انتخاب دستی وقتی مقدار همان است — تا اثر همگام‌سازی بی‌دلیل رندر نکند + const syncEditLang = useCallback((next: EditLang) => { + setEditLangState((v) => { + if (v === next) return v + sessionStorage.setItem('aramesh_edit_lang', next) + return next + }) + }, []) + const login = useCallback(async (username: string, password: string): Promise => { await adminApi.login(username, password) const nextRole = roleFromToken(getToken()) ?? 'admin' @@ -194,8 +206,9 @@ export function AdminProvider({ children }: { children: ReactNode }) { runSave, editLang, toggleEditLang, + syncEditLang, }), - [isAuthenticated, role, canManageSite, isEditMode, toggleEditMode, login, logout, saveStatus, runSave, editLang, toggleEditLang], + [isAuthenticated, role, canManageSite, isEditMode, toggleEditMode, login, logout, saveStatus, runSave, editLang, toggleEditLang, syncEditLang], ) return {children} diff --git a/frontend/src/admin/entities.ts b/frontend/src/admin/entities.ts index 44ac0f8..4280ff5 100644 --- a/frontend/src/admin/entities.ts +++ b/frontend/src/admin/entities.ts @@ -176,6 +176,14 @@ export const ENTITIES: Record = { fields: [F('label', 'عنوان'), F('href', 'مسیر (مثل /about)', 'text', undefined, true)], defaults: { label: 'آیتم جدید', href: '/' }, }, + 'status-labels': { + resource: 'status-labels', dataKey: 'status_labels', title: 'برچسب‌های وضعیت پروژه', kind: 'collection', + titleKey: 'label', + // نبودِ این تعریف یعنی isTranslatable همیشه false برمی‌گشت و ویرایشِ برچسب روی + // صفحهٔ انگلیسی به‌جای ستون label_en ستون فارسی را بازنویسی می‌کرد + fields: [F('label', 'برچسب'), F('key', 'کلید وضعیت', 'text', 'done یا progress', true)], + defaults: { key: 'done', label: 'برچسب جدید' }, + }, seo_meta: { resource: 'seo-meta', dataKey: 'seo_meta', title: 'سئوی صفحه', kind: 'collection', titleKey: 'page_key',