feat(router-with-admin): App.tsx +/admin route + Nav admin-link bei admin-role [tsc:ok]

This commit is contained in:
Dennis (via Claude+Gemma) 2026-05-23 05:18:21 +02:00
parent 0a3b293c62
commit 38d9258912
4 changed files with 63 additions and 4 deletions

View File

@ -3,8 +3,9 @@
"admin-user-management",
"csv-export-time-entries",
"error-boundary",
"dashboard-charts"
"dashboard-charts",
"api-client-phase4"
],
"current_feature": "api-client-phase4",
"current_feature": "router-with-admin",
"started_at": "2026-05-23T05:10:51.482879"
}

View File

@ -515,3 +515,15 @@ undefined
- `05:17:24` **INFO** wrote 3845 chars in 34.1s (attempt 1)
- `05:17:24` **INFO** Running tsc --noEmit on api…
- `05:17:26` **INFO** tsc clean ✓
- `05:17:26` **INFO** Committed feature api-client-phase4
- `05:17:26` **INFO** Pushed: rc=0
## Phase-3 Feature: router-with-admin (2026-05-23 05:17:26)
- `05:17:26` **INFO** Description: App.tsx +/admin route + Nav admin-link bei admin-role
- `05:17:26` **INFO** Generating apps/web/src/App.tsx (ERWEITERT — füge Route /admin (AdminUsers component) hinzu. Auth-Check…)
- `05:17:50` **INFO** wrote 2745 chars in 24.1s (attempt 1)
- `05:17:50` **INFO** Generating apps/web/src/components/Nav.tsx (ERWEITERT — Nav zeigt Admin-Link nur wenn current user role='admin'. u…)
- `05:18:20` **INFO** wrote 3580 chars in 29.7s (attempt 1)
- `05:18:20` **INFO** Running tsc --noEmit on api…
- `05:18:21` **INFO** tsc clean ✓

View File

@ -5,6 +5,7 @@ import TimeEntries from "./pages/TimeEntries"
import Customers from "./pages/Customers"
import Projects from "./pages/Projects"
import Profile from "./pages/Profile"
import AdminUsers from "./pages/AdminUsers"
import Nav from "./components/Nav"
import { ToastProvider } from "./components/Toast"
import ErrorBoundary from "./components/ErrorBoundary"
@ -35,6 +36,22 @@ const authCheck = async () => {
}
}
const adminCheck = async () => {
try {
const user = await api.getMe()
if (user.role !== "admin") {
throw redirect({ to: "/" })
}
} catch (error: any) {
if (error.status === 401) {
throw redirect({ to: "/login" })
} else if (error.status === 302 || error.status === 403) {
throw error
}
throw redirect({ to: "/" })
}
}
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/",
@ -70,13 +87,21 @@ const profileRoute = createRoute({
component: Profile
})
const adminRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/admin",
beforeLoad: adminCheck,
component: AdminUsers
})
const routeTree = rootRoute.addChildren([
indexRoute,
loginRoute,
timeEntriesRoute,
customersRoute,
projectsRoute,
profileRoute
profileRoute,
adminRoute
])
const router = createRouter({

View File

@ -6,13 +6,20 @@ import {
Users,
FolderKanban,
User,
LogOut
LogOut,
ShieldCheck
} from "lucide-react"
import { useQuery } from "@tanstack/react-query"
import { api } from "../lib/api"
export default function Nav() {
const location = useLocation()
const { data: user } = useQuery({
queryKey: ['me'],
queryFn: api.getMe
})
const navItems = [
{ label: "Dashboard", to: "/", icon: Home },
{ label: "Time Entries", to: "/time-entries", icon: Clock },
@ -60,6 +67,20 @@ export default function Nav() {
</Link>
)
})}
{user?.role === 'admin' && (
<Link
to="/admin"
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
location.pathname === "/admin"
? "bg-indigo-50 text-indigo-700"
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
}`}
>
<ShieldCheck className="w-4 h-4" />
Admin
</Link>
)}
</div>
</div>