Skip to content
Merged
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
34 changes: 34 additions & 0 deletions apps/app-portal/src/app/(admin)/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from "react";
const tiles = [
{
title: "Settings",
},
{
title: "Applicants",
},
{
title: "Stats",
},
];

export default function AdminPage() {
return (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold">Admin Dashboard</h1>

<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">
{tiles.map((t) => (
<div key={t.title} className="rounded-xl border p-6 shadow-sm">
<h2 className="text-xl font-semibold">{t.title}</h2>

<div className="mt-4 text-sm font-medium text-blue-600">Open →</div>
</div>
))}
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions apps/app-portal/src/app/(admin)/admin/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import ShowDecisionToggle from "@/components/admin/ShowDecisionToggle";
import DateControls from "@/components/admin/DateControl";
import FormConfigEditor from "@/components/admin/FormConfigEditor";

export default function Page() {
return (
<div>
<ShowDecisionToggle />
<DateControls />
<FormConfigEditor />
</div>
);
}
25 changes: 25 additions & 0 deletions apps/app-portal/src/app/(admin)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";
import Link from "next/link";

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>

<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>

<main className="flex-1">
<header className="border-b p-4">
<h1 className="text-xl font-semibold">Admin Portal</h1>
</header>
</main>
</div>
);
}
59 changes: 59 additions & 0 deletions apps/app-portal/src/app/api/v1/admin/form-config/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { NextResponse } from "next/server";

type QuestionType = "text" | "textarea";

type Question = {
id: string;
label: string;
type: QuestionType;
};

type Section = {
id: string;
title: string;
questions: Question[];
};

type FormConfig = {
sections: Section[];
};

const mockFormConfig: FormConfig = {
sections: [
{
id: "basic",
title: "Basic Info",
questions: [
{
id: "name",
label: "Full Name",
type: "text",
},
{
id: "reason",
label: "Why are you applying?",
type: "textarea",
},
],
},
{
id: "experience",
title: "Experience",
questions: [
{
id: "background",
label: "Tell us about your background",
type: "textarea",
},
],
},
],
};

export async function GET() {
return NextResponse.json(mockFormConfig);
}

export async function POST() {
return NextResponse.json({ message: "Not implemented" }, { status: 501 });
}
27 changes: 27 additions & 0 deletions apps/app-portal/src/app/api/v1/dates/confirm-by/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextResponse } from "next/server";
import { SingletonKey } from "@/lib/admin/singleton-keys";

type SingletonResponse = {
key: SingletonKey;
value: string;
};

export async function GET() {
const data: SingletonResponse = {
key: "confirm-by",
value: "2026-06-15T23:59:00Z",
};

return NextResponse.json(data);
}

export async function POST() {
return NextResponse.json(
{
message: "Not implemented",
},
{
status: 501,
},
);
}
27 changes: 27 additions & 0 deletions apps/app-portal/src/app/api/v1/dates/registration-closed/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextResponse } from "next/server";
import { SingletonKey } from "@/lib/admin/singleton-keys";

type SingletonResponse = {
key: SingletonKey;
value: string;
};

export async function GET() {
const data: SingletonResponse = {
key: "registration-closed",
value: "2026-06-15T23:59:00Z",
};

return NextResponse.json(data);
}

export async function POST() {
return NextResponse.json(
{
message: "Not implemented",
},
{
status: 501,
},
);
}
27 changes: 27 additions & 0 deletions apps/app-portal/src/app/api/v1/dates/registration-open/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextResponse } from "next/server";
import { SingletonKey } from "@/lib/admin/singleton-keys";

type SingletonResponse = {
key: SingletonKey;
value: string;
};

export async function GET() {
const data: SingletonResponse = {
key: "registration-open",
value: "2026-06-15T23:59:00Z",
};

return NextResponse.json(data);
}

export async function POST() {
return NextResponse.json(
{
message: "Not implemented",
},
{
status: 501,
},
);
}
27 changes: 27 additions & 0 deletions apps/app-portal/src/app/api/v1/show-decision/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextResponse } from "next/server";
import { SingletonKey } from "@/lib/admin/singleton-keys";

type SingletonResponse = {
key: SingletonKey;
value: string;
};

export async function GET() {
const data: SingletonResponse = {
key: "show-decision",
value: "2026-06-15T23:59:00Z",
};

return NextResponse.json(data);
}

export async function POST() {
return NextResponse.json(
{
message: "Not implemented",
},
{
status: 501,
},
);
}
5 changes: 5 additions & 0 deletions apps/app-portal/src/components/admin/AdminSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export default function AdminSidebar() {
return <div>AdminSidebar here</div>;
}
13 changes: 13 additions & 0 deletions apps/app-portal/src/components/admin/DateControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

export default function DateControls() {
return (
<div className="border p-4 rounded-lg space-y-4">
<h2 className="text-lg font-semibold">Application Deadline</h2>

<input type="datetime-local" className="border p-2 rounded w-full" />

<button>Save</button>
</div>
);
}
18 changes: 18 additions & 0 deletions apps/app-portal/src/components/admin/FormConfigEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";

export default function FormConfigEditor() {
return (
<div className="border p-4 rounded-lg space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold">Form Questions</h2>

<button className="border px-3 py-1 rounded">Add Question</button>
</div>

<div>
Add Question here
<button className="border px-3 py-1 rounded">Edit</button>
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions apps/app-portal/src/components/admin/ShowDecisionToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use client";

import { useState } from "react";
import React from "react";

export default function ShowDecisionToggle() {
const [enabled, setEnabled] = useState(false);

return (
<div className="border rounded-lg p-4">
<h3 className="font-semibold mb-2">Show Decision</h3>
<label className="flex items-center gap-2">
<input
type="checkbox"
checked={enabled}
onChange={() => setEnabled(!enabled)}
/>
<span>{enabled ? "Enabled" : "Disabled"}</span>
</label>
</div>
);
}
33 changes: 20 additions & 13 deletions apps/app-portal/src/components/ui/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const badgeVariants = cva("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", {
variants: {
variant: {
default: "border-transparent bg-black text-white",
secondary: "border-transparent bg-neutral-100 text-neutral-900",
destructive: "border-transparent bg-red-600 text-white",
outline: "text-neutral-950",
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors",
{
variants: {
variant: {
default: "border-transparent bg-black text-white",
secondary: "border-transparent bg-neutral-100 text-neutral-900",
destructive: "border-transparent bg-red-600 text-white",
outline: "text-neutral-950",
},
},
defaultVariants: {
variant: "default",
},
},
defaultVariants: {
variant: "default",
},
});
);

export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}

export { Badge, badgeVariants };
8 changes: 7 additions & 1 deletion apps/app-portal/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ export interface ButtonProps
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";
Expand Down
Loading