Merge pull request #4468 from Ocelot-Social-Community/4464-flexible-footer-links

feat: 🍰 Flexible Footer Links
This commit is contained in:
Wolfgang Huß 2021-06-03 18:03:20 +02:00 committed by GitHub
commit a99b9ed052
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 267 additions and 36 deletions

View File

@ -1,7 +1,13 @@
// this file is duplicated in `backend/src/config/links.js` and `webapp/constants/links.js` and replaced on rebranding
export default {
ORGANIZATION: 'https://ocelot.social',
DONATE: 'https://ocelot-social.herokuapp.com/donations',
FAQ: 'https://ocelot.social',
SUPPORT: 'https://ocelot.social',
// on null or empty strings internal imprint is used, see 'webapp/locales/html/'
DONATE: 'https://ocelot-social.herokuapp.com/donations', // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly
IMPRINT: 'https://ocelot-social.herokuapp.com/imprint', // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly
TERMS_AND_CONDITIONS: null,
CODE_OF_CONDUCT: null,
DATA_PRIVACY: null,
FAQ: 'https://ocelot.social',
}

View File

@ -1,6 +1,6 @@
import { config, mount } from '@vue/test-utils'
import PageFooter from './PageFooter.vue'
import links from '~/constants/links.js'
import linksDefault from '~/constants/links.js'
const localVue = global.localVue
@ -8,6 +8,7 @@ config.stubs['nuxt-link'] = '<span class="nuxt-link"><slot /></span>'
describe('PageFooter.vue', () => {
let mocks
let wrapper
beforeEach(() => {
mocks = {
@ -15,30 +16,118 @@ describe('PageFooter.vue', () => {
$env: {
VERSION: 'v1.0.0',
},
links,
}
})
describe('mount', () => {
let wrapper
const Wrapper = () => {
return mount(PageFooter, { mocks, localVue })
}
beforeEach(() => {
wrapper = Wrapper()
describe('links.js', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders four links', () => {
expect(wrapper.findAll('a')).toHaveLength(4)
})
it('renders three nuxt-links', () => {
expect(wrapper.findAll('.nuxt-link')).toHaveLength(3)
})
it('renders version', () => {
expect(wrapper.find('.ds-footer').text()).toContain('v1.0.0')
})
})
it('renders three links', () => {
expect(wrapper.findAll('a')).toHaveLength(3)
describe('inflexible links', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders ORGANIZATION', () => {
expect(wrapper.find('a[data-test="organization-link"]').exists()).toBe(true)
})
it('renders version', () => {
expect(wrapper.find('a[data-test="version-link"]').exists()).toBe(true)
})
})
it('renders four nuxt-links', () => {
expect(wrapper.findAll('.nuxt-link')).toHaveLength(4)
describe('flexible links not set', () => {
beforeEach(async () => {
const links = {
...linksDefault,
IMPRINT: null,
TERMS_AND_CONDITIONS: null,
CODE_OF_CONDUCT: null,
DATA_PRIVACY: null,
FAQ: null,
}
wrapper = Wrapper()
wrapper.setData({ links })
await wrapper.vm.$nextTick()
})
it('renders IMPRINT as nuxt-link', () => {
expect(wrapper.find('span[data-test="imprint-nuxt-link"]').exists()).toBe(true)
})
it('renders TERMS_AND_CONDITIONS as nuxt-link', () => {
expect(wrapper.find('span[data-test="terms-nuxt-link"]').exists()).toBe(true)
})
it('renders CODE_OF_CONDUCT as nuxt-link', () => {
expect(wrapper.find('span[data-test="code-nuxt-link"]').exists()).toBe(true)
})
it('renders DATA_PRIVACY as nuxt-link', () => {
expect(wrapper.find('span[data-test="data-nuxt-link"]').exists()).toBe(true)
})
it('renders FAQ as nuxt-link', () => {
expect(wrapper.find('span[data-test="faq-nuxt-link"]').exists()).toBe(true)
})
})
it('renders version', () => {
expect(wrapper.find('.ds-footer').text()).toContain('v1.0.0')
describe('flexible links set', () => {
beforeEach(async () => {
const links = {
...linksDefault,
IMPRINT: 'https://ocelot.social/IMPRINT',
TERMS_AND_CONDITIONS: 'https://ocelot.social/TERMS_AND_CONDITIONS',
CODE_OF_CONDUCT: 'https://ocelot.social/CODE_OF_CONDUCT',
DATA_PRIVACY: 'https://ocelot.social/DATA_PRIVACY',
FAQ: 'https://ocelot.social/FAQ',
}
wrapper = Wrapper()
wrapper.setData({ links })
await wrapper.vm.$nextTick()
})
it('renders IMPRINT as "a" tag link', () => {
expect(wrapper.find(`a[href="https://ocelot.social/IMPRINT"]`).exists()).toBe(true)
})
it('renders TERMS_AND_CONDITIONS as "a" tag link', () => {
expect(wrapper.find(`a[href="https://ocelot.social/TERMS_AND_CONDITIONS"]`).exists()).toBe(
true,
)
})
it('renders CODE_OF_CONDUCT as "a" tag link', () => {
expect(wrapper.find(`a[href="https://ocelot.social/CODE_OF_CONDUCT"]`).exists()).toBe(true)
})
it('renders DATA_PRIVACY as "a" tag link', () => {
expect(wrapper.find(`a[href="https://ocelot.social/DATA_PRIVACY"]`).exists()).toBe(true)
})
it('renders FAQ as "a" tag link', () => {
expect(wrapper.find(`a[href="https://ocelot.social/FAQ"]`).exists()).toBe(true)
})
})
})
})

View File

@ -1,26 +1,67 @@
<template>
<div id="footer" class="ds-footer">
<a :href="links.ORGANIZATION" target="_blank" v-html="$t('site.made')"></a>
<!-- made with -->
<a :href="links.ORGANIZATION" target="_blank" data-test="organization-link">
{{ $t('site.made') }}
</a>
<span>-</span>
<nuxt-link to="/imprint">
<!-- imprint -->
<nuxt-link v-if="noLinkDefined(links.IMPRINT)" to="/imprint" data-test="imprint-nuxt-link">
{{ $t('site.imprint') }}
</nuxt-link>
<a v-else :href="links.IMPRINT" target="_blank">
{{ $t('site.imprint') }}
</a>
<span>-</span>
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAndConditions') }}</nuxt-link>
<!-- terms and conditions -->
<nuxt-link
v-if="noLinkDefined(links.TERMS_AND_CONDITIONS)"
to="/terms-and-conditions"
data-test="terms-nuxt-link"
>
{{ $t('site.termsAndConditions') }}
</nuxt-link>
<a v-else :href="links.TERMS_AND_CONDITIONS" target="_blank">
{{ $t('site.termsAndConditions') }}
</a>
<span>-</span>
<nuxt-link to="/code-of-conduct">{{ $t('site.code-of-conduct') }}</nuxt-link>
<!-- code of conduct -->
<nuxt-link
v-if="noLinkDefined(links.CODE_OF_CONDUCT)"
to="/code-of-conduct"
data-test="code-nuxt-link"
>
{{ $t('site.code-of-conduct') }}
</nuxt-link>
<a v-else :href="links.CODE_OF_CONDUCT" target="_blank">
{{ $t('site.code-of-conduct') }}
</a>
<span>-</span>
<nuxt-link to="/data-privacy">
<!-- data privacy -->
<nuxt-link
v-if="noLinkDefined(links.DATA_PRIVACY)"
to="/data-privacy"
data-test="data-nuxt-link"
>
{{ $t('site.data-privacy') }}
</nuxt-link>
<a v-else :href="links.DATA_PRIVACY" target="_blank">
{{ $t('site.data-privacy') }}
</a>
<span>-</span>
<a :href="links.FAQ" target="_blank">
<!-- faq -->
<nuxt-link v-if="noLinkDefined(links.FAQ)" to="/faq" data-test="faq-nuxt-link">
{{ $t('site.faq') }}
</nuxt-link>
<a v-else :href="links.FAQ" target="_blank">
{{ $t('site.faq') }}
</a>
<span>-</span>
<!-- version -->
<a
href="https://github.com/Ocelot-Social-Community/Ocelot-Social/blob/master/CHANGELOG.md"
target="_blank"
data-test="version-link"
>
{{ version }}
</a>
@ -29,10 +70,16 @@
<script>
import links from '~/constants/links.js'
export default {
data() {
return { links, version: `v${this.$env.VERSION}` }
},
methods: {
noLinkDefined(link) {
return !link || link.length === 0
},
},
}
</script>

View File

@ -1,7 +1,13 @@
// this file is duplicated in `backend/src/config/links.js` and `webapp/constants/links.js` and replaced on rebranding
export default {
ORGANIZATION: 'https://ocelot.social',
DONATE: 'https://ocelot-social.herokuapp.com/donations',
FAQ: 'https://ocelot.social',
SUPPORT: 'https://ocelot.social',
// on null or empty strings internal imprint is used, see 'webapp/locales/html/'
DONATE: 'https://ocelot-social.herokuapp.com/donations', // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly
IMPRINT: 'https://ocelot-social.herokuapp.com/imprint', // we use 'ocelot-social.herokuapp.com' at the moment, because redirections of 'ocelot.social' subpages are not working correctly
TERMS_AND_CONDITIONS: null,
CODE_OF_CONDUCT: null,
DATA_PRIVACY: null,
FAQ: 'https://ocelot.social',
}

View File

@ -771,7 +771,7 @@
"faq": "FAQ",
"germany": "Deutschland",
"imprint": "Impressum",
"made": "Mit &#10084; gemacht",
"made": "Mit ❤️ gemacht",
"register": "Registernummer",
"responsible": "Verantwortlich für Inhalte dieser Seite (§ 55 Abs. 2 RStV)",
"taxident": "Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz (Deutschland)",

View File

@ -771,7 +771,7 @@
"faq": "FAQ",
"germany": "Germany",
"imprint": "Imprint",
"made": "Made with &#10084;",
"made": "Made with ❤️",
"register": "Registry number",
"responsible": "responsible for contents of this page (§ 55 Abs. 2 RStV)",
"taxident": "USt-ID. according to §27a of the German Sales Tax Law:",

View File

@ -694,7 +694,7 @@
"faq": "Preguntas más frecuentes",
"germany": "Alemania",
"imprint": "Pie de imprenta",
"made": "Hecho con &#10084;",
"made": "Hecho con ❤️",
"register": "Número de registro",
"responsible": "Responsable según § 55 Abs. 2 RStV (Alemania)",
"taxident": "Número de identificación del impuesto sobre el valor añadido según el § 27 a de la Ley del Impuesto sobre el Valor Añadido (Alemania)",

View File

@ -662,7 +662,7 @@
"faq": "FAQ",
"germany": "Allemagne",
"imprint": "Mentions légales",
"made": "Fabriqué avec &#10084;",
"made": "Fabriqué avec ❤️",
"register": "Numéro de registre",
"responsible": "Responsable selon § 55 Abs. 2 RStV (Allemagne)",
"taxident": "Numéro d'identification à la taxe sur la valeur ajoutée selon § 27 a de la loi sur la taxe sur la valeur ajoutée (Allemagne)",

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Ich bin der Inhalt vom Verhaltenskodex</p>

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Das hier wäre der Inhalt der Datenschutzbestimmungen</p>

View File

@ -0,0 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Hier stehen die FAQs</p>

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Ich bin das Impressum</p>

View File

@ -1,11 +1,13 @@
import termsAndConditions from './terms-and-conditions.html'
import codeOfConduct from './code-of-conduct.html'
import dataPrivacy from './data-privacy.html'
import faq from './faq.html'
import imprint from './imprint.html'
export default {
termsAndConditions,
codeOfConduct,
dataPrivacy,
faq,
imprint,
}

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Ich bin der Inhalt der Seite "Nutzungsbedingungen"</p>

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>I am the content of the code of conduct</p>

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>This would be our data privacy section</p>

View File

@ -0,0 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>Here are the FAQs</p>

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>I am the imprint</p>

View File

@ -1,11 +1,13 @@
import termsAndConditions from './terms-and-conditions.html'
import codeOfConduct from './code-of-conduct.html'
import dataPrivacy from './data-privacy.html'
import faq from './faq.html'
import imprint from './imprint.html'
export default {
termsAndConditions,
codeOfConduct,
dataPrivacy,
faq,
imprint,
}

View File

@ -1 +1,3 @@
<!-- this file is replaced on rebranding -->
<p>I am the content of the page "terms and conditions"<p>

View File

@ -612,7 +612,7 @@
"faq": null,
"germany": "Germania",
"imprint": "Impressum",
"made": "Con &#10084; fatto",
"made": "Con ❤️ fatto",
"register": "numero di registro",
"responsible": "Responsabile ai sensi del § 55 Abs. 2 RStV (Germania)",
"taxident": "Numero di identificazione dell'imposta sul valore aggiunto ai sensi del § 27 a Legge sull'imposta sul valore aggiunto (Germania)",

View File

@ -165,7 +165,7 @@
"director": "Directeur",
"germany": "Duitsland",
"imprint": "Afdruk",
"made": "Met &#10084; gemaakt",
"made": "Met ❤️ gemaakt",
"register": "inschrijfnummer",
"responsible": "Verantwoordelijk volgens § 55 Abs. 2 RStV (Duitsland).",
"taxident": "Identificatienummer voor de belasting over de toegevoegde waarde overeenkomstig § 27 a Wet op de belasting over de toegevoegde waarde (Duitsland).",

View File

@ -350,7 +350,7 @@
"director": "Dyrektor zarządzający",
"germany": "Niemcy",
"imprint": "Nadruk",
"made": "Z &#10084; zrobiony",
"made": "Z ❤️ zrobiony",
"register": "numer rejestracyjny",
"responsible": "Odpowiedzialny zgodnie z § 55 Abs. 2 RStV (Niemcy)",
"taxident": "Numer identyfikacyjny podatku od wartości dodanej zgodnie z § 27 a Ustawa o podatku od wartości dodanej (Niemcy)",

View File

@ -647,7 +647,7 @@
"faq": "FAQ",
"germany": "Alemanha",
"imprint": "Impressão",
"made": "Feito com &#10084;",
"made": "Feito com ❤️",
"register": "número de registo",
"responsible": "Responsável segundo § 55 Abs. 2 RStV (Alemanha) ",
"taxident": "Número de identificação do imposto sobre o valor acrescentado de acordo com o § 27 da Lei do Imposto sobre o Valor Acrescentado (Alemanha)",

View File

@ -694,7 +694,7 @@
"faq": "ЧаВо (FAQ)",
"germany": "Германия",
"imprint": "Импрессум",
"made": "Сделано с &#10084;",
"made": "Сделано с ❤️",
"register": "Регистрационный номер",
"responsible": "ответственный за содержание этой страницы (§ 55 Abs. 2 RStV)",
"taxident": "UST-ID. в соответствии с §27a Закона о налоге с продаж Германии:",

View File

@ -1,6 +1,6 @@
<template>
<div>
<ds-space>
<ds-space margin="small">
<ds-heading tag="h2">{{ $t('site.code-of-conduct') }}</ds-heading>
</ds-space>
<ds-container>

View File

@ -1,9 +1,8 @@
<template>
<div>
<ds-space>
<ds-space margin="small">
<ds-heading tag="h2">{{ $t('site.data-privacy') }}</ds-heading>
</ds-space>
<ds-container>
<div v-html="$t('html.dataPrivacy')" />
</ds-container>

38
webapp/pages/faq.spec.js Normal file
View File

@ -0,0 +1,38 @@
import { mount } from '@vue/test-utils'
import Faq from './faq.vue'
import VueMeta from 'vue-meta'
const localVue = global.localVue
localVue.use(VueMeta, { keyName: 'head' })
describe('faq.vue', () => {
let wrapper
let mocks
beforeEach(() => {
mocks = {
$t: (t) => t,
}
})
describe('mount', () => {
const Wrapper = () => {
return mount(Faq, {
mocks,
localVue,
})
}
beforeEach(() => {
wrapper = Wrapper()
})
it('renders', () => {
expect(wrapper.is('div')).toBe(true)
})
it('has correct <head> content', () => {
expect(wrapper.vm.$metaInfo.title).toBe('site.faq')
})
})
})

21
webapp/pages/faq.vue Normal file
View File

@ -0,0 +1,21 @@
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h2">{{ $t('site.faq') }}</ds-heading>
</ds-space>
<ds-container>
<div v-html="$t('html.faq')" />
</ds-container>
</div>
</template>
<script>
export default {
layout: 'basic',
head() {
return {
title: this.$t('site.faq'),
}
},
}
</script>

View File

@ -1,9 +1,8 @@
<template>
<div>
<ds-space>
<ds-space margin="small">
<ds-heading tag="h2">{{ $t('site.imprint') }}</ds-heading>
</ds-space>
<ds-container>
<div v-html="$t('html.imprint')" />
</ds-container>

View File

@ -1,6 +1,6 @@
<template>
<div>
<ds-space>
<ds-space margin="small">
<ds-heading tag="h2">{{ $t('site.termsAndConditions') }}</ds-heading>
</ds-space>
<ds-container>