Implement end-to-end registration: POST /api/auth/register creates a user, returns a JWT, and the frontend RegisterPage stores the token and redirects to home. Backend: - Add AuthController with POST /api/auth/register endpoint - Add RegisterRequest record (@Email, @NotBlank, @Size(min=8)) - Add AuthResponse and ErrorResponse DTOs - Add GlobalExceptionHandler (@RestControllerAdvice with logging) - EmailAlreadyExistsException -> 409 (Swedish message) - MethodArgumentNotValidException -> 400 (field errors) - Generic Exception -> 500 (Swedish message + server-side log) Frontend: - Add api/client.ts: centralized fetch wrapper with Bearer token interceptor, ApiError class, JSON error parsing - Add api/auth.ts: register() function - Add stores/authStore.ts: Pinia store with token persistence via localStorage, registerUser/logout/isAuthenticated - Add pages/RegisterPage.vue: email + password + confirm password form with client-side validation, submit handler, error display, redirect to home on success - Add route /registrera pointing to RegisterPage - Add 'Registrera' link to AppHeader navigation Infrastructure: - Add __tests__/setup.ts: localStorage polyfill for jsdom 29 (jsdom 29 lacks standard Storage method implementations) - Register polyfill via vitest config setupFiles Tests (17 new, 2 extended): - AuthControllerTest (@SpringBootTest + @AutoConfigureMockMvc): 5 backend tests (success 201, duplicate 409, invalid email 400, short password 400, missing email 400) - authStore.spec.ts: 5 tests (unauthenticated start, localStorage restore, register success, register failure, logout) - RegisterPage.spec.ts: 12 tests (render, validation, submit, redirect, error display, login link) - AppHeader.spec.ts: added 'Registrera' link test - Router.spec.ts: added /registrera route resolution test Build: 95 tests pass (57 frontend + 38 backend), lint clean.
48 lines
918 B
Vue
48 lines
918 B
Vue
<script setup lang="ts">
|
|
import { RouterLink } from 'vue-router'
|
|
</script>
|
|
|
|
<template>
|
|
<header class="app-header">
|
|
<RouterLink to="/" class="app-header__logo">BilHälsning</RouterLink>
|
|
<nav class="app-header__nav">
|
|
<RouterLink to="/" class="app-header__link">Hem</RouterLink>
|
|
<RouterLink to="/registrera" class="app-header__link"
|
|
>Registrera</RouterLink
|
|
>
|
|
</nav>
|
|
</header>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.app-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
background: #fff;
|
|
}
|
|
|
|
.app-header__logo {
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: #1a202c;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.app-header__nav {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.app-header__link {
|
|
color: #4a5568;
|
|
text-decoration: none;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.app-header__link:hover {
|
|
color: #1a202c;
|
|
}
|
|
</style>
|