mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 22:31:46 +00:00
feat: add configurable permissions system with admin panel
Adds a full permissions management feature allowing admins to control who can perform actions across the app (trip CRUD, files, places, budget, packing, reservations, collab, members, share links). - New server/src/services/permissions.ts: 16 configurable actions, in-memory cache, checkPermission() helper, backwards-compatible defaults matching upstream behaviour - GET/PUT /admin/permissions endpoints; permissions loaded into app-config response so clients have them on startup - checkPermission() applied to all mutating route handlers across 10 server route files; getTripOwnerId() helper eliminates repeated inline DB queries; trips.ts and files.ts now reuse canAccessTrip() result to avoid redundant DB round-trips - New client/src/store/permissionsStore.ts: Zustand store + useCanDo() hook; TripOwnerContext type accepts both Trip and DashboardTrip shapes without casting at call sites - New client/src/components/Admin/PermissionsPanel.tsx: categorised UI with per-action dropdowns, customised badge, save/reset - AdminPage, DashboardPage, FileManager, PlacesSidebar, TripMembersModal gated via useCanDo(); no prop drilling - 46 perm.* translation keys added to all 12 language files
This commit is contained in:
+7
-2
@@ -14,6 +14,7 @@ import SharedTripPage from './pages/SharedTripPage'
|
||||
import { ToastContainer } from './components/shared/Toast'
|
||||
import { TranslationProvider, useTranslation } from './i18n'
|
||||
import { authApi } from './api/client'
|
||||
import { usePermissionsStore, PermissionLevel } from './store/permissionsStore'
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
children: ReactNode
|
||||
@@ -21,7 +22,10 @@ interface ProtectedRouteProps {
|
||||
}
|
||||
|
||||
function ProtectedRoute({ children, adminRequired = false }: ProtectedRouteProps) {
|
||||
const { isAuthenticated, user, isLoading, appRequireMfa } = useAuthStore()
|
||||
const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
|
||||
const user = useAuthStore((s) => s.user)
|
||||
const isLoading = useAuthStore((s) => s.isLoading)
|
||||
const appRequireMfa = useAuthStore((s) => s.appRequireMfa)
|
||||
const { t } = useTranslation()
|
||||
const location = useLocation()
|
||||
|
||||
@@ -78,12 +82,13 @@ export default function App() {
|
||||
if (token) {
|
||||
loadUser()
|
||||
}
|
||||
authApi.getAppConfig().then(async (config: { demo_mode?: boolean; has_maps_key?: boolean; version?: string; timezone?: string; require_mfa?: boolean; trip_reminders_enabled?: boolean }) => {
|
||||
authApi.getAppConfig().then(async (config: { demo_mode?: boolean; has_maps_key?: boolean; version?: string; timezone?: string; require_mfa?: boolean; trip_reminders_enabled?: boolean; permissions?: Record<string, PermissionLevel> }) => {
|
||||
if (config?.demo_mode) setDemoMode(true)
|
||||
if (config?.has_maps_key !== undefined) setHasMapsKey(config.has_maps_key)
|
||||
if (config?.timezone) setServerTimezone(config.timezone)
|
||||
if (config?.require_mfa !== undefined) setAppRequireMfa(!!config.require_mfa)
|
||||
if (config?.trip_reminders_enabled !== undefined) setTripRemindersEnabled(config.trip_reminders_enabled)
|
||||
if (config?.permissions) usePermissionsStore.getState().setPermissions(config.permissions)
|
||||
|
||||
if (config?.version) {
|
||||
const storedVersion = localStorage.getItem('trek_app_version')
|
||||
|
||||
Reference in New Issue
Block a user