Commit graph

60 commits

Author SHA1 Message Date
2fa161f4fa Fix frontend tests after admin status error UX.
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m4s
CI / E2E browser tests (pull_request) Failing after 1m9s
Align AdminDashboard unit test with API error messages shown in UI.
Stabilize account-settings E2E by relying on waitForEmailChangeToken only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 13:00:28 +02:00
1c9269699e Add admin order fulfillment tracking.
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Failing after 1m50s
CI / E2E browser tests (pull_request) Failing after 1m38s
Register PostNord shipments, admin notes, and guarded status transitions
with customer emails. Expandable admin UI, V11 migration, serial E2E suite,
and AGENTS.md Docker-only E2E guidance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 12:21:17 +02:00
144791b7e6 Fix deferred-payment E2E failures under parallel CI workers.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m8s
CI / E2E browser tests (pull_request) Successful in 1m2s
Remove the brittle filter-empty assertion from admin search helpers.
Run deferred-payment-admin in an isolated Playwright project with one
worker so serial tests keep shared order state. Stabilize unpaid-order
lookup by searching order id first, then plate text from the admin row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 13:45:16 +02:00
cf938501c5 Fix flaky admin plate search in deferred-payment E2E.
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m9s
CI / E2E browser tests (pull_request) Failing after 1m2s
Merge admin lookup checks into one serial test, create the plate when
the order is created, and search using the plate shown in the admin row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 13:26:22 +02:00
4d3beeffb4 Stabilize deferred-payment admin E2E search assertions.
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m22s
CI / E2E browser tests (pull_request) Failing after 1m6s
CI intermittently failed when searching admin orders by registration
number because the table was queried before data and filters settled.
Wait for the admin list to load, clear the search field between queries,
and use a longer timeout when expecting the matching row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 13:16:11 +02:00
7a95c1423c Make customer-facing UI usable on smartphones.
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m22s
CI / E2E browser tests (pull_request) Failing after 1m3s
Mobile traffic was breaking on narrow viewports because the header nav
overflowed and several pages used desktop-only spacing. This adds a
shared phone breakpoint, a hamburger menu, and scroll-to-top on route
changes so footer and menu navigation always land at the top of the page.

- Add --page-gutter and max-width 639px rules in base.css
- AppHeader: hamburger panel on small screens; flat account links on mobile
- AppFooter: stack footer links vertically on phones
- Home, compose, edit order, orders, auth, and legal pages: tighter gutters
  and responsive layout (orders card actions stack; home grids single-column)
- Router scrollBehavior: scroll to top on navigation; restore on browser back
- Tests: AppHeader menu toggle, Router scrollBehavior, mobile Playwright checks

Admin page is intentionally unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 13:03:35 +02:00
b2aaeb5733 Merge origin/master into feature/account-settings-dropdown.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m24s
CI / E2E browser tests (pull_request) Successful in 1m31s
Resolve router conflict: keep /bekrafta-epost confirm route alongside
master's /om-oss about page and /om redirect.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 14:34:38 +02:00
3532e4d486 Add account settings dropdown and verified email change flow.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m9s
CI / E2E browser tests (pull_request) Successful in 1m55s
Replace the header "Byt lösenord" link with an Inställningar menu for
changing email or password. Email changes are two-step: request with
password, confirmation link to the new address, then password again on
confirm so a wrong inbox cannot take over the account.

