# Les 8 — Live Coding Guide ## Supabase × Next.js + Auth > **Jouw spiekbriefje.** Dit bestand staat op je privéscherm. Op de beamer draait Cursor. > Volg stap voor stap. Typ exact wat hier staat. Leg uit met de "Vertel:" blokken. --- ## VOOR DE LES BEGINT **Zorg dat je dit hebt klaargemaakt:** - [ ] Het poll-demo project geopend in Cursor - [ ] feature/les-8 branch checked out (VOOR de nieuwe commits) - [ ] De code hieronder klopt met wat je ziet (BEFORE-state) - [ ] Supabase project aangemaakt en database klaar (polls + options tabellen) - [ ] Twee demo polls in de database - [ ] Slides geopend (voor Deel 2) --- # DEEL 1: LIVE CODING — Supabase Koppelen (09:10–10:15) **Doel:** De poll-app offline maken en live verbinden met Supabase. Alle data gaat via het Supabase API. --- ## STAP 1: Installeer @supabase/supabase-js ```bash npm install @supabase/supabase-js ``` **Vertel:** "We gaan de Supabase client library installeren. Dit is de JavaScript SDK waarmee we rechtstreeks kunnen communiceren met Supabase — zonder een eigen backend API te hoeven schrijven." --- ## STAP 2: Maak .env.local aan Bestand: `.env.local` (in de root van je project) ``` NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` **Vertel:** "Deze environment variables bevatten je Supabase project URL en de anonieme API key. Ze beginnen beide met NEXT_PUBLIC_, dus ze worden in de browser zichtbaar — maar dat is oké want dit zijn public credentials. Je private key bewaar je nooit in de client code." **Waar vind je deze?** - Ga naar je Supabase project dashboard - Settings → API - Kopieer Project URL en anon key --- ## STAP 3: Maak lib/supabase.ts aan Bestand: `lib/supabase.ts` ```typescript import { createClient } from "@supabase/supabase-js"; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!; const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; export const supabase = createClient(supabaseUrl, supabaseAnonKey); ``` **Vertel:** "Dit is onze Supabase client — één plek waar we de verbinding opzetten. We gebruiken `createClient()` om één client aan te maken die we overal importeren. De `!` betekent 'deze mag nooit undefined zijn'." --- ## STAP 4: Update types/index.ts **BEFORE:** ```typescript export interface Poll { id: string; question: string; options: string[]; votes: number[]; } ``` **AFTER:** ```typescript export interface Poll { id: string; question: string; created_at: string; options: Option[]; } export interface Option { id: string; poll_id: string; text: string; votes: number; } ``` **Vertel:** "De database structuur is anders dan wat we hadden. Nu hebben we twee aparte tabellen: `polls` en `options`. Elke option is een eigen record met een `poll_id` referentie. Dit is genormaliseerde data — beter voor grote apps. De votes tellen we per option, niet meer als een array." --- ## STAP 5: Rewrite lib/data.ts **BEFORE:** ```typescript import { Poll } from "@/types"; let polls: Poll[] = [ { id: "1", question: "Ik ben een vraag", options: ["optie 1", "optie 2", "optie 3", "optie 4"], votes: [1,1,1,1] }, { id: "2", question: "Ik ben een vraag 2", options: ["optie 1", "optie 2", "optie 3", "optie 4"], votes: [1,1,1,1] } ] export function getPolls(): Poll[] { return polls } export function getPollById(id: string): Poll | undefined { return polls.find((poll) => poll.id === id) } export function votePoll(id: string, optionIndex: number) { const poll = polls.find((p) => p.id === id) if (!poll) return undefined; if (optionIndex < 0 || optionIndex >= poll.options.length) return undefined; poll.votes[optionIndex]++; return poll; } ``` **AFTER:** ```typescript import { supabase } from "./supabase"; import { Poll, Option } from "@/types"; export async function getPolls(): Promise { const { data: polls, error } = await supabase .from("polls") .select("*, options(*)") .order("created_at", { ascending: false }); if (error) { console.error("Error fetching polls:", error); return []; } return polls || []; } export async function getPollById(id: string): Promise { const { data: poll, error } = await supabase .from("polls") .select("*, options(*)") .eq("id", id) .single(); if (error) { console.error("Error fetching poll:", error); return null; } return poll; } export async function votePoll(pollId: string, optionId: string): Promise