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 { user, tab } = toRefs(props)
|
||||
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS']
|
||||
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS', 'PRIVACY-POLICY']
|
||||
const loading = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||
)
|
||||
|
@ -37,6 +37,7 @@
|
||||
switch (tab) {
|
||||
case 'ACCOUNT':
|
||||
case 'PICTURE':
|
||||
case 'PRIVACY-POLICY':
|
||||
return `/profile/edit/${tab.toLocaleLowerCase()}`
|
||||
case 'APPS':
|
||||
case 'PREFERENCES':
|
||||
|
@ -10,8 +10,10 @@
|
||||
"ENTER_PASSWORD": "Enter a password",
|
||||
"FILTER_ON_USERNAME": "Filter on username",
|
||||
"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.",
|
||||
"LANGUAGE": "Language",
|
||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "The privacy policy has been updated, please {0} it before proceeding.",
|
||||
"LOGIN": "Login",
|
||||
"LOGOUT": "Logout",
|
||||
"LOG_IN": "log in",
|
||||
@ -68,6 +70,7 @@
|
||||
"PICTURE_REMOVE": "Remove picture",
|
||||
"PICTURE_UPDATE": "Update picture",
|
||||
"PREFERENCES_EDITION": "Preferences edition",
|
||||
"PRIVACY-POLICY_EDITION": "Privacy policy",
|
||||
"PROFILE_EDITION": "Profile edition",
|
||||
"REGISTRATION_DATE": "Registration date",
|
||||
"SPORT": {
|
||||
@ -89,6 +92,7 @@
|
||||
"APPS": "apps",
|
||||
"PICTURE": "picture",
|
||||
"PREFERENCES": "preferences",
|
||||
"PRIVACY-POLICY": "privacy policy",
|
||||
"PROFILE": "profile",
|
||||
"SPORTS": "sports"
|
||||
},
|
||||
@ -104,9 +108,11 @@
|
||||
"REGISTER_DISABLED": "Sorry, registration is disabled.",
|
||||
"RESENT_ACCOUNT_CONFIRMATION": "Resend account confirmation email",
|
||||
"RESET_PASSWORD": "Reset your password",
|
||||
"REVIEW": "review",
|
||||
"SHOW_PASSWORD": "show password",
|
||||
"THIS_USER_ACCOUNT_IS_INACTIVE": "This user account is inactive.",
|
||||
"USERNAME": "Username",
|
||||
"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",
|
||||
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
|
||||
"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.",
|
||||
"LANGUAGE": "Langue",
|
||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La politique de confidentialité a été mise à jour. Veuillez l'{0} avant de poursuivre.",
|
||||
"LOGIN": "Se connecter",
|
||||
"LOGOUT": "Se déconnecter",
|
||||
"LOG_IN": "connecter",
|
||||
@ -68,6 +70,7 @@
|
||||
"PICTURE_REMOVE": "Supprimer",
|
||||
"PICTURE_UPDATE": "Mettre à jour l'image",
|
||||
"PREFERENCES_EDITION": "Mise à jour des préférences",
|
||||
"PRIVACY-POLICY_EDITION": "Politique de confidentialité",
|
||||
"PROFILE_EDITION": "Mise à jour du profil",
|
||||
"REGISTRATION_DATE": "Date d'inscription",
|
||||
"SPORT": {
|
||||
@ -89,6 +92,7 @@
|
||||
"APPS": "apps",
|
||||
"PICTURE": "image",
|
||||
"PREFERENCES": "préférences",
|
||||
"PRIVACY-POLICY": "politique de confidentialité",
|
||||
"PROFILE": "profil",
|
||||
"SPORTS": "sports"
|
||||
},
|
||||
@ -104,9 +108,11 @@
|
||||
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
|
||||
"RESENT_ACCOUNT_CONFIRMATION": "Envoyer à nouveau le courriel de confirmation de compte",
|
||||
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
|
||||
"REVIEW": "accepter",
|
||||
"SHOW_PASSWORD": "afficher le mot de passe",
|
||||
"THIS_USER_ACCOUNT_IS_INACTIVE": "Le compte de cet utilisateur est inactif.",
|
||||
"USERNAME": "Nom d'utilisateur",
|
||||
"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 UserPictureEdition from '@/components/User/ProfileEdition/UserPictureEdition.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 AuthorizeUserApp from '@/components/User/UserApps/AuthorizeUserApp.vue'
|
||||
import UserApps from '@/components/User/UserApps/index.vue'
|
||||
@ -219,6 +220,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
component: UserSportPreferences,
|
||||
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))
|
||||
},
|
||||
[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 {
|
||||
ACCEPT_PRIVACY_POLICY = 'ACCEPT_PRIVACY_POLICY',
|
||||
CHECK_AUTH_USER = 'CHECK_AUTH_USER',
|
||||
CONFIRM_ACCOUNT = 'CONFIRM_ACCOUNT',
|
||||
CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
||||
|
@ -110,6 +110,11 @@ export interface IAuthUserActions {
|
||||
[AUTH_USER_STORE.ACTIONS.DELETE_PICTURE](
|
||||
context: ActionContext<IAuthUserState, IRootState>
|
||||
): void
|
||||
|
||||
[AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY](
|
||||
context: ActionContext<IAuthUserState, IRootState>,
|
||||
acceptedPolicy: boolean
|
||||
): void
|
||||
}
|
||||
|
||||
export interface IAuthUserGetters {
|
||||
|
@ -25,6 +25,7 @@ export interface IUserProfile {
|
||||
}
|
||||
|
||||
export interface IAuthUserProfile extends IUserProfile {
|
||||
accepted_privacy_policy: boolean
|
||||
display_ascent: boolean
|
||||
imperial_units: boolean
|
||||
language: string | null
|
||||
|
@ -36,6 +36,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="container privacy-policy-message"
|
||||
v-if="!authUser.accepted_privacy_policy"
|
||||
>
|
||||
<PrivacyPolicyToAccept />
|
||||
</div>
|
||||
<div class="container">
|
||||
<UserStatsCards :user="authUser" />
|
||||
</div>
|
||||
@ -80,6 +86,7 @@
|
||||
import UserMonthStats from '@/components/Dashboard/UserMonthStats.vue'
|
||||
import UserRecords from '@/components/Dashboard/UserRecords/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 { ISport } from '@/types/sports'
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
@ -126,6 +133,11 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.privacy-policy-message {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $medium-limit) {
|
||||
padding-bottom: 60px;
|
||||
.dashboard-container {
|
||||
|
Loading…
Reference in New Issue
Block a user