- Backend: EmailChangeService, V10 email_change_tokens, confirm API
- Frontend: ChangeEmailPage, ConfirmEmailChangePage, header dropdown
- E2E: account-settings round-trips, Mailpit verification, wrong-password guard
- Flyway: V9 restore for dev DBs, CI migration checks, V10 for email tokens

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 14:33:06 +02:00
a12e07ec1c Register routes for integritetspolicy and villkor legal pages.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m4s
CI / E2E browser tests (pull_request) Successful in 57s
- Add /integritetspolicy and /villkor to Vue Router
- Add Router tests confirming both public legal routes resolve

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 13:51:20 +02:00
ec62ba7673 Add användarvillkor page for Bilhej service terms.
- Create TermsOfServicePage covering Swish payment, letter content rules, and liability
- Describe edit/cancel before payment and refund expectations after posting
- Link to integritetspolicy and support contact in footer CTA
- Add TermsOfServicePage unit tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 13:51:20 +02:00
258f6f5a17 Add integritetspolicy page with Phase 0 privacy copy.
- Create PrivacyPolicyPage with sections on data, rights, and letter recipients
- Use plain Swedish without technical jargon or operational detail
- Link to kontakt page and mailto for privacy questions
- Add PrivacyPolicyPage unit tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 13:51:20 +02:00
bce2447238 Rework contact page emails and simplify mailto actions.
- Add support@bilhej.se for orders and technical issues
- Move complaints to klagomal@bilhej.se instead of personal Gmail
- Show one mailto chip per card instead of duplicate link and button
- Update ContactPage tests and production email checklist for all @bilhej.se addresses

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 13:51:20 +02:00
c0c32b718b Merge about page prose into hero and drop redundant section heading.
- Move the three explanatory paragraphs into the hero card under the lead
- Remove the separate "Vad vi gör" section that repeated the same framing
- Add a light divider between lead and body text for readability

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 13:51:11 +02:00
081a1f90d3 Add expand/collapse for long letter previews on orders page.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 1m59s
CI / E2E browser tests (pull_request) Successful in 57s
- Truncate previews over 120 characters with a Visa mer toggle
- Allow per-order expand state on pending and completed cards
- Add styles for expanded preview and toggle button
- Cover long and short message behavior in OrdersPage tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:47:46 +02:00
162002dfb1 Fix printed letter footer contact address to kontakt@bilhej.se.
- Replace obsolete hej@bilhalsning.se in ComposePage GDPR footer
- Apply the same correction on EditOrderPage for edited orders

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:47:46 +02:00
60cb07fc89 Redesign contact page with separate support and complaint channels.
- Replace single placeholder mailto with two contact cards
- Show kontakt@bilhej.se for general questions and service issues
- Show jcamorling@gmail.com for complaints with clearer labeling
- Add tips section pointing users to Mina beställningar first
- Extend ContactPage tests for both email addresses

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:47:46 +02:00
758ace1b92 Redesign about page and move route to /om-oss.
- Replace placeholder about card with hero, prose, steps, and CTA
- Add primary route /om-oss with redirect from legacy /om
- Update footer tagline and Om oss link to match new URL
- Extend AboutPage and AppFooter tests for new content and routing

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:47:44 +02:00
139250b2ac Redesign homepage with clearer marketing sections and honest copy.
- Add structured use-case cards mapped to real letter templates
- Replace generic hero with bullets on traceability, anonymity, and timing
- Add three-step how-it-works flow with manual posting disclaimer
- Reframe trust section around convenience rather than hidden addresses
- Refresh layout with gradient heroes, icons, and consistent section styling

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:47:42 +02:00
15d7b4ae4c Fix order cancellation by allowing cancelled in the database status constraint.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m26s
CI / E2E browser tests (pull_request) Successful in 1m18s
The cancel API returned 500 because ck_orders_status did not include cancelled.
Adds Flyway V9 and an E2E test for cancelling a pending order from /orders.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 11:53:25 +02:00
ca5ce12812 Polish orders page UI for pending and completed cards.
All checks were successful
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m0s
CI / E2E browser tests (pull_request) Successful in 1m27s
Redesigns the order list so unpaid and paid orders share a consistent
card layout, with clearer payment context and labeled metadata users
need before paying via Swish.

- Split list into Obetalda/Tidigare sections with pending orders first
- Pending cards: preview box, labeled Beställnings-ID, price row, Betala 49 kr
- Completed cards: same header/preview layout, prominent Spåra brev button
- Replace em-dash pay label and update unit/E2E selectors

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 11:38:26 +02:00
3d0b7fe799 Allow users to edit or cancel unpaid orders before payment.
Adds backend endpoints and frontend edit page so pending orders can be updated or soft-cancelled without admin intervention.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 11:21:47 +02:00
86fb946e33 Add password reset, logged-in change password, and Mailpit email dev/E2E.
All checks were successful
CI / Lint, type check, unit tests, coverage (push) Successful in 2m2s
CI / E2E browser tests (push) Successful in 1m55s
Operators can fix prod admin passwords without email via Byt lösenord;
end users can use forgot-password when SMTP is configured. Local and CI
use Mailpit to capture outbound mail and verify reset links end-to-end.

- Backend: V8 password_reset_tokens, PasswordResetService, EmailService,
  POST /api/auth/forgot-password, reset-password, change-password
- Optional testToken in forgot-password response (docker profile only, for E2E)
- Frontend: ForgotPasswordPage, ResetPasswordPage, ChangePasswordPage,
  routes, login link, header Byt lösenord
