Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/app-portal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.4",
"@repo/ui": "*",
"@tanstack/react-table": "^8.20.5",
"@repo/util": "*",
"@tanstack/react-table": "^8.20.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.4.0",
"lucide-react": "^1.14.0",
"mongodb": "^7.2.0",
"next": "^14.2.3",
"react": "^18.2.0",
"react-day-picker": "^10.0.1",
"react-dom": "^18.2.0",
"react-hook-form": "^7.75.0",
"recharts": "3.8.0",
Expand Down
29 changes: 25 additions & 4 deletions apps/app-portal/src/app/(admin)/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import React from "react";
import Link from "next/link";

const tiles = [
{
title: "Settings",
title: "Config Portal Settings",
description:
"Manage site configuration, application preferences, and administrative options.",
link: "/admin/settings",
},
{
title: "Applicants",
description:
"Review applicant information, track application status, and manage submissions.",
link: "/admin/applicants",
},
{
title: "Stats",
description:
"View platform metrics, application trends, and key performance statistics.",
link: "/admin/stats",
},
];

Expand All @@ -20,12 +31,22 @@ export default function AdminPage() {
<p className="text-gray-500 mt-1">Welcome to the admin portal.</p>
</div>

<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div className="grid grid-cols-3 gap-6">
{tiles.map((t) => (
<div key={t.title} className="rounded-xl border p-6 shadow-sm">
<div
key={t.title}
className="flex-1 rounded-2xl border bg-white p-8 shadow hover:shadow-lg transition"
>
<h2 className="text-xl font-semibold">{t.title}</h2>
<p className="text-sm">{t.description}</p>

<div className="mt-4 text-sm font-medium text-blue-600">Open →</div>
<Link
href={t.link}
style={{ backgroundColor: "#1890ff" }}
className="mt-4 inline-block rounded border bg-blue-400 px-3 py-1 text-white"
>
Open
</Link>
</div>
))}
</div>
Expand Down
41 changes: 37 additions & 4 deletions apps/app-portal/src/app/(admin)/admin/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
import React from "react";
import ShowDecisionToggle from "@/components/admin/ShowDecisionToggle";
import DateControls from "@/components/admin/DateControl";
import DateControls from "@/components/admin/DateControls";
import FormConfigEditor from "@/components/admin/FormConfigEditor";

export default function Page() {
return (
<div>
<ShowDecisionToggle />
<DateControls />
<FormConfigEditor />
<h1 className="text-3xl font-bold">Configure Portal Settings</h1>

<div className="flex flex-col gap-8">
<section>
<h2 className="mb-4 text-xl font-semibold">Dates</h2>
<div className="flex flex-col gap-4">
<DateControls
label="Registration Opens:"
endpoint="/api/v1/dates/open"
initialValue="2026-06-01T00:00:00Z"
/>

<DateControls
label="Registration Closes:"
endpoint="/api/v1/dates/close"
initialValue="2026-06-10T00:00:00Z"
/>

<DateControls
label="Confirm By:"
endpoint="/api/v1/dates/rsvp"
initialValue="2026-06-15T00:00:00Z"
/>
</div>
</section>

<section>
<h2 className="mb-4 text-xl font-semibold">Display</h2>
<ShowDecisionToggle />
</section>

<section>
<h2 className="mb-4 text-xl font-semibold">Form Configuration</h2>
<FormConfigEditor />
</section>
</div>
</div>
);
}
42 changes: 27 additions & 15 deletions apps/app-portal/src/app/(admin)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import React from "react";
import Link from "next/link";
import AdminSidebar from "@/components/admin/AdminSidebar";
import { redirect } from "next/navigation";

async function requireAdmin(): Promise<boolean> {
return true;
}

export default async function AdminLayout({
children,
}: {
children: React.ReactNode;
}) {
const isAdmin = await requireAdmin();

if (!isAdmin) {
redirect("/");
}

export default function AdminLayout() {
return (
<div className="flex min-h-screen">
<aside className="w-64 border-r p-4">
<h2 className="font-bold mb-4">Admin</h2>
<AdminSidebar />

<nav className="flex flex-col gap-2">
<Link href="/admin">Dashboard</Link>
<Link href="/admin/settings">Settings</Link>
<Link href="/admin/applicants">Applicants</Link>
<Link href="/admin/stats">Stats</Link>
</nav>
</aside>
<div className="flex flex-1 flex-col desktop:ml-64">
<header className="flex h-16 items-center justify-between border-b bg-white px-6">
<div>
<h1 className="text-xl font-semibold">Admin Portal</h1>
</div>

<main className="flex-1">
<header className="border-b p-4">
<h1 className="text-xl font-semibold">Admin Portal</h1>
<div className="flex items-center gap-4">Place user menu here</div>
</header>
</main>

<main className="flex-1 p-6">{children}</main>
</div>
</div>
);
}
3 changes: 2 additions & 1 deletion apps/app-portal/src/app/(landing)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
// import Layout from "../(admin)/layout";

export default function Page(): JSX.Element {
return <>poop</>;
return <div>{/* <Layout children={undefined} /> */}</div>;
}
//TODO: update to redirect authed users to /dashboard
102 changes: 101 additions & 1 deletion apps/app-portal/src/components/admin/AdminSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,105 @@
"use client";

import React from "react";
import Link from "next/link";
import HackBeanpotLogo from "../../../../../packages/ui/src/Logos/HackBeanpotLogo";
import { usePathname } from "next/navigation";
import useDevice from "@repo/util/hooks/useDevice";
import { MenuIcon } from "lucide-react";

export default function AdminSidebar() {
return <div>AdminSidebar here</div>;
const pathname = usePathname();
const { isMobile } = useDevice();
const [open, setOpen] = React.useState(false);

const Active = (href: string) => {
const isActive =
href === "/admin" ? pathname === "/admin" : pathname.startsWith(href);

return isActive
? {
backgroundColor: "#1890ff",
color: "white",
fontWeight: "bold" as const,
}
: {
color: "#808080",
};
};

const NavLinks = () => (
<>
<Link href="/">
<HackBeanpotLogo className="text-white" />
</Link>

<Link
href="/admin"
style={Active("/admin")}
className="block rounded px-3 py-2 text-lg"
>
Admin
</Link>

<Link
href="/admin/settings"
style={Active("/admin/settings")}
className="block rounded px-3 py-2 text-lg"
>
Portal Settings
</Link>

<Link
href="/admin/applicants"
style={Active("/admin/applicants")}
className="block rounded px-3 py-2 text-lg"
>
Applicants
</Link>

<Link
href="/admin/stats"
style={Active("/admin/stats")}
className="block rounded px-3 py-2 text-lg"
>
Stats
</Link>
</>
);

if (isMobile) {
return (
<>
<button
onClick={() => setOpen(true)}
style={{ backgroundColor: "transparent", color: "blue" }}
className="fixed top-4 left-4 z-100 rounded p-2"
>
<MenuIcon />
</button>

{open && (
<>
<div
className="fixed inset-0 bg-black/40 z-40"
onClick={() => setOpen(false)}
/>

<aside className="fixed left-0 top-0 z-50 h-screen bg-[#001529] p-4">
<NavLinks />
</aside>
</>
)}
</>
);
}

return (
<div
style={{ backgroundColor: "#001529" }}
className="fixed left-0 top-0 h-full shadow desktop:w-64 border-r p-4"
>
<NavLinks />
</div>
);
}
13 changes: 0 additions & 13 deletions apps/app-portal/src/components/admin/DateControl.tsx

This file was deleted.

Loading