Client - add privacy review when user has not accepted the last policy
This commit is contained in:
parent
3834e71c95
commit
713b86bfb3
25
fittrackee_client/src/components/PrivacyPolicyToAccept.vue
Normal file
25
fittrackee_client/src/components/PrivacyPolicyToAccept.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div class="privacy-policy-message">
|
||||||
|
<span>
|
||||||
|
<i18n-t keypath="user.LAST_PRIVACY_POLICY_TO_VALIDATE">
|
||||||
|
<router-link to="/profile/edit/privacy-policy">
|
||||||
|
{{ $t('user.REVIEW') }}
|
||||||
|
</router-link>
|
||||||
|
</i18n-t>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~@/scss/vars.scss';
|
||||||
|
.privacy-policy-message {
|
||||||
|
background: var(--alert-background-color);
|
||||||
|
color: var(--alert-color);
|
||||||
|
border-radius: $border-radius;
|
||||||
|
padding: $default-padding $default-padding*2;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<div id="user-privacy-policy">
|
||||||
|
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||||
|
<div v-if="user.accepted_privacy_policy">
|
||||||
|
<p>
|
||||||
|
<i18n-t keypath="user.YOU_HAVE_ACCEPTED_PRIVACY_POLICY">
|
||||||
|
<router-link to="/privacy-policy">
|
||||||
|
{{ $t('privacy_policy.TITLE') }}
|
||||||
|
</router-link>
|
||||||
|
</i18n-t>
|
||||||
|
</p>
|
||||||
|
<button class="cancel" @click="$router.push('/profile')">
|
||||||
|
{{ $t('user.PROFILE.BACK_TO_PROFILE') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form v-else @submit.prevent="onSubmit()">
|
||||||
|
<div class="policy-content">
|
||||||
|
<PrivacyPolicy />
|
||||||
|
</div>
|
||||||
|
<label
|
||||||
|
for="accepted_policy"
|
||||||
|
class="accepted_policy"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="accepted_policy"
|
||||||
|
required
|
||||||
|
v-model="acceptedPolicy"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
<i18n-t keypath="user.READ_AND_ACCEPT_PRIVACY_POLICY">
|
||||||
|
{{ $t('privacy_policy.TITLE') }}
|
||||||
|
</i18n-t>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<router-link to="/profile/edit/account">
|
||||||
|
{{ $t('user.I_WANT_TO_DELETE_MY_ACCOUNT') }}
|
||||||
|
</router-link>
|
||||||
|
<div class="form-buttons">
|
||||||
|
<button class="confirm" type="submit">
|
||||||
|
{{ $t('buttons.SUBMIT') }}
|
||||||
|
</button>
|
||||||
|
<button class="cancel" @click="$router.push('/profile')">
|
||||||
|
{{ $t('user.PROFILE.BACK_TO_PROFILE') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ComputedRef, computed, ref, onUnmounted, toRefs } from 'vue'
|
||||||
|
|
||||||
|
import PrivacyPolicy from '@/components/PrivacyPolicy.vue'
|
||||||
|
import {AUTH_USER_STORE, ROOT_STORE} from '@/store/constants'
|
||||||
|
import { IAuthUserProfile } from '@/types/user'
|
||||||
|
import { useStore } from '@/use/useStore'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
user: IAuthUserProfile
|
||||||
|
}
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const { user } = toRefs(props)
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||||
|
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||||
|
)
|
||||||
|
const acceptedPolicy= ref(false)
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
store.dispatch(
|
||||||
|
AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY, acceptedPolicy.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/scss/vars.scss';
|
||||||
|
|
||||||
|
#user-privacy-policy {
|
||||||
|
padding: $default-padding 0;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $default-padding;
|
||||||
|
|
||||||
|
.policy-content {
|
||||||
|
height: 500px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
overflow: auto;
|
||||||
|
margin: $default-margin;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
|
||||||
|
@media screen and (max-width: $small-limit) {
|
||||||
|
margin: $default-margin 0;
|
||||||
|
font-size: .9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy-policy-text {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: $default-padding;
|
||||||
|
flex-direction: row;
|
||||||
|
@media screen and (max-width: $x-small-limit) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -34,7 +34,7 @@
|
|||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const { user, tab } = toRefs(props)
|
const { user, tab } = toRefs(props)
|
||||||
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS']
|
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS', 'PRIVACY-POLICY']
|
||||||
const loading = computed(
|
const loading = computed(
|
||||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||||
)
|
)
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'ACCOUNT':
|
case 'ACCOUNT':
|
||||||
case 'PICTURE':
|
case 'PICTURE':
|
||||||
|
case 'PRIVACY-POLICY':
|
||||||
return `/profile/edit/${tab.toLocaleLowerCase()}`
|
return `/profile/edit/${tab.toLocaleLowerCase()}`
|
||||||
case 'APPS':
|
case 'APPS':
|
||||||
case 'PREFERENCES':
|
case 'PREFERENCES':
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
"ENTER_PASSWORD": "Enter a password",
|
"ENTER_PASSWORD": "Enter a password",
|
||||||
"FILTER_ON_USERNAME": "Filter on username",
|
"FILTER_ON_USERNAME": "Filter on username",
|
||||||
"HIDE_PASSWORD": "hide password",
|
"HIDE_PASSWORD": "hide password",
|
||||||
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "I want to delete my account",
|
||||||
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
|
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
|
||||||
"LANGUAGE": "Language",
|
"LANGUAGE": "Language",
|
||||||
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "The privacy policy has been updated, please {0} it before proceeding.",
|
||||||
"LOGIN": "Login",
|
"LOGIN": "Login",
|
||||||
"LOGOUT": "Logout",
|
"LOGOUT": "Logout",
|
||||||
"LOG_IN": "log in",
|
"LOG_IN": "log in",
|
||||||
@ -68,6 +70,7 @@
|
|||||||
"PICTURE_REMOVE": "Remove picture",
|
"PICTURE_REMOVE": "Remove picture",
|
||||||
"PICTURE_UPDATE": "Update picture",
|
"PICTURE_UPDATE": "Update picture",
|
||||||
"PREFERENCES_EDITION": "Preferences edition",
|
"PREFERENCES_EDITION": "Preferences edition",
|
||||||
|
"PRIVACY-POLICY_EDITION": "Privacy policy",
|
||||||
"PROFILE_EDITION": "Profile edition",
|
"PROFILE_EDITION": "Profile edition",
|
||||||
"REGISTRATION_DATE": "Registration date",
|
"REGISTRATION_DATE": "Registration date",
|
||||||
"SPORT": {
|
"SPORT": {
|
||||||
@ -89,6 +92,7 @@
|
|||||||
"APPS": "apps",
|
"APPS": "apps",
|
||||||
"PICTURE": "picture",
|
"PICTURE": "picture",
|
||||||
"PREFERENCES": "preferences",
|
"PREFERENCES": "preferences",
|
||||||
|
"PRIVACY-POLICY": "privacy policy",
|
||||||
"PROFILE": "profile",
|
"PROFILE": "profile",
|
||||||
"SPORTS": "sports"
|
"SPORTS": "sports"
|
||||||
},
|
},
|
||||||
@ -104,9 +108,11 @@
|
|||||||
"REGISTER_DISABLED": "Sorry, registration is disabled.",
|
"REGISTER_DISABLED": "Sorry, registration is disabled.",
|
||||||
"RESENT_ACCOUNT_CONFIRMATION": "Resend account confirmation email",
|
"RESENT_ACCOUNT_CONFIRMATION": "Resend account confirmation email",
|
||||||
"RESET_PASSWORD": "Reset your password",
|
"RESET_PASSWORD": "Reset your password",
|
||||||
|
"REVIEW": "review",
|
||||||
"SHOW_PASSWORD": "show password",
|
"SHOW_PASSWORD": "show password",
|
||||||
"THIS_USER_ACCOUNT_IS_INACTIVE": "This user account is inactive.",
|
"THIS_USER_ACCOUNT_IS_INACTIVE": "This user account is inactive.",
|
||||||
"USERNAME": "Username",
|
"USERNAME": "Username",
|
||||||
"USERNAME_INFO": "3 to 30 characters required, only alphanumeric characters and the underscore character \"_\" allowed.",
|
"USERNAME_INFO": "3 to 30 characters required, only alphanumeric characters and the underscore character \"_\" allowed.",
|
||||||
"USER_PICTURE": "user picture"
|
"USER_PICTURE": "user picture",
|
||||||
|
"YOU_HAVE_ACCEPTED_PRIVACY_POLICY": "You have accepted the {0}."
|
||||||
}
|
}
|
@ -10,8 +10,10 @@
|
|||||||
"ENTER_PASSWORD": "Saisissez un mot de passe",
|
"ENTER_PASSWORD": "Saisissez un mot de passe",
|
||||||
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
|
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
|
||||||
"HIDE_PASSWORD": "masquer le mot de passe",
|
"HIDE_PASSWORD": "masquer le mot de passe",
|
||||||
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Je souhaite supprimer mon compte",
|
||||||
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
|
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
|
||||||
"LANGUAGE": "Langue",
|
"LANGUAGE": "Langue",
|
||||||
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La politique de confidentialité a été mise à jour. Veuillez l'{0} avant de poursuivre.",
|
||||||
"LOGIN": "Se connecter",
|
"LOGIN": "Se connecter",
|
||||||
"LOGOUT": "Se déconnecter",
|
"LOGOUT": "Se déconnecter",
|
||||||
"LOG_IN": "connecter",
|
"LOG_IN": "connecter",
|
||||||
@ -68,6 +70,7 @@
|
|||||||
"PICTURE_REMOVE": "Supprimer",
|
"PICTURE_REMOVE": "Supprimer",
|
||||||
"PICTURE_UPDATE": "Mettre à jour l'image",
|
"PICTURE_UPDATE": "Mettre à jour l'image",
|
||||||
"PREFERENCES_EDITION": "Mise à jour des préférences",
|
"PREFERENCES_EDITION": "Mise à jour des préférences",
|
||||||
|
"PRIVACY-POLICY_EDITION": "Politique de confidentialité",
|
||||||
"PROFILE_EDITION": "Mise à jour du profil",
|
"PROFILE_EDITION": "Mise à jour du profil",
|
||||||
"REGISTRATION_DATE": "Date d'inscription",
|
"REGISTRATION_DATE": "Date d'inscription",
|
||||||
"SPORT": {
|
"SPORT": {
|
||||||
@ -89,6 +92,7 @@
|
|||||||
"APPS": "apps",
|
"APPS": "apps",
|
||||||
"PICTURE": "image",
|
"PICTURE": "image",
|
||||||
"PREFERENCES": "préférences",
|
"PREFERENCES": "préférences",
|
||||||
|
"PRIVACY-POLICY": "politique de confidentialité",
|
||||||
"PROFILE": "profil",
|
"PROFILE": "profil",
|
||||||
"SPORTS": "sports"
|
"SPORTS": "sports"
|
||||||
},
|
},
|
||||||
@ -104,9 +108,11 @@
|
|||||||
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
|
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
|
||||||
"RESENT_ACCOUNT_CONFIRMATION": "Envoyer à nouveau le courriel de confirmation de compte",
|
"RESENT_ACCOUNT_CONFIRMATION": "Envoyer à nouveau le courriel de confirmation de compte",
|
||||||
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
|
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
|
||||||
|
"REVIEW": "accepter",
|
||||||
"SHOW_PASSWORD": "afficher le mot de passe",
|
"SHOW_PASSWORD": "afficher le mot de passe",
|
||||||
"THIS_USER_ACCOUNT_IS_INACTIVE": "Le compte de cet utilisateur est inactif.",
|
"THIS_USER_ACCOUNT_IS_INACTIVE": "Le compte de cet utilisateur est inactif.",
|
||||||
"USERNAME": "Nom d'utilisateur",
|
"USERNAME": "Nom d'utilisateur",
|
||||||
"USERNAME_INFO": "3 à 30 caractères requis, seuls les caractères alphanumériques et le caractère _ sont autorisés.",
|
"USERNAME_INFO": "3 à 30 caractères requis, seuls les caractères alphanumériques et le caractère _ sont autorisés.",
|
||||||
"USER_PICTURE": "photo de l'utilisateur"
|
"USER_PICTURE": "photo de l'utilisateur",
|
||||||
|
"YOU_HAVE_ACCEPTED_PRIVACY_POLICY": "Vous avez accepté la {0}."
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import UserAccountEdition from '@/components/User/ProfileEdition/UserAccountEdit
|
|||||||
import UserInfosEdition from '@/components/User/ProfileEdition/UserInfosEdition.vue'
|
import UserInfosEdition from '@/components/User/ProfileEdition/UserInfosEdition.vue'
|
||||||
import UserPictureEdition from '@/components/User/ProfileEdition/UserPictureEdition.vue'
|
import UserPictureEdition from '@/components/User/ProfileEdition/UserPictureEdition.vue'
|
||||||
import UserPreferencesEdition from '@/components/User/ProfileEdition/UserPreferencesEdition.vue'
|
import UserPreferencesEdition from '@/components/User/ProfileEdition/UserPreferencesEdition.vue'
|
||||||
|
import UserPrivacyPolicyValidation from '@/components/User/ProfileEdition/UserPrivacyPolicyValidation.vue'
|
||||||
import AddUserApp from '@/components/User/UserApps/AddUserApp.vue'
|
import AddUserApp from '@/components/User/UserApps/AddUserApp.vue'
|
||||||
import AuthorizeUserApp from '@/components/User/UserApps/AuthorizeUserApp.vue'
|
import AuthorizeUserApp from '@/components/User/UserApps/AuthorizeUserApp.vue'
|
||||||
import UserApps from '@/components/User/UserApps/index.vue'
|
import UserApps from '@/components/User/UserApps/index.vue'
|
||||||
@ -219,6 +220,11 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: UserSportPreferences,
|
component: UserSportPreferences,
|
||||||
props: { isEdition: true },
|
props: { isEdition: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'privacy-policy',
|
||||||
|
name: 'UserPrivacyPolicy',
|
||||||
|
component: UserPrivacyPolicyValidation,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -427,4 +427,24 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
|
|||||||
})
|
})
|
||||||
.catch((error) => handleError(context, error))
|
.catch((error) => handleError(context, error))
|
||||||
},
|
},
|
||||||
|
[AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY](
|
||||||
|
context: ActionContext<IAuthUserState, IRootState>,
|
||||||
|
acceptedPolicy: boolean
|
||||||
|
): void {
|
||||||
|
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||||
|
authApi
|
||||||
|
.post('auth/account/privacy-policy', {
|
||||||
|
accepted_policy: acceptedPolicy,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.status === 'success') {
|
||||||
|
context
|
||||||
|
.dispatch(AUTH_USER_STORE.ACTIONS.GET_USER_PROFILE)
|
||||||
|
.then(() => router.push('/profile'))
|
||||||
|
} else {
|
||||||
|
handleError(context, null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => handleError(context, error))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum AuthUserActions {
|
export enum AuthUserActions {
|
||||||
|
ACCEPT_PRIVACY_POLICY = 'ACCEPT_PRIVACY_POLICY',
|
||||||
CHECK_AUTH_USER = 'CHECK_AUTH_USER',
|
CHECK_AUTH_USER = 'CHECK_AUTH_USER',
|
||||||
CONFIRM_ACCOUNT = 'CONFIRM_ACCOUNT',
|
CONFIRM_ACCOUNT = 'CONFIRM_ACCOUNT',
|
||||||
CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
||||||
|
@ -110,6 +110,11 @@ export interface IAuthUserActions {
|
|||||||
[AUTH_USER_STORE.ACTIONS.DELETE_PICTURE](
|
[AUTH_USER_STORE.ACTIONS.DELETE_PICTURE](
|
||||||
context: ActionContext<IAuthUserState, IRootState>
|
context: ActionContext<IAuthUserState, IRootState>
|
||||||
): void
|
): void
|
||||||
|
|
||||||
|
[AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY](
|
||||||
|
context: ActionContext<IAuthUserState, IRootState>,
|
||||||
|
acceptedPolicy: boolean
|
||||||
|
): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthUserGetters {
|
export interface IAuthUserGetters {
|
||||||
|
@ -25,6 +25,7 @@ export interface IUserProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthUserProfile extends IUserProfile {
|
export interface IAuthUserProfile extends IUserProfile {
|
||||||
|
accepted_privacy_policy: boolean
|
||||||
display_ascent: boolean
|
display_ascent: boolean
|
||||||
imperial_units: boolean
|
imperial_units: boolean
|
||||||
language: string | null
|
language: string | null
|
||||||
|
@ -36,6 +36,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="container privacy-policy-message"
|
||||||
|
v-if="!authUser.accepted_privacy_policy"
|
||||||
|
>
|
||||||
|
<PrivacyPolicyToAccept />
|
||||||
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<UserStatsCards :user="authUser" />
|
<UserStatsCards :user="authUser" />
|
||||||
</div>
|
</div>
|
||||||
@ -80,6 +86,7 @@
|
|||||||
import UserMonthStats from '@/components/Dashboard/UserMonthStats.vue'
|
import UserMonthStats from '@/components/Dashboard/UserMonthStats.vue'
|
||||||
import UserRecords from '@/components/Dashboard/UserRecords/index.vue'
|
import UserRecords from '@/components/Dashboard/UserRecords/index.vue'
|
||||||
import UserStatsCards from '@/components/Dashboard/UserStatsCards/index.vue'
|
import UserStatsCards from '@/components/Dashboard/UserStatsCards/index.vue'
|
||||||
|
import PrivacyPolicyToAccept from '@/components/PrivacyPolicyToAccept.vue'
|
||||||
import { AUTH_USER_STORE, SPORTS_STORE } from '@/store/constants'
|
import { AUTH_USER_STORE, SPORTS_STORE } from '@/store/constants'
|
||||||
import { ISport } from '@/types/sports'
|
import { ISport } from '@/types/sports'
|
||||||
import { IAuthUserProfile } from '@/types/user'
|
import { IAuthUserProfile } from '@/types/user'
|
||||||
@ -126,6 +133,11 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.privacy-policy-message {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $medium-limit) {
|
@media screen and (max-width: $medium-limit) {
|
||||||
padding-bottom: 60px;
|
padding-bottom: 60px;
|
||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
|
Loading…
Reference in New Issue
Block a user