-
منطقهٔ زمانی شعبه
-
-
+ {error && (
+
+ {error}
-
- {totalRanges === 0 ? 'هیچ بازهای تعریف نشده' : `${totalRanges} بازه در هفته`}
-
-
- )}
+ )}
- {loading ? (
-
در حال بارگذاری...
- ) : (
-
- {DAY_LABELS.map((label, day) => {
- const ranges = draft[day] ?? [];
- return (
-
-
-
-
{label}
- {ranges.length === 0 && (
-
بسته
+ {branch && canUpdate && (
+
+
منطقهٔ زمانی شعبه
+
+
+
+
+ {totalRanges === 0 ? 'هیچ بازهای تعریف نشده' : `${totalRanges} بازه در هفته`}
+
+
+ )}
+
+ {loading ? (
+
در حال بارگذاری...
+ ) : (
+
+ {DAY_LABELS.map((label, day) => {
+ const ranges = draft[day] ?? [];
+ return (
+
+
+
+ {label}
+ {ranges.length === 0 && (
+ بسته
+ )}
+
+ {canUpdate && (
+
+ {ranges.length > 0 && (
+
copyToWholeWeek(day)}>
+ اعمال روی همهٔ روزها
+
+ )}
+
addRange(day)}>
+ بازه
+
+
)}
- {canUpdate && (
-
- {ranges.length > 0 && (
-
copyToWholeWeek(day)}>
- اعمال روی همهٔ روزها
-
- )}
-
addRange(day)}>
- بازه
-
-
- )}
-
-
- {ranges.map((range, index) => (
-
-
از
-
editRange(day, index, { start: e.target.value })}
- style={{ width: 120 }}
- />
-
تا
- {range.endOfDay ? (
-
۲۴:۰۰
- ) : (
+
+ {ranges.map((range, index) => (
+
+ از
editRange(day, index, { end: e.target.value })}
+ onChange={(e) => editRange(day, index, { start: e.target.value })}
style={{ width: 120 }}
/>
- )}
-
- editRange(day, index, { endOfDay: e.target.checked })}
- />
- تا پایان روز
-
- {canUpdate && (
- removeRange(day, index)}
- aria-label="حذف بازه"
- >
-
-
- )}
-
- ))}
+
تا
+ {range.endOfDay ? (
+
۲۴:۰۰
+ ) : (
+
editRange(day, index, { end: e.target.value })}
+ style={{ width: 120 }}
+ />
+ )}
+
+ editRange(day, index, { endOfDay: e.target.checked })}
+ />
+ تا پایان روز
+
+ {canUpdate && (
+
removeRange(day, index)}
+ aria-label="حذف بازه"
+ >
+
+
+ )}
+
+ ))}
+
-
- );
- })}
-
- )}
-
+ );
+ })}
+
+ )}
+
+
);
}
diff --git a/assets/admin/pages/BranchesPage.tsx b/assets/admin/pages/BranchesPage.tsx
index 5f263e3b..3c5449d5 100644
--- a/assets/admin/pages/BranchesPage.tsx
+++ b/assets/admin/pages/BranchesPage.tsx
@@ -8,6 +8,7 @@ import { useUrlState } from '../hooks/useUrlState';
import { usePermissions } from '../hooks/usePermissions';
import { useBranches } from '../hooks/useBranches';
import type { Branch } from '../types';
+import SettingsLayout from '../components/layout/SettingsLayout';
/**
* شعبهها — همان محلهای نوبتدهی محیط جاری.
@@ -91,65 +92,67 @@ export default function BranchesPage() {
];
return (
-
-
+
+
+
-
setUrlState({ search: v })}
- searchPlaceholder="جستجو در شعبهها..."
- emptyMessage="هیچ شعبهای برای این محیط ثبت نشده است"
- headerExtra={
-
- setUrlState({ status: v })}
- />
-
- }
- actions={(b) => (
-
-
-
ساعت کاری
-
-
-
اتاقها
-
- {canUpdate && (
-
{
- if (
- b.active &&
- activeCount === 1 &&
- !window.confirm('این تنها شعبهٔ فعال است. با غیرفعال کردن آن، هیچ شعبهٔ فعالی باقی نمیماند. ادامه میدهید؟')
- ) {
- return;
+ setUrlState({ search: v })}
+ searchPlaceholder="جستجو در شعبهها..."
+ emptyMessage="هیچ شعبهای برای این محیط ثبت نشده است"
+ headerExtra={
+
+ setUrlState({ status: v })}
+ />
+
+ }
+ actions={(b) => (
+
+
+ ساعت کاری
+
+
+ اتاقها
+
+ {canUpdate && (
+
- {b.active ? 'غیرفعال کردن' : 'فعال کردن'}
-
- )}
-
- )}
- />
-
+ onClick={() => {
+ if (
+ b.active &&
+ activeCount === 1 &&
+ !window.confirm('این تنها شعبهٔ فعال است. با غیرفعال کردن آن، هیچ شعبهٔ فعالی باقی نمیماند. ادامه میدهید؟')
+ ) {
+ return;
+ }
+ update.mutate({ uuid: b.uuid, d: { active: !b.active } });
+ }}
+ >
+ {b.active ? 'غیرفعال کردن' : 'فعال کردن'}
+
+ )}
+
+ )}
+ />
+
+
);
}
diff --git a/assets/admin/pages/CatalogCategoriesPage.tsx b/assets/admin/pages/CatalogCategoriesPage.tsx
index f50268b4..de970b8b 100644
--- a/assets/admin/pages/CatalogCategoriesPage.tsx
+++ b/assets/admin/pages/CatalogCategoriesPage.tsx
@@ -10,6 +10,7 @@ import { useUrlState } from '../hooks/useUrlState';
import { usePermissions } from '../hooks/usePermissions';
import { useCatalogCategories, useCategoryIncludes } from '../hooks/useCatalogCategories';
import type { CatalogCategory } from '../types';
+import SettingsLayout from '../components/layout/SettingsLayout';
/** یک ردیف از درخت، صافشده — با عمق، تا تورفتگی نشان دهد کجای درخت است. */
type Row = CatalogCategory & { depth: number };
@@ -58,81 +59,83 @@ export default function CatalogCategoriesPage() {
];
return (
-
-
setEditing({ open: true, category: null })}>
- افزودن دستهبندی
-
- ) : undefined
- }
- />
-
-
- columns={columns}
- data={rows}
- loading={loading}
- searchValue={urlState.search}
- onSearchChange={(v) => setUrlState({ search: v })}
- searchPlaceholder="جستجو در دستهبندیها..."
- emptyMessage="هنوز دستهبندیای تعریف نشده است"
- actions={
- canUpdate
- ? (c) => (
-
- setEditing({ open: true, category: c })}>
- ویرایش
-
- setIncludesFor(c)}>
- شامل
-
- setToDelete(c)}>
- حذف
-
-
- )
- : undefined
- }
- />
-
- setEditing({ open: false, category: null })}
- onSave={(payload) => {
- const done = { onSuccess: () => setEditing({ open: false, category: null }) };
-
- if (editing.category) {
- update.mutate({ uuid: editing.category.uuid, d: { name: payload.name, sort_order: payload.sort_order, active: payload.active } }, done);
- } else {
- create.mutate({ name: payload.name, parent_uuid: payload.parent_uuid }, done);
+
+
+
setEditing({ open: true, category: null })}>
+ افزودن دستهبندی
+
+ ) : undefined
}
- }}
- />
+ />
- setIncludesFor(null)}
- />
+
+ columns={columns}
+ data={rows}
+ loading={loading}
+ searchValue={urlState.search}
+ onSearchChange={(v) => setUrlState({ search: v })}
+ searchPlaceholder="جستجو در دستهبندیها..."
+ emptyMessage="هنوز دستهبندیای تعریف نشده است"
+ actions={
+ canUpdate
+ ? (c) => (
+
+ setEditing({ open: true, category: c })}>
+ ویرایش
+
+ setIncludesFor(c)}>
+ شامل
+
+ setToDelete(c)}>
+ حذف
+
+
+ )
+ : undefined
+ }
+ />
- toDelete && remove.mutate(toDelete.uuid, { onSuccess: () => setToDelete(null) })}
- onCancel={() => setToDelete(null)}
- />
-
+ setEditing({ open: false, category: null })}
+ onSave={(payload) => {
+ const done = { onSuccess: () => setEditing({ open: false, category: null }) };
+
+ if (editing.category) {
+ update.mutate({ uuid: editing.category.uuid, d: { name: payload.name, sort_order: payload.sort_order, active: payload.active } }, done);
+ } else {
+ create.mutate({ name: payload.name, parent_uuid: payload.parent_uuid }, done);
+ }
+ }}
+ />
+
+ setIncludesFor(null)}
+ />
+
+ toDelete && remove.mutate(toDelete.uuid, { onSuccess: () => setToDelete(null) })}
+ onCancel={() => setToDelete(null)}
+ />
+
+
);
}
diff --git a/assets/admin/pages/HolidaysSettingsPage.tsx b/assets/admin/pages/HolidaysSettingsPage.tsx
index 25e372ea..25287b12 100644
--- a/assets/admin/pages/HolidaysSettingsPage.tsx
+++ b/assets/admin/pages/HolidaysSettingsPage.tsx
@@ -7,6 +7,7 @@ import { usePermissions } from '../hooks/usePermissions';
import { useHolidays } from '../hooks/useResourceCalendar';
import { formatDate } from '../lib/utils';
import type { NationalHoliday } from '../types';
+import SettingsLayout from '../components/layout/SettingsLayout';
/** سالِ شمسی جاری از همان فرمتکنندهٔ شمسیِ مرورگر گرفته میشود، نه با محاسبهٔ دستی. */
function currentJalaliYear(): number {
@@ -54,69 +55,71 @@ export default function HolidaysSettingsPage() {
const years = Array.from({ length: 5 }, (_, i) => thisYear - 1 + i);
return (
-
-
+
+
+
-
- ({ value: String(y), label: String(y) }))}
- value={String(year)}
- onChange={(v) => setUrlState({ year: v ? String(v) : String(thisYear) })}
- placeholder="سال"
- height={36}
- />
-
- }
- actions={
- canUpdate
- ? (h) => {
- const override = overrideByDate.get(h.date);
- return (
-
- {override?.is_working ? (
- removeOverride.mutate(override.uuid)}
- >
- تعطیل کن
-
- ) : (
- setOverride.mutate({ date: h.date, is_working: true })}
- >
- این روز بازیم
-
- )}
-
- );
- }
- : undefined
- }
- />
+
+ ({ value: String(y), label: String(y) }))}
+ value={String(year)}
+ onChange={(v) => setUrlState({ year: v ? String(v) : String(thisYear) })}
+ placeholder="سال"
+ height={36}
+ />
+
+ }
+ actions={
+ canUpdate
+ ? (h) => {
+ const override = overrideByDate.get(h.date);
+ return (
+
+ {override?.is_working ? (
+ removeOverride.mutate(override.uuid)}
+ >
+ تعطیل کن
+
+ ) : (
+ setOverride.mutate({ date: h.date, is_working: true })}
+ >
+ این روز بازیم
+
+ )}
+
+ );
+ }
+ : undefined
+ }
+ />
-
!o.is_working)}
- canUpdate={canUpdate}
- saving={setOverride.isPending}
- onAdd={(date, note) => setOverride.mutate({ date, is_working: false, note })}
- onRemove={(uuid) => removeOverride.mutate(uuid)}
- />
-
+