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',