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>
This commit is contained in:
parent
258f6f5a17
commit
ec62ba7673
2 changed files with 316 additions and 0 deletions
58
frontend/src/__tests__/TermsOfServicePage.spec.ts
Normal file
58
frontend/src/__tests__/TermsOfServicePage.spec.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import { createRouter, createMemoryHistory } from 'vue-router'
|
||||||
|
import TermsOfServicePage from '@/pages/TermsOfServicePage.vue'
|
||||||
|
|
||||||
|
function createTestRouter() {
|
||||||
|
return createRouter({
|
||||||
|
history: createMemoryHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/villkor',
|
||||||
|
name: 'terms',
|
||||||
|
component: TermsOfServicePage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/integritetspolicy',
|
||||||
|
name: 'privacy',
|
||||||
|
component: { template: '<div>Integritet</div>' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/kontakt',
|
||||||
|
name: 'contact',
|
||||||
|
component: { template: '<div>Kontakt</div>' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('TermsOfServicePage', () => {
|
||||||
|
it('renders title and lead', () => {
|
||||||
|
const router = createTestRouter()
|
||||||
|
const wrapper = mount(TermsOfServicePage, {
|
||||||
|
global: { plugins: [router] },
|
||||||
|
})
|
||||||
|
expect(wrapper.text()).toContain('Användarvillkor')
|
||||||
|
expect(wrapper.text()).toContain('49 kr')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('describes payment and order rules', () => {
|
||||||
|
const router = createTestRouter()
|
||||||
|
const wrapper = mount(TermsOfServicePage, {
|
||||||
|
global: { plugins: [router] },
|
||||||
|
})
|
||||||
|
expect(wrapper.text()).toContain('Swish')
|
||||||
|
expect(wrapper.text()).toContain('Obetalda beställningar kan redigeras')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to privacy policy and support email', () => {
|
||||||
|
const router = createTestRouter()
|
||||||
|
const wrapper = mount(TermsOfServicePage, {
|
||||||
|
global: { plugins: [router] },
|
||||||
|
})
|
||||||
|
expect(wrapper.find('a[href="/integritetspolicy"]').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('a[href="mailto:support@bilhej.se"]').exists()).toBe(
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
258
frontend/src/pages/TermsOfServicePage.vue
Normal file
258
frontend/src/pages/TermsOfServicePage.vue
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { RouterLink } from 'vue-router'
|
||||||
|
|
||||||
|
const sections = [
|
||||||
|
{
|
||||||
|
id: 'tjansten',
|
||||||
|
title: 'Tjänsten',
|
||||||
|
paragraphs: [
|
||||||
|
'Bilhej (bilhej.se) är en tjänst där du som avsändare kan beställa utskick av ett fysiskt brev till en fordonsägare via registreringsnummer. Vi är mellanhand för att posta brevet. Vi är inte part i innehållet mellan dig och mottagaren.',
|
||||||
|
'Genom att skapa konto, beställa eller betala accepterar du dessa villkor.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'konto',
|
||||||
|
title: 'Konto',
|
||||||
|
paragraphs: [
|
||||||
|
'Du ansvarar för att uppgifterna i ditt konto stämmer och att ditt lösenord hålls hemligt.',
|
||||||
|
'Du måste vara minst 18 år, eller ha målsmans tillstånd, för att använda tjänsten.',
|
||||||
|
'Vi får stänga av eller avsluta konton som bryter mot villkoren eller missbrukar tjänsten.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'bestallning',
|
||||||
|
title: 'Beställning och betalning',
|
||||||
|
paragraphs: [
|
||||||
|
'Priset för ett brev framgår i tjänsten (för närvarande 49 kr). Betalning sker via Swish enligt instruktionerna i beställningsflödet.',
|
||||||
|
'Du ser hela brevet innan du betalar. Kontrollera registreringsnummer och text noga.',
|
||||||
|
'Obetalda beställningar kan redigeras eller avbrytas i Mina beställningar. Efter betalning behandlas beställningen för utskick.',
|
||||||
|
'Vi kan avvisa eller stoppa beställningar med olagligt, kränkande, hotfullt eller uppenbart missbrukande innehåll. Betald avgift återbetalas i så fall om utskick inte hunnit ske.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'innehåll',
|
||||||
|
title: 'Innehåll i brevet',
|
||||||
|
paragraphs: [
|
||||||
|
'Du ansvarar själv för texten du skickar. Brevet ska vara respektfullt och följa svensk lag.',
|
||||||
|
'Du får inte använda tjänsten för trakasserier, hot, olaglig reklam, spridning av personuppgifter om tredje man, eller annat otillbörligt innehåll.',
|
||||||
|
'Om du anger kontaktuppgifter i brevet kan mottagaren svara dig direkt. Annars är avsändaren anonym gentemot mottagaren.',
|
||||||
|
'Du garanterar att du har rätt att skicka innehållet och ger oss rätt att skriva ut och posta brevet en gång för att fullgöra beställningen.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'utskick',
|
||||||
|
title: 'Utskick och leverans',
|
||||||
|
paragraphs: [
|
||||||
|
'Efter betalning hanterar vi utskick av brevet. Det sker normalt inom några vardagar, men exakt tid kan variera.',
|
||||||
|
'Vi garanterar inte att mottagaren läser eller svarar på brevet.',
|
||||||
|
'När spårning finns tillgänglig visas den i Mina beställningar. Postens leveranstider ligger utanför vår kontroll.',
|
||||||
|
'Om registreringsnumret är felaktigt eller mottagaren inte kan nås kan utskick misslyckas. Kontakta support@bilhej.se så hjälper vi dig.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reklamation',
|
||||||
|
title: 'Reklamation och återbetalning',
|
||||||
|
paragraphs: [
|
||||||
|
'Har något blivit fel? Kontakta support@bilhej.se så snart som möjligt och ange beställnings-ID.',
|
||||||
|
'Om brevet inte skickats kan vi i normalfallet återbetala eller korrigera beställningen.',
|
||||||
|
'Efter att brevet postats kan återbetalning normalt inte ske, eftersom tjänsten då är utförd.',
|
||||||
|
'Som konsument har du enligt lag rätt att reklamera fel i tjänsten inom tre år. Kontakta oss först så löser vi det i god tro.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ansvar',
|
||||||
|
title: 'Ansvar',
|
||||||
|
paragraphs: [
|
||||||
|
'Tjänsten tillhandahålls i befintligt skick. Vi ansvarar inte för indirekta skador, utebliven vinst eller följder av innehållet i brev du skrivit.',
|
||||||
|
'Vårt ansvar gentemot dig som konsument begränsas inte i strid med tvingande lag.',
|
||||||
|
'Du håller Bilhej skadeslöst från krav från tredje part som beror på ditt innehåll eller ditt brott mot dessa villkor, i den utsträckning lagen tillåter.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'integritet',
|
||||||
|
title: 'Personuppgifter',
|
||||||
|
paragraphs: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'andringar',
|
||||||
|
title: 'Ändringar av villkoren',
|
||||||
|
paragraphs: [
|
||||||
|
'Vi kan uppdatera villkoren när tjänsten ändras. Fortsatt användning efter att ändringar publicerats innebär att du accepterar de uppdaterade villkoren.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tvist',
|
||||||
|
title: 'Tillämplig lag och kontakt',
|
||||||
|
paragraphs: [
|
||||||
|
'Svensk lag gäller för dessa villkor. Tvister ska i första hand lösas i samförstånd. Konsument kan vända sig till Allmänna reklamationsnämnden (arn.se).',
|
||||||
|
'Frågor om tjänsten: support@bilhej.se. Allmän kontakt: kontakt@bilhej.se. Klagomål: klagomal@bilhej.se.',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="terms">
|
||||||
|
<section class="terms__hero">
|
||||||
|
<p class="terms__eyebrow">Villkor</p>
|
||||||
|
<h1 class="terms__title">Användarvillkor</h1>
|
||||||
|
<p class="terms__lead">
|
||||||
|
Villkor för att använda Bilhej när du beställer utskick av brev till
|
||||||
|
fordonsägare.
|
||||||
|
</p>
|
||||||
|
<p class="terms__updated">Senast uppdaterad: 22 maj 2026</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section
|
||||||
|
v-for="section in sections"
|
||||||
|
:key="section.id"
|
||||||
|
:id="section.id"
|
||||||
|
class="terms__section"
|
||||||
|
>
|
||||||
|
<h2 class="terms__section-title">{{ section.title }}</h2>
|
||||||
|
<div class="terms__prose">
|
||||||
|
<p v-if="section.id === 'integritet'">
|
||||||
|
Vi behandlar personuppgifter enligt vår
|
||||||
|
<RouterLink to="/integritetspolicy" class="terms__link"
|
||||||
|
>integritetspolicy</RouterLink
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
<p v-for="(paragraph, index) in section.paragraphs" :key="index">
|
||||||
|
{{ paragraph }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="terms__section terms__section--cta">
|
||||||
|
<div class="terms__cta-box">
|
||||||
|
<h2 class="terms__cta-title">Frågor om villkoren?</h2>
|
||||||
|
<p class="terms__cta-text">
|
||||||
|
Hör av dig via
|
||||||
|
<a class="terms__mailto" href="mailto:support@bilhej.se"
|
||||||
|
>support@bilhej.se</a
|
||||||
|
>
|
||||||
|
eller vår
|
||||||
|
<RouterLink to="/kontakt" class="terms__link">kontaktsida</RouterLink>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.terms {
|
||||||
|
max-width: 48rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: var(--space-3xl) var(--space-lg) var(--space-3xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__hero {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__lead {
|
||||||
|
margin: 0 0 var(--space-md) 0;
|
||||||
|
font-size: 1.0625rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: var(--color-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__updated {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: var(--color-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__section {
|
||||||
|
margin-bottom: var(--space-2xl);
|
||||||
|
scroll-margin-top: var(--space-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__section-title {
|
||||||
|
margin: 0 0 var(--space-md) 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__prose p {
|
||||||
|
margin: 0 0 var(--space-md) 0;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: var(--color-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__prose p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__cta-title {
|
||||||
|
margin: 0 0 var(--space-sm) 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--color-primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__cta-text {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.65;
|
||||||
|
color: var(--color-primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__mailto,
|
||||||
|
.terms__link {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms__mailto:hover,
|
||||||
|
.terms__link:hover {
|
||||||
|
color: var(--color-primary-dark);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue