Made some small requests changes

This commit is contained in:
Tim Howitz 2025-06-01 14:30:18 +01:00
parent 74ed7bd50a
commit 13d36012a8
2 changed files with 213 additions and 247 deletions

View File

@ -17,7 +17,7 @@ export async function GET() {
} }
} }
export async function PUT(req: NextRequest) { export async function POST(req: NextRequest) {
try { try {
const { id, outcome } = await req.json(); const { id, outcome } = await req.json();
if (!["FULFILLED", "REJECTED"].includes(outcome)) { if (!["FULFILLED", "REJECTED"].includes(outcome)) {

View File

@ -1,4 +1,5 @@
"use client"; "use client";
import axios from "axios";
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { useStoreState } from "@hooks/store"; import { useStoreState } from "@hooks/store";
@ -64,16 +65,13 @@ export default function RequestManagementPage() {
useEffect(() => { useEffect(() => {
setLoading(true); setLoading(true);
setError(null); setError(null);
fetch("/api/requests") axios
.get("/api/requests")
.then((res) => { .then((res) => {
if (!res.ok) throw new Error("Failed to fetch requests"); setRequests(res.data.requests || []);
return res.json();
})
.then((data) => {
setRequests(data.requests || []);
setLoading(false); setLoading(false);
}) })
.catch((err) => { .catch(() => {
setError("Failed to load requests."); setError("Failed to load requests.");
setLoading(false); setLoading(false);
}); });
@ -81,43 +79,23 @@ export default function RequestManagementPage() {
// Filtering for non-admins to only their requests // Filtering for non-admins to only their requests
const filteredRequests = React.useMemo( const filteredRequests = React.useMemo(
() => () => (isAdmin ? requests : requests.filter((r) => r.requestingUser.id === userId)),
isAdmin
? requests
: requests.filter((r) => r.requestingUser.id === userId),
[isAdmin, requests, userId] [isAdmin, requests, userId]
); );
// Sorted: newest first // Sorted: newest first
filteredRequests.sort((a, b) => filteredRequests.sort((a, b) => (b.createdAt ?? "").localeCompare(a.createdAt ?? ""));
(b.createdAt ?? "").localeCompare(a.createdAt ?? "")
);
async function handleAction( async function handleAction(requestId: number, action: "FULFILLED" | "REJECTED") {
requestId: number,
action: "FULFILLED" | "REJECTED"
) {
setActionLoading(requestId); setActionLoading(requestId);
setActionError(null); setActionError(null);
setActionSuccess(null); setActionSuccess(null);
try { try {
const res = await fetch("/api/requests", { const res = await axios.post("/api/requests", { id: requestId, outcome: action });
method: "PUT", setRequests((prev) => prev.map((r) => (r.id === requestId ? { ...r, outcome: action } : r)));
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: requestId, outcome: action }),
});
if (!res.ok) {
const data = await res.json().catch(() => ({}));
throw new Error(data?.error || "Failed to update request");
}
setRequests((prev) =>
prev.map((r) =>
r.id === requestId ? { ...r, outcome: action } : r
)
);
setActionSuccess("Request updated."); setActionSuccess("Request updated.");
} catch (err: any) { } catch (err: any) {
setActionError(err?.message || "Failed to update request"); setActionError(err.response?.data?.error || "Failed to update request");
} finally { } finally {
setActionLoading(null); setActionLoading(null);
} }
@ -136,9 +114,7 @@ export default function RequestManagementPage() {
return ( return (
<div className="max-w-5xl mx-auto py-10 px-4"> <div className="max-w-5xl mx-auto py-10 px-4">
<div className="mb-8"> <div className="mb-8">
<h1 className="text-2xl font-bold"> <h1 className="text-2xl font-bold">{isAdmin ? "All Requests" : "My Requests"}</h1>
{isAdmin ? "All Requests" : "My Requests"}
</h1>
<p className="text-gray-600 mt-2"> <p className="text-gray-600 mt-2">
View {isAdmin ? "and manage pending" : "your"} requests related to scientist management. View {isAdmin ? "and manage pending" : "your"} requests related to scientist management.
</p> </p>
@ -149,7 +125,7 @@ export default function RequestManagementPage() {
) : error ? ( ) : error ? (
<div className="text-red-600 text-center py-10">{error}</div> <div className="text-red-600 text-center py-10">{error}</div>
) : ( ) : (
<div className="bg-white rounded-lg shadow p-5 overflow-x-auto"> <div className="bg-white border-neutral-200 border rounded-lg shadow p-5 overflow-x-auto">
<table className="min-w-full text-sm"> <table className="min-w-full text-sm">
<thead> <thead>
<tr className="border-b"> <tr className="border-b">
@ -163,34 +139,26 @@ export default function RequestManagementPage() {
<tbody> <tbody>
{filteredRequests.length === 0 ? ( {filteredRequests.length === 0 ? (
<tr> <tr>
<td <td className="py-12 text-center text-gray-400 font-semibold" colSpan={isAdmin ? 5 : 4}>
className="py-12 text-center text-gray-400 font-semibold"
colSpan={isAdmin ? 5 : 4}
>
No requests found. No requests found.
</td> </td>
</tr> </tr>
) : ( ) : (
filteredRequests.map((req) => ( filteredRequests.map((req) => (
<tr key={req.id} className="border-b last:border-0 hover:bg-neutral-50"> <tr key={req.id} className="border-b last:border-0 hover:bg-neutral-50">
<td className="px-4 py-2 whitespace-nowrap"> <td className="px-4 py-2 whitespace-nowrap">{formatDate(req.createdAt)}</td>
{formatDate(req.createdAt)} <td className="px-4 py-2">{requestTypeLabels[req.requestType] || req.requestType}</td>
</td>
<td className="px-4 py-2">
{requestTypeLabels[req.requestType] || req.requestType}
</td>
<td className="px-4 py-2 whitespace-nowrap"> <td className="px-4 py-2 whitespace-nowrap">
<span className="font-medium">{req.requestingUser.name}</span> <span className="font-medium">{req.requestingUser.name}</span>
<span className="ml-1 text-xs text-gray-500"> <span className="ml-1 text-xs text-gray-500">({req.requestingUser.email})</span>
({req.requestingUser.email})
</span>
</td> </td>
<td className="px-4 py-2"> <td className="px-4 py-2">
<span className={ <span
className={
"inline-block px-2 py-1 rounded-xl text-xs font-semibold " + "inline-block px-2 py-1 rounded-xl text-xs font-semibold " +
(outcomeColors[req.outcome] || (outcomeColors[req.outcome] || "bg-gray-100 text-gray-600")
"bg-gray-100 text-gray-600") }
}> >
{req.outcome.replace(/_/g, " ")} {req.outcome.replace(/_/g, " ")}
</span> </span>
</td> </td>
@ -222,10 +190,8 @@ export default function RequestManagementPage() {
) : ( ) : (
<span className="text-xs text-gray-400">No actions</span> <span className="text-xs text-gray-400">No actions</span>
)} )}
{(actionError && actionLoading === req.id) && ( {actionError && actionLoading === req.id && <div className="text-xs text-red-600">{actionError}</div>}
<div className="text-xs text-red-600">{actionError}</div> {actionSuccess && actionLoading === req.id && (
)}
{(actionSuccess && actionLoading === req.id) && (
<div className="text-xs text-green-600">{actionSuccess}</div> <div className="text-xs text-green-600">{actionSuccess}</div>
)} )}
</td> </td>