I'm building a book management application using Next.js. I have a form that collects book details and submits them using an asynchronous function (onSubmit). The form data is sent to an action.ts
file where it is validated and inserted into a Supabase database. After a successful submission, I want to redirect the user to an edit page while passing the ISBN
of the newly submitted book in the URL.
//submitting the forms
async function onSubmit(data: BookInferSchema) {
try {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(
key,
value instanceof Date ? value.toISOString() : value.toString()
);
});
//sending the formData to the action.ts for submitting the forms
const response = action(formData) as {
error?: string;
message?: string;
} | void;
//Error or success messages for any submissions and any errors/success from the server
if (response?.error) {
toast({
title: "Error",
description: `An error occurred: ${response.error}`,
});
} else {
//after submitting the form, reset the form
// form.reset();
}
} catch {
toast({
title: "Error",
description: "An unexpected error occured.",
});
}
}
And here’s a snippet of my action.ts
where I validate and insert the book into the database:
const validatedFields = BookSchema.safeParse({
ISBN: formData.get("ISBN"),
//...other fields
});
if (!validatedFields.success) {
console.error("Validation Errors:", validatedFields.error.format());
return {
errors: validatedFields.error.flatten().fieldErrors,
};
}
const { ISBN } = validatedFields.data;
const supabase = createClient();
const { data, error } = await (await supabase)
.from('books')
.insert({
isbn: ISBN,
// ... other fields
});
if (error) {
return {
error: true,
message: error.message,
};
}
return {
error: false,
message: 'Book updated successfully',
};
What I tried:
I tried returning the ISBN:
const successMessage = {
error: false,
message: "Book updated successfully",
ISBN,
};
return successMessage;
and use it here inside a !response?.error
and it would just show as undefined when checking for the value of the response
.
2nd try:
I put this code in the action.ts
after submissions:
// Perform the redirect after returning the success message
redirect(`/admin/books/${ISBN}/edit`);
But it would show this an application error, and this is what the console would redirect me with:
This is the edit book page link: /admin/books/${id}/edit
:
I am sure that I can access this page as I am also handling a redirect page for viewing each book.
const BookEdit = async (props: { params: Promise<{ id: string }> }) => {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return redirect("/login");
}
const params = await props.params;
const id = params.id;
const books = await fetchAllBooks(id);
const bookData = books ? books[0] : null;
return <h1>Edit Book {JSON.stringify(bookData, null, 2)}</h1>;
};
export default BookEdit;
3rd try: This worked, however, which is a better approach? should I put it inside the useEffect
or just leave it ouside?
useEffect(() => {
if (state?.message) {
toast({
title: state?.error ? "Error" : "Success",
description: state?.message,
});
}
}, [state]);
if (state?.id) {
router.push(`/admin/books/${state.id}/edit`);
}
I'm building a book management application using Next.js. I have a form that collects book details and submits them using an asynchronous function (onSubmit). The form data is sent to an action.ts
file where it is validated and inserted into a Supabase database. After a successful submission, I want to redirect the user to an edit page while passing the ISBN
of the newly submitted book in the URL.
//submitting the forms
async function onSubmit(data: BookInferSchema) {
try {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(
key,
value instanceof Date ? value.toISOString() : value.toString()
);
});
//sending the formData to the action.ts for submitting the forms
const response = action(formData) as {
error?: string;
message?: string;
} | void;
//Error or success messages for any submissions and any errors/success from the server
if (response?.error) {
toast({
title: "Error",
description: `An error occurred: ${response.error}`,
});
} else {
//after submitting the form, reset the form
// form.reset();
}
} catch {
toast({
title: "Error",
description: "An unexpected error occured.",
});
}
}
And here’s a snippet of my action.ts
where I validate and insert the book into the database:
const validatedFields = BookSchema.safeParse({
ISBN: formData.get("ISBN"),
//...other fields
});
if (!validatedFields.success) {
console.error("Validation Errors:", validatedFields.error.format());
return {
errors: validatedFields.error.flatten().fieldErrors,
};
}
const { ISBN } = validatedFields.data;
const supabase = createClient();
const { data, error } = await (await supabase)
.from('books')
.insert({
isbn: ISBN,
// ... other fields
});
if (error) {
return {
error: true,
message: error.message,
};
}
return {
error: false,
message: 'Book updated successfully',
};
What I tried:
I tried returning the ISBN:
const successMessage = {
error: false,
message: "Book updated successfully",
ISBN,
};
return successMessage;
and use it here inside a !response?.error
and it would just show as undefined when checking for the value of the response
.
2nd try:
I put this code in the action.ts
after submissions:
// Perform the redirect after returning the success message
redirect(`/admin/books/${ISBN}/edit`);
But it would show this an application error, and this is what the console would redirect me with: https://nextjs./docs/messages/sync-dynamic-apis
This is the edit book page link: /admin/books/${id}/edit
:
I am sure that I can access this page as I am also handling a redirect page for viewing each book.
const BookEdit = async (props: { params: Promise<{ id: string }> }) => {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return redirect("/login");
}
const params = await props.params;
const id = params.id;
const books = await fetchAllBooks(id);
const bookData = books ? books[0] : null;
return <h1>Edit Book {JSON.stringify(bookData, null, 2)}</h1>;
};
export default BookEdit;
3rd try: This worked, however, which is a better approach? should I put it inside the useEffect
or just leave it ouside?
useEffect(() => {
if (state?.message) {
toast({
title: state?.error ? "Error" : "Success",
description: state?.message,
});
}
}, [state]);
if (state?.id) {
router.push(`/admin/books/${state.id}/edit`);
}
Share
Improve this question
edited Mar 15 at 5:56
JS3
asked Mar 15 at 4:33
JS3JS3
1,8694 gold badges34 silver badges83 bronze badges
1
- i would begin by doing a bit more research on your first attempt. Surely there's a reason whatever process you are returning to is ignoring the extra property you set. – Kevin B Commented Mar 15 at 4:42
1 Answer
Reset to default 0In your action.ts
file, try selecting data from supabase after .insert()
const { ISBN } = validatedFields.data;
const supabase = createClient();
const { data, error } = await supabase
.from('books')
.insert({ isbn: ISBN })
.select()
if (error) {
return {
error: true,
message: error.message
};
}
return {
error: false,
message: 'Book updated successfully',
data
};
Supabase Docs : Here
You can then use useRouter
(If Client Component) or redirect
from next/navigation
and route the user to the edit
page by getting data from response.
Next.Js Routing Docs: Here