diff --git a/app/src/components/Navbar.tsx b/app/src/components/Navbar.tsx index 8f7bd6d1..246ae61d 100644 --- a/app/src/components/Navbar.tsx +++ b/app/src/components/Navbar.tsx @@ -1,4 +1,4 @@ -import { Menu, Search, User, X } from "lucide-react"; +import { Menu, Search, ShieldCogCorner, User, X } from "lucide-react"; import { Link, useNavigate } from "@tanstack/react-router"; import { useState } from "react"; @@ -16,25 +16,37 @@ import { import { Separator } from "@/components/ui/separator"; import { Logo } from "@/components/Logo"; -// `roles`, when set, hides the item from anyone holding none of them. -const navItems: Array<{ label: string; to: string; roles?: Array }> = [ +const navItems: Array<{ label: string; to: string }> = [ { label: "Browse", to: "/browse" }, { label: "Subjects", to: "/subjects" }, { label: "Objectives", to: "/objectives" }, { label: "Todo", to: "/todos" }, - { label: "Review", to: "/review", roles: ["verifier", "admin"] }, ]; // Profile isn't here because its link needs the signed-in username. const profileItems = [{ label: "Settings", to: "/settings" }]; +// `roles`, when set, hides the item from anyone holding none of them. +const sepcialRoleItems: Array<{ + label: string; + to: string; + roles?: Array; +}> = [ + { + label: "Review Queue", + to: "/review", + roles: ["verifier", "lead-verifier", "admin"], + }, + { label: "Dashboard", to: "/dashboard", roles: ["lead-verifier", "admin"] }, +]; + export function Navbar() { const [mobileOpen, setMobileOpen] = useState(false); const [query, setQuery] = useState(""); const { session, roles, currentProfile } = useAuth(); const navigate = useNavigate(); - const visibleNavItems = navItems.filter( + const visibleRoleItems = sepcialRoleItems.filter( (item) => !item.roles || item.roles.some((r) => roles.includes(r)) ); @@ -62,7 +74,7 @@ export function Navbar() {
+ {roles.length > 0 && ( +
+ + + + + + + {visibleRoleItems.map((item) => ( + + + {item.label} + + + ))} + + +
+ )} + {session ? ( /* Desktop Profile Dropdown */
@@ -189,7 +227,7 @@ export function Navbar() { {/* Nav */}
- {visibleNavItems.map((item) => ( + {navItems.map((item) => ( + {roles.length > 0 && ( + <> + {visibleRoleItems.map((item) => ( + setMobileOpen(false)} + className="py-2 font-mono text-sm text-muted-foreground uppercase hover:text-foreground" + > + {item.label} + + ))} + + )} + + + {session ? ( <> {currentProfile && ( diff --git a/app/src/components/icons/UserRoundArrowLeft.tsx b/app/src/components/icons/UserRoundArrowLeft.tsx new file mode 100644 index 00000000..067f7686 --- /dev/null +++ b/app/src/components/icons/UserRoundArrowLeft.tsx @@ -0,0 +1,21 @@ +export const UserRoundArrowLeft = () => { + return ( + + + + + + + ); +}; diff --git a/app/src/components/sidebar/DashboardSidebar.tsx b/app/src/components/sidebar/DashboardSidebar.tsx new file mode 100644 index 00000000..adc3ef6b --- /dev/null +++ b/app/src/components/sidebar/DashboardSidebar.tsx @@ -0,0 +1,113 @@ +import { Link, useRouterState } from "@tanstack/react-router"; +import { FileCheckCorner, Shield, Users } from "lucide-react"; +import type { LucideProps } from "lucide-react"; +import type { ForwardRefExoticComponent, RefAttributes } from "react"; +import { cn } from "@/lib/utils"; +import { Separator } from "@/components/ui/separator"; +import { useAuth } from "@/lib/authContext"; + +const items: Array<{ + label: string; + to: string; + icon: ForwardRefExoticComponent< + Omit & RefAttributes + >; + roles?: Array; +}> = [ + { + label: "Members", + to: "/dashboard/members", + icon: Users, + roles: ["admin"], + }, + { + label: "Roles", + to: "/dashboard/roles", + icon: Shield, + roles: ["admin"], + }, + { + label: "Verifier Assignments", + to: "/dashboard/assignments", + icon: FileCheckCorner, + roles: ["lead-verifier", "admin"], + }, +]; + +export const DashboardSidebar = () => { + const pathname = useRouterState({ + select: (state) => state.location.pathname, + }); + + const { roles } = useAuth(); + + const isAdmin = roles.includes("admin"); + const isLeadVerifier = roles.includes("lead-verifier"); + + const visibleItems = items.filter( + (item) => !item.roles || item.roles.some((r) => roles.includes(r)) + ); + + return ( + + ); +}; + +export const DashboardTabs = () => { + const pathname = useRouterState({ + select: (state) => state.location.pathname, + }); + + return ( + + ); +}; diff --git a/app/src/components/ActivityColumnFilters.tsx b/app/src/components/tables/ActivityColumnFilters.tsx similarity index 100% rename from app/src/components/ActivityColumnFilters.tsx rename to app/src/components/tables/ActivityColumnFilters.tsx diff --git a/app/src/components/profile/ActivityTable.tsx b/app/src/components/tables/ActivityTable.tsx similarity index 99% rename from app/src/components/profile/ActivityTable.tsx rename to app/src/components/tables/ActivityTable.tsx index 84a994bd..f0c1a098 100644 --- a/app/src/components/profile/ActivityTable.tsx +++ b/app/src/components/tables/ActivityTable.tsx @@ -16,7 +16,7 @@ import { ChoiceColumnFilter, DateColumnFilter, TextColumnFilter, -} from "@/components/ActivityColumnFilters"; +} from "@/components/tables/ActivityColumnFilters"; import { Table, TableBody, diff --git a/app/src/components/tables/MembersTable.tsx b/app/src/components/tables/MembersTable.tsx new file mode 100644 index 00000000..8f0726c0 --- /dev/null +++ b/app/src/components/tables/MembersTable.tsx @@ -0,0 +1,149 @@ +import { useState } from "react"; +import { Checkbox } from "../ui/checkbox"; +import { Badge } from "@/components/ui/badge"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +export const MembersTable = () => { + const [selectedIds, setSelectedIds] = useState>(new Set()); + + const profiles = [ + { + id: "001", + username: "andrea", + display_name: "Andrea", + bio: "Software Engineer", + date_created: "08-14-2026", + date_updated: "08-21-2026", + status: "active", + }, + { + id: "002", + username: "bob", + display_name: "Bob", + bio: "Writer", + date_created: "08-14-2026", + date_updated: "08-21-2026", + status: "suspended", + }, + ]; + + const allSelected = + profiles.length > 0 && + profiles.every((profile) => selectedIds.has(profile.id)); + + function toggleProfile(profileId: string) { + setSelectedIds((current) => { + const next = new Set(current); + + if (next.has(profileId)) { + next.delete(profileId); + } else { + next.add(profileId); + } + + return next; + }); + } + + function toggleAll() { + setSelectedIds((current) => { + if (allSelected) { + const next = new Set(current); + profiles.forEach((profile) => next.delete(profile.id)); + return next; + } + + return new Set(profiles.map((profile) => profile.id)); + }); + } + + return ( + + + + + + + + + Username + + + + Display Name + + + + Bio + + + + Date Created + + + + Date Updated + + + + Status + + + + + + {profiles.map((profile) => ( + + + toggleProfile(profile.id)} + aria-label={`Select ${profile.username}`} + /> + + + + {profile.username} + + + + {profile.display_name} + + + + {profile.bio || "—"} + + + + {profile.date_created} + + + + {profile.date_updated} + + + + + {profile.status} + + + + ))} + +
+ ); +}; diff --git a/app/src/components/tables/RolesTable.tsx b/app/src/components/tables/RolesTable.tsx new file mode 100644 index 00000000..529e1ef9 --- /dev/null +++ b/app/src/components/tables/RolesTable.tsx @@ -0,0 +1,146 @@ +import { useState } from "react"; +import { Checkbox } from "../ui/checkbox"; +import { Badge } from "@/components/ui/badge"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +export const RolesTable = () => { + const [selectedIds, setSelectedIds] = useState>(new Set()); + + const roleData = [ + { + id: "001", + username: "andrea", + roles: ["admin", "curator"], + date_created: "08-14-2026", + date_updated: "08-21-2026", + status: "active", + }, + { + id: "002", + username: "bob", + roles: ["verifier"], + date_created: "08-14-2026", + date_updated: "08-21-2026", + status: "suspended", + }, + ]; + + const allSelected = + roleData.length > 0 && + roleData.every((profile) => selectedIds.has(profile.id)); + + function toggleUser(userId: string) { + setSelectedIds((current) => { + const next = new Set(current); + + if (next.has(userId)) { + next.delete(userId); + } else { + next.add(userId); + } + + return next; + }); + } + + function toggleAll() { + setSelectedIds((current) => { + if (allSelected) { + const next = new Set(current); + roleData.forEach((user) => next.delete(user.id)); + return next; + } + + return new Set(roleData.map((user) => user.id)); + }); + } + + return ( + + + + + + + + + Username + + + + Roles + + + + Date Created + + + + Date Updated + + + + Status + + + + + + {roleData.map((user) => ( + + + toggleUser(user.id)} + aria-label={`Select ${user.username}`} + /> + + + + {user.username} + + + + {user.roles.map((role) => ( + + {role} + + ))} + + + + {user.date_created} + + + + {user.date_updated} + + + + + {user.status} + + + + ))} + +
+ ); +}; diff --git a/app/src/routeTree.gen.ts b/app/src/routeTree.gen.ts index 975881c1..b5fadd33 100644 --- a/app/src/routeTree.gen.ts +++ b/app/src/routeTree.gen.ts @@ -20,6 +20,7 @@ import { Route as ProfileRouteImport } from './routes/profile' import { Route as ObjectivesRouteImport } from './routes/objectives' import { Route as LoginRouteImport } from './routes/login' import { Route as ForgotPasswordRouteImport } from './routes/forgot-password' +import { Route as DashboardRouteImport } from './routes/dashboard' import { Route as ContributeRouteImport } from './routes/contribute' import { Route as BrowseRouteImport } from './routes/browse' import { Route as IndexRouteImport } from './routes/index' @@ -28,6 +29,7 @@ import { Route as SettingsIndexRouteImport } from './routes/settings.index' import { Route as ReviewIndexRouteImport } from './routes/review.index' import { Route as ObjectivesIndexRouteImport } from './routes/objectives.index' import { Route as GuidesIndexRouteImport } from './routes/guides/index' +import { Route as DashboardIndexRouteImport } from './routes/dashboard/index' import { Route as SubjectsSlugRouteImport } from './routes/subjects.$slug' import { Route as SettingsProfileRouteImport } from './routes/settings.profile' import { Route as SettingsAppearanceRouteImport } from './routes/settings.appearance' @@ -36,6 +38,9 @@ import { Route as ReviewCaseIdRouteImport } from './routes/review.$caseId' import { Route as ProfileUsernameRouteImport } from './routes/profile.$username' import { Route as ObjectivesSlugRouteImport } from './routes/objectives/$slug' import { Route as GuidesSlugRouteImport } from './routes/guides/$slug' +import { Route as DashboardRolesRouteImport } from './routes/dashboard/roles' +import { Route as DashboardMembersRouteImport } from './routes/dashboard/members' +import { Route as DashboardAssignmentsRouteImport } from './routes/dashboard/assignments' import { Route as ObjectivesSlugIndexRouteImport } from './routes/objectives/$slug/index' import { Route as GuidesSlugIndexRouteImport } from './routes/guides/$slug/index' import { Route as GuidesSlugWalkthroughRouteImport } from './routes/guides/$slug/walkthrough' @@ -99,6 +104,11 @@ const ForgotPasswordRoute = ForgotPasswordRouteImport.update({ path: '/forgot-password', getParentRoute: () => rootRouteImport, } as any) +const DashboardRoute = DashboardRouteImport.update({ + id: '/dashboard', + path: '/dashboard', + getParentRoute: () => rootRouteImport, +} as any) const ContributeRoute = ContributeRouteImport.update({ id: '/contribute', path: '/contribute', @@ -139,6 +149,11 @@ const GuidesIndexRoute = GuidesIndexRouteImport.update({ path: '/guides/', getParentRoute: () => rootRouteImport, } as any) +const DashboardIndexRoute = DashboardIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => DashboardRoute, +} as any) const SubjectsSlugRoute = SubjectsSlugRouteImport.update({ id: '/$slug', path: '/$slug', @@ -179,6 +194,21 @@ const GuidesSlugRoute = GuidesSlugRouteImport.update({ path: '/guides/$slug', getParentRoute: () => rootRouteImport, } as any) +const DashboardRolesRoute = DashboardRolesRouteImport.update({ + id: '/roles', + path: '/roles', + getParentRoute: () => DashboardRoute, +} as any) +const DashboardMembersRoute = DashboardMembersRouteImport.update({ + id: '/members', + path: '/members', + getParentRoute: () => DashboardRoute, +} as any) +const DashboardAssignmentsRoute = DashboardAssignmentsRouteImport.update({ + id: '/assignments', + path: '/assignments', + getParentRoute: () => DashboardRoute, +} as any) const ObjectivesSlugIndexRoute = ObjectivesSlugIndexRouteImport.update({ id: '/', path: '/', @@ -223,6 +253,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/browse': typeof BrowseRoute '/contribute': typeof ContributeRoute + '/dashboard': typeof DashboardRouteWithChildren '/forgot-password': typeof ForgotPasswordRoute '/login': typeof LoginRoute '/objectives': typeof ObjectivesRouteWithChildren @@ -234,6 +265,9 @@ export interface FileRoutesByFullPath { '/subjects': typeof SubjectsRouteWithChildren '/todos': typeof TodosRoute '/verify-email': typeof VerifyEmailRoute + '/dashboard/assignments': typeof DashboardAssignmentsRoute + '/dashboard/members': typeof DashboardMembersRoute + '/dashboard/roles': typeof DashboardRolesRoute '/guides/$slug': typeof GuidesSlugRouteWithChildren '/objectives/$slug': typeof ObjectivesSlugRouteWithChildren '/profile/$username': typeof ProfileUsernameRoute @@ -242,6 +276,7 @@ export interface FileRoutesByFullPath { '/settings/appearance': typeof SettingsAppearanceRoute '/settings/profile': typeof SettingsProfileRoute '/subjects/$slug': typeof SubjectsSlugRoute + '/dashboard/': typeof DashboardIndexRoute '/guides/': typeof GuidesIndexRoute '/objectives/': typeof ObjectivesIndexRoute '/review/': typeof ReviewIndexRoute @@ -266,12 +301,16 @@ export interface FileRoutesByTo { '/reset-password': typeof ResetPasswordRoute '/todos': typeof TodosRoute '/verify-email': typeof VerifyEmailRoute + '/dashboard/assignments': typeof DashboardAssignmentsRoute + '/dashboard/members': typeof DashboardMembersRoute + '/dashboard/roles': typeof DashboardRolesRoute '/profile/$username': typeof ProfileUsernameRoute '/review/$caseId': typeof ReviewCaseIdRoute '/settings/account': typeof SettingsAccountRoute '/settings/appearance': typeof SettingsAppearanceRoute '/settings/profile': typeof SettingsProfileRoute '/subjects/$slug': typeof SubjectsSlugRoute + '/dashboard': typeof DashboardIndexRoute '/guides': typeof GuidesIndexRoute '/objectives': typeof ObjectivesIndexRoute '/review': typeof ReviewIndexRoute @@ -290,6 +329,7 @@ export interface FileRoutesById { '/': typeof IndexRoute '/browse': typeof BrowseRoute '/contribute': typeof ContributeRoute + '/dashboard': typeof DashboardRouteWithChildren '/forgot-password': typeof ForgotPasswordRoute '/login': typeof LoginRoute '/objectives': typeof ObjectivesRouteWithChildren @@ -301,6 +341,9 @@ export interface FileRoutesById { '/subjects': typeof SubjectsRouteWithChildren '/todos': typeof TodosRoute '/verify-email': typeof VerifyEmailRoute + '/dashboard/assignments': typeof DashboardAssignmentsRoute + '/dashboard/members': typeof DashboardMembersRoute + '/dashboard/roles': typeof DashboardRolesRoute '/guides/$slug': typeof GuidesSlugRouteWithChildren '/objectives/$slug': typeof ObjectivesSlugRouteWithChildren '/profile/$username': typeof ProfileUsernameRoute @@ -309,6 +352,7 @@ export interface FileRoutesById { '/settings/appearance': typeof SettingsAppearanceRoute '/settings/profile': typeof SettingsProfileRoute '/subjects/$slug': typeof SubjectsSlugRoute + '/dashboard/': typeof DashboardIndexRoute '/guides/': typeof GuidesIndexRoute '/objectives/': typeof ObjectivesIndexRoute '/review/': typeof ReviewIndexRoute @@ -328,6 +372,7 @@ export interface FileRouteTypes { | '/' | '/browse' | '/contribute' + | '/dashboard' | '/forgot-password' | '/login' | '/objectives' @@ -339,6 +384,9 @@ export interface FileRouteTypes { | '/subjects' | '/todos' | '/verify-email' + | '/dashboard/assignments' + | '/dashboard/members' + | '/dashboard/roles' | '/guides/$slug' | '/objectives/$slug' | '/profile/$username' @@ -347,6 +395,7 @@ export interface FileRouteTypes { | '/settings/appearance' | '/settings/profile' | '/subjects/$slug' + | '/dashboard/' | '/guides/' | '/objectives/' | '/review/' @@ -371,12 +420,16 @@ export interface FileRouteTypes { | '/reset-password' | '/todos' | '/verify-email' + | '/dashboard/assignments' + | '/dashboard/members' + | '/dashboard/roles' | '/profile/$username' | '/review/$caseId' | '/settings/account' | '/settings/appearance' | '/settings/profile' | '/subjects/$slug' + | '/dashboard' | '/guides' | '/objectives' | '/review' @@ -394,6 +447,7 @@ export interface FileRouteTypes { | '/' | '/browse' | '/contribute' + | '/dashboard' | '/forgot-password' | '/login' | '/objectives' @@ -405,6 +459,9 @@ export interface FileRouteTypes { | '/subjects' | '/todos' | '/verify-email' + | '/dashboard/assignments' + | '/dashboard/members' + | '/dashboard/roles' | '/guides/$slug' | '/objectives/$slug' | '/profile/$username' @@ -413,6 +470,7 @@ export interface FileRouteTypes { | '/settings/appearance' | '/settings/profile' | '/subjects/$slug' + | '/dashboard/' | '/guides/' | '/objectives/' | '/review/' @@ -431,6 +489,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute BrowseRoute: typeof BrowseRoute ContributeRoute: typeof ContributeRoute + DashboardRoute: typeof DashboardRouteWithChildren ForgotPasswordRoute: typeof ForgotPasswordRoute LoginRoute: typeof LoginRoute ObjectivesRoute: typeof ObjectivesRouteWithChildren @@ -525,6 +584,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ForgotPasswordRouteImport parentRoute: typeof rootRouteImport } + '/dashboard': { + id: '/dashboard' + path: '/dashboard' + fullPath: '/dashboard' + preLoaderRoute: typeof DashboardRouteImport + parentRoute: typeof rootRouteImport + } '/contribute': { id: '/contribute' path: '/contribute' @@ -581,6 +647,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof GuidesIndexRouteImport parentRoute: typeof rootRouteImport } + '/dashboard/': { + id: '/dashboard/' + path: '/' + fullPath: '/dashboard/' + preLoaderRoute: typeof DashboardIndexRouteImport + parentRoute: typeof DashboardRoute + } '/subjects/$slug': { id: '/subjects/$slug' path: '/$slug' @@ -637,6 +710,27 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof GuidesSlugRouteImport parentRoute: typeof rootRouteImport } + '/dashboard/roles': { + id: '/dashboard/roles' + path: '/roles' + fullPath: '/dashboard/roles' + preLoaderRoute: typeof DashboardRolesRouteImport + parentRoute: typeof DashboardRoute + } + '/dashboard/members': { + id: '/dashboard/members' + path: '/members' + fullPath: '/dashboard/members' + preLoaderRoute: typeof DashboardMembersRouteImport + parentRoute: typeof DashboardRoute + } + '/dashboard/assignments': { + id: '/dashboard/assignments' + path: '/assignments' + fullPath: '/dashboard/assignments' + preLoaderRoute: typeof DashboardAssignmentsRouteImport + parentRoute: typeof DashboardRoute + } '/objectives/$slug/': { id: '/objectives/$slug/' path: '/' @@ -689,6 +783,24 @@ declare module '@tanstack/react-router' { } } +interface DashboardRouteChildren { + DashboardAssignmentsRoute: typeof DashboardAssignmentsRoute + DashboardMembersRoute: typeof DashboardMembersRoute + DashboardRolesRoute: typeof DashboardRolesRoute + DashboardIndexRoute: typeof DashboardIndexRoute +} + +const DashboardRouteChildren: DashboardRouteChildren = { + DashboardAssignmentsRoute: DashboardAssignmentsRoute, + DashboardMembersRoute: DashboardMembersRoute, + DashboardRolesRoute: DashboardRolesRoute, + DashboardIndexRoute: DashboardIndexRoute, +} + +const DashboardRouteWithChildren = DashboardRoute._addFileChildren( + DashboardRouteChildren, +) + interface ObjectivesSlugRouteChildren { ObjectivesSlugIndexRoute: typeof ObjectivesSlugIndexRoute ObjectivesSlugRevisionsRevisionIdRoute: typeof ObjectivesSlugRevisionsRevisionIdRoute @@ -799,6 +911,7 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BrowseRoute: BrowseRoute, ContributeRoute: ContributeRoute, + DashboardRoute: DashboardRouteWithChildren, ForgotPasswordRoute: ForgotPasswordRoute, LoginRoute: LoginRoute, ObjectivesRoute: ObjectivesRouteWithChildren, diff --git a/app/src/routes/dashboard.tsx b/app/src/routes/dashboard.tsx new file mode 100644 index 00000000..14818346 --- /dev/null +++ b/app/src/routes/dashboard.tsx @@ -0,0 +1,29 @@ +import { Outlet, createFileRoute } from "@tanstack/react-router"; +import { + DashboardSidebar, + DashboardTabs, +} from "@/components/sidebar/DashboardSidebar"; +import { requireSession } from "@/lib/auth"; + +export const Route = createFileRoute("/dashboard")({ + ssr: false, + beforeLoad: requireSession, + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+
+ {/* Left Sidebar Navigation */} + + + {/* Right Content Area */} +
+ + +
+
+
+ ); +} diff --git a/app/src/routes/dashboard/assignments.tsx b/app/src/routes/dashboard/assignments.tsx new file mode 100644 index 00000000..d03ac159 --- /dev/null +++ b/app/src/routes/dashboard/assignments.tsx @@ -0,0 +1,34 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { UserRoundArrowLeft } from "@/components/icons/UserRoundArrowLeft"; +import { Button } from "@/components/ui/button"; + +export const Route = createFileRoute("/dashboard/assignments")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+
+
+

+ Manage Guide Assignments +

+
+ +
+ +
+
+ +
+
+ {/* AssignmentsTable */} +
+
+
+ ); +} diff --git a/app/src/routes/dashboard/index.tsx b/app/src/routes/dashboard/index.tsx new file mode 100644 index 00000000..aa46ac6e --- /dev/null +++ b/app/src/routes/dashboard/index.tsx @@ -0,0 +1,7 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; + +export const Route = createFileRoute("/dashboard/")({ + beforeLoad: () => { + throw redirect({ to: "/dashboard/members" }); + }, +}); diff --git a/app/src/routes/dashboard/members.tsx b/app/src/routes/dashboard/members.tsx new file mode 100644 index 00000000..10635903 --- /dev/null +++ b/app/src/routes/dashboard/members.tsx @@ -0,0 +1,38 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { Ban } from "lucide-react"; +import { MembersTable } from "@/components/tables/MembersTable"; +import { Button } from "@/components/ui/button"; + +export const Route = createFileRoute("/dashboard/members")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+
+
+

+ Manage Members +

+
+ +
+ +
+
+ +
+
+ +
+
+
+ ); +} diff --git a/app/src/routes/dashboard/roles.tsx b/app/src/routes/dashboard/roles.tsx new file mode 100644 index 00000000..29d0b819 --- /dev/null +++ b/app/src/routes/dashboard/roles.tsx @@ -0,0 +1,48 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ShieldMinus, ShieldPlus, SquareArrowRightExit } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { RolesTable } from "@/components/tables/RolesTable"; + +export const Route = createFileRoute("/dashboard/roles")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+
+
+

+ Manage Roles +

+
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+ ); +} diff --git a/app/src/routes/profile.$username.tsx b/app/src/routes/profile.$username.tsx index 89c9c642..96dea483 100644 --- a/app/src/routes/profile.$username.tsx +++ b/app/src/routes/profile.$username.tsx @@ -4,7 +4,7 @@ import type { ProfileActivitySearch } from "@bluelearn/schemas"; import { getAvatarUrl, getInitials } from "@/lib/profile"; import { getProfilePage } from "@/lib/api/identity"; import { cn } from "@/lib/utils"; -import { ActivityTable } from "@/components/profile/ActivityTable"; +import { ActivityTable } from "@/components/tables/ActivityTable"; import { Separator } from "@/components/ui/separator"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; diff --git a/app/src/routes/review.index.tsx b/app/src/routes/review.index.tsx index acf14599..df9228e6 100644 --- a/app/src/routes/review.index.tsx +++ b/app/src/routes/review.index.tsx @@ -28,7 +28,7 @@ function Shell({ children }: { children: React.ReactNode }) {
-

+

Review Queue