feat: home page per role — selector in RolesTab, saved to DB and applied on login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -309,7 +309,7 @@ export const api = {
|
||||
'GET', `/api/hotels/${slug}/role-permissions`),
|
||||
|
||||
save: (slug: string, roleKey: string, data: {
|
||||
name: string; color: string; isSystem: boolean; permissions: Record<string, boolean>
|
||||
name: string; color: string; isSystem: boolean; permissions: Record<string, boolean>; homePage?: string | null
|
||||
}) =>
|
||||
req<import('../contexts/RolePermissionsContext').SavedRolePermission>(
|
||||
'PUT', `/api/hotels/${slug}/role-permissions/${roleKey}`, data),
|
||||
|
||||
@@ -41,6 +41,7 @@ interface RolePermissions {
|
||||
color: string
|
||||
isSystem: boolean
|
||||
permissions: Record<string, boolean>
|
||||
homePage?: string | null
|
||||
}
|
||||
|
||||
// ── Constants ──────────────────────────────────────────────────────────────────
|
||||
@@ -134,6 +135,36 @@ const ALL_MODULE_KEYS = MODULE_GROUPS.flatMap(g => g.modules.map(m => m.key))
|
||||
const allPerms = (v: boolean) =>
|
||||
Object.fromEntries(ALL_MODULE_KEYS.map(k => [k, v]))
|
||||
|
||||
// Permission key → route path (for home page selector)
|
||||
const PERM_TO_ROUTE: Record<string, string> = {
|
||||
calendar: '/calendar',
|
||||
bookings: '/bookings',
|
||||
guests: '/guests',
|
||||
rooms: '/rooms',
|
||||
availability: '/availability',
|
||||
housekeeping: '/housekeeping',
|
||||
maintenance: '/maintenance',
|
||||
room_service: '/room-service',
|
||||
rental: '/rental',
|
||||
pos: '/pos',
|
||||
tariffs: '/tariffs',
|
||||
pricing: '/dynamic-pricing',
|
||||
discounts: '/discounts',
|
||||
loyalty: '/loyalty',
|
||||
reports: '/reports',
|
||||
channels: '/channels',
|
||||
reviews: '/reviews',
|
||||
website: '/website',
|
||||
floor_map: '/floor-map',
|
||||
equipment: '/equipment',
|
||||
wifi: '/wifi',
|
||||
ttlock: '/ttlock',
|
||||
users: '/users',
|
||||
schedule: '/schedule',
|
||||
documents: '/documents',
|
||||
settings: '/settings',
|
||||
}
|
||||
|
||||
const INITIAL_ROLE_PERMISSIONS: RolePermissions[] = [
|
||||
{
|
||||
id: 'rp_hotel_admin',
|
||||
@@ -492,7 +523,7 @@ function RolesTab() {
|
||||
if (!s) return def
|
||||
// Ensure all module keys are present (new modules default to false)
|
||||
const fullPerms = { ...allPerms(false), ...s.permissions }
|
||||
return { ...def, permissions: fullPerms }
|
||||
return { ...def, permissions: fullPerms, homePage: s.homePage ?? def.homePage }
|
||||
})
|
||||
|
||||
// Custom roles (not in system list)
|
||||
@@ -505,6 +536,7 @@ function RolesTab() {
|
||||
color: r.color,
|
||||
isSystem: false,
|
||||
permissions: { ...allPerms(false), ...r.permissions },
|
||||
homePage: r.homePage ?? null,
|
||||
}))
|
||||
|
||||
setRoles([...merged, ...custom])
|
||||
@@ -534,6 +566,12 @@ function RolesTab() {
|
||||
))
|
||||
}
|
||||
|
||||
const setHomePage = (page: string | null) => {
|
||||
setRoles(prev => prev.map(r =>
|
||||
r.id === selectedRoleId ? { ...r, homePage: page } : r
|
||||
))
|
||||
}
|
||||
|
||||
// ── Save to API ────────────────────────────────────────────────────────────
|
||||
const handleSave = async () => {
|
||||
if (!slug || saving) return
|
||||
@@ -546,6 +584,7 @@ function RolesTab() {
|
||||
color: role.color,
|
||||
isSystem: role.isSystem,
|
||||
permissions: role.permissions,
|
||||
homePage: role.homePage ?? null,
|
||||
})
|
||||
}))
|
||||
setSaveOk(true)
|
||||
@@ -786,6 +825,38 @@ function RolesTab() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Home page selector */}
|
||||
<div className="px-4 pb-4 border-t border-slate-100 dark:border-slate-700 pt-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex-1">
|
||||
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide mb-1">
|
||||
Стартовая страница
|
||||
</p>
|
||||
<p className="text-xs text-slate-400 dark:text-slate-500 mb-2">
|
||||
Страница, которая открывается при входе в систему
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
value={selectedRole.homePage ?? ''}
|
||||
onChange={e => setHomePage(e.target.value || null)}
|
||||
className="input text-sm w-full sm:w-72"
|
||||
>
|
||||
<option value="">— По умолчанию для роли —</option>
|
||||
{ALL_MODULE_KEYS
|
||||
.filter(k => selectedRole.permissions[k] && PERM_TO_ROUTE[k])
|
||||
.map(k => {
|
||||
const mod = MODULE_GROUPS.flatMap(g => g.modules).find(m => m.key === k)
|
||||
return (
|
||||
<option key={k} value={PERM_TO_ROUTE[k]}>
|
||||
{mod?.label ?? k}
|
||||
</option>
|
||||
)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{selectedRole.isSystem && (
|
||||
<div className="px-4 pb-4">
|
||||
<div className="flex items-center gap-2 p-3 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
|
||||
|
||||
Reference in New Issue
Block a user