Saltar al contenido principal

Toast

1. Toast

src\components\ui\toast\index.ts
// class Toast {}

2. Op. Persist Toast

  • Permite definir un toast antes de navegar a otra página
  • Ej. Al agregar un producto, se actualiza correctamente, pero si redirige a otra página el toast normal no se muestra durante el tiempo definido, entonces con el persistente se muestra en la otra página, después de navegar

1. Wrapper

src\components\ui\toast\persist-toast.ts
import type { ToastOptions, ToastType } from "@/components/ui/toast";
import { toast } from "@/components/ui/toast";

const STORAGE_KEY = "persisted_toast";

interface PersistedToast {
  message: string;
  type: ToastType;
  options: ToastOptions;
}

export const persistToast = {
  show(
    message: string,
    type: ToastType = "default",
    options: ToastOptions = {}
  ): void {
    const data: PersistedToast = { message, type, options };
    sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
  },

  checkAndShow(): void {
    const persisted = sessionStorage.getItem(STORAGE_KEY);

    if (persisted) {
      const { message, type, options } = JSON.parse(
        persisted
      ) as PersistedToast;

      toast.show(message, type, options);
      sessionStorage.removeItem(STORAGE_KEY);
    }
  },
};

2. Inicializar

  • Inicializar en el archivo principal, como MainLayout.astro o scripts.ts
src\layouts\Layout.astro
<html>
</html>

<script>
  import { persistToast } from "@/components/ui/toast/persist-toast";

  document.addEventListener("DOMContentLoaded", () => {
    persistToast.checkAndShow();
  });
</script>

3. Uso

src\pages\unit\edit[unitId].astro
<MainLayout title="Edit Unit">
</MainLayout>

<script>
  import { toast } from "@/components/ui/toast";
  import { persistToast } from "@/components/ui/toast/persist-toast";
  import { ActionInputError, actions } from "astro:actions";

  const form = document.querySelector("form") as HTMLFormElement;
  const btnSubmit = document.getElementById("btn-submit") as HTMLButtonElement;

  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    btnSubmit.setAttribute("disabled", "disabled");
    // Guardar referencia del Loading Toast
    const loadingToast = toast.loading("Guardando...");

    const formData = new FormData(form);
    const { error } = await actions.updateUnit(formData);

    // Cerrar Loading Toast
    loadingToast.dismiss();
   
    if (error) {
      const errorMessage =
        error instanceof ActionInputError
          ? Object.entries(error.fields)
              .map(([field, messages]) => `${field}: ${messages?.join(", ")}`)
              .join("\n")
          : error.message;

      // Toast
      toast.error(errorMessage);
      btnSubmit.removeAttribute("disabled");
      return;
    }

    // Toast con persistencia entre páginas
    persistToast.show("Unidad actualizada correctamente", "success");
    const courseId = form.getAttribute("data-courseId");
    window.location.replace(`/course/${courseId}`);
  });
</script>
src\pages\lessons[unitId].astro
<MainLayout title="Lessons">
</MainLayout>

<script>
  import { toast } from "@/components/ui/toast";
  import { actions } from "astro:actions";

  // Delete register and row
  const btnDelete = document.querySelectorAll(".btn-delete");
  btnDelete.forEach((btn) => {
    btn.addEventListener("click", async (e) => {
      const id = btn.getAttribute("data-id");
      if (!id) return;

      // Confirm Toast
      const confirmDelete = await toast.confirm(
        "¿Estás seguro de eliminar esta lección?"
      );
      if (!confirmDelete) return;

      const { error } = await actions.deleteLesson(+id);
      if (error) {
        toast.error(error.message);
        return;
      }

      document.getElementById(id.toString())?.remove();
      toast.default("Lección eliminada correctamente");
    });
  });
</script>