Compare commits
No commits in common. "081a1f90d35d0752f9d98128e5c217b68be3ed7f" and "15d7b4ae4c7d36cbe436378b5e2116c62aeccef2" have entirely different histories.
081a1f90d3
...
15d7b4ae4c
12 changed files with 162 additions and 1551 deletions
|
|
@ -1,44 +1,10 @@
|
||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import { createRouter, createMemoryHistory } from 'vue-router'
|
|
||||||
import AboutPage from '@/pages/AboutPage.vue'
|
import AboutPage from '@/pages/AboutPage.vue'
|
||||||
|
|
||||||
function createTestRouter() {
|
|
||||||
return createRouter({
|
|
||||||
history: createMemoryHistory(),
|
|
||||||
routes: [
|
|
||||||
{ path: '/om-oss', name: 'about', component: AboutPage },
|
|
||||||
{ path: '/', name: 'home', component: { template: '<div>Home</div>' } },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('AboutPage', () => {
|
describe('AboutPage', () => {
|
||||||
it('renders heading and lead', () => {
|
it('renders heading', () => {
|
||||||
const router = createTestRouter()
|
const wrapper = mount(AboutPage)
|
||||||
const wrapper = mount(AboutPage, {
|
|
||||||
global: { plugins: [router] },
|
|
||||||
})
|
|
||||||
expect(wrapper.text()).toContain('Om Bilhej')
|
expect(wrapper.text()).toContain('Om Bilhej')
|
||||||
expect(wrapper.text()).toContain('Bilhej gör det enkelt')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders how-it-works steps', () => {
|
|
||||||
const router = createTestRouter()
|
|
||||||
const wrapper = mount(AboutPage, {
|
|
||||||
global: { plugins: [router] },
|
|
||||||
})
|
|
||||||
expect(wrapper.text()).toContain('Skriv brevet här')
|
|
||||||
expect(wrapper.text()).toContain('Vi postar åt dig')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('links to home page', () => {
|
|
||||||
const router = createTestRouter()
|
|
||||||
const wrapper = mount(AboutPage, {
|
|
||||||
global: { plugins: [router] },
|
|
||||||
})
|
|
||||||
const cta = wrapper.find('a.about__cta-btn')
|
|
||||||
expect(cta.exists()).toBe(true)
|
|
||||||
expect(cta.attributes('href')).toBe('/')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,10 @@ function createTestRouter() {
|
||||||
history: createMemoryHistory(),
|
history: createMemoryHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/om-oss',
|
path: '/om',
|
||||||
name: 'about',
|
name: 'about',
|
||||||
component: { template: '<div>About</div>' },
|
component: { template: '<div>About</div>' },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/om',
|
|
||||||
redirect: '/om-oss',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/kontakt',
|
path: '/kontakt',
|
||||||
name: 'contact',
|
name: 'contact',
|
||||||
|
|
@ -44,7 +40,7 @@ describe('AppFooter', () => {
|
||||||
const links = wrapper.findAll('a')
|
const links = wrapper.findAll('a')
|
||||||
|
|
||||||
expect(links[0].text()).toBe('Om oss')
|
expect(links[0].text()).toBe('Om oss')
|
||||||
expect(links[0].attributes('href')).toBe('/om-oss')
|
expect(links[0].attributes('href')).toBe('/om')
|
||||||
|
|
||||||
expect(links[1].text()).toBe('Kontakt')
|
expect(links[1].text()).toBe('Kontakt')
|
||||||
expect(links[1].attributes('href')).toBe('/kontakt')
|
expect(links[1].attributes('href')).toBe('/kontakt')
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,8 @@ import { mount } from '@vue/test-utils'
|
||||||
import ContactPage from '@/pages/ContactPage.vue'
|
import ContactPage from '@/pages/ContactPage.vue'
|
||||||
|
|
||||||
describe('ContactPage', () => {
|
describe('ContactPage', () => {
|
||||||
it('renders heading and lead', () => {
|
it('renders heading', () => {
|
||||||
const wrapper = mount(ContactPage)
|
const wrapper = mount(ContactPage)
|
||||||
expect(wrapper.text()).toContain('Kontakta oss')
|
expect(wrapper.text()).toContain('Kontakta oss')
|
||||||
expect(wrapper.text()).toContain('klagomål')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders general support email', () => {
|
|
||||||
const wrapper = mount(ContactPage)
|
|
||||||
const link = wrapper.find('a[href="mailto:kontakt@bilhej.se"]')
|
|
||||||
expect(link.exists()).toBe(true)
|
|
||||||
expect(link.text()).toBe('kontakt@bilhej.se')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders complaints email', () => {
|
|
||||||
const wrapper = mount(ContactPage)
|
|
||||||
const link = wrapper.find('a[href="mailto:jcamorling@gmail.com"]')
|
|
||||||
expect(link.exists()).toBe(true)
|
|
||||||
expect(wrapper.text()).toContain('jcamorling@gmail.com')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -337,42 +337,4 @@ describe('OrdersPage', () => {
|
||||||
const badge = wrapper.find('.badge')
|
const badge = wrapper.find('.badge')
|
||||||
expect(badge.classes()).toContain('badge--primary')
|
expect(badge.classes()).toContain('badge--primary')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows expand toggle for long messages and reveals full text', async () => {
|
|
||||||
const longText =
|
|
||||||
'Hej! Jag ville nämna en situation i trafiken där vi båda kanske blev lite frustrerade. Det är lätt att det blir så när man kör bil i rusningstid och tempot blir högt.'
|
|
||||||
const ordersWithLongMessage = [
|
|
||||||
{
|
|
||||||
id: 'c1eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
|
|
||||||
plate: 'ABC123',
|
|
||||||
letterText: longText,
|
|
||||||
status: 'processing',
|
|
||||||
trackingId: null,
|
|
||||||
createdAt: '2026-05-11T12:00:00Z',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
mockOrdersFetch(ordersWithLongMessage)
|
|
||||||
const { wrapper } = mountPage()
|
|
||||||
await new Promise((r) => setTimeout(r, 50))
|
|
||||||
|
|
||||||
const card = wrapper.find('.orders__card')
|
|
||||||
const preview = card.find('.orders__preview')
|
|
||||||
const toggle = card.find('.orders__preview-toggle')
|
|
||||||
|
|
||||||
expect(toggle.exists()).toBe(true)
|
|
||||||
expect(toggle.text()).toBe('Visa mer')
|
|
||||||
expect(preview.classes()).not.toContain('orders__preview--expanded')
|
|
||||||
|
|
||||||
await toggle.trigger('click')
|
|
||||||
|
|
||||||
expect(preview.classes()).toContain('orders__preview--expanded')
|
|
||||||
expect(toggle.text()).toBe('Visa mindre')
|
|
||||||
expect(card.text()).toContain(longText)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not show expand toggle for short messages', async () => {
|
|
||||||
const { wrapper } = mountPage()
|
|
||||||
await new Promise((r) => setTimeout(r, 50))
|
|
||||||
expect(wrapper.find('.orders__preview-toggle').exists()).toBe(false)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@ import { RouterLink } from 'vue-router'
|
||||||
<footer class="app-footer">
|
<footer class="app-footer">
|
||||||
<div class="app-footer__inner">
|
<div class="app-footer__inner">
|
||||||
<p class="app-footer__tagline">
|
<p class="app-footer__tagline">
|
||||||
Skriv brevet här. Vi postar det till rätt bilägare.
|
Bilhej hjälper dig att skicka brev till bilägare via
|
||||||
|
registreringsnummer.
|
||||||
</p>
|
</p>
|
||||||
<nav class="app-footer__links">
|
<nav class="app-footer__links">
|
||||||
<RouterLink to="/om-oss" class="app-footer__link">Om oss</RouterLink>
|
<RouterLink to="/om" class="app-footer__link">Om oss</RouterLink>
|
||||||
<RouterLink to="/kontakt" class="app-footer__link">Kontakt</RouterLink>
|
<RouterLink to="/kontakt" class="app-footer__link">Kontakt</RouterLink>
|
||||||
<RouterLink to="/integritetspolicy" class="app-footer__link"
|
<RouterLink to="/integritetspolicy" class="app-footer__link"
|
||||||
>Integritetspolicy</RouterLink
|
>Integritetspolicy</RouterLink
|
||||||
|
|
|
||||||
|
|
@ -1,225 +1,39 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts"></script>
|
||||||
import { RouterLink } from 'vue-router'
|
|
||||||
|
|
||||||
const highlights = [
|
|
||||||
{
|
|
||||||
title: 'Skriv brevet här',
|
|
||||||
description:
|
|
||||||
'Välj mall eller skriv fritt. Du ser hela brevet innan du betalar 49 kr via Swish.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Registreringsnummer räcker',
|
|
||||||
description:
|
|
||||||
'Du behöver inte veta vem som äger bilen eller var personen bor. Vi kopplar brevet till rätt mottagare.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Vi postar åt dig',
|
|
||||||
description:
|
|
||||||
'Efter betalning hanterar vi utskick manuellt. Du följer status i Mina beställningar och får spårning när brevet skickats.',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="about">
|
<div class="page">
|
||||||
<section class="about__hero">
|
<div class="page__card">
|
||||||
<p class="about__eyebrow">Om oss</p>
|
<h1>Om Bilhej</h1>
|
||||||
<h1 class="about__title">Om Bilhej</h1>
|
<p>
|
||||||
<p class="about__lead">
|
Bilhej är en tjänst som låter dig skicka fysiska brev till fordonsägare
|
||||||
Bilhej gör det enkelt att nå en bilägare med ett fysiskt brev. Du
|
via registreringsnummer.
|
||||||
skriver meddelandet, vi sköter utskick och post.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</div>
|
||||||
|
|
||||||
<section class="about__section">
|
|
||||||
<h2 class="about__section-title">Vad vi gör</h2>
|
|
||||||
<div class="about__prose">
|
|
||||||
<p>
|
|
||||||
Många situationer i trafiken eller på parkeringen är enklare att lösa
|
|
||||||
med ett kort, respektfullt brev än med lapp i vindrutan eller
|
|
||||||
konfrontation på plats. Bilhej är till för det.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Du anger registreringsnummer, skriver vad du vill säga och betalar.
|
|
||||||
Därefter ser vi till att brevet når rätt person med vanlig post. Du
|
|
||||||
behöver inte hantera adress eller jaga upp ägaren själv.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Tjänsten passar till exempel köpförfrågan, tips om något på bilen,
|
|
||||||
vänlig feedback efter trafik eller ett meddelande du formulerar helt
|
|
||||||
själv.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="about__section">
|
|
||||||
<h2 class="about__section-title">Så fungerar det</h2>
|
|
||||||
<div class="about__cards">
|
|
||||||
<article
|
|
||||||
v-for="(item, index) in highlights"
|
|
||||||
:key="item.title"
|
|
||||||
class="about__card"
|
|
||||||
>
|
|
||||||
<span class="about__card-step">Steg {{ index + 1 }}</span>
|
|
||||||
<h3>{{ item.title }}</h3>
|
|
||||||
<p>{{ item.description }}</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="about__section about__section--cta">
|
|
||||||
<div class="about__cta-box">
|
|
||||||
<h2 class="about__cta-title">Redo att skriva?</h2>
|
|
||||||
<p class="about__cta-text">
|
|
||||||
Börja med registreringsnumret på startsidan. Det tar bara några
|
|
||||||
minuter att skriva och betala.
|
|
||||||
</p>
|
|
||||||
<RouterLink to="/" class="btn btn--primary about__cta-btn">
|
|
||||||
Till startsidan
|
|
||||||
</RouterLink>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.about {
|
.page {
|
||||||
max-width: 48rem;
|
max-width: 36rem;
|
||||||
margin: 0 auto;
|
margin: var(--space-3xl) auto 0;
|
||||||
padding: var(--space-3xl) var(--space-lg) var(--space-3xl);
|
padding: 0 var(--space-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__hero {
|
.page__card {
|
||||||
margin-bottom: var(--space-2xl);
|
|
||||||
padding: var(--space-2xl);
|
|
||||||
background: linear-gradient(
|
|
||||||
145deg,
|
|
||||||
var(--color-surface) 0%,
|
|
||||||
#f8faff 55%,
|
|
||||||
var(--color-paper) 100%
|
|
||||||
);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__eyebrow {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 0.06em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: var(--color-primary-dark);
|
|
||||||
background: var(--color-primary-soft);
|
|
||||||
border: 1px solid #bfdbfe;
|
|
||||||
padding: 0.35rem 0.75rem;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__title {
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: clamp(1.75rem, 4vw, 2.25rem);
|
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: -0.02em;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__lead {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.0625rem;
|
|
||||||
line-height: 1.75;
|
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__section {
|
|
||||||
margin-bottom: var(--space-2xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__section-title {
|
|
||||||
margin: 0 0 var(--space-lg) 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__prose p {
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
line-height: 1.75;
|
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__prose p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__cards {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--space-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__card {
|
|
||||||
background: var(--color-surface);
|
background: var(--color-surface);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
border-radius: var(--radius-xl);
|
border-radius: var(--radius-xl);
|
||||||
padding: var(--space-lg);
|
padding: var(--space-xl);
|
||||||
box-shadow: var(--shadow-card);
|
box-shadow: var(--shadow-card);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__card-step {
|
h1 {
|
||||||
display: inline-flex;
|
margin: 0 0 var(--space-md) 0;
|
||||||
margin-bottom: var(--space-sm);
|
font-size: 1.5rem;
|
||||||
padding: 0.2rem 0.65rem;
|
|
||||||
font-size: 0.6875rem;
|
|
||||||
font-weight: 700;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: var(--color-primary-dark);
|
|
||||||
background: var(--color-primary-soft);
|
|
||||||
border: 1px solid #bfdbfe;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__card h3 {
|
p {
|
||||||
margin: 0 0 var(--space-sm) 0;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__card p {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.9375rem;
|
line-height: 1.7;
|
||||||
line-height: 1.65;
|
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__cta-box {
|
|
||||||
padding: var(--space-xl);
|
|
||||||
text-align: center;
|
|
||||||
background: linear-gradient(
|
|
||||||
135deg,
|
|
||||||
var(--color-primary-soft) 0%,
|
|
||||||
#eef2ff 100%
|
|
||||||
);
|
|
||||||
border: 1px solid #bfdbfe;
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__cta-title {
|
|
||||||
margin: 0 0 var(--space-sm) 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
color: var(--color-primary-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__cta-text {
|
|
||||||
margin: 0 0 var(--space-lg) 0;
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
line-height: 1.65;
|
|
||||||
color: var(--color-primary-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.about__cta-btn {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const canSubmit = computed(
|
||||||
)
|
)
|
||||||
|
|
||||||
const GDPR_FOOTER =
|
const GDPR_FOOTER =
|
||||||
'Detta brev skickades via Bilhej. Din adress hämtades från Transportstyrelsens fordonsregister och har raderats efter utskick. För frågor: kontakt@bilhej.se'
|
'Detta brev skickades via Bilhej. Din adress hämtades från Transportstyrelsens fordonsregister och har raderats efter utskick. För frågor: hej@bilhalsning.se'
|
||||||
|
|
||||||
function handleTemplateSelect(template: LetterTemplate) {
|
function handleTemplateSelect(template: LetterTemplate) {
|
||||||
letterText.value = template.body
|
letterText.value = template.body
|
||||||
|
|
|
||||||
|
|
@ -1,143 +1,25 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts"></script>
|
||||||
const contactChannels = [
|
|
||||||
{
|
|
||||||
variant: 'general',
|
|
||||||
title: 'Frågor om tjänsten',
|
|
||||||
description:
|
|
||||||
'Beställningar, betalning, tekniska problem eller allmänna frågor om hur Bilhej fungerar.',
|
|
||||||
email: 'kontakt@bilhej.se',
|
|
||||||
label: 'Skicka e-post',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variant: 'complaints',
|
|
||||||
title: 'Klagomål och synpunkter',
|
|
||||||
description:
|
|
||||||
'Om något gått fel eller du vill lämna ett klagomål direkt till oss som driver tjänsten.',
|
|
||||||
email: 'jcamorling@gmail.com',
|
|
||||||
label: 'Skicka klagomål',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="contact">
|
<div class="page">
|
||||||
<section class="contact__hero">
|
<div class="page__card">
|
||||||
<p class="contact__eyebrow">Kontakt</p>
|
<h1>Kontakta oss</h1>
|
||||||
<h1 class="contact__title">Kontakta oss</h1>
|
<p>
|
||||||
<p class="contact__lead">
|
Har du frågor eller feedback? Hör av dig till oss på
|
||||||
Vi svarar så snart vi kan. Välj rätt adress beroende på om det gäller en
|
<a href="mailto:hej@bilhalsning.se">hej@bilhalsning.se</a>.
|
||||||
vanlig fråga eller ett klagomål.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</div>
|
||||||
|
|
||||||
<section class="contact__section">
|
|
||||||
<div class="contact__cards">
|
|
||||||
<article
|
|
||||||
v-for="channel in contactChannels"
|
|
||||||
:key="channel.email"
|
|
||||||
class="contact__card"
|
|
||||||
:class="`contact__card--${channel.variant}`"
|
|
||||||
>
|
|
||||||
<h2>{{ channel.title }}</h2>
|
|
||||||
<p>{{ channel.description }}</p>
|
|
||||||
<a class="contact__email" :href="`mailto:${channel.email}`">
|
|
||||||
{{ channel.email }}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="btn btn--ghost contact__btn"
|
|
||||||
:href="`mailto:${channel.email}`"
|
|
||||||
>
|
|
||||||
{{ channel.label }}
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="contact__section">
|
|
||||||
<div class="contact__tips">
|
|
||||||
<h2 class="contact__tips-title">Innan du skriver</h2>
|
|
||||||
<ul class="contact__tips-list">
|
|
||||||
<li>
|
|
||||||
Har du en pågående beställning? Kontrollera
|
|
||||||
<strong>Mina beställningar</strong> först. Där ser du status och
|
|
||||||
spårning.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Vid klagomål, skriv gärna med beställnings-ID och
|
|
||||||
registreringsnummer så kan vi hitta ärendet snabbare.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Vi läser all e-post manuellt och återkommer när vi har tittat på
|
|
||||||
ditt ärende.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.contact {
|
.page {
|
||||||
max-width: 48rem;
|
max-width: 36rem;
|
||||||
margin: 0 auto;
|
margin: var(--space-3xl) auto 0;
|
||||||
padding: var(--space-3xl) var(--space-lg) var(--space-3xl);
|
padding: 0 var(--space-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact__hero {
|
.page__card {
|
||||||
margin-bottom: var(--space-2xl);
|
|
||||||
padding: var(--space-2xl);
|
|
||||||
background: linear-gradient(
|
|
||||||
145deg,
|
|
||||||
var(--color-surface) 0%,
|
|
||||||
#f8faff 55%,
|
|
||||||
var(--color-paper) 100%
|
|
||||||
);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__eyebrow {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 0.06em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: var(--color-primary-dark);
|
|
||||||
background: var(--color-primary-soft);
|
|
||||||
border: 1px solid #bfdbfe;
|
|
||||||
padding: 0.35rem 0.75rem;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__title {
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: clamp(1.75rem, 4vw, 2.25rem);
|
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: -0.02em;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__lead {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.0625rem;
|
|
||||||
line-height: 1.75;
|
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__section {
|
|
||||||
margin-bottom: var(--space-2xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__cards {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--space-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__card {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
background: var(--color-surface);
|
background: var(--color-surface);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
border-radius: var(--radius-xl);
|
border-radius: var(--radius-xl);
|
||||||
|
|
@ -145,80 +27,13 @@ const contactChannels = [
|
||||||
box-shadow: var(--shadow-card);
|
box-shadow: var(--shadow-card);
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact__card::before {
|
h1 {
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 4px;
|
|
||||||
background: var(--contact-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__card--general {
|
|
||||||
--contact-accent: linear-gradient(90deg, #1d4ed8, #60a5fa);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__card--complaints {
|
|
||||||
--contact-accent: linear-gradient(90deg, #4338ca, #818cf8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__card h2 {
|
|
||||||
margin: 0 0 var(--space-sm) 0;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__card p {
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
margin: 0 0 var(--space-md) 0;
|
||||||
font-size: 0.9375rem;
|
font-size: 1.5rem;
|
||||||
line-height: 1.65;
|
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact__email {
|
p {
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: var(--space-md);
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-primary);
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__email:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__btn {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__tips {
|
|
||||||
padding: var(--space-xl);
|
|
||||||
background: var(--color-border-light);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__tips-title {
|
|
||||||
margin: 0 0 var(--space-md) 0;
|
|
||||||
font-size: 1.0625rem;
|
|
||||||
color: var(--color-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__tips-list {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 1.25rem;
|
line-height: 1.7;
|
||||||
color: var(--color-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__tips-list li + li {
|
|
||||||
margin-top: var(--space-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact__tips-list li {
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
line-height: 1.65;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const canSubmit = computed(
|
||||||
)
|
)
|
||||||
|
|
||||||
const GDPR_FOOTER =
|
const GDPR_FOOTER =
|
||||||
'Detta brev skickades via Bilhej. Din adress hämtades från Transportstyrelsens fordonsregister och har raderats efter utskick. För frågor: kontakt@bilhej.se'
|
'Detta brev skickades via Bilhej. Din adress hämtades från Transportstyrelsens fordonsregister och har raderats efter utskick. För frågor: hej@bilhalsning.se'
|
||||||
|
|
||||||
function handleTemplateSelect(template: LetterTemplate) {
|
function handleTemplateSelect(template: LetterTemplate) {
|
||||||
letterText.value = template.body
|
letterText.value = template.body
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -12,27 +12,6 @@ const loading = ref(true)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const actionError = ref('')
|
const actionError = ref('')
|
||||||
const cancellingId = ref<string | null>(null)
|
const cancellingId = ref<string | null>(null)
|
||||||
const expandedPreviewIds = ref<Set<string>>(new Set())
|
|
||||||
|
|
||||||
const PREVIEW_CHAR_LIMIT = 120
|
|
||||||
|
|
||||||
function isLongMessage(text: string): boolean {
|
|
||||||
return text.length > PREVIEW_CHAR_LIMIT
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPreviewExpanded(orderId: string): boolean {
|
|
||||||
return expandedPreviewIds.value.has(orderId)
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePreview(orderId: string) {
|
|
||||||
const next = new Set(expandedPreviewIds.value)
|
|
||||||
if (next.has(orderId)) {
|
|
||||||
next.delete(orderId)
|
|
||||||
} else {
|
|
||||||
next.add(orderId)
|
|
||||||
}
|
|
||||||
expandedPreviewIds.value = next
|
|
||||||
}
|
|
||||||
|
|
||||||
const pendingOrders = computed(() =>
|
const pendingOrders = computed(() =>
|
||||||
orders.value.filter((order) => order.status === 'pending_payment'),
|
orders.value.filter((order) => order.status === 'pending_payment'),
|
||||||
|
|
@ -171,22 +150,7 @@ onMounted(loadOrders)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="orders__preview-box">
|
<div class="orders__preview-box">
|
||||||
<p
|
<p class="orders__preview">{{ order.letterText }}</p>
|
||||||
class="orders__preview"
|
|
||||||
:class="{
|
|
||||||
'orders__preview--expanded': isPreviewExpanded(order.id),
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ order.letterText }}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
v-if="isLongMessage(order.letterText)"
|
|
||||||
type="button"
|
|
||||||
class="orders__preview-toggle"
|
|
||||||
@click="togglePreview(order.id)"
|
|
||||||
>
|
|
||||||
{{ isPreviewExpanded(order.id) ? 'Visa mindre' : 'Visa mer' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="orders__order-date">
|
<p class="orders__order-date">
|
||||||
|
|
@ -269,22 +233,7 @@ onMounted(loadOrders)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="orders__preview-box">
|
<div class="orders__preview-box">
|
||||||
<p
|
<p class="orders__preview">{{ order.letterText }}</p>
|
||||||
class="orders__preview"
|
|
||||||
:class="{
|
|
||||||
'orders__preview--expanded': isPreviewExpanded(order.id),
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ order.letterText }}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
v-if="isLongMessage(order.letterText)"
|
|
||||||
type="button"
|
|
||||||
class="orders__preview-toggle"
|
|
||||||
@click="togglePreview(order.id)"
|
|
||||||
>
|
|
||||||
{{ isPreviewExpanded(order.id) ? 'Visa mindre' : 'Visa mer' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="orders__order-date">
|
<p class="orders__order-date">
|
||||||
|
|
@ -425,29 +374,6 @@ onMounted(loadOrders)
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.orders__preview--expanded {
|
|
||||||
display: block;
|
|
||||||
-webkit-line-clamp: unset;
|
|
||||||
line-clamp: unset;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orders__preview-toggle {
|
|
||||||
margin-top: var(--space-sm);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-primary);
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orders__preview-toggle:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orders__order-date {
|
.orders__order-date {
|
||||||
margin: 0 0 var(--space-sm) 0;
|
margin: 0 0 var(--space-sm) 0;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
|
|
|
||||||
|
|
@ -84,14 +84,10 @@ const router = createRouter({
|
||||||
meta: { guestOnly: true },
|
meta: { guestOnly: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/om-oss',
|
path: '/om',
|
||||||
name: 'about',
|
name: 'about',
|
||||||
component: AboutPage,
|
component: AboutPage,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/om',
|
|
||||||
redirect: '/om-oss',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/kontakt',
|
path: '/kontakt',
|
||||||
name: 'contact',
|
name: 'contact',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue