Added requesting new role on profile api route

This commit is contained in:
Tim Howitz 2025-06-01 23:01:37 +01:00
parent 4bca956cbb
commit bc78626a24
3 changed files with 44 additions and 48 deletions

View File

@ -2,20 +2,18 @@ import { NextResponse } from "next/server";
import { prisma } from "@utils/prisma"; import { prisma } from "@utils/prisma";
export async function POST(req: Request) { export async function POST(req: Request) {
try { try {
const { requestType, requestingUserId, scientistId, comment } = await req.json(); const { requestType, requestingUserId, scientistId, comment } = await req.json();
const request = await prisma.request.create({ const request = await prisma.request.create({
data: { data: {
requestType, requestType,
requestingUser: { connect: { id: requestingUserId } }, requestingUser: { connect: { id: requestingUserId } },
outcome: "IN_PROGRESS", outcome: "IN_PROGRESS",
// Optionally you can connect to Scientist via an inline relation if you have a foreign key },
// If the model has comment or details fields, add it! });
}, return NextResponse.json({ request }, { status: 201 });
}); } catch (error) {
return NextResponse.json({ request }, { status: 201 }); console.error("Request create error:", error);
} catch (error) { return NextResponse.json({ error: "Failed to create request" }, { status: 500 });
console.error("Request create error:", error); }
return NextResponse.json({ error: "Failed to create request" }, { status: 500 });
}
} }

View File

@ -13,8 +13,7 @@ export async function POST(req: Request) {
if ("user" in authResult === false) return authResult; if ("user" in authResult === false) return authResult;
const { user } = authResult; const { user } = authResult;
// todo handle requestedRole const { userId, email, name, password, requestedRole } = await req.json();
const { userId, email, name, password } = await req.json();
// Trying to update a different user than themselves // Trying to update a different user than themselves
// Only available to admins // Only available to admins
@ -58,6 +57,12 @@ export async function POST(req: Request) {
passwordHash = await bcryptjs.hash(password, 10); passwordHash = await bcryptjs.hash(password, 10);
} }
if (requestedRole && ["GUEST", "SCIENTIST", "ADMIN"].includes(requestedRole) && requestedRole !== user.role) {
await prisma.request.create({
data: { requestType: requestedRole, requestingUserId: userId || user.id },
});
}
const updatedUser = await prisma.user.update({ const updatedUser = await prisma.user.update({
where: { id: userId || user.id }, where: { id: userId || user.id },
data: { data: {

View File

@ -11,28 +11,6 @@ import EarthquakeSearchModal from "@components/EarthquakeSearchModal";
import EarthquakeLogModal from "@components/EarthquakeLogModal"; // If you use a separate log modal import EarthquakeLogModal from "@components/EarthquakeLogModal"; // If you use a separate log modal
import { useStoreState } from "@hooks/store"; import { useStoreState } from "@hooks/store";
// Optional: "No Access Modal" - as in your original
function NoAccessModal({ open, onClose }) {
if (!open) return null;
return (
<div className="fixed z-50 inset-0 bg-black/40 flex items-center justify-center">
<div className="bg-white rounded-lg shadow-lg p-8 max-w-xs w-full text-center relative">
<button onClick={onClose} className="absolute right-4 top-4 text-gray-500 hover:text-black text-lg" aria-label="Close">
&times;
</button>
<h2 className="font-bold text-xl mb-4">Access Denied</h2>
<p className="text-gray-600 mb-3">
Sorry, you do not have access rights to Log an Earthquake. Please Log in here, or contact an Admin if you believe this
is a mistake
</p>
<button onClick={onClose} className="bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700 mt-2">
OK
</button>
</div>
</div>
);
}
export default function Earthquakes() { export default function Earthquakes() {
const [selectedEventId, setSelectedEventId] = useState(""); const [selectedEventId, setSelectedEventId] = useState("");
const [hoveredEventId, setHoveredEventId] = useState(""); const [hoveredEventId, setHoveredEventId] = useState("");
@ -40,12 +18,9 @@ export default function Earthquakes() {
const [logModalOpen, setLogModalOpen] = useState(false); const [logModalOpen, setLogModalOpen] = useState(false);
const [noAccessModalOpen, setNoAccessModalOpen] = useState(false); const [noAccessModalOpen, setNoAccessModalOpen] = useState(false);
// Your user/role logic
const user = useStoreState((state) => state.user); const user = useStoreState((state) => state.user);
const role: "GUEST" | "SCIENTIST" | "ADMIN" = user?.role ?? "GUEST"; const canLogEarthquake = user?.role === "SCIENTIST" || user?.role === "ADMIN";
const canLogEarthquake = role === "SCIENTIST" || role === "ADMIN";
// Fetch earthquakes (10 days recent)
const { data, error, isLoading, mutate } = useSWR("/api/earthquakes", createPoster({ rangeDaysPrev: 10 })); const { data, error, isLoading, mutate } = useSWR("/api/earthquakes", createPoster({ rangeDaysPrev: 10 }));
// Shape for Map/Sidebar // Shape for Map/Sidebar
@ -80,6 +55,27 @@ export default function Earthquakes() {
} }
}; };
function NoAccessModal({ open, onClose }: { open: typeof noAccessModalOpen; onClose: () => void }) {
if (!open) return null;
return (
<div className="fixed z-50 inset-0 bg-black/40 flex items-center justify-center">
<div className="bg-white rounded-lg shadow-lg p-8 max-w-xs w-full text-center relative">
<button onClick={onClose} className="absolute right-4 top-4 text-gray-500 hover:text-black text-lg" aria-label="Close">
&times;
</button>
<h2 className="font-bold text-xl mb-4">Access Denied</h2>
<p className="text-gray-600 mb-3">
Sorry, you do not have access rights to Log an Earthquake. Please Log in here, or contact an Admin if you believe this
is a mistake
</p>
<button onClick={onClose} className="bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700 mt-2">
OK
</button>
</div>
</div>
);
}
return ( return (
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden"> <div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
<div className="flex-grow h-full"> <div className="flex-grow h-full">
@ -107,15 +103,12 @@ export default function Earthquakes() {
onButton2Click={() => setSearchModalOpen(true)} onButton2Click={() => setSearchModalOpen(true)}
button1Disabled={!canLogEarthquake} button1Disabled={!canLogEarthquake}
/> />
{/* ---- SEARCH MODAL ---- */}
<EarthquakeSearchModal <EarthquakeSearchModal
open={searchModalOpen} open={searchModalOpen}
onClose={() => setSearchModalOpen(false)} onClose={() => setSearchModalOpen(false)}
onSelect={(eq) => setSelectedEventId(eq.code)} onSelect={(eq) => setSelectedEventId(eq.code)}
/> />
{/* ---- LOGGING MODAL ---- */}
<EarthquakeLogModal open={logModalOpen} onClose={() => setLogModalOpen(false)} onSuccess={() => mutate()} /> <EarthquakeLogModal open={logModalOpen} onClose={() => setLogModalOpen(false)} onSuccess={() => mutate()} />
{/* ---- NO ACCESS ---- */}
<NoAccessModal open={noAccessModalOpen} onClose={() => setNoAccessModalOpen(false)} /> <NoAccessModal open={noAccessModalOpen} onClose={() => setNoAccessModalOpen(false)} />
</div> </div>
); );