#Best Practice

53 messages · Page 1 of 1 (latest)

warm basin
#

I am in the current Page of an Item, there is a delete option to delete currentTask, but how can I do it so no errors come up that they were unable to fetch task with id = ".." since that task would have been deleted.

drowsy quiverBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

warm basin
#

Single Task Page: ```import { getTaskById } from "@/services/taskServices";
import TaskEditIcon from "../_components/TaskEditIcon";
import TaskDeleteIcon from "../_components/TaskDeleteIcon";

const SingleTaskPage = async ({ params }: { params: { id: number } }) => {
const task = await getTaskById(Number(params.id));
if (!task) return;
return (
<div>
<h1>Title: {task?.title}</h1>
<h1>Description: {task?.description}</h1>
<h1>
Updated At:{" "}
{task?.updatedAt?.toLocaleDateString() !== null
? task?.updatedAt?.toLocaleDateString()
: task?.createdAt?.toLocaleDateString()}
</h1>
<TaskEditIcon task={task} />
<TaskDeleteIcon taskId={params.id} />
</div>
);
};

export default SingleTaskPage;

#

TaskDeleteIcon: ```"use client";
import { GiTrashCan } from "react-icons/gi";
import { deleteTask } from "../action";

import { toast } from "sonner";
import { useTransition } from "react";
import { usePathname, useRouter } from "next/navigation";
const TaskDeleteIcon = ({ taskId }: { taskId: number }) => {
const [isPending, startTransition] = useTransition();
const pathName = usePathname();
const router = useRouter();
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

startTransition(() => {
  deleteTask(Number(taskId)).then((data) => {
    router.replace("/tasks");
    if (data?.error) {
      toast.error(data.error);
    }
    if (data?.success) {
      toast.success(data.success);
    }
  });
});

};
return (
<form onSubmit={onSubmit}>
<button type="submit" disabled={isPending}>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</button>
</form>
);
};

export default TaskDeleteIcon;

#

Action: ```
export const deleteTask = async (id: number) => {
const user = await currentUser();
const task = await db.task.findUnique({ where: { id } });
if (user?.id != task?.creatorId)
return { error: "You cannot delete tasks for others." };

await db.task.delete({ where: { id } });
revalidatePath("/tasks");
return { success: "Task deleted successfully" };
};```

opal folio
opal folio
# warm basin Action: ``` export const deleteTask = async (id: number) => { const user = awa...
export const deleteTask = async (id: number) => {
  const user = await currentUser();
  const task = await db.task.findUnique({ where: { id } });
  if (!task) {
    return { error: "Task doesn't exist" }
  }
  if (user?.id != task?.creatorId)
    return { error: "You cannot delete tasks for others." };

  await db.task.delete({ where: { id } });
  revalidatePath("/tasks");
  return { success: "Task deleted successfully" };
};
warm basin
#

error thrown in the console since it couldnt fetch a deleted task since it wouldn't exist after deletion:

#

getTaskById: ```export const getTaskById = async (id: number) => {
const user = await currentUser();
try {
const task = await db.task.findFirst({
where: {
id,
},
});
if (task?.creatorId !== user?.id)
throw new Error("You cannot fetch other people's tasks.");
return task;
} catch (error) {
throw new Error("Failed to fetch task");
}
};

opal folio
warm basin
#

if you notice I tried rerouiting inside TaskDeleteIcon but I think there is more efficent way

opal folio
#

findFirst return null if it is not exist

#

and you have this line

if (task?.creatorId !== user?.id)
      throw new Error("You cannot fetch other people's tasks.");
#

add this line if (!task) return null

warm basin
opal folio
#

it also return null if not exist

warm basin
#

yep working now, what do you think of this, should I redirect in the delete function instead of in the TaskDeleteIcon?

warm basin
opal folio
#

I don't think you need this

#

if the task is not exist, that button will not show right?

warm basin
#

right

#

the button is rendered as part of the task, every task has a button

opal folio
#

yes so there is no need for redirect

warm basin
#

so I remove the router.replace insdie the TaskDeleteIcon?

warm basin
#

now if I delete, not found page shows up tho

opal folio
#

what do you mean?

warm basin
#

this is the task page

opal folio
warm basin
#

if i click delete, the task is no longer there, so the route is technically not found

opal folio
#
export const deleteTask = async (id: number) => {
  const user = await currentUser();
  const task = await db.task.findUnique({ where: { id } });
  if (!task) {
    return { error: "Task doesn't exist" }
  }
  if (user?.id != task?.creatorId)
    return { error: "You cannot delete tasks for others." };

  await db.task.delete({ where: { id } });
  revalidatePath("/tasks");
  redirect('/tash');
};
#
"use client";
import { GiTrashCan } from "react-icons/gi";
import { deleteTask } from "../action";

import { toast } from "sonner";
import { useTransition } from "react";
import { usePathname, useRouter } from "next/navigation";
const TaskDeleteIcon = ({ taskId }: { taskId: number }) => {
  const [isPending, startTransition] = useTransition();
  const pathName = usePathname();
  const router = useRouter();
  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    startTransition(() => {
      deleteTask(Number(taskId)).then((data) => {
        if (data?.error) {
          toast.error(data.error);
        }
        if (data?.success) {
          toast.success("Task deleted successfully");
        }
      });
    });
  };
  return (
    <form onSubmit={onSubmit}>
      <button type="submit" disabled={isPending}>
        <GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
      </button>
    </form>
  );
};

export default TaskDeleteIcon;
warm basin
opal folio
#

it will handle it in one request and response

warm basin
#

so no redundant redirects will take place, if I delete from the /tasks page

warm basin
#

if i redirect there, I cannot return success

#

I need the success message for my toaster

warm basin
#

I was thinking to add this in my TaskDeleteIcon: const pathName = ... if(pathName == `tasks/${taskId}`) router.replace("/tasks");

#

so it only redirects if the user was initially on the tasks/id page

opal folio
#

its up to you but I would use redirect with server action

warm basin
#

and will only delete and not redirect if the user on the /tasks pafe

opal folio
#

because router.replace() will make an extra request

#

you could check the network tab on browser dev tools

warm basin
#

oh okay

#

do I make my success message static for my toaster then?

warm basin
#

perfect, thanks mate.