ZeroToShip

Docs/Tutorial

// tutorial

Creare una pagina privata

In ZeroToShip tutto quello che sta sotto /app/dashboard/ è già protetto. Non devi controllare l'auth in ogni pagina: lo fa il layout una volta sola.

1. Il layout protetto

Dentro app/dashboard/layout.tsx c'è un server component che chiama supabase.auth.getUser(). Se non c'è utente, redirect al login:

app/dashboard/layout.tsx
tsx
import { redirect } from "next/navigation";
import { createClient } from "@/libs/supabase/server";
import config from "@/config";

export default async function LayoutPrivate({ children }) {
  const supabase = await createClient();
  const { data: { user } } = await supabase.auth.getUser();

  if (!user) redirect(config.auth.loginUrl);

  return <>{children}</>;
}

config.auth.loginUrl è definito in config.ts (default: /signin).

2. Aggiungi una nuova pagina

Crea una cartella dentro /app/dashboard/. Il file page.tsx è già protetto: il layout gira prima della pagina.

app/dashboard/impostazioni/page.tsx
tsx
export const dynamic = "force-dynamic";

export default async function Impostazioni() {
  return (
    <main className="p-8">
      <h1>Impostazioni</h1>
      <p>Solo utenti loggati vedono questa pagina.</p>
    </main>
  );
}

dynamic = "force-dynamic" ci serve perché la pagina dipende dai cookie dell'utente e Next non deve provare a pre-renderizzarla staticamente.

3. Leggi i dati dell'utente

Dato che è server component, hai accesso diretto al client server di Supabase. Recuperi l'utente e — se vuoi — leggi il suo profilo dal database:

app/dashboard/impostazioni/page.tsx
tsx
import { createClient } from "@/libs/supabase/server";

export default async function Impostazioni() {
  const supabase = await createClient();
  const { data: { user } } = await supabase.auth.getUser();

  const { data: profile } = await supabase
    .from("profiles")
    .select("*")
    .eq("id", user.id)
    .single();

  return (
    <main className="p-8">
      <h1>Ciao {user.email}</h1>
      <p>Accesso: {profile?.has_access ? "attivo" : "non attivo"}</p>
    </main>
  );
}

4. Sezione privata parallela

Se vuoi un'altra sezione protetta fuori da /dashboard (es. /admin), copia lo stesso pattern: crea app/admin/layout.tsx con il check getUser() + redirect() e ci sei. Vuoi anche un check di ruolo? Leggi profile.role dal DB nel layout e redirect se non è admin.