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
73 changes: 47 additions & 26 deletions app/admin/applications/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,49 @@
"use client";

import Link from "next/link";
import { getApplicationById } from "@/services/mockApplications";
import ApproveRejectButtons from "@/components/admin/ApproveRejectButtons";
import { useEffect, useState } from "react";

type Props = {
params: Promise<{ id: string }>;
const STATUS_STYLES: Record<string, string> = {
pending: "bg-amber-50 text-amber-700 ring-1 ring-amber-200",
approved: "bg-emerald-50 text-emerald-700 ring-1 ring-emerald-200",
rejected: "bg-red-50 text-red-600 ring-1 ring-red-200",
};

export default async function ApplicationDetail({ params }: Props) {
const { id } = await params;
const app = getApplicationById(id);

if (!app) {
return (
<div className="p-6">
<h2 className="text-xl font-semibold">Application not found</h2>
<p className="mt-2">No mock application matches id {id}.</p>
<Link href="/admin/applications" className="text-blue-600 hover:underline mt-4 inline-block">
Back to applications
</Link>
</div>
);
interface Application {
id: string;
type: string;
status: string;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you define type ApplicationStatus = "pending" | "approved" | "rejected"; in app/admin/applications/page.tsx

Not sure if you either wanted to move ApplicationStatus to a shared types file and import it... or use the union type here too like this: status: "pending" | "approved" | "rejected";

(Not necessary.. up to you)

submitterName: string;
submitterEmail: string;
payload: Record<string, unknown>;
createdAt: string;
updatedAt: string;
}

export default function ApplicationDetail({ params }: { params: { id: string } }) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at this: https://nextjs.org/docs/app/api-reference/functions/use-params

I believe in nextjs 15 params is a Promise for both server and client components.. so if we are doing "use-client" we should import useParams from "next/navigation" and wrap id with useParams...

like this:

import { useParams } from "next/navigation";

export default function ApplicationDetail() {
  const { id } = useParams<{ id: string }>();

***then you would have to replace every params.id to just id (just one instance below)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should verify and look into this if necessary though.. I am a little confused myself which approach should be taken

const [app, setApp] = useState<Application | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [actioning, setActioning] = useState<"approved" | "rejected" | null>(null);
const [actionError, setActionError] = useState<string | null>(null);

async function handleAction(status: "approved" | "rejected") {
setActioning(status);
setActionError(null);
try {
const res = await fetch(`/api/admin/applications/${params.id}`, {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going off of the above comment about Futures.. if you go with the approach I mentioned above... this should be id not params.is

method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status }),
});
if (!res.ok) { const b = await res.json(); throw new Error(b.error ?? "Failed to update"); }
const { data } = await res.json();
setApp(data);
} catch (err: any) {
setActionError(err.message);
} finally {
setActioning(null);
}
}

useEffect(() => {
Expand Down Expand Up @@ -61,15 +83,14 @@ export default async function ApplicationDetail({ params }: Props) {
if (!app) return null;

return (
<div className="p-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-semibold">Application: {app.name}</h1>
<div className="flex items-center gap-4">
<ApproveRejectButtons id={app.id} />
<Link href="/admin/applications" className="text-blue-600 hover:underline">
Back
</Link>
<PageShell>
{/* Header */}
<div className="flex items-start justify-between mb-8">
<div>
<h1 className="text-2xl font-semibold text-gray-900">{app.submitterName}</h1>
<p className="text-sm text-gray-500 mt-1">{app.submitterEmail}</p>
</div>
<BackLink />
</div>

<div className="bg-white border border-gray-200 rounded-lg shadow-sm mb-6">
Expand Down
3 changes: 2 additions & 1 deletion app/api/admin/applications/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to import NextRequest, auth, Role, Prisma... complete block something like this:

import { NextRequest, NextResponse } from "next/server";
import { Role, Prisma } from "@/generated/prisma/client";
import { prisma } from "@/lib/prisma";
import { auth } from "@/auth";

import { prisma } from "@/lib/prisma";

export async function GET() {
export async function GET(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.email) {
Expand Down Expand Up @@ -43,6 +43,7 @@ export async function GET() {
});

return NextResponse.json({ data: applications }, { status: 200 });

} catch (err) {
console.error(err);
return NextResponse.json(
Expand Down