diff --git a/docs/superpowers/plans/2026-11-06-repairs-app-phase-2.md b/docs/superpowers/plans/2026-11-06-repairs-app-phase-2.md index a4a4cc4..695855c 100644 --- a/docs/superpowers/plans/2026-11-06-repairs-app-phase-2.md +++ b/docs/superpowers/plans/2026-11-06-repairs-app-phase-2.md @@ -24,6 +24,38 @@ - Commit per task with the exact message given. Stage by explicit path — never `git add -A`. - Follow this repo's existing conventions. Read `src/app/(rep)/rep/layout.tsx` and `public/manifest-rep.json` before you start — you are copying that pattern, not inventing one. +## How the browser token is obtained — read this before writing any fetch + +The browser session token is NOT on the auth context. §useAuth()§ from +§@/components/auth-provider§ exposes §user§, §loading§ and the auth actions, +and **no §token§**. Reading §useAuth().token§ gives §undefined§, which makes +§authHeaders()§ silently send NO session and every route answers 401. + +The token lives in the PocketBase client auth store. This is the house +pattern — copy it exactly: + +§§§ts +import { getPocketBase } from "@/lib/pocketbase"; + +const token = getPocketBase().authStore.token; +const headers = token ? { Authorization: "Bearer " + token } : {}; +§§§ + +§src/app/(app)/delivery-pool/page.tsx§ and §src/app/(app)/search/page.tsx§ +both do this. The Task 1 implementer confirmed it against the real +§auth-provider.tsx§, and every repairs fetch in the office screens now +uses it. + +**In tests**, mock the pocketbase module, not the auth provider: + +§§§ts +vi.mock("@/lib/pocketbase", () => ({ + getPocketBase: () => ({ authStore: { token: "t" } }), +})); +§§§ + +--- + ## What is already in place (do not re-create it) - `@/lib/repair-status` — `REPAIR_STATUS`, `REPAIR_STATUS_LABEL`, `REPAIR_STATUS_VARIANT`, `REPAIR_TRANSITIONS`, `nextStepFor(status)` returning `{ label, action, to }` or `null`, `type RepairStatus`, `type RepairAction`, `interface RepairNextStep`. @@ -163,7 +195,7 @@ In `src/app/(app)/repairs/page.tsx` and `src/app/(app)/repairs/[id]/page.tsx`, e Read the token from `useAuth()` — the same hook `MobileAuthGate` uses. Add a small helper in each page, matching the repo's existing shape: ```ts - const { token } = useAuth(); + const token = getPocketBase().authStore.token; const authHeaders = () => (token ? { Authorization: "Bearer " + token } : {}); ``` @@ -508,8 +540,8 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import { RepairBoard } from "./repair-board"; -vi.mock("@/components/auth-provider", () => ({ - useAuth: () => ({ token: "t", user: { id: "u1" }, loading: false }), +vi.mock("@/lib/pocketbase", () => ({ + getPocketBase: () => ({ authStore: { token: "t" } }), })); const REPAIRS = [ @@ -628,7 +660,7 @@ Create `src/app/(repairs-app)/repairs-app/repair-board.tsx`: import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { Badge } from "@/components/ui/badge"; -import { useAuth } from "@/components/auth-provider"; +import { getPocketBase } from "@/lib/pocketbase"; import { REPAIR_STATUS, REPAIR_STATUS_LABEL, @@ -661,7 +693,7 @@ const EMPTY_COUNTS: Counts = { * must not invent one. */ export function RepairBoard() { - const { token } = useAuth(); + const token = getPocketBase().authStore.token; const [repairs, setRepairs] = useState([]); const [counts, setCounts] = useState(EMPTY_COUNTS); const [status, setStatus] = useState(""); @@ -882,8 +914,8 @@ vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn(), replace: vi.fn() }), })); -vi.mock("@/components/auth-provider", () => ({ - useAuth: () => ({ token: "t", user: { id: "u1" }, loading: false }), +vi.mock("@/lib/pocketbase", () => ({ + getPocketBase: () => ({ authStore: { token: "t" } }), })); vi.mock("@/components/ui/customer-search", () => ({ @@ -965,7 +997,7 @@ import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { CustomerSearch } from "@/components/ui/customer-search"; import { SupplierSearch } from "@/components/ui/supplier-search"; -import { useAuth } from "@/components/auth-provider"; +import { getPocketBase } from "@/lib/pocketbase"; const MAX_PHOTOS = 10; @@ -979,7 +1011,7 @@ const MAX_PHOTOS = 10; */ export function BookInForm() { const router = useRouter(); - const { token } = useAuth(); + const token = getPocketBase().authStore.token; const fileRef = useRef(null); const [customerId, setCustomerId] = useState(null); @@ -1231,8 +1263,8 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import { RepairDetail } from "./repair-detail"; -vi.mock("@/components/auth-provider", () => ({ - useAuth: () => ({ token: "t", user: { id: "u1" }, loading: false }), +vi.mock("@/lib/pocketbase", () => ({ + getPocketBase: () => ({ authStore: { token: "t" } }), })); const REPAIR = { @@ -1322,7 +1354,7 @@ Create `src/app/(repairs-app)/repairs-app/[id]/repair-detail.tsx`: import { useCallback, useEffect, useRef, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { useAuth } from "@/components/auth-provider"; +import { getPocketBase } from "@/lib/pocketbase"; import { REPAIR_STATUS, REPAIR_STATUS_LABEL, @@ -1340,7 +1372,7 @@ import type { Repair } from "@/lib/types"; * rather than a dead one. */ export function RepairDetail({ repairId }: { repairId: string }) { - const { token } = useAuth(); + const token = getPocketBase().authStore.token; const fileRef = useRef(null); const [repair, setRepair] = useState(null); const [error, setError] = useState(null);