- Mailpit (ghcr.io/axllent/mailpit:v1.28) in docker-compose + e2e stack
- E2E: password-reset.spec.ts + Mailpit API helper tests SMTP delivery
- Separate dev/e2e Docker image names to avoid overwriting bilhej-frontend
- Docs: README email section, production-email-checklist, .env.example
- Unit/integration tests for reset, change password, and Vitest page specs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 18:05:15 +02:00
7731eb1155 Apply ESLint formatting fixes to admin and orders pages.
All checks were successful
CI / Lint, type check, unit tests, coverage (push) Successful in 3m46s
CI / E2E browser tests (push) Successful in 1m46s
Auto-fix from eslint src/ --fix after ./gradlew check touched these
files. No functional changes.
2026-05-21 16:00:53 +02:00
49b5a91f4a Include E2E browser tests in ./gradlew check.
Local verification should match Forgejo CI. Wire frontendE2E into check
and point it at docker-compose.e2e.yml with the same test env vars.

- Add frontendE2E to check after frontend unit tests
- Run docker-compose.e2e.yml directly from Gradle with CI secrets
- Update npm test:e2e:ci to use the e2e compose file
2026-05-21 15:58:09 +02:00
ec122e86b8 Fix admin dashboard e2e tests for updated UI selectors.
All checks were successful
CI / Lint, type check, unit tests, coverage (push) Successful in 3m47s
CI / E2E browser tests (push) Successful in 1m42s
The admin search label and parallel compose tests made strict-mode
Playwright locators ambiguous after the dashboard rework.

- Assert table columns via columnheader roles instead of getByText
- Target seeded order by ID when opening the message modal

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 15:41:03 +02:00
93ece8128a Use bilhej.se domain for dev test user email.
Aligns seeded and test login addresses with production branding while
keeping admin@bilhalsning.se for local docker admin seed only.

- Change test@bilhalsning.se to test@bilhej.se in dev migration and all tests
2026-05-21 15:14:11 +02:00
3ba7560f82 Add e2e coverage for deferred payment and admin lookup.
Manual Swish flow means users often pay later; admins match payments via
order ID or regnr under Att göra.

- User flow: create order, leave payment, pay from orders page
- Admin: find order via partial ID, full ID, and plate search
- Assert unpaid orders appear under Väntar, not Att göra
- Use unique plates per run to avoid collisions with seed data
2026-05-21 14:49:50 +02:00
01db53860b Rework admin dashboard filtering, search, and message viewing.
Admins need to find orders quickly and read full letter text without a
cramped table column.

- Make stat cards clickable filters (Totalt, Att göra, Betalda, Väntar)
- Add search by partial order ID or registration number
- Show shortened order ID in table with full ID on hover
- Replace message column with "Visa meddelande" opening a modal
- Keep expanded row for tracking only; remove duplicate brevtext block
- Update AdminDashboard unit tests and admin-dashboard e2e specs
2026-05-21 14:49:50 +02:00
b9a0bdb318 Clarify Swish reference order ID on the payment page.
The full UUID is required as the Swish message but was easy to miss when
embedded only in instruction text.

- Show beställnings-ID in a dedicated box above payment summary
- Point Swish instructions to that ID instead of repeating inline
- Add PaymentRedirect unit test for full order ID display
2026-05-21 14:49:50 +02:00
dfb3e0dedc Improve orders page with details and deferred payment.
Users who leave the payment step can return later and still see what
they ordered. Unpaid orders get a clear path back to Swish checkout.

- Add letterText to frontend Order type
- Show beställnings-ID, message, and formatted date on each order card
- Add "Betala nu" link to payment route for pending_payment orders
- Extend OrdersPage unit tests and order-history e2e for pay-later flow
2026-05-21 14:49:50 +02:00
0f613b21a6 fix: allow frontend container host in vite preview and update payment E2E tests
Some checks failed
CI / Lint, type check, unit tests, coverage (push) Successful in 11m18s
CI / E2E browser tests (push) Failing after 54s
fix: add preview.allowedHosts and preview.host to vite.config.ts

Vite preview server blocks requests from non-localhost hosts by default.
In the E2E Docker Compose stack, Playwright accesses the frontend via
http://frontend (container hostname). Without allowedHosts, Vite returns
"Blocked request. This host is not allowed." and the SPA never mounts,
causing all 59 E2E tests to fail with blank pages and missing elements.

