Replies: 1 comment
-
With the help of Rarity on Discord, I was able to solve this. It turns out that the Mantine modals being set up with
export async function clientLoader({ params }: Route.ClientLoaderArgs) {
const res = await fetch(`/api/posts/${params.postId}`);
const post = (await res.json()) as Post;
return post;
}
export async function clientAction({
request,
params,
}: Route.ClientActionArgs) {
const data = await request.formData();
const id = params.postId;
const intent = data.get("intent");
// Prevent intent being passed to backend as field to update
data.delete("intent");
if (intent === "edit") {
return await fetch(`/api/posts/${id}/edit`, {
method: "POST",
body: data,
});
} else if (intent === "delete") {
const confirmation = data.get("confirmation");
if (
typeof confirmation === "string" &&
confirmation.toLowerCase() === "delete"
) {
await fetch(`/api/posts/${id}/delete`, {
method: "POST",
});
return redirect("/");
} else {
return { ok: false, error: "Please confirm deletion" };
}
} else {
throw new Error(`Invalid intent!`);
}
}
export default function ShowPost({ loaderData }: Route.ComponentProps) {
const post = loaderData;
const fetcher = useFetcher();
return (
<fetcher.Form method="post">
<DeletePostButton />
<ActionIcon
type="submit"
name="intent"
value="edit"
>
Submit
</ActionIcon>
{/* --- edit fields --- */}
</fetcher.Form>
);
}
export default function DeletePostButton() {
const fetcher = useFetcher();
const [opened, { open, close }] = useDisclosure(false);
let confirmDeletionError = false;
if (
"error" in fetcher.data &&
(fetcher.data as { ok: boolean; error: string }).error ===
"Please confirm deletion"
) {
confirmDeletionError = true;
}
return (
<>
<Button onClick={open}>
Delete
</Button>
<Modal
opened={opened}
onClose={close}
>
<Text>
Are you sure you want to delete this post?
</Text>
<Text {...(confirmDeletionError ? { c: "red" } : {})}>
To confirm, please type <Code>delete</Code> into the field below.
</Text>
<fetcher.Form method="post">
<PinInput
length={6}
name="confirmation"
/>
<Button
type="submit"
name="intent"
value="delete"
disabled={fetcher.state === "submitting"}
>
Permanently delete this post
</Button>
</fetcher.Form>
</Modal>
</>
);
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm very new to both React and react-router, so apologies if I'm making an obvious mistake.
I'm working on a pretty basic CRUD app that stores posts, using Mantine UI components. The page to edit a post has a form with a submit button to save changes. It does this via a fetcher that calls my API endpoint
/posts/<postId>/edit
:app/routes/posts.$postId_.edit.tsx
This works fine. The issue is that I want to add a second button that calls the endpoint
/posts/<postId>/delete
to delete a post. I've tried to do this by adding avalue
to each button and using that to determine the action to take inclientAction
:app/routes/posts.$postId_.edit.tsx
However, with this approach, the HTML
<form>
that gets rendered inside the modal has the attributeaction="/"
, which of course sends the request to the root route instead of the current route and causes a405 Method Not Allowed
error. The<form>
element with the original edit button, however, works normally, with noaction
attribute set.Of course, I'm able to specifically set the modal form with the delete button to have
action={`/posts/${post.id.toString()}/edit`}
, and that works fine. But this feels a bit too hacky, and I'd like to understand why this is happening in the first place.Is there a better way to do this?
Beta Was this translation helpful? Give feedback.
All reactions