Thank you both. My problem was the way I was architecting it. The form on the button using <form action="/api/invite" method="post"> just wasn't working for god know why.
So I said screw it, moved the trigger to a button like so <button onClick={handleSubmit}>Submit</button> and my handleSubmit function looks like
const handleSubmit = useCallback(async () => {
try {
const response = await fetch("/api/invite", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(fields),
})
switch (response.status) {
case 200: {
location.reload()
break
}
case 403: {
const duplicate = await response.text()
console.error("Error submitting form on duplicate", duplicate)
setError(true)
break
}
default: {
throw new Error("Failed to submit form")
}
}
} catch (e) {
setError(true)
console.error("Error submitting form:", e)
}
}, [fields])
After the reload, the modal closes, and the page reloads triggering the handle method on the original page, which triggers a fetch on the server-side for a rendered page which checks the database.
If this was client-side rendered I wouldn't have to make so many calls to the database, but oh well