- Add preview.host: true (bind to 0.0.0.0)
- Add preview.allowedHosts: ['frontend', 'localhost']

test: update payment-redirect E2E tests to match current UI

The payment page was redesigned to a two-step confirmation flow:
"Jag har betalat" → confirmation → "Ja, jag har betalat". The E2E
tests still referenced the old single-step "Genomför testbetalning"
button and a removed .payment__note CSS class.

- Update 'payment button marks order as paid' to click through both steps
- Rename 'shows mock payment note' to 'shows Swish payment instructions'
  and assert on actual UI elements (Swish label + payment button)

Result: E2E suite now passes 59/59 tests in the Docker Compose CI stack.
2026-05-19 19:40:40 +02:00
98d5545be0 feat: replace Stripe mock with manual Swish payment flow
Replace the mock test-payment button with a real manual Swish flow
where the user sends a Swish payment with the order ID as message
and confirms via a button. Admin verifies Swish and processes manually.

Backend
- Rename OrderStatus LOOKUP_STARTED to PROCESSING (Swedish: Hanteras)
- Update V5 migration CHECK constraint from lookup_started to processing
- Rename OrderService.markAsPaid() to confirmPayment(), sets PROCESSING
  instead of PAID, stop hardcoding amountPaid
- Add GET /api/payment/swish-info endpoint returning swish number and
  letter price from app.payment config
- Permit /api/payment/swish-info without authentication
- Update UpdateStatusRequest regex to accept processing
- Update PaymentControllerTest for renamed method, new status, and
  public swish-info endpoint test

Frontend
- Rewrite PaymentRedirect.vue: Swish number, order ID as message,
  Jag har betalat button with confirmation dialog
- Add fetchSwishInfo() to api/payment.ts
- AdminPage: rename Skickade stat to Att göra (processing orders),
  highlight processing rows with admin__row--todo
- OrdersPage: update status labels/badge classes for new flow
- Refactor ApiError in client.ts to property declaration syntax
- Exclude __tests__ from tsconfig.app.json and Docker builds

Tests
- Rewrite PaymentRedirect.spec.ts for Swish info, confirmation dialog,
  cancel flow, and processing status
- Update OrdersPage.spec.ts with processing status test
- Update AdminDashboard.spec.ts with Att göra stat and row highlight
- Add amountPaid to ComposePage.spec.ts mock

Config
- Add SWISH_NUMBER to .env.example and docker-compose.yml
2026-05-19 19:23:37 +02:00
e8530b8d95 fix: E2E pipeline — vite preview instead of nginx, ts build fixes
Some checks failed
CI / Lint, type check, unit tests, coverage (push) Successful in 11m12s
CI / E2E browser tests (push) Failing after 8m0s
Three problems caused E2E browser tests to fail in Forgejo CI:

1. TypeScript build errors in  (frontend.e2e.Dockerfile):
   -  used parameter property  which violates
     . Replaced with explicit property declaration.
   -  included  in type-checking, causing
     mock Response type mismatches. Added .
   -  mock Order was missing  field.

2. Nginx SSL crash:
   -  copied production
     which references SSL certs that don't exist in the e2e image.
   - Replaced nginx entirely with  (simpler, no SSL needed).
   - Added  to  so  routes to backend.

3. Docker context hygiene:
   -  excludes  so test files don't
     bloat the build context or trigger type errors in the container.

All other files untouched.
2026-05-19 18:53:52 +02:00
df539f7cb7 test: update unit tests for real vehicle API and fuel field
- HomePage.spec.ts: replace setTimeout fake data with mocked lookupVehicle()
  API call, mock resolved/rejected/pending states, add fuel to mock responses
- VehicleInfo.spec.ts: add fuel field to mockVehicle data,
  update assertion to include Bensin in rendered text
2026-05-19 15:16:52 +02:00
be7775f680 test: add E2E tests for homepage vehicle lookup flow
- enters plate and sees vehicle info with CTA button:
  types HDO732, verifies Peugeot 107 1.0, 2011, Gul, Bensin appear,
  verifies Fortsatt till brevet link has correct href
- shows not found for unknown plate (ZZZ999)
- CTA navigates to compose when authenticated:
  logs in as test@bilhalsning.se, performs lookup, clicks CTA,
  verifies redirect to /compose?plate=HDO732
