diff --git a/__tests__/components/mobile/logout-button.test.tsx b/__tests__/components/mobile/logout-button.test.tsx
new file mode 100644
index 0000000..bffa8fe
--- /dev/null
+++ b/__tests__/components/mobile/logout-button.test.tsx
@@ -0,0 +1,46 @@
+// @vitest-environment jsdom
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+import { render, screen, fireEvent, waitFor } from '@testing-library/react'
+
+const { logoutMock } = vi.hoisted(() => ({
+ logoutMock: vi.fn().mockResolvedValue(undefined),
+}))
+vi.mock('@/actions/auth', () => ({ logoutAction: logoutMock }))
+
+import { LogoutButton } from '@/components/mobile/logout-button'
+
+beforeEach(() => {
+ logoutMock.mockClear()
+})
+
+describe('LogoutButton', () => {
+ it('toont initieel alleen de Uitloggen-knop, geen dialog', () => {
+ render()
+ expect(screen.getByRole('button', { name: /Uitloggen/ })).toBeTruthy()
+ expect(screen.queryByText(/Weet je zeker/)).toBeNull()
+ })
+
+ it('opent AlertDialog bij klikken op de knop', () => {
+ render()
+ fireEvent.click(screen.getByRole('button', { name: /Uitloggen/ }))
+ expect(screen.getByText('Uitloggen?')).toBeTruthy()
+ expect(screen.getByText(/Weet je zeker/)).toBeTruthy()
+ })
+
+ it('roept logoutAction aan op bevestigen', async () => {
+ const { container } = render()
+ fireEvent.click(screen.getByRole('button', { name: /Uitloggen/ }))
+ // Het body-portal wordt buiten container gerenderd; query op document.body.
+ const allButtons = Array.from(document.body.querySelectorAll('button'))
+ const confirmBtn = allButtons.find(b => b.textContent?.trim() === 'Uitloggen' && !container.contains(b)) ?? allButtons[allButtons.length - 1]
+ fireEvent.click(confirmBtn)
+ await waitFor(() => expect(logoutMock).toHaveBeenCalledTimes(1))
+ })
+
+ it('roept logoutAction NIET aan bij annuleren', () => {
+ render()
+ fireEvent.click(screen.getByRole('button', { name: /Uitloggen/ }))
+ fireEvent.click(screen.getByText('Annuleren'))
+ expect(logoutMock).not.toHaveBeenCalled()
+ })
+})
diff --git a/app/(mobile)/m/settings/page.tsx b/app/(mobile)/m/settings/page.tsx
new file mode 100644
index 0000000..d1a7070
--- /dev/null
+++ b/app/(mobile)/m/settings/page.tsx
@@ -0,0 +1,92 @@
+// PBI-11 / ST-1136: Mobile Settings — read-only account, product-selector,
+// QR-pairing-instructie, logout. Eigenlijke productactivering loopt via de
+// bestaande setActiveProductAction (ActivateProductButton).
+
+import Link from 'next/link'
+import { prisma } from '@/lib/prisma'
+import { productAccessFilter } from '@/lib/product-access'
+import { requireSession } from '@/lib/auth-guard'
+import { ActivateProductButton } from '@/components/shared/activate-product-button'
+import { LogoutButton } from '@/components/mobile/logout-button'
+import { Badge } from '@/components/ui/badge'
+
+export const metadata = {
+ title: 'Settings',
+}
+
+export default async function MobileSettingsPage() {
+ const session = await requireSession()
+
+ const [user, products] = await Promise.all([
+ prisma.user.findUnique({
+ where: { id: session.userId },
+ select: { username: true, is_demo: true, active_product_id: true },
+ }),
+ prisma.product.findMany({
+ where: { archived: false, ...productAccessFilter(session.userId) },
+ orderBy: { name: 'asc' },
+ select: { id: true, name: true },
+ }),
+ ])
+
+ const isDemo = user?.is_demo ?? false
+
+ return (
+
+
Settings
+
+
+ Account
+
+ {user?.username ?? '—'}
+ {isDemo && (
+ Demo
+ )}
+
+
+
+
+ Actief product
+ {products.length === 0 ? (
+ Geen producten beschikbaar.
+ ) : (
+
+ )}
+
+
+
+ Inloggen op desktop
+
+ Open scrum4me.app/login op je desktop om in te loggen via QR-code. QR-pairing start vanaf de desktop.
+
+
+
+
+
+ )
+}
diff --git a/components/mobile/logout-button.tsx b/components/mobile/logout-button.tsx
new file mode 100644
index 0000000..82f0819
--- /dev/null
+++ b/components/mobile/logout-button.tsx
@@ -0,0 +1,56 @@
+'use client'
+
+import { useState, useTransition } from 'react'
+import { LogOut } from 'lucide-react'
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from '@/components/ui/alert-dialog'
+import { Button } from '@/components/ui/button'
+import { logoutAction } from '@/actions/auth'
+
+export function LogoutButton() {
+ const [open, setOpen] = useState(false)
+ const [pending, startTransition] = useTransition()
+
+ function confirm() {
+ startTransition(async () => {
+ await logoutAction()
+ })
+ }
+
+ return (
+ <>
+
+
+
+
+ Uitloggen?
+
+ Weet je zeker dat je wilt uitloggen?
+
+
+
+ setOpen(false)}>Annuleren
+
+ {pending ? 'Bezig…' : 'Uitloggen'}
+
+
+
+
+ >
+ )
+}