Implemented comprehensive permission-based access control across all mobile screens, matching the web app's security model. Users now only see and can access screens they have permissions for.
- File:
components/AccessDenied.tsx - Purpose: Reusable component shown when users lack permission
- Features:
- Lock icon (Ionicons)
- "Access Denied" title
- Customizable message prop
- Centered layout with proper styling
- File:
hooks/usePermissions.ts - Changes:
- Exported
UserPermissionsinterface for TypeScript support - Already had proper permission checking logic
- Supports tenant admin bypass (all permissions)
- Exported
- File:
components/BottomTabNavigator.tsx - Changes:
- Added
usePermissionsimport - Conditionally render tabs based on permissions:
- Dashboard: Always visible (no permission required)
- Calendar: Requires
access_calendar - Reservations: Requires
access_bookings - Expenses: Requires
access_expenses - Accounts: Requires
access_accounts - Reports: Requires
access_reports
- Tabs without permission are completely hidden (not just disabled)
- Added
All screens now check permissions before rendering content. Users without permission see the AccessDenied component.
-
DashboardScreen ✅
- Uses
usePermissionshook - Has permission logic for components
- Uses
-
ReportsScreen ✅
- Permission:
access_reports - Custom AccessDenied UI already implemented
- Permission:
-
ExpensesScreen ✅
- Permission:
access_expenses - Custom AccessDenied UI already implemented
- Permission:
-
UsersScreen ✅
- Permission:
access_users - Already had permission checks
- Permission:
-
CalendarScreen
- Permission:
access_calendar - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
MasterFilesScreen
- Permission:
access_master_files - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
SettingsScreen
- Permissions: Tab-level granular control
- Tabs and required permissions:
- Profile: No permission needed
- Form Fields: No permission needed
- Expense Categories:
access_master_files - Income Types:
access_accounts - Currency Settings: No permission needed
- Booking Management:
access_booking_channels
- Behavior:
- Unauthorized tabs are disabled (gray, non-clickable)
- Clicking disabled tab shows AccessDenied in content area
- Added proper TypeScript typing for tab permissions
-
BookingChannelsScreen
- Permission:
access_booking_channels - Was a stub screen
- Added:
usePermissionshook andAccessDeniedcomponent
- Permission:
-
RoomsScreen
- Permission:
access_rooms - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
ReservationsScreen
- Permission:
access_bookings - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
HotelLocationsScreen
- Permission:
access_master_files - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
TourGuidesScreen
- Permission:
access_master_files - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
TravelAgentsScreen
- Permission:
access_master_files - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
CommissionSettingsScreen
- Permission:
access_settings - Was a stub screen
- Added:
usePermissionshook andAccessDeniedcomponent
- Permission:
-
BillingSubscriptionsScreen
- Permission:
access_settings - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
-
AccountsScreen
- Permission:
access_accounts - Added:
usePermissionshook andAccessDeniedcomponent - Early return if permission denied
- Permission:
| Screen/Feature | Permission Key | Description |
|---|---|---|
| Dashboard | access_dashboard |
Dashboard overview |
| Calendar | access_calendar |
Calendar timeline view |
| Reservations | access_bookings |
Booking management |
| Rooms | access_rooms |
Room management |
| Expenses | access_expenses |
Expense tracking |
| Accounts | access_accounts |
Account management |
| Reports | access_reports |
Financial reports |
| Users | access_users |
User management |
| Settings | access_settings |
Settings management |
| Master Files | access_master_files |
Locations, guides, agents |
| Booking Channels | access_booking_channels |
Online booking platforms |
Standard implementation pattern used across all screens:
import AccessDenied from "@/components/AccessDenied";
import { usePermissions } from "@/hooks/usePermissions";
export default function SomeScreen() {
const { hasPermission } = usePermissions();
if (!hasPermission("access_xxx")) {
return (
<AccessDenied message="You don't have permission to access [Feature]." />
);
}
// Rest of component...
}- Only sees Dashboard tab
- Clicking Dashboard works normally
- All other tabs are hidden
- Direct navigation to restricted screens shows AccessDenied
- Sees Dashboard, Calendar, and Expenses tabs
- All other tabs are hidden
- Can navigate between allowed tabs
- Direct navigation to restricted screens shows AccessDenied
- Can access: HotelLocations, TourGuides, TravelAgents
- Settings tab shows Expense Categories (enabled)
- Other master file sections work normally
- Sees all tabs in navigation
- Can access all screens
- No AccessDenied messages shown
- All features fully functional
- Profile tab always visible
- Form Fields tab always visible
- Expense Categories requires
access_master_files - Income Types requires
access_accounts - Currency Settings always visible
- Booking Management requires
access_booking_channels - Clicking unauthorized tab shows content AccessDenied
All files pass TypeScript checks:
- ✅ No compilation errors
- ✅ Proper type imports
- ✅ UserPermissions interface exported and used correctly
- ✅ Permission keys properly typed
- Device Testing: Test on physical devices to ensure UX is smooth
- Permission Matrix Testing: Verify all permission combinations work
- Navigation Flow: Ensure no navigation edge cases exist
- Error Scenarios: Test with database connection issues
- Performance: Check that permission checks don't slow down navigation
components/AccessDenied.tsxPERMISSION_SYSTEM_IMPLEMENTATION.md(this file)
hooks/usePermissions.ts- Exported UserPermissions interfacecomponents/BottomTabNavigator.tsx- Conditional tab renderingcomponents/screens/SettingsScreen.tsx- Tab-level permissionscomponents/screens/CalendarScreen.tsx- Permission guardcomponents/screens/MasterFilesScreen.tsx- Permission guardcomponents/screens/BookingChannelsScreen.tsx- Permission guardcomponents/screens/RoomsScreen.tsx- Permission guardcomponents/screens/ReservationsScreen.tsx- Permission guardcomponents/screens/HotelLocationsScreen.tsx- Permission guardcomponents/screens/TourGuidesScreen.tsx- Permission guardcomponents/screens/TravelAgentsScreen.tsx- Permission guardcomponents/screens/CommissionSettingsScreen.tsx- Permission guardcomponents/screens/BillingSubscriptionsScreen.tsx- Permission guardcomponents/screens/AccountsScreen.tsx- Permission guard
Total Files: 16 modified/created
- Unauthorized Access Prevention: Users can't access features they don't have permission for
- Clear User Feedback: AccessDenied component provides clear explanation
- Navigation Clarity: Users only see tabs they can use
- Consistent Security Model: Matches web app's permission system exactly
- Type Safety: TypeScript ensures permission keys are correct
✅ COMPLETE - All screens now have permission guards
✅ COMPLETE - Navigation filters tabs by permissions
✅ COMPLETE - TypeScript errors resolved
✅ COMPLETE - Consistent pattern across all screens
⏳ PENDING - User testing on physical devices