2026-05-19 15:16:34 +02:00
1b87e15a21 feat: replace fake vehicle data with real API lookup on homepage
- Add typed API module api/vehicles.ts with lookupVehicle(plate) function
- Replace FAKE_VEHICLES record with async API call in HomePage.vue
- Remove setTimeout-based fake lookup, use lookupVehicle() instead
- Handle errors: show not-found for unknown plates, catch network failures
- Add fuel field to VehicleInfo interface and display (e.g. 'Gul, Bensin')
- VehicleInfo now shows make, model, year, color, and fuel from API
2026-05-19 15:16:23 +02:00
2506a0283c test: update Vitest and E2E specs for redesigned UI
- Update HomePage specs: new headline, CTA class from btn--success to btn--primary
- Update ComposePage specs: new button text, brand name in GDPR footer
- Update PaymentRedirect specs: button text, class, and test payment note
- Update TemplatePicker specs: remove emoji icon assertion
- Update AdminDashboard specs: expand button selectors instead of row clicks
- Update AppHeader specs: BilHälsning to Bilhej brand text
- Update AboutPage specs: BilHälsning to Bilhej heading
- Update App specs: new homepage headline text
- Update OrdersPage specs: badge class renames
- Update LoginPage specs: form name/action attribute tests
- Update E2E compose specs: button text, GDPR footer brand name
- Update E2E payment specs: button text and note selectors
- Update E2E admin-dashboard specs: expand button and tracking label selectors
- Update E2E header-auth specs: new test additions for admin visibility
2026-05-16 16:11:58 +02:00
851cd8afa0 refactor: redesign all pages and components with new design system
- Rewrite homepage: practical headline, use-case cards, calm trust note
- Switch from purple to blue brand tokens across all pages
- Replace all CTA buttons with brand-primary, reserve green for success
- Remove emoji from template picker and compose page
- Replace unicode chevrons with SVG expand buttons in admin
- Redesign template picker modal with accessibility semantics
- Add aria-invalid, aria-describedby to form validation
- Add role=status/alert to loading, error, and result messages
- Remove inline styles, replace with scoped utility classes
- Update compose submit text, payment button, order empty state copy
- Remove icon field from letter templates
2026-05-16 16:11:01 +02:00
00327674ed refactor: add design system with CSS tokens, utilities, and app shell
- Add design tokens (colors, spacing, radius, shadows, typography, transitions)
- Add global reset, body/link/focus/typography base styles
- Add utility classes (container, surface-card, btn variants, field, badge, message, divider)
- Replace header ✉ symbol with inline SVG envelope icon
- Update favicon to license-plate shaped mark with blue gradient and bold B
- Rename brand from BilHälsning to Bilhej in header, footer, and HTML title
- Rewrite footer tagline: focus on service, not privacy
- Add theme-color meta tag for browser chrome
2026-05-16 16:09:35 +02:00
8cd7991603 test: add payment flow tests and fix strict-mode e2e violations
Vitest:
  - PaymentRedirect.spec.ts (8 tests): renders heading and 49 kr,
    shows plate from query, Betalt button exists, calls payOrder on
    click, navigates to /orders on success, shows error on failure,
    disables button while paying, shows mock note
  - ComposePage.spec.ts: update navigation test to expect /betalning
    route with orderId param instead of /orders; add payment route
    to test router; add PaymentRedirect import

Playwright E2E:
  - payment-redirect.spec.ts (4 tests): compose→payment navigation,
    Betalt→orders flow, auth guard redirects to login, mock note
    visible
  - compose.spec.ts: rename test and update assertion from /orders
    to /betalning/ URL pattern; use getByRole('heading',
    { name: 'Betalning' }) to avoid strict mode violation with
    mock-note paragraph containing the word 'Betalning'
2026-05-15 20:31:16 +02:00
c3c1513ac1 feat: add payment page and wire compose submit to payment flow
- api/payment.ts: payOrder(orderId) calls POST /api/payment/{id}/pay
- api/orders.ts: add amountPaid (number|null) to Order type
- PaymentRedirect.vue: route /betalning/:orderId, shows plate from
  query?plate, amount label (49 kr), green Betalt button, mock note:
  "Detta är en mock-betalning. I framtiden skickas du till Stripe."
  On click: calls payOrder, on success navigates to /orders, on
  failure shows error. Button disables and shows "Bearbetar..." while
  paying.
- ComposePage.vue: after createOrder success, captures returned order
  object and navigates to /betalning/{orderId}?plate=... instead of
  the old direct-to-orders route
