← Tilbake til oversikten

Next.js + React + Supabase

Først lager dere en enkel Next-app med Header/Footer. Deretter bygger dere en liten, artig mini-app med Supabase: Kudos-vegg (korte, snille meldinger + emoji).

Trinn 1 — Installer (...dersom du ikke har gjort det)

  • 1.1Installer Node LTS fra nodejs.org.
  • 1.2Lag en tom mappe på skrivebordet (f.eks. web-prosjekter) og dra mappen inn i VS Code.
  • 1.3Åpne terminalen i VS Code: Ctrl + ` (backtick).
  • 1.4Test installasjonen:
node -v
npm -v

Hvis du får versjonsnumre (f.eks. v20.x og 10.x), er alt klart.

Trinn 2 — Opprett nytt Next.js-prosjekt

  • 2.1Med mappen fra 1.2 åpen i VS Code-terminalen, skriv:
npx create-next-app my-first-app

Du kan bruke eget navn, men kun små bokstaver (f.eks. npx create-next-app my-first-project).

  • 2.2Velg disse svarene for enklest mulig start:
✔ Would you like to use TypeScript?        No
✔ Would you like to use ESLint?            Yes
✔ Would you like to use Tailwind CSS?      No (kan være Yes hvis du vil)
✔ Would you like to use `src/` directory?  No
✔ Would you like to use App Router?        Yes
✔ Would you like to customize import alias? No
  • 2.3Gå inn i prosjektmappen og start dev-serveren:
cd my-first-app
npm run dev

Åpne http://localhost:3000 – du skal se Next.js sin velkomstside (React kjører 🎉).

OBS: Hvis dette ikke fungerer, står du sannsynligvis i feil mappe når du kjører npm run dev.

Trinn 3 — Lag egne komponenter

Lag en ny mappe components inni prosjektet ditt. Opprett Header.js og Footer.js inni denne mappen.

A) Header.js

Kopier koden under inn i filen og lagre filen.

export default function Header() {
  return (
    <header style={{ background: "#000", color: "#fff", padding: "12px 0" }}>
      <div style={{ maxWidth: "1024px", margin: "0 auto", padding: "0 16px" }}>
        Ditt React-prosjekt
      </div>
    </header>
  );
}
B) Footer.js
export default function Footer() {
  return (
    <footer style={{ background: "#000", color: "#fff", padding: "12px 0", textAlign: "center" }}>
      © 2025 – Mitt andre React-prosjekt
    </footer>
  );
}
C) Bruk komponentene i app/layout.js

Erstatt all koden i filen med koden under:

import "./globals.css";
import Header from "../components/Header";
import Footer from "../components/Footer";

export const metadata = {
  title: "Mitt andre React-prosjekt",
  description: "Next.js + React - test",
};

export default function RootLayout({ children }) {
  return (
    <html lang="no">
      <body>
        <Header />
        <main style={{ background: "#fff", minHeight: "90vh", padding: "24px 0", color: "#111" }}>
          {children}
        </main>
        <Footer />
      </body>
    </html>
  );
}
D) Oppdater app/page.js

Erstatt all koden i filen med koden under:

export default function Home() {
  return (
    <section style={{ maxWidth: "1024px", margin: "0 auto", padding: "0 16px" }}>
      <h1>Velkommen til ditt første React-prosjekt</h1>
      <p>Dette er startsiden i Next.js (React).</p>
    </section>
  );
}
Kjør igjen: npm run dev → åpne localhost:3000. Du skal nå se svart header, hvit body og svart footer.

Trinn 4 — Endre globals.css

Next.js-prosjektet har en fil som heter globals.css i app/-mappen. Dette er global styling som gjelder for hele appen.

A) Åpne filen

Åpne: app/globals.css

B) Slett alt og lim inn dette:
/* Nullstill margin/padding */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Sett base-font */
body {
  font-family: Arial, Helvetica, sans-serif;
  background-color: #f7f7f7;
  color: #111;
  line-height: 1.5;
}

/* Overskrifter */
h1, h2, h3 {
  font-weight: 600;
  margin-bottom: 12px;
}

/* Standard spacing for seksjoner */
section {
  margin-bottom: 32px;
}

Når du lagrer filen, vil siden oppdatere automatisk (hot reload).

Trinn 7 — Supabase mini-app: Kudos-vegg (enkelt og artig)

Mål: Lag en side i Next som lar elevene sende en kort, hyggelig melding + emoji (kudos). Meldingen lagres i Supabase og vises som en liste.

Tips til klasse-regler: maks 80 tegn, kun snille meldinger, ingen navn om dere vil holde det anonymt.

7ALag tabell i Supabase

I Supabase → Table editor eller SQL editor.

create table if not exists public.kudos (
  id uuid primary key default gen_random_uuid(),
  message text not null,
  emoji text not null default '⭐',
  created_at timestamp with time zone not null default now()
);

7BInstaller Supabase i prosjektet

npm i @supabase/supabase-js

7CLegg inn env-variabler

Lag .env.local i prosjektrota (samme nivå som package.json).

NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...

Etterpå: stopp og start dev-serveren på nytt (Ctrl + C, så npm run dev).

7DLag Supabase-klient

Lag fil: lib/supabaseClient.js

import { createClient } from "@supabase/supabase-js";

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
);

7ELag siden: app/kudos/page.js

Dette er en client component (state + knappetrykk).

"use client";

import { useEffect, useState } from "react";
import { supabase } from "../../lib/supabaseClient";

export default function KudosPage() {
  const [message, setMessage] = useState("");
  const [emoji, setEmoji] = useState("⭐");
  const [items, setItems] = useState([]);
  const [status, setStatus] = useState("");

  async function fetchKudos() {
    const { data, error } = await supabase
      .from("kudos")
      .select("*")
      .order("created_at", { ascending: false })
      .limit(30);

    if (error) setStatus("Kunne ikke hente kudos 😕");
    else setItems(data || []);
  }

  useEffect(() => {
    fetchKudos();
  }, []);

  async function addKudos(e) {
    e.preventDefault();
    setStatus("");

    const clean = message.trim();
    if (!clean) return setStatus("Skriv en kort kudos først 🙂");
    if (clean.length > 80) return setStatus("Maks 80 tegn 🙂");

    const { error } = await supabase
      .from("kudos")
      .insert([{ message: clean, emoji }]);

    if (error) return setStatus("Kunne ikke lagre 😕 (sjekk RLS/policy)");

    setMessage("");
    setEmoji("⭐");
    setStatus("Lagret! 🎉");
    fetchKudos();
  }

  return (
    <section style={{ maxWidth: "720px", margin: "0 auto", padding: "0 16px" }}>
      <h1>Kudos-vegg</h1>
      <p>Gi en hyggelig melding til noen i klassen (kort og snill!).</p>

      <form onSubmit={addKudos} style={{ display: "flex", gap: "8px", margin: "12px 0" }}>
        <select value={emoji} onChange={(e) => setEmoji(e.target.value)}>
          <option>⭐</option>
          <option>🔥</option>
          <option>👏</option>
          <option>💡</option>
          <option>💚</option>
        </select>

        <input
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          placeholder="F.eks: Takk for hjelpen i dag!"
          style={{ flex: 1, padding: "8px" }}
        />

        <button type="submit" style={{ padding: "8px 12px" }}>Send</button>
      </form>

      {status && <p style={{ marginBottom: "12px" }}>{status}</p>}

      <div style={{ display: "grid", gap: "8px" }}>
        {items.map((k) => (
          <div key={k.id} style={{ background: "#fff", padding: "10px 12px", borderRadius: "8px" }}>
            <strong style={{ marginRight: "8px" }}>{k.emoji}</strong>
            {k.message}
            <div style={{ fontSize: "12px", opacity: 0.7, marginTop: "6px" }}>
              {new Date(k.created_at).toLocaleString("no-NO")}
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

7FLegg lenke i Header

I components/Header.js, legg til en lenke til /kudos.

// Eksempel (inne i div-en i Header)
<a href="/kudos" style={{ color: "#fff", textDecoration: "none" }}>Kudos</a>
Vanligste feil:
  • Glemte å starte serveren på nytt etter endring i .env.local.
  • Feil import-sti til supabaseClient (sjekk at du har lib/-mappen).
  • RLS/policy i Supabase blokkerer insert eller select.