aed0572071
Build out the full web route map from music-selfhost-routes.md as scaffolding (no functionality on new screens): - Full route tree: /login, /albums/:id, /artists/:id, /playlists(+detail), /discover, /upload, metadata editor (single + batch), /storage/maintenance, /queue, nested /settings and /admin, and a 404. - Sidebar rebuilt to the A1 spec with permission-gated Discover/Upload. - ProtectedRoute gains requirePermission; Permission exported. - AppShell wraps Outlet in a Suspense boundary for lazy routes. - Reusable Placeholder + SubNav; Settings/Admin become nested layouts. - Settings/Profile: wired language + theme selectors. - Remove orphaned Home feature (web has no Home; / -> /library) and the now-unused house icon + nav.home keys. - i18n keys (en + ru) and CSS for page-title/sub-nav. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
736 B
TypeScript
35 lines
736 B
TypeScript
import { useAppSelector } from './useAppDispatch';
|
|
|
|
export type Permission =
|
|
| 'download'
|
|
| 'upload'
|
|
| 'admin'
|
|
| 'manage_users'
|
|
| 'edit_metadata'
|
|
| 'delete_tracks';
|
|
|
|
const ROLE_PERMISSIONS: Record<string, Permission[]> = {
|
|
admin: [
|
|
'download',
|
|
'upload',
|
|
'admin',
|
|
'manage_users',
|
|
'edit_metadata',
|
|
'delete_tracks',
|
|
],
|
|
user: ['download', 'upload'],
|
|
};
|
|
|
|
export function usePermissions() {
|
|
const user = useAppSelector((s) => s.auth.user);
|
|
|
|
const hasPermission = (permission: Permission): boolean => {
|
|
if (!user) return false;
|
|
return ROLE_PERMISSIONS[user.role]?.includes(permission) ?? false;
|
|
};
|
|
|
|
const isAdmin = user?.role === 'admin';
|
|
|
|
return { hasPermission, isAdmin, user };
|
|
}
|