- Router: add /betalning/:orderId route (name: payment, component:
  PaymentRedirect, meta: { requiresAuth: true })
2026-05-15 20:30:15 +02:00
0f34d29a2a test: add tracking entry vitest and e2e tests, fix pre-existing flaky tests
- AdminDashboard.spec.ts (+6 tests):
  - tracking input and save button visible in expanded row
  - PostNord link visible when trackingId is set
  - PostNord link hidden when trackingId is null
  - save button fires PATCH to correct URL
  - tracking error shown on failed save
- admin-dashboard.spec.ts (+4 tests):
  - tracking input and save button visible after row expand
  - PostNord link with postnord href visible for orders with tracking
  - PostNord link hidden for orders without tracking
  - fix row selector to use .last() for deterministic tracking check
    (compose test creates extra ABC123 order that shifts row order)
- compose.spec.ts: fix strict mode violation — getByText('ABC123')
  resolved to 2 elements (strong + preview paragraph) after admin
  test expanded an ABC123 row; use .first()
- order-history.spec.ts: fix strict mode violations — ABC123 and
  Levererat resolve to 2 elements due to compose test creating
  an extra ABC123 order with status changed to delivered; use
  .first() on affected assertions
2026-05-15 19:59:00 +02:00
dcc466439e feat: add tracking input, save button, and PostNord link to admin dashboard
- api/admin.ts: updateTracking(orderId, trackingId) calls PATCH
  /api/admin/orders/{id} with JSON { trackingId }
- AdminPage.vue expanded row: add "Spårnings-ID" section below
  Brevtext with text input, save button, and PostNord link
- trackingInputValues reactive map tracks per-order input state
- toggleExpand initialises trackingInputValues[orderId] from
  order.trackingId on first expand
- handleTrackingSave: PATCH API call with optimistic local update,
  reverts on error, shows red inline error
- PostNord link (<a target="_blank">): https://www.postnord.se/
  verktyg/spara/?id={trackingId}, only visible when trackingId
  is non-null
- trackingError ref for inline error state
- CSS: tracking section styling, input focus ring, blue save button
2026-05-15 19:58:46 +02:00
e654d42a4f chore: add vitest coverage enforcement to frontend
- Install @vitest/coverage-v8 as devDependency (13 packages)
- Add coverage block to vite.config.ts test config:
  - provider: 'v8' (Node.js native coverage, faster than istanbul)
  - reporters: text, html, lcov, json
  - thresholds: 70% lines, 60% branches, 70% functions, 70% statements
  - exclude: test files and e2e directory
- Add "test:coverage": "vitest run --coverage" script to package.json
- Coverage report output: frontend/coverage/index.html
  JSON output:     frontend/coverage/coverage-final.json
- Thresholds are enforced by vitest itself — build exits non-zero
  if any threshold is not met
2026-05-15 12:15:55 +02:00
668cd023be test: add admin dashboard Vitest and Playwright E2E tests
Vitest (14 tests) — AdminDashboard.spec.ts:
  - renders heading, subtitle, table columns, order data in rows
  - shows loading, empty, and error states
  - fetches GET /api/admin/orders on mount
  - expands row on click to reveal letter content (Brevtext label)
  - collapses row on second click
  - only one row expanded at a time (clicking row 2 closes row 1)
  - status dropdown change fires PATCH /api/admin/orders/{id}/status
    with correct URL, method, and JSON body
  - shows error message on failed status update

Playwright E2E (8 tests) — admin-dashboard.spec.ts:
  - admin login (admin@bilhalsning.se / test1234) before each test
  - admin can navigate to /admin and see heading
  - non-admin user (test@bilhalsning.se) is redirected away from /admin
  - table renders Datum/E-post/Regnr/Status column headers
  - seeded order plates visible (ABC123, DEF456, GHI789)
  - click row expands letter content
  - click again collapses letter content
  - status dropdown change persists (selectOption delivered)
  - unauthenticated access redirects to login with ?redirect=/admin
2026-05-15 12:15:36 +02:00
9b4f08469c feat: build admin dashboard with orders table and status dropdown
- api/admin.ts: AdminOrder interface (id, email, plate, letterText,
  status, trackingId, amountPaid, createdAt), fetchAllOrders() calls
  GET /api/admin/orders, updateOrderStatus(orderId, status) calls
  PATCH /api/admin/orders/{id}/status
