Client - init privacy policy and instance description
This commit is contained in:
@ -46,16 +46,24 @@
|
||||
{{ weather_provider.name }}
|
||||
</a>
|
||||
</div>
|
||||
<template v-if="appConfig.about">
|
||||
<p class="about-instance">{{ $t('about.ABOUT_THIS_INSTANCE') }}</p>
|
||||
<div
|
||||
v-html="snarkdown(linkifyAndClean(appConfig.about))"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import snarkdown from 'snarkdown'
|
||||
import { ComputedRef, computed, capitalize } from 'vue'
|
||||
|
||||
import { ROOT_STORE } from '@/store/constants'
|
||||
import { TAppConfig } from '@/types/application'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { linkifyAndClean } from '@/utils/inputs'
|
||||
|
||||
const store = useStore()
|
||||
const appConfig: ComputedRef<TAppConfig> = computed(
|
||||
@ -84,11 +92,17 @@
|
||||
|
||||
.about-text {
|
||||
margin-top: 200px;
|
||||
margin-right: 100px;
|
||||
@media screen and (max-width: $small-limit) {
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.fa-padding {
|
||||
padding-right: $default-padding;
|
||||
}
|
||||
.about-instance {
|
||||
font-weight: bold;
|
||||
margin-top: $default-margin*3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -73,6 +73,42 @@
|
||||
:disabled="!edition"
|
||||
/>
|
||||
</label>
|
||||
<label class="about-label" for="about">
|
||||
{{ $t('admin.ABOUT.TEXT') }}:
|
||||
</label>
|
||||
<span class="textarea-description">
|
||||
{{ $t('admin.ABOUT.DESCRIPTION') }}
|
||||
</span>
|
||||
<textarea
|
||||
v-if="edition"
|
||||
id="about"
|
||||
name="about"
|
||||
rows="10"
|
||||
v-model="appData.about"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-html="snarkdown(linkifyAndClean(appData.about ? appData.about : $t('admin.NO_TEXT_ENTERED')))"
|
||||
class="textarea-content"
|
||||
/>
|
||||
<label class="privacy-policy-label" for="privacy_policy">
|
||||
{{ capitalize($t('privacy_policy.TITLE')) }}:
|
||||
</label>
|
||||
<span class="textarea-description">
|
||||
{{ $t('admin.PRIVACY_POLICY_DESCRIPTION') }}
|
||||
</span>
|
||||
<textarea
|
||||
v-if="edition"
|
||||
id="privacy_policy"
|
||||
name="privacy_policy"
|
||||
rows="20"
|
||||
v-model="appData.privacy_policy"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-html="snarkdown(linkifyAndClean(appData.privacy_policy ? appData.privacy_policy : $t('admin.NO_TEXT_ENTERED')))"
|
||||
class="textarea-content"
|
||||
/>
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<div class="form-buttons" v-if="edition">
|
||||
<button class="confirm" type="submit">
|
||||
@ -100,8 +136,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import snarkdown from 'snarkdown'
|
||||
import {
|
||||
ComputedRef,
|
||||
capitalize,
|
||||
computed,
|
||||
reactive,
|
||||
withDefaults,
|
||||
@ -114,6 +152,7 @@
|
||||
import { TAppConfig, TAppConfigForm } from '@/types/application'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getFileSizeInMB } from '@/utils/files'
|
||||
import { linkifyAndClean } from '@/utils/inputs'
|
||||
|
||||
interface Props {
|
||||
appConfig: TAppConfig
|
||||
@ -133,6 +172,8 @@
|
||||
max_single_file_size: 0,
|
||||
max_zip_file_size: 0,
|
||||
gpx_limit_import: 0,
|
||||
about: '',
|
||||
privacy_policy: '',
|
||||
})
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
@ -150,9 +191,15 @@
|
||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
(appData[key] = getFileSizeInMB(appConfig[key]))
|
||||
: // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
: ['about', 'privacy_policy'].includes(key)
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
(appData[key] = appConfig[key])
|
||||
? appData[key] = appConfig[key]!== null
|
||||
? appConfig[key]
|
||||
: ''
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
: (appData[key] = appConfig[key])
|
||||
})
|
||||
}
|
||||
function onCancel() {
|
||||
@ -171,16 +218,30 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/scss/vars.scss';
|
||||
|
||||
.user-limit-help {
|
||||
display: flex;
|
||||
span {
|
||||
#admin-app {
|
||||
.user-limit-help {
|
||||
display: flex;
|
||||
span {
|
||||
font-style: italic;
|
||||
}
|
||||
.fa-info-circle {
|
||||
margin-right: $default-margin;
|
||||
}
|
||||
}
|
||||
.no-contact {
|
||||
font-style: italic;
|
||||
}
|
||||
.fa-info-circle {
|
||||
margin-right: $default-margin;
|
||||
|
||||
textarea {
|
||||
margin-bottom: $default-padding;
|
||||
}
|
||||
}
|
||||
.no-contact {
|
||||
font-style: italic;
|
||||
.textarea-description {
|
||||
font-style: italic;
|
||||
}
|
||||
.textarea-content {
|
||||
margin-bottom: $default-margin;
|
||||
padding: $default-padding;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
@ -17,13 +17,9 @@
|
||||
</div>
|
||||
<div class="footer-item bullet">•</div>
|
||||
<div class="footer-item">
|
||||
<a
|
||||
href="https://samr1.github.io/FitTrackee/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $t('common.DOCUMENTATION') }}
|
||||
</a>
|
||||
<router-link to="/privacy-policy">
|
||||
{{ $t('privacy_policy.TITLE') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,6 +57,7 @@
|
||||
|
||||
.footer-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
|
||||
@ -76,14 +73,17 @@
|
||||
|
||||
@media screen and (max-width: $x-small-limit) {
|
||||
.footer-items {
|
||||
border-top: solid 1px var(--footer-border-color);
|
||||
font-size: 0.85em;
|
||||
padding: 0 0 2px;
|
||||
|
||||
.footer-item {
|
||||
padding: 5px 5px;
|
||||
border-top: none;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.bullet {
|
||||
padding: 5px 0;
|
||||
padding: 1px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
91
fittrackee_client/src/components/PrivacyPolicy.vue
Normal file
91
fittrackee_client/src/components/PrivacyPolicy.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="privacy-policy-text">
|
||||
<h1>
|
||||
{{ capitalize($t('privacy_policy.TITLE')) }}
|
||||
</h1>
|
||||
<p class="last-update">
|
||||
{{ $t('privacy_policy.LAST_UPDATE')}}: {{ private_policy_date }}
|
||||
</p>
|
||||
<template v-if="appConfig.privacy_policy">
|
||||
<div
|
||||
v-html="snarkdown(linkifyAndClean(appConfig.privacy_policy))"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-for="paragraph in paragraphs" :key="paragraph">
|
||||
<h2>
|
||||
{{ $t(`privacy_policy.CONTENT.${paragraph}.TITLE`)}}
|
||||
</h2>
|
||||
<p v-html="snarkdown($t(`privacy_policy.CONTENT.${paragraph}.CONTENT`))" />
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import snarkdown from 'snarkdown'
|
||||
import { ComputedRef, capitalize, computed } from 'vue'
|
||||
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { TAppConfig } from '@/types/application'
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { dateStringFormats, formatDate } from '@/utils/dates'
|
||||
import { linkifyAndClean } from '@/utils/inputs'
|
||||
|
||||
const store = useStore()
|
||||
const fittrackee_private_policy_date = 'Sun, 26 Feb 2023 17:00:00 GMT'
|
||||
const appConfig: ComputedRef<TAppConfig> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
|
||||
)
|
||||
const language: ComputedRef<string> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
|
||||
)
|
||||
const authUser: ComputedRef<IAuthUserProfile> = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.AUTH_USER_PROFILE]
|
||||
)
|
||||
const dateFormat = computed(() => getDateFormat())
|
||||
const timezone = computed(() => getTimezone())
|
||||
const private_policy_date = computed(() => getPolicyDate())
|
||||
const paragraphs = [
|
||||
'DATA_COLLECTED', 'INFORMATION_USAGE', 'INFORMATION_PROTECTION',
|
||||
'INFORMATION_DISCLOSURE', 'SITE_USAGE_BY_CHILDREN','ACCOUNT_DELETION',
|
||||
'YOUR_CONSENT', 'CHANGES_TO_OUR_PRIVACY_POLICY'
|
||||
]
|
||||
|
||||
function getTimezone() {
|
||||
return authUser.value.timezone
|
||||
? authUser.value.timezone
|
||||
: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
: 'Europe/Paris'
|
||||
}
|
||||
function getDateFormat() {
|
||||
return dateStringFormats[language.value]
|
||||
}
|
||||
function getPolicyDate() {
|
||||
return formatDate(
|
||||
appConfig.value.privacy_policy && appConfig.value.privacy_policy_date
|
||||
? `${appConfig.value.privacy_policy_date}`
|
||||
: fittrackee_private_policy_date,
|
||||
timezone.value,
|
||||
dateFormat.value,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/scss/base.scss';
|
||||
|
||||
.privacy-policy-text {
|
||||
margin: 10px 50px 20px;
|
||||
padding: $default-padding;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (max-width: $small-limit) {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -98,6 +98,27 @@
|
||||
@updatePassword="updatePassword"
|
||||
@passwordError="invalidateForm"
|
||||
/>
|
||||
<label
|
||||
v-if="action === 'register'"
|
||||
for="accepted_policy"
|
||||
class="accepted_policy"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="accepted_policy"
|
||||
:disabled="registration_disabled"
|
||||
required
|
||||
@invalid="invalidateForm"
|
||||
v-model="formData.accepted_policy"
|
||||
/>
|
||||
<span>
|
||||
<i18n-t keypath="user.READ_AND_ACCEPT_PRIVACY_POLICY">
|
||||
<router-link to="/privacy-policy">
|
||||
{{ $t('privacy_policy.TITLE') }}
|
||||
</router-link>
|
||||
</i18n-t>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
@ -176,6 +197,7 @@
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
accepted_policy: false
|
||||
})
|
||||
const buttonText: ComputedRef<string> = computed(() =>
|
||||
getButtonText(props.action)
|
||||
@ -261,6 +283,7 @@
|
||||
formData.username = ''
|
||||
formData.email = ''
|
||||
formData.password = ''
|
||||
formData.accepted_policy = false
|
||||
}
|
||||
|
||||
onUnmounted(() => store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES))
|
||||
@ -310,6 +333,12 @@
|
||||
.success-message {
|
||||
margin: $default-margin;
|
||||
}
|
||||
.accepted_policy {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: .85em;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $medium-limit) {
|
||||
|
Reference in New Issue
Block a user