- AdminPage.vue replaces placeholder with full dashboard:
  - Table columns: Datum, E-post, Regnr, Status, expand chevron
  - Click any row to toggle expanded letter preview below the row
  - Only one row expanded at a time; second click collapses
  - Status column has a <select> dropdown showing Swedish labels
  - Changing dropdown fires PATCH API immediately (no save button)
  - On API failure the dropdown reverts to previous value and a
    red inline error "Kunde inte uppdatera status" appears
  - Loading, empty, and API error states with Swedish messages
  - Responsive table wrapper for horizontal scroll on small screens
  - Expanded rows use a separate <tr> with colspan(5) for clean
    table semantics
2026-05-15 12:15:19 +02:00
96508d63cd feat: add template picker modal to compose page
- Add LetterTemplate.icon field and 7th template 'Mindre parkeringsskada' (🅿️)
- Create TemplatePicker.vue component: modal overlay with 2-column card grid,
  emits 'select' and 'close' events, closes on overlay click
- Add ' Visa mallar' pill button above textarea in ComposePage
- Clicking button opens TemplatePicker modal, selecting a template fills
  textarea and closes modal
- Style button as pill/badge with light blue background and icon
- Add 7 Vitest tests for TemplatePicker (renders cards, emits events, close
  behavior, parking damage template)
- Add 4 Vitest tests for ComposePage template picker integration
- Add 2 Playwright E2E tests (opens picker, fills textarea and closes)
2026-05-14 17:39:21 +02:00
6ab5e2f707 refactor: remove template from order flow
Templates serve as a brand shield (showing the platform facilitates all
kinds of messaging), not as a compose-flow form control. Remove them from
the data model and compose page. Templates will live as branding elements
on the landing page in a future commit.

Backend:
- Remove template field from Order entity (getter/setter removed)
- Remove template from CreateOrderRequest DTO
- Remove template from OrderResponse DTO
- Remove template param from OrderService.createOrder()
- Remove template passthrough in OrderController
- Remove /api/templates permitAll from SecurityConfig
- Edit V5 migration: remove template column from orders table
- Edit V6 migration: remove template from seed data
- Update OrderControllerTest (remove template from assertions/requests)
- Update OrderServiceTest (remove template from createOrder calls)

Frontend:
- Remove template from Order interface in api/orders.ts
- Remove template param from createOrder() function
- Remove template display from OrdersPage.vue cards
- Rewrite ComposePage.vue: remove template selector, keep textarea + preview + submit
- Update ComposePage.spec.ts (remove template tests, add preview/GDPR tests)
- Update OrdersPage.spec.ts (remove template from mock data and display test)
- Update compose.spec.ts E2E (remove template selector interactions)
- Update order-history.spec.ts E2E (remove template names test)
- Fix unused import in Router.spec.ts
- Also includes minor Prettier formatting in AppHeader.spec.ts, AdminPage.vue, authStore.ts
2026-05-14 16:55:59 +02:00
5fa903d9af feat: build out compose page with template selector, letter editor, and preview
- Add createOrder(plate, template, letterText) to frontend api/orders.ts
- Create data/templates.ts with 6 Swedish letter templates (Komplimang,
  Jag vill köpa din bil, Tips / servicebehov, Synpunkter på körbeteende,
  Tuta / frustration, Fritt meddelande) with pre-filled body text
- Rewrite ComposePage.vue with full compose flow:
  - Template selector dropdown (Fritt meddelande selected by default)
  - Textarea with 1000-char limit and live character counter
  - Inline A4 letter preview with plate, body, and GDPR Art. 14 footer
  - 'Skicka brev (49 kr)' submit button, disabled when empty
  - On success: redirects to /orders; on error: shows error message
  - Shows error with back link if no plate in route query
- Add 12 Vitest tests for ComposePage (template fill, char counter, submit
  validation, createOrder call, navigation, null template for Fritt meddelande)
- Add 8 Playwright E2E tests (auth guard, no-plate error, template selection,
  textarea edit, submit button state, order creation, preview content)
2026-05-14 16:02:14 +02:00
0c62d7e60a feat: add orders link to header nav for authenticated users
- Add 'Mina beställningar' RouterLink to AppHeader in authenticated template
- Add Vitest tests: link visible when authenticated, hidden when not
- Add Playwright E2E test: shows orders link when authenticated
- Add Playwright E2E test: can navigate from home to orders via header link
2026-05-14 15:31:06 +02:00