Client - add password reset + refacto
This commit is contained in:
parent
c4eb9bdbf8
commit
8d93024a5f
@ -22,7 +22,7 @@
|
||||
"register-service-worker": "^1.7.1",
|
||||
"vue": "^3.0.0",
|
||||
"vue-chart-3": "^0.5.8",
|
||||
"vue-i18n": "^9.1.0",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.0-0"
|
||||
},
|
||||
|
@ -1,22 +1,17 @@
|
||||
<template>
|
||||
<div class="alert-message">
|
||||
<div v-html="t(message)" />
|
||||
<div v-html="$t(message)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AlertMessage',
|
||||
props: {
|
||||
message: String,
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -9,14 +9,13 @@
|
||||
@input="updateText"
|
||||
/>
|
||||
<div class="remaining-chars">
|
||||
{{ t('workouts.REMAINING_CHARS') }}: {{ text.length }}/{{ charLimit }}
|
||||
{{ $t('workouts.REMAINING_CHARS') }}: {{ text.length }}/{{ charLimit }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CustomTextarea',
|
||||
@ -40,7 +39,6 @@
|
||||
},
|
||||
emits: ['updateValue'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n()
|
||||
let text = ref('')
|
||||
|
||||
function updateText(event: Event & { target: HTMLInputElement }) {
|
||||
@ -54,7 +52,7 @@
|
||||
}
|
||||
)
|
||||
|
||||
return { t, text, updateText }
|
||||
return { text, updateText }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -2,26 +2,21 @@
|
||||
<div class="error-message">
|
||||
<ul v-if="Array.isArray(message)">
|
||||
<li v-for="(subMessage, index) in message" :key="index">
|
||||
{{ t(subMessage) }}
|
||||
{{ $t(subMessage) }}
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else>{{ t(message) }}</div>
|
||||
<div v-else>{{ $t(message) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ErrorMessage',
|
||||
props: {
|
||||
message: [String, Array],
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
63
fittrackee_client/src/components/Common/Images/EmailSent.vue
Normal file
63
fittrackee_client/src/components/Common/Images/EmailSent.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 345.834 345.834"
|
||||
style="enable-background: new 0 0 345.834 345.834"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M339.798,260.429c0.13-0.026,0.257-0.061,0.385-0.094c0.109-0.028,0.219-0.051,0.326-0.084
|
||||
c0.125-0.038,0.247-0.085,0.369-0.129c0.108-0.039,0.217-0.074,0.324-0.119c0.115-0.048,0.226-0.104,0.338-0.157
|
||||
c0.109-0.052,0.22-0.1,0.327-0.158c0.107-0.057,0.208-0.122,0.312-0.184c0.107-0.064,0.215-0.124,0.319-0.194
|
||||
c0.111-0.074,0.214-0.156,0.321-0.236c0.09-0.067,0.182-0.13,0.27-0.202c0.162-0.133,0.316-0.275,0.466-0.421
|
||||
c0.027-0.026,0.056-0.048,0.083-0.075c0.028-0.028,0.052-0.059,0.079-0.088c0.144-0.148,0.284-0.3,0.416-0.46
|
||||
c0.077-0.094,0.144-0.192,0.216-0.289c0.074-0.1,0.152-0.197,0.221-0.301c0.074-0.111,0.139-0.226,0.207-0.34
|
||||
c0.057-0.096,0.118-0.19,0.171-0.289c0.062-0.115,0.114-0.234,0.169-0.351c0.049-0.104,0.101-0.207,0.146-0.314
|
||||
c0.048-0.115,0.086-0.232,0.128-0.349c0.041-0.114,0.085-0.227,0.12-0.343c0.036-0.118,0.062-0.238,0.092-0.358
|
||||
c0.029-0.118,0.063-0.234,0.086-0.353c0.028-0.141,0.045-0.283,0.065-0.425c0.014-0.1,0.033-0.199,0.043-0.3
|
||||
c0.025-0.249,0.038-0.498,0.038-0.748V92.76c0-4.143-3.357-7.5-7.5-7.5h-236.25c-0.066,0-0.13,0.008-0.196,0.01
|
||||
c-0.143,0.004-0.285,0.01-0.427,0.022c-0.113,0.009-0.225,0.022-0.337,0.037c-0.128,0.016-0.255,0.035-0.382,0.058
|
||||
c-0.119,0.021-0.237,0.046-0.354,0.073c-0.119,0.028-0.238,0.058-0.356,0.092c-0.117,0.033-0.232,0.069-0.346,0.107
|
||||
c-0.117,0.04-0.234,0.082-0.349,0.128c-0.109,0.043-0.216,0.087-0.322,0.135c-0.118,0.053-0.235,0.11-0.351,0.169
|
||||
c-0.099,0.051-0.196,0.103-0.292,0.158c-0.116,0.066-0.23,0.136-0.343,0.208c-0.093,0.06-0.184,0.122-0.274,0.185
|
||||
c-0.106,0.075-0.211,0.153-0.314,0.235c-0.094,0.075-0.186,0.152-0.277,0.231c-0.09,0.079-0.179,0.158-0.266,0.242
|
||||
c-0.099,0.095-0.194,0.194-0.288,0.294c-0.047,0.05-0.097,0.094-0.142,0.145c-0.027,0.03-0.048,0.063-0.074,0.093
|
||||
c-0.094,0.109-0.182,0.223-0.27,0.338c-0.064,0.084-0.13,0.168-0.19,0.254c-0.078,0.112-0.15,0.227-0.222,0.343
|
||||
c-0.059,0.095-0.12,0.189-0.174,0.286c-0.063,0.112-0.118,0.227-0.175,0.342c-0.052,0.105-0.106,0.21-0.153,0.317
|
||||
c-0.049,0.113-0.092,0.23-0.135,0.345c-0.043,0.113-0.087,0.225-0.124,0.339c-0.037,0.115-0.067,0.232-0.099,0.349
|
||||
c-0.032,0.12-0.066,0.239-0.093,0.36c-0.025,0.113-0.042,0.228-0.062,0.342c-0.022,0.13-0.044,0.26-0.06,0.39
|
||||
c-0.013,0.108-0.019,0.218-0.027,0.328c-0.01,0.14-0.019,0.28-0.021,0.421c-0.001,0.041-0.006,0.081-0.006,0.122v46.252
|
||||
c0,4.143,3.357,7.5,7.5,7.5s7.5-3.357,7.5-7.5v-29.595l66.681,59.037c-0.348,0.245-0.683,0.516-0.995,0.827l-65.687,65.687v-49.288
|
||||
c0-4.143-3.357-7.5-7.5-7.5s-7.5,3.357-7.5,7.5v9.164h-38.75c-4.143,0-7.5,3.357-7.5,7.5s3.357,7.5,7.5,7.5h38.75v43.231
|
||||
c0,4.143,3.357,7.5,7.5,7.5h236.25c0.247,0,0.494-0.013,0.74-0.037c0.115-0.011,0.226-0.033,0.339-0.049
|
||||
C339.542,260.469,339.67,260.454,339.798,260.429z M330.834,234.967l-65.688-65.687c-0.042-0.042-0.087-0.077-0.13-0.117
|
||||
l49.383-41.897c3.158-2.68,3.546-7.412,0.866-10.571c-2.678-3.157-7.41-3.547-10.571-0.866l-84.381,71.59l-98.444-87.158h208.965
|
||||
V234.967z M185.878,179.888c0.535-0.535,0.969-1.131,1.308-1.765l28.051,24.835c1.418,1.255,3.194,1.885,4.972,1.885
|
||||
c1.726,0,3.451-0.593,4.853-1.781l28.587-24.254c0.26,0.38,0.553,0.743,0.89,1.08l65.687,65.687H120.191L185.878,179.888z"
|
||||
/>
|
||||
<path
|
||||
d="M7.5,170.676h126.667c4.143,0,7.5-3.357,7.5-7.5s-3.357-7.5-7.5-7.5H7.5c-4.143,0-7.5,3.357-7.5,7.5
|
||||
S3.357,170.676,7.5,170.676z"
|
||||
/>
|
||||
<path
|
||||
d="M20.625,129.345H77.5c4.143,0,7.5-3.357,7.5-7.5s-3.357-7.5-7.5-7.5H20.625c-4.143,0-7.5,3.357-7.5,7.5
|
||||
S16.482,129.345,20.625,129.345z"
|
||||
/>
|
||||
<path
|
||||
d="M62.5,226.51h-55c-4.143,0-7.5,3.357-7.5,7.5s3.357,7.5,7.5,7.5h55c4.143,0,7.5-3.357,7.5-7.5S66.643,226.51,62.5,226.51z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmailSent',
|
||||
}
|
||||
</script>
|
94
fittrackee_client/src/components/Common/Images/Password.vue
Normal file
94
fittrackee_client/src/components/Common/Images/Password.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 512.001 512.001"
|
||||
style="enable-background: new 0 0 512.001 512.001"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M468.683,287.265h-69.07c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h69.07
|
||||
c4.147,0,7.508-3.361,7.508-7.508C476.191,290.626,472.83,287.265,468.683,287.265z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M105.012,268.377L85.781,256l19.231-12.376c3.487-2.243,4.495-6.888,2.251-10.376c-2.244-3.486-6.888-4.497-10.376-2.25
|
||||
l-17.471,11.243v-20.776c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.47-11.243
|
||||
c-3.486-2.245-8.132-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L58.034,256l-19.231,12.376
|
||||
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.47-11.243v20.775
|
||||
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
|
||||
c2.467,0,4.885-1.216,6.32-3.446C109.507,275.266,108.499,270.62,105.012,268.377z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M194.441,268.377L175.21,256l19.231-12.376c3.487-2.244,4.495-6.889,2.25-10.376c-2.245-3.486-6.888-4.497-10.376-2.25
|
||||
l-17.47,11.243v-20.775c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.776l-17.471-11.243
|
||||
c-3.487-2.245-8.133-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L147.463,256l-19.231,12.376
|
||||
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.471-11.243v20.776
|
||||
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.47,11.243c1.257,0.809,2.664,1.196,4.056,1.196
|
||||
c2.467,0,4.885-1.216,6.32-3.446C198.936,275.266,197.928,270.62,194.441,268.377z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M283.871,268.377L264.64,256l19.231-12.376c3.487-2.243,4.495-6.888,2.251-10.376c-2.245-3.486-6.888-4.497-10.376-2.25
|
||||
l-17.471,11.243v-20.775c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.471-11.243
|
||||
c-3.486-2.245-8.134-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L236.892,256l-19.231,12.376
|
||||
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.471-11.243v20.775
|
||||
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
|
||||
c2.467,0,4.886-1.216,6.32-3.446C288.366,275.266,287.358,270.62,283.871,268.377z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M373.3,268.377L354.069,256l19.231-12.376c3.487-2.244,4.495-6.889,2.25-10.376c-2.244-3.486-6.888-4.497-10.376-2.25
|
||||
l-17.471,11.243v-20.776c0-4.147-3.361-7.508-7.508-7.508c-4.147,0-7.508,3.361-7.508,7.508v20.775l-17.47-11.243
|
||||
c-3.486-2.245-8.132-1.238-10.376,2.25c-2.245,3.487-1.237,8.133,2.25,10.376L326.322,256l-19.231,12.376
|
||||
c-3.487,2.244-4.495,6.889-2.25,10.376c1.435,2.23,3.852,3.446,6.32,3.446c1.391,0,2.799-0.386,4.056-1.196l17.47-11.243v20.776
|
||||
c0,4.147,3.361,7.508,7.508,7.508c4.147,0,7.508-3.361,7.508-7.508V269.76l17.471,11.243c1.257,0.809,2.664,1.196,4.056,1.196
|
||||
c2.467,0,4.885-1.216,6.32-3.446C377.795,275.266,376.787,270.62,373.3,268.377z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M271.792,330.359H15.016V181.642h93.1c4.147,0,7.508-3.361,7.508-7.508c0-4.147-3.361-7.508-7.508-7.508H12.513
|
||||
C5.613,166.626,0,172.24,0,179.14v153.722c0,6.9,5.613,12.513,12.513,12.513h259.278c4.147,0,7.508-3.361,7.508-7.508
|
||||
C279.299,333.72,275.939,330.359,271.792,330.359z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M499.487,166.626H162.174c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h334.811v148.716H323.848
|
||||
c-4.147,0-7.508,3.361-7.508,7.508c0,4.147,3.361,7.508,7.508,7.508h175.64c6.9,0,12.513-5.613,12.513-12.513V179.14
|
||||
C512.001,172.24,506.387,166.626,499.487,166.626z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Password',
|
||||
}
|
||||
</script>
|
@ -17,12 +17,12 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import CyclingSport from '@/components/Common/SportImage/CyclingSport.vue'
|
||||
import CyclingTransport from '@/components/Common/SportImage/CyclingTransport.vue'
|
||||
import Hiking from '@/components/Common/SportImage/Hiking.vue'
|
||||
import MountainBiking from '@/components/Common/SportImage/MountainBiking.vue'
|
||||
import Running from '@/components/Common/SportImage/Running.vue'
|
||||
import Walking from '@/components/Common/SportImage/Walking.vue'
|
||||
import CyclingSport from '@/components/Common/Images/SportImage/CyclingSport.vue'
|
||||
import CyclingTransport from '@/components/Common/Images/SportImage/CyclingTransport.vue'
|
||||
import Hiking from '@/components/Common/Images/SportImage/Hiking.vue'
|
||||
import MountainBiking from '@/components/Common/Images/SportImage/MountainBiking.vue'
|
||||
import Running from '@/components/Common/Images/SportImage/Running.vue'
|
||||
import Walking from '@/components/Common/Images/SportImage/Walking.vue'
|
||||
import { sportColors } from '@/utils/sports'
|
||||
|
||||
export default defineComponent({
|
@ -10,10 +10,10 @@
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<div class="modal-buttons">
|
||||
<button class="confirm" @click="emit('confirmAction')">
|
||||
{{ t('buttons.YES') }}
|
||||
{{ $t('buttons.YES') }}
|
||||
</button>
|
||||
<button class="cancel" @click="emit('cancelAction')">
|
||||
{{ t('buttons.NO') }}
|
||||
{{ $t('buttons.NO') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { ComputedRef, computed, defineComponent, onUnmounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
|
||||
@ -49,13 +48,12 @@
|
||||
},
|
||||
emits: ['cancelAction', 'confirmAction'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
)
|
||||
onUnmounted(() => store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES))
|
||||
return { errorMessages, t, emit }
|
||||
return { errorMessages, emit }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<Error
|
||||
title="404"
|
||||
:message="t(`error.NOT_FOUND.${target}`)"
|
||||
:message="$t(`error.NOT_FOUND.${target}`)"
|
||||
:button-text="t('common.HOME')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Error from '@/components/Common/Error.vue'
|
||||
|
||||
@ -23,9 +22,5 @@
|
||||
default: 'PAGE',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="start-chart">
|
||||
<div v-if="hideChartIfNoData && emptyStats">
|
||||
{{ t('workouts.NO_WORKOUTS') }}
|
||||
{{ $t('workouts.NO_WORKOUTS') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="chart-radio">
|
||||
@ -12,7 +12,7 @@
|
||||
:checked="displayedData === 'total_distance'"
|
||||
@click="updateDisplayData"
|
||||
/>
|
||||
{{ t('workouts.DISTANCE') }}
|
||||
{{ $t('workouts.DISTANCE') }}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
@ -21,7 +21,7 @@
|
||||
:checked="displayedData === 'total_duration'"
|
||||
@click="updateDisplayData"
|
||||
/>
|
||||
{{ t('workouts.DURATION') }}
|
||||
{{ $t('workouts.DURATION') }}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
@ -30,7 +30,7 @@
|
||||
:checked="displayedData === 'nb_workouts'"
|
||||
@click="updateDisplayData"
|
||||
/>
|
||||
{{ t('workouts.WORKOUT', 2) }}
|
||||
{{ $t('workouts.WORKOUT', 2) }}
|
||||
</label>
|
||||
</div>
|
||||
<Chart
|
||||
@ -57,7 +57,6 @@
|
||||
watch,
|
||||
onBeforeMount,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Chart from '@/components/Common/StatsChart/Chart.vue'
|
||||
import { STATS_STORE } from '@/store/constants'
|
||||
@ -106,7 +105,6 @@
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
let displayedData: Ref<TStatisticsDatasetKeys> = ref('total_distance')
|
||||
const statistics: ComputedRef<TStatisticsFromApi> = computed(
|
||||
@ -168,7 +166,6 @@
|
||||
labels: computed(() => formattedStats.value.labels),
|
||||
emptyStats: computed(() => Object.keys(statistics.value).length === 0),
|
||||
displayedData,
|
||||
t,
|
||||
updateDisplayData,
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div id="timeline">
|
||||
<div class="section-title">{{ t('workouts.LATEST_WORKOUTS') }}</div>
|
||||
<div class="section-title">{{ $t('workouts.LATEST_WORKOUTS') }}</div>
|
||||
<div v-if="user.nb_workouts > 0 && workouts.length === 0">
|
||||
<WorkoutCard
|
||||
v-for="index in [...Array(initWorkoutsCount).keys()]"
|
||||
@ -23,7 +23,7 @@
|
||||
<NoWorkouts v-if="workouts.length === 0" />
|
||||
<div v-if="moreWorkoutsExist" class="more-workouts">
|
||||
<button @click="loadMoreWorkouts">
|
||||
{{ t('workouts.LOAD_MORE_WORKOUT') }}
|
||||
{{ $t('workouts.LOAD_MORE_WORKOUT') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,7 +39,6 @@
|
||||
ref,
|
||||
onBeforeMount,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import WorkoutCard from '@/components/Workout/WorkoutCard.vue'
|
||||
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
|
||||
@ -67,7 +66,6 @@
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
let page = ref(1)
|
||||
const per_page = 5
|
||||
@ -103,7 +101,6 @@
|
||||
moreWorkoutsExist,
|
||||
per_page,
|
||||
workouts,
|
||||
t,
|
||||
loadMoreWorkouts,
|
||||
}
|
||||
},
|
||||
|
@ -25,7 +25,7 @@
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import { IWorkout } from '@/types/workouts'
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -18,7 +18,6 @@
|
||||
<script lang="ts">
|
||||
import { endOfMonth, startOfMonth } from 'date-fns'
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import StatChart from '@/components/Common/StatsChart/index.vue'
|
||||
@ -42,7 +41,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const date = new Date()
|
||||
return {
|
||||
chartParams: {
|
||||
@ -51,7 +49,6 @@
|
||||
end: endOfMonth(date),
|
||||
},
|
||||
selectedSportIds: props.sports.map((sport) => sport.id),
|
||||
t,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -31,7 +31,7 @@
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import { IRecord } from '@/types/workouts'
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -2,11 +2,11 @@
|
||||
<div class="user-records-section">
|
||||
<div class="section-title">
|
||||
<i class="fa fa-trophy custom-fa-small" aria-hidden="true" />
|
||||
{{ t('workouts.RECORD', 2) }}
|
||||
{{ $t('workouts.RECORD', 2) }}
|
||||
</div>
|
||||
<div class="user-records">
|
||||
<div v-if="Object.keys(recordsBySport).length === 0" class="no-records">
|
||||
{{ t('workouts.NO_RECORDS') }}
|
||||
{{ $t('workouts.NO_RECORDS') }}
|
||||
</div>
|
||||
<RecordsCard
|
||||
v-for="sportTranslatedLabel in Object.keys(recordsBySport).sort()"
|
||||
@ -52,7 +52,7 @@
|
||||
props.user.timezone
|
||||
)
|
||||
)
|
||||
return { recordsBySport, t }
|
||||
return { recordsBySport }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -3,12 +3,12 @@
|
||||
<UserStatCard
|
||||
icon="calendar"
|
||||
:value="user.nb_workouts"
|
||||
:text="t('workouts.WORKOUT', user.nb_workouts)"
|
||||
:text="$t('workouts.WORKOUT', user.nb_workouts)"
|
||||
/>
|
||||
<UserStatCard
|
||||
icon="road"
|
||||
:value="Number(user.total_distance).toFixed(2)"
|
||||
:text="t('workouts.KM')"
|
||||
:text="$t('workouts.KM')"
|
||||
/>
|
||||
<UserStatCard
|
||||
icon="clock-o"
|
||||
@ -18,7 +18,7 @@
|
||||
<UserStatCard
|
||||
icon="tags"
|
||||
:value="user.nb_sports"
|
||||
:text="t('workouts.SPORT', user.nb_sports)"
|
||||
:text="$t('workouts.SPORT', user.nb_sports)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -63,10 +63,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
total_duration: computed(() => get_duration(total_duration)),
|
||||
}
|
||||
return { total_duration: computed(() => get_duration(total_duration)) }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -21,19 +21,19 @@
|
||||
<div class="nav-items-app-menu" @click="closeMenu()">
|
||||
<div class="nav-items-group" v-if="isAuthenticated">
|
||||
<router-link class="nav-item" to="/">{{
|
||||
t('dashboard.DASHBOARD')
|
||||
$t('dashboard.DASHBOARD')
|
||||
}}</router-link>
|
||||
<router-link class="nav-item" to="/workouts">
|
||||
{{ capitalize(t('workouts.WORKOUT', 2)) }}
|
||||
{{ capitalize($t('workouts.WORKOUT', 2)) }}
|
||||
</router-link>
|
||||
<router-link class="nav-item" to="/statistics">
|
||||
{{ t('statistics.STATISTICS') }}
|
||||
{{ $t('statistics.STATISTICS') }}
|
||||
</router-link>
|
||||
<div v-if="isAuthenticated && authUser.admin" class="nav-item">
|
||||
{{ t('administration.ADMIN') }}
|
||||
{{ $t('administration.ADMIN') }}
|
||||
</div>
|
||||
<router-link class="nav-item" to="/workouts/add">
|
||||
{{ t('workouts.ADD_WORKOUT') }}
|
||||
{{ $t('workouts.ADD_WORKOUT') }}
|
||||
</router-link>
|
||||
<div class="nav-item nav-separator" />
|
||||
</div>
|
||||
@ -47,15 +47,15 @@
|
||||
{{ authUser.username }}
|
||||
</router-link>
|
||||
<div class="nav-item nav-link" @click="logout">
|
||||
{{ t('user.LOGOUT') }}
|
||||
{{ $t('user.LOGOUT') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-items-group" v-else>
|
||||
<router-link class="nav-item" to="/login" @click="closeMenu">{{
|
||||
t('user.LOGIN')
|
||||
$t('user.LOGIN')
|
||||
}}</router-link>
|
||||
<router-link class="nav-item" to="/register" @click="closeMenu">{{
|
||||
t('user.REGISTER')
|
||||
$t('user.REGISTER')
|
||||
}}</router-link>
|
||||
</div>
|
||||
<Dropdown
|
||||
@ -93,7 +93,7 @@
|
||||
},
|
||||
emits: ['menuInteraction'],
|
||||
setup(props, { emit }) {
|
||||
const { t, locale, availableLocales } = useI18n()
|
||||
const { locale, availableLocales } = useI18n()
|
||||
const store = useStore()
|
||||
|
||||
const availableLanguages = availableLocales.map((l) => {
|
||||
@ -140,7 +140,6 @@
|
||||
isAuthenticated,
|
||||
isMenuOpen,
|
||||
language,
|
||||
t,
|
||||
capitalize,
|
||||
openMenu,
|
||||
closeMenu,
|
||||
|
@ -66,7 +66,7 @@
|
||||
stroke: none;
|
||||
fill-rule: nonzero;
|
||||
fill: var(--app-color);
|
||||
filter: drop-shadow(10px 10px 10px var(--app-shadow-color));
|
||||
filter: var(--svg-filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
:checked="selectedTimeFrame === frame"
|
||||
@input="onUpdateTimeFrame(frame)"
|
||||
/>
|
||||
<span>{{ t(`statistics.TIME_FRAMES.${frame}`) }}</span>
|
||||
<span>{{ $t(`statistics.TIME_FRAMES.${frame}`) }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,13 +39,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StatsMenu',
|
||||
emits: ['arrowClick', 'timeFrameUpdate'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n()
|
||||
let selectedTimeFrame = ref('month')
|
||||
const timeFrames = ['week', 'month', 'year']
|
||||
|
||||
@ -56,7 +54,6 @@
|
||||
|
||||
return {
|
||||
selectedTimeFrame,
|
||||
t,
|
||||
timeFrames,
|
||||
onUpdateTimeFrame,
|
||||
emit,
|
||||
|
@ -23,7 +23,7 @@
|
||||
import { ComputedRef, PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import { ISport, ITranslatedSport } from '@/types/sports'
|
||||
import { translateSports, sportColors } from '@/utils/sports'
|
||||
|
||||
|
@ -107,7 +107,6 @@
|
||||
chartParams,
|
||||
selectedTimeFrame,
|
||||
sportColors,
|
||||
t,
|
||||
timeFrames,
|
||||
translatedSports,
|
||||
selectedSportIds,
|
||||
|
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div id="password-action-done">
|
||||
<EmailSent v-if="action === 'request-sent'" />
|
||||
<Password v-else />
|
||||
<div class="password-message">
|
||||
<span v-if="action === 'request-sent'"
|
||||
>{{ $t('user.PASSWORD_SENT_EMAIL_TEXT') }}
|
||||
</span>
|
||||
<i18n-t v-else keypath="user.PASSWORD_UPDATED">
|
||||
<router-link to="/login">
|
||||
{{ $t('common.HERE') }}
|
||||
</router-link>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
import EmailSent from '@/components/Common/Images/EmailSent.vue'
|
||||
import Password from '@/components/Common/Images/Password.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PasswordActionDone',
|
||||
components: {
|
||||
EmailSent,
|
||||
Password,
|
||||
},
|
||||
props: {
|
||||
action: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/scss/base';
|
||||
|
||||
#password-action-done {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 100px auto;
|
||||
width: 700px;
|
||||
@media screen and (max-width: $medium-limit) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: none;
|
||||
fill-rule: nonzero;
|
||||
fill: var(--app-color);
|
||||
filter: var(--svg-filter);
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.password-message {
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
|
||||
@media screen and (max-width: $medium-limit) {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div id="password-reset-request">
|
||||
<Card>
|
||||
<template #title>{{ $t('user.RESET_PASSWORD') }}</template>
|
||||
<template #content>
|
||||
<UserAuthForm :action="action" :token="token" />
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import UserAuthForm from '@/components/User/UserAuthForm.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PasswordResetForm',
|
||||
components: {
|
||||
Card,
|
||||
UserAuthForm,
|
||||
},
|
||||
props: {
|
||||
action: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~@/scss/base';
|
||||
|
||||
#password-reset-request {
|
||||
margin: 100px auto;
|
||||
width: 700px;
|
||||
@media screen and (max-width: $medium-limit) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::v-deep(.card) {
|
||||
.card-content {
|
||||
#user-form {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,36 +1,36 @@
|
||||
<template>
|
||||
<div id="user-infos" class="description-list">
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.REGISTRATION_DATE') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.REGISTRATION_DATE') }}:</dt>
|
||||
<dd>{{ registrationDate }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.FIRST_NAME') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.FIRST_NAME') }}:</dt>
|
||||
<dd>{{ user.first_name }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.LAST_NAME') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.LAST_NAME') }}:</dt>
|
||||
<dd>{{ user.last_name }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.BIRTH_DATE') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.BIRTH_DATE') }}:</dt>
|
||||
<dd>{{ birthDate }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.LOCATION') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.LOCATION') }}:</dt>
|
||||
<dd>{{ user.location }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.BIO') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.BIO') }}:</dt>
|
||||
<dd class="user-bio">
|
||||
{{ user.bio }}
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="profile-buttons">
|
||||
<button @click="$router.push('/profile/edit')">
|
||||
{{ t('user.PROFILE.EDIT') }}
|
||||
{{ $t('user.PROFILE.EDIT') }}
|
||||
</button>
|
||||
<button @click="$router.push('/')">{{ t('common.HOME') }}</button>
|
||||
<button @click="$router.push('/')">{{ $t('common.HOME') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -38,7 +38,6 @@
|
||||
<script lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import { PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
|
||||
@ -51,7 +50,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const registrationDate = computed(() =>
|
||||
props.user.created_at
|
||||
? format(new Date(props.user.created_at), 'dd/MM/yyyy HH:mm')
|
||||
@ -62,7 +60,7 @@
|
||||
? format(new Date(props.user.birth_date), 'dd/MM/yyyy')
|
||||
: ''
|
||||
)
|
||||
return { birthDate, registrationDate, t }
|
||||
return { birthDate, registrationDate }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -1,29 +1,28 @@
|
||||
<template>
|
||||
<div id="user-preferences" class="description-list">
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.LANGUAGE') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.LANGUAGE') }}:</dt>
|
||||
<dd>{{ language }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.TIMEZONE') }}:</dt>
|
||||
<dt>{{ $t('user.PROFILE.TIMEZONE') }}:</dt>
|
||||
<dd>{{ timezone }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ t('user.PROFILE.FIRST_DAY_OF_WEEK') }}:</dt>
|
||||
<dd>{{ t(`user.PROFILE.${fistDayOfWeek}`) }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}:</dt>
|
||||
<dd>{{ $t(`user.PROFILE.${fistDayOfWeek}`) }}</dd>
|
||||
</dl>
|
||||
<div class="profile-buttons">
|
||||
<button @click="$router.push('/profile/edit/preferences')">
|
||||
{{ t('user.PROFILE.EDIT_PREFERENCES') }}
|
||||
{{ $t('user.PROFILE.EDIT_PREFERENCES') }}
|
||||
</button>
|
||||
<button @click="$router.push('/')">{{ t('common.HOME') }}</button>
|
||||
<button @click="$router.push('/')">{{ $t('common.HOME') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
|
||||
@ -36,7 +35,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const language = computed(() =>
|
||||
props.user.language ? props.user.language.toUpperCase() : 'EN'
|
||||
)
|
||||
@ -46,7 +44,7 @@
|
||||
const timezone = computed(() =>
|
||||
props.user.timezone ? props.user.timezone : 'Europe/Paris'
|
||||
)
|
||||
return { fistDayOfWeek, language, t, timezone }
|
||||
return { fistDayOfWeek, language, timezone }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="user-stat">
|
||||
<span class="stat-number">{{ user.nb_workouts }}</span>
|
||||
<span class="stat-label">
|
||||
{{ t('workouts.WORKOUT', user.nb_workouts) }}
|
||||
{{ $t('workouts.WORKOUT', user.nb_workouts) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="user-stat">
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="user-stat hide-small">
|
||||
<span class="stat-number">{{ user.nb_sports }}</span>
|
||||
<span class="stat-label">
|
||||
{{ t('workouts.SPORT', user.nb_sports) }}
|
||||
{{ $t('workouts.SPORT', user.nb_sports) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,7 +36,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { ComputedRef, PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import UserInfos from '@/components/User/ProfileDisplay/UserInfos.vue'
|
||||
import UserPreferences from '@/components/User/ProfileDisplay/UserPreferences.vue'
|
||||
@ -64,14 +63,13 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const tabs = ['PROFILE', 'PREFERENCES']
|
||||
const authUserPictureUrl: ComputedRef<string> = computed(() =>
|
||||
props.user.picture
|
||||
? `${getApiUrl()}/users/${props.user.username}/picture?${Date.now()}`
|
||||
: ''
|
||||
)
|
||||
return { authUserPictureUrl, t, tabs }
|
||||
return { authUserPictureUrl, tabs }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div id="user-infos-edition">
|
||||
<Modal
|
||||
v-if="displayModal"
|
||||
:title="t('common.CONFIRMATION')"
|
||||
:message="t('user.CONFIRM_ACCOUNT_DELETION')"
|
||||
:title="$t('common.CONFIRMATION')"
|
||||
:message="$t('user.CONFIRM_ACCOUNT_DELETION')"
|
||||
@confirmAction="deleteAccount(user.username)"
|
||||
@cancelAction="updateDisplayModal(false)"
|
||||
/>
|
||||
@ -11,15 +11,15 @@
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<form @submit.prevent="updateProfile">
|
||||
<label class="form-items" for="email">
|
||||
{{ t('user.EMAIL') }}
|
||||
{{ $t('user.EMAIL') }}
|
||||
<input id="email" :value="user.email" disabled />
|
||||
</label>
|
||||
<label class="form-items" for="registrationDate">
|
||||
{{ t('user.PROFILE.REGISTRATION_DATE') }}
|
||||
{{ $t('user.PROFILE.REGISTRATION_DATE') }}
|
||||
<input id="registrationDate" :value="registrationDate" disabled />
|
||||
</label>
|
||||
<label class="form-items" for="password">
|
||||
{{ t('user.PASSWORD') }}
|
||||
{{ $t('user.PASSWORD') }}
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
@ -28,7 +28,7 @@
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items" for="passwordConfirmation">
|
||||
{{ t('user.PASSWORD_CONFIRMATION') }}
|
||||
{{ $t('user.PASSWORD_CONFIRMATION') }}
|
||||
<input
|
||||
id="passwordConfirmation"
|
||||
type="password"
|
||||
@ -38,7 +38,7 @@
|
||||
</label>
|
||||
<hr />
|
||||
<label class="form-items" for="first_name">
|
||||
{{ t('user.PROFILE.FIRST_NAME') }}
|
||||
{{ $t('user.PROFILE.FIRST_NAME') }}
|
||||
<input
|
||||
id="first_name"
|
||||
v-model="userForm.first_name"
|
||||
@ -46,11 +46,11 @@
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items" for="last_name">
|
||||
{{ t('user.PROFILE.LAST_NAME') }}
|
||||
{{ $t('user.PROFILE.LAST_NAME') }}
|
||||
<input id="last_name" v-model="userForm.last_name" />
|
||||
</label>
|
||||
<label class="form-items" for="birth_date">
|
||||
{{ t('user.PROFILE.BIRTH_DATE') }}
|
||||
{{ $t('user.PROFILE.BIRTH_DATE') }}
|
||||
<input
|
||||
id="birth_date"
|
||||
type="date"
|
||||
@ -60,7 +60,7 @@
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items" for="location">
|
||||
{{ t('user.PROFILE.LOCATION') }}
|
||||
{{ $t('user.PROFILE.LOCATION') }}
|
||||
<input
|
||||
id="location"
|
||||
v-model="userForm.location"
|
||||
@ -68,7 +68,7 @@
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items">
|
||||
{{ t('user.PROFILE.BIO') }}
|
||||
{{ $t('user.PROFILE.BIO') }}
|
||||
<CustomTextArea
|
||||
name="bio"
|
||||
:charLimit="200"
|
||||
@ -79,13 +79,13 @@
|
||||
</label>
|
||||
<div class="form-buttons">
|
||||
<button class="confirm" type="submit">
|
||||
{{ t('buttons.SUBMIT') }}
|
||||
{{ $t('buttons.SUBMIT') }}
|
||||
</button>
|
||||
<button class="cancel" @click.prevent="$router.go(-1)">
|
||||
{{ t('buttons.CANCEL') }}
|
||||
{{ $t('buttons.CANCEL') }}
|
||||
</button>
|
||||
<button class="danger" @click.prevent="updateDisplayModal(true)">
|
||||
{{ t('buttons.DELETE_MY_ACCOUNT') }}
|
||||
{{ $t('buttons.DELETE_MY_ACCOUNT') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -105,7 +105,6 @@
|
||||
ref,
|
||||
onMounted,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import CustomTextArea from '@/components/Common/CustomTextArea.vue'
|
||||
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
|
||||
@ -128,7 +127,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
const userForm: IUserPayload = reactive({
|
||||
password: '',
|
||||
@ -185,7 +183,6 @@
|
||||
errorMessages,
|
||||
loading,
|
||||
registrationDate,
|
||||
t,
|
||||
userForm,
|
||||
deleteAccount,
|
||||
updateBio,
|
||||
|
@ -12,16 +12,16 @@
|
||||
/>
|
||||
<div class="picture-buttons">
|
||||
<button type="submit" :disabled="!pictureFile">
|
||||
{{ t('user.PROFILE.PICTURE_UPDATE') }}
|
||||
{{ $t('user.PROFILE.PICTURE_UPDATE') }}
|
||||
</button>
|
||||
<button class="danger" v-if="user.picture" @click="deleteUserPicture">
|
||||
{{ t('user.PROFILE.PICTURE_REMOVE') }}
|
||||
{{ $t('user.PROFILE.PICTURE_REMOVE') }}
|
||||
</button>
|
||||
<button class="cancel" @click="$router.push('/profile')">
|
||||
{{ t('user.PROFILE.BACK_TO_PROFILE') }}
|
||||
{{ $t('user.PROFILE.BACK_TO_PROFILE') }}
|
||||
</button>
|
||||
</div>
|
||||
<span>{{ t('workouts.MAX_SIZE') }}: {{ fileSizeLimit }}</span>
|
||||
<span>{{ $t('workouts.MAX_SIZE') }}: {{ fileSizeLimit }}</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,7 +36,6 @@
|
||||
computed,
|
||||
ref,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
|
||||
import UserPicture from '@/components/User/UserPicture.vue'
|
||||
@ -59,7 +58,6 @@
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
@ -92,7 +90,6 @@
|
||||
errorMessages,
|
||||
fileSizeLimit,
|
||||
pictureFile,
|
||||
t,
|
||||
deleteUserPicture,
|
||||
updateUserPicture,
|
||||
updatePictureFile,
|
||||
|
@ -4,7 +4,7 @@
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<form @submit.prevent="updateProfile">
|
||||
<label class="form-items">
|
||||
{{ t('user.PROFILE.LANGUAGE') }}
|
||||
{{ $t('user.PROFILE.LANGUAGE') }}
|
||||
<select id="language" v-model="userForm.language" :disabled="loading">
|
||||
<option
|
||||
v-for="lang in availableLanguages"
|
||||
@ -16,7 +16,7 @@
|
||||
</select>
|
||||
</label>
|
||||
<label class="form-items" for="timezone">
|
||||
{{ t('user.PROFILE.TIMEZONE') }}
|
||||
{{ $t('user.PROFILE.TIMEZONE') }}
|
||||
<input
|
||||
id="timezone"
|
||||
v-model="userForm.timezone"
|
||||
@ -24,23 +24,23 @@
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items">
|
||||
{{ t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
|
||||
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
|
||||
<select id="weekm" v-model="userForm.weekm" :disabled="loading">
|
||||
<option
|
||||
v-for="start in weekStart"
|
||||
:value="start.value"
|
||||
:key="start.value"
|
||||
>
|
||||
{{ t(`user.PROFILE.${start.label}`) }}
|
||||
{{ $t(`user.PROFILE.${start.label}`) }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="form-buttons">
|
||||
<button class="confirm" type="submit">
|
||||
{{ t('buttons.SUBMIT') }}
|
||||
{{ $t('buttons.SUBMIT') }}
|
||||
</button>
|
||||
<button class="cancel" @click.prevent="$router.go(-1)">
|
||||
{{ t('buttons.CANCEL') }}
|
||||
{{ $t('buttons.CANCEL') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -76,7 +76,7 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t, availableLocales } = useI18n()
|
||||
const { availableLocales } = useI18n()
|
||||
const store = useStore()
|
||||
const userForm: IUserPreferencesPayload = reactive({
|
||||
language: '',
|
||||
@ -122,7 +122,6 @@
|
||||
availableLanguages,
|
||||
errorMessages,
|
||||
loading,
|
||||
t,
|
||||
userForm,
|
||||
weekStart,
|
||||
updateProfile,
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="user-profile-edition">
|
||||
<Card>
|
||||
<template #title>{{ t(`user.PROFILE.${tab}_EDITION`) }}</template>
|
||||
<template #title>{{ $t(`user.PROFILE.${tab}_EDITION`) }}</template>
|
||||
<template #content>
|
||||
<UserProfileTabs
|
||||
:tabs="tabs"
|
||||
@ -18,8 +18,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent, ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { PropType, computed, defineComponent, ref } from 'vue'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import UserInfosEdition from '@/components/User/ProfileEdition/UserInfosEdition.vue'
|
||||
@ -50,14 +49,13 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
const tabs = ['PROFILE', 'PICTURE', 'PREFERENCES']
|
||||
const selectedTab = ref(props.tab)
|
||||
const loading = computed(
|
||||
() => store.getters[USER_STORE.GETTERS.USER_LOADING]
|
||||
)
|
||||
return { loading, selectedTab, t, tabs }
|
||||
return { loading, selectedTab, tabs }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="login-or-register-form">
|
||||
<div id="user-auth-form">
|
||||
<div id="user-form">
|
||||
<div
|
||||
class="form-box"
|
||||
@ -19,38 +19,57 @@
|
||||
:disabled="registration_disabled"
|
||||
required
|
||||
v-model="formData.username"
|
||||
:placeholder="t('user.USERNAME')"
|
||||
:placeholder="$t('user.USERNAME')"
|
||||
/>
|
||||
<input
|
||||
v-if="action !== 'reset'"
|
||||
id="email"
|
||||
:disabled="registration_disabled"
|
||||
required
|
||||
type="email"
|
||||
v-model="formData.email"
|
||||
:placeholder="t('user.EMAIL')"
|
||||
:placeholder="
|
||||
action === 'reset-request'
|
||||
? $t('user.ENTER_EMAIL')
|
||||
: $t('user.EMAIL')
|
||||
"
|
||||
/>
|
||||
<input
|
||||
v-if="action !== 'reset-request'"
|
||||
id="password"
|
||||
:disabled="registration_disabled"
|
||||
required
|
||||
type="password"
|
||||
v-model="formData.password"
|
||||
:placeholder="t('user.PASSWORD')"
|
||||
:placeholder="
|
||||
action === 'reset'
|
||||
? $t('user.ENTER_PASSWORD')
|
||||
: $t('user.PASSWORD')
|
||||
"
|
||||
/>
|
||||
<input
|
||||
v-if="action === 'register'"
|
||||
v-if="['register', 'reset'].includes(action)"
|
||||
id="confirm-password"
|
||||
:disabled="registration_disabled"
|
||||
type="password"
|
||||
required
|
||||
v-model="formData.password_conf"
|
||||
:placeholder="t('user.PASSWORD_CONFIRM')"
|
||||
:placeholder="
|
||||
action === 'reset'
|
||||
? $t('user.ENTER_PASSWORD_CONFIRMATION')
|
||||
: $t('user.PASSWORD_CONFIRM')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" :disabled="registration_disabled">
|
||||
{{ t(buttonText) }}
|
||||
{{ $t(buttonText) }}
|
||||
</button>
|
||||
</form>
|
||||
<div v-if="action === 'login'">
|
||||
<router-link class="password-forgotten" to="/password-reset/request">
|
||||
{{ $t('user.PASSWORD_FORGOTTEN') }}
|
||||
</router-link>
|
||||
</div>
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
</div>
|
||||
</div>
|
||||
@ -59,19 +78,17 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { ComputedRef, computed, defineComponent, reactive, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import AlertMessage from '@/components/Common/AlertMessage.vue'
|
||||
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
|
||||
import router from '@/router'
|
||||
import { ROOT_STORE, USER_STORE } from '@/store/constants'
|
||||
import { IAppConfig } from '@/types/application'
|
||||
import { ILoginRegisterFormData } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LoginOrRegisterForm',
|
||||
name: 'UserAuthForm',
|
||||
components: {
|
||||
AlertMessage,
|
||||
ErrorMessage,
|
||||
@ -81,6 +98,10 @@
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const formData: ILoginRegisterFormData = reactive({
|
||||
@ -89,12 +110,11 @@
|
||||
password: '',
|
||||
password_conf: '',
|
||||
})
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
|
||||
const buttonText: ComputedRef<string> = computed(() =>
|
||||
props.action === 'register' ? 'buttons.REGISTER' : 'buttons.LOGIN'
|
||||
getButtonText(props.action)
|
||||
)
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
@ -108,11 +128,42 @@
|
||||
!appConfig.value.is_registration_enabled
|
||||
)
|
||||
|
||||
function getButtonText(action: string): string {
|
||||
switch (action) {
|
||||
case 'reset-request':
|
||||
case 'reset':
|
||||
return 'buttons.SUBMIT'
|
||||
default:
|
||||
return `buttons.${props.action.toUpperCase()}`
|
||||
}
|
||||
}
|
||||
function onSubmit(actionType: string) {
|
||||
return store.dispatch(USER_STORE.ACTIONS.LOGIN_OR_REGISTER, {
|
||||
actionType,
|
||||
formData,
|
||||
})
|
||||
switch (actionType) {
|
||||
case 'reset':
|
||||
if (!props.token) {
|
||||
return store.commit(
|
||||
ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGES,
|
||||
'user.INVALID_TOKEN'
|
||||
)
|
||||
}
|
||||
return store.dispatch(USER_STORE.ACTIONS.RESET_USER_PASSWORD, {
|
||||
password: formData.password,
|
||||
password_conf: formData.password_conf,
|
||||
token: props.token,
|
||||
})
|
||||
case 'reset-request':
|
||||
return store.dispatch(
|
||||
USER_STORE.ACTIONS.SEND_PASSWORD_RESET_REQUEST,
|
||||
{
|
||||
email: formData.email,
|
||||
}
|
||||
)
|
||||
default:
|
||||
store.dispatch(USER_STORE.ACTIONS.LOGIN_OR_REGISTER, {
|
||||
actionType,
|
||||
formData,
|
||||
})
|
||||
}
|
||||
}
|
||||
function resetFormData() {
|
||||
formData.username = ''
|
||||
@ -128,13 +179,11 @@
|
||||
}
|
||||
)
|
||||
return {
|
||||
t,
|
||||
appConfig,
|
||||
buttonText,
|
||||
errorMessages,
|
||||
formData,
|
||||
registration_disabled,
|
||||
router,
|
||||
onSubmit,
|
||||
}
|
||||
},
|
||||
@ -144,7 +193,7 @@
|
||||
<style scoped lang="scss">
|
||||
@import '~@/scss/base';
|
||||
|
||||
#login-or-register-form {
|
||||
#user-auth-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -154,6 +203,12 @@
|
||||
#user-form {
|
||||
width: 60%;
|
||||
|
||||
.password-forgotten {
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
padding-left: $default-padding;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: $default-margin;
|
||||
border: solid 1px var(--app-color);
|
@ -3,7 +3,7 @@
|
||||
<img
|
||||
v-if="authUserPictureUrl !== ''"
|
||||
class="nav-profile-user-img"
|
||||
:alt="t('user.USER_PICTURE')"
|
||||
:alt="$t('user.USER_PICTURE')"
|
||||
:src="authUserPictureUrl"
|
||||
/>
|
||||
<div v-else class="no-picture">
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
import { getApiUrl } from '@/utils'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UserPicture',
|
||||
props: {
|
||||
@ -27,14 +27,12 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
return {
|
||||
authUserPictureUrl: computed(() =>
|
||||
props.user.picture
|
||||
? `${getApiUrl()}users/${props.user.username}/picture?${Date.now()}`
|
||||
: ''
|
||||
),
|
||||
t,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -11,7 +11,7 @@
|
||||
:disabled="disabled"
|
||||
@input="$router.push(getPath(tab))"
|
||||
/>
|
||||
<span>{{ t(`user.PROFILE.TABS.${tab}`) }}</span>
|
||||
<span>{{ $t(`user.PROFILE.TABS.${tab}`) }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -20,7 +20,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UserProfileTabs',
|
||||
@ -43,7 +42,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
function getPath(tab: string) {
|
||||
switch (tab) {
|
||||
case 'PICTURE':
|
||||
@ -55,7 +53,7 @@
|
||||
return `/profile${props.edition ? '/edit' : ''}`
|
||||
}
|
||||
}
|
||||
return { t, getPath }
|
||||
return { getPath }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<img
|
||||
class="profile-img"
|
||||
v-if="userPictureUrl !== ''"
|
||||
:alt="t('user.USER_PICTURE')"
|
||||
:alt="$t('user.USER_PICTURE')"
|
||||
:src="userPictureUrl"
|
||||
/>
|
||||
<div v-else class="no-picture">
|
||||
@ -49,7 +49,7 @@
|
||||
<div v-if="workout">
|
||||
<StaticMap v-if="workout.with_gpx" :workout="workout" />
|
||||
<div v-else class="no-map">
|
||||
{{ t('workouts.NO_MAP') }}
|
||||
{{ $t('workouts.NO_MAP') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -78,9 +78,8 @@
|
||||
<script lang="ts">
|
||||
import { Locale, format, formatDistance } from 'date-fns'
|
||||
import { PropType, defineComponent, ComputedRef, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import StaticMap from '@/components/Common/StaticMap.vue'
|
||||
import { ROOT_STORE } from '@/store/constants'
|
||||
import { ISport } from '@/types/sports'
|
||||
@ -111,7 +110,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
|
||||
const userPictureUrl: ComputedRef<string> = computed(() =>
|
||||
@ -128,7 +126,6 @@
|
||||
formatDistance,
|
||||
getDateWithTZ,
|
||||
locale,
|
||||
t,
|
||||
userPictureUrl,
|
||||
}
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="workout-chart">
|
||||
<Card>
|
||||
<template #title>{{ t('workouts.ANALYSIS') }} </template>
|
||||
<template #title>{{ $t('workouts.ANALYSIS') }} </template>
|
||||
<template #content>
|
||||
<div class="chart-radio">
|
||||
<label>
|
||||
@ -11,7 +11,7 @@
|
||||
:checked="displayDistance"
|
||||
@click="updateDisplayDistance"
|
||||
/>
|
||||
{{ t('workouts.DISTANCE') }}
|
||||
{{ $t('workouts.DISTANCE') }}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
@ -20,7 +20,7 @@
|
||||
:checked="!displayDistance"
|
||||
@click="updateDisplayDistance"
|
||||
/>
|
||||
{{ t('workouts.DURATION') }}
|
||||
{{ $t('workouts.DURATION') }}
|
||||
</label>
|
||||
</div>
|
||||
<LineChart
|
||||
@ -29,7 +29,7 @@
|
||||
@mouseleave="emitEmptyCoordinates"
|
||||
/>
|
||||
<div class="no-data-cleaning">
|
||||
{{ t('workouts.NO_DATA_CLEANING') }}
|
||||
{{ $t('workouts.NO_DATA_CLEANING') }}
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
@ -201,7 +201,6 @@
|
||||
return {
|
||||
displayDistance,
|
||||
lineChartProps,
|
||||
t,
|
||||
emitEmptyCoordinates,
|
||||
updateDisplayDistance,
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
:class="{ inactive: !workoutObject.previousUrl }"
|
||||
:title="
|
||||
workoutObject.previousUrl
|
||||
? t(`workouts.PREVIOUS_${workoutObject.type}`)
|
||||
: t(`workouts.NO_PREVIOUS_${workoutObject.type}`)
|
||||
? $t(`workouts.PREVIOUS_${workoutObject.type}`)
|
||||
: $t(`workouts.NO_PREVIOUS_${workoutObject.type}`)
|
||||
"
|
||||
@click="
|
||||
workoutObject.previousUrl
|
||||
@ -42,7 +42,7 @@
|
||||
<span class="workout-segment">
|
||||
—
|
||||
<i class="fa fa-map-marker" aria-hidden="true" />
|
||||
{{ t('workouts.SEGMENT') }}
|
||||
{{ $t('workouts.SEGMENT') }}
|
||||
{{ workoutObject.segmentId + 1 }}
|
||||
</span>
|
||||
</div>
|
||||
@ -57,7 +57,7 @@
|
||||
params: { workoutId: workoutObject.workoutId },
|
||||
}"
|
||||
>
|
||||
> {{ t('workouts.BACK_TO_WORKOUT') }}
|
||||
> {{ $t('workouts.BACK_TO_WORKOUT') }}
|
||||
</router-link></span
|
||||
>
|
||||
</div>
|
||||
@ -68,8 +68,8 @@
|
||||
:class="{ inactive: !workoutObject.nextUrl }"
|
||||
:title="
|
||||
workoutObject.nextUrl
|
||||
? t(`workouts.NEXT_${workoutObject.type}`)
|
||||
: t(`workouts.NO_NEXT_${workoutObject.type}`)
|
||||
? $t(`workouts.NEXT_${workoutObject.type}`)
|
||||
: $t(`workouts.NO_NEXT_${workoutObject.type}`)
|
||||
"
|
||||
@click="
|
||||
workoutObject.nextUrl ? $router.push(workoutObject.nextUrl) : null
|
||||
@ -82,9 +82,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import { ISport } from '@/types/sports'
|
||||
import { IWorkoutObject } from '@/types/workouts'
|
||||
|
||||
@ -105,8 +104,7 @@
|
||||
},
|
||||
emits: ['displayModal'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n()
|
||||
return { t, emit }
|
||||
return { emit }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -2,25 +2,26 @@
|
||||
<div id="workout-info">
|
||||
<div class="workout-data">
|
||||
<i class="fa fa-clock-o" aria-hidden="true" />
|
||||
{{ t('workouts.DURATION') }}: <span>{{ workoutObject.moving }}</span>
|
||||
{{ $t('workouts.DURATION') }}: <span>{{ workoutObject.moving }}</span>
|
||||
<WorkoutRecord :workoutObject="workoutObject" record_type="LD" />
|
||||
<div v-if="withPause">
|
||||
({{ t('workouts.PAUSES') }}: <span>{{ workoutObject.pauses }}</span> -
|
||||
{{ t('workouts.TOTAL_DURATION') }}:
|
||||
({{ $t('workouts.PAUSES') }}: <span>{{ workoutObject.pauses }}</span> -
|
||||
{{ $t('workouts.TOTAL_DURATION') }}:
|
||||
<span>{{ workoutObject.duration }})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workout-data">
|
||||
<i class="fa fa-road" aria-hidden="true" />
|
||||
{{ t('workouts.DISTANCE') }}: <span>{{ workoutObject.distance }} km</span>
|
||||
{{ $t('workouts.DISTANCE') }}:
|
||||
<span>{{ workoutObject.distance }} km</span>
|
||||
<WorkoutRecord :workoutObject="workoutObject" record_type="FD" />
|
||||
</div>
|
||||
<div class="workout-data">
|
||||
<i class="fa fa-tachometer" aria-hidden="true" />
|
||||
{{ t('workouts.AVERAGE_SPEED') }}:
|
||||
{{ $t('workouts.AVERAGE_SPEED') }}:
|
||||
<span>{{ workoutObject.aveSpeed }} km/h</span
|
||||
><WorkoutRecord :workoutObject="workoutObject" record_type="AS" /><br />
|
||||
{{ t('workouts.MAX_SPEED') }}:
|
||||
{{ $t('workouts.MAX_SPEED') }}:
|
||||
<span>{{ workoutObject.maxSpeed }} km/h</span>
|
||||
<WorkoutRecord :workoutObject="workoutObject" record_type="MS" />
|
||||
</div>
|
||||
@ -31,11 +32,11 @@
|
||||
<img
|
||||
class="mountains"
|
||||
src="/img/workouts/mountains.svg"
|
||||
:alt="t('workouts.ELEVATION')"
|
||||
:alt="$t('workouts.ELEVATION')"
|
||||
/>
|
||||
{{ t('workouts.MIN_ALTITUDE') }}: <span>{{ workoutObject.minAlt }} m</span
|
||||
><br />
|
||||
{{ t('workouts.MAX_ALTITUDE') }}:
|
||||
{{ $t('workouts.MIN_ALTITUDE') }}:
|
||||
<span>{{ workoutObject.minAlt }} m</span><br />
|
||||
{{ $t('workouts.MAX_ALTITUDE') }}:
|
||||
<span>{{ workoutObject.maxAlt }} m</span>
|
||||
</div>
|
||||
<div
|
||||
@ -43,9 +44,9 @@
|
||||
v-if="workoutObject.ascent !== null && workoutObject.descent !== null"
|
||||
>
|
||||
<i class="fa fa-location-arrow" aria-hidden="true" />
|
||||
{{ t('workouts.ASCENT') }}: <span>{{ workoutObject.ascent }} m</span
|
||||
{{ $t('workouts.ASCENT') }}: <span>{{ workoutObject.ascent }} m</span
|
||||
><br />
|
||||
{{ t('workouts.DESCENT') }}: <span>{{ workoutObject.descent }} m</span>
|
||||
{{ $t('workouts.DESCENT') }}: <span>{{ workoutObject.descent }} m</span>
|
||||
</div>
|
||||
<WorkoutWeather :workoutObject="workoutObject" />
|
||||
</div>
|
||||
@ -53,7 +54,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import WorkoutRecord from '@/components/Workout/WorkoutDetail/WorkoutRecord.vue'
|
||||
import WorkoutWeather from '@/components/Workout/WorkoutDetail/WorkoutWeather.vue'
|
||||
@ -72,14 +72,12 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
return {
|
||||
withPause: computed(
|
||||
() =>
|
||||
props.workoutObject.pauses !== '0:00:00' &&
|
||||
props.workoutObject.pauses !== null
|
||||
),
|
||||
t,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -23,7 +23,7 @@
|
||||
/>
|
||||
</LMap>
|
||||
</div>
|
||||
<div v-else class="no-map">{{ t('workouts.NO_MAP') }}</div>
|
||||
<div v-else class="no-map">{{ $t('workouts.NO_MAP') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -32,7 +32,6 @@
|
||||
import { gpx } from '@tmcw/togeojson'
|
||||
import { LGeoJson, LMap, LMarker, LTileLayer } from '@vue-leaflet/vue-leaflet'
|
||||
import { ComputedRef, PropType, computed, defineComponent, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { ROOT_STORE } from '@/store/constants'
|
||||
import { IAppConfig } from '@/types/application'
|
||||
@ -59,7 +58,6 @@
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
|
||||
function getGeoJson(gpxContent: string): GeoJSONData {
|
||||
@ -120,7 +118,6 @@
|
||||
bounds,
|
||||
center,
|
||||
geoJson,
|
||||
t,
|
||||
workoutMap,
|
||||
fitBounds,
|
||||
getApiUrl,
|
||||
|
@ -9,17 +9,17 @@
|
||||
<th />
|
||||
<th>
|
||||
<div class="weather-th">
|
||||
{{ t('workouts.START') }}
|
||||
{{ $t('workouts.START') }}
|
||||
<img
|
||||
class="weather-img"
|
||||
:src="`/img/weather/${workoutObject.weatherStart.icon}.svg`"
|
||||
:alt="
|
||||
t(
|
||||
$t(
|
||||
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherStart.icon}`
|
||||
)
|
||||
"
|
||||
:title="
|
||||
t(
|
||||
$t(
|
||||
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherStart.icon}`
|
||||
)
|
||||
"
|
||||
@ -28,17 +28,17 @@
|
||||
</th>
|
||||
<th>
|
||||
<div class="weather-th">
|
||||
{{ t('workouts.END') }}
|
||||
{{ $t('workouts.END') }}
|
||||
<img
|
||||
class="weather-img"
|
||||
:src="`/img/weather/${workoutObject.weatherEnd.icon}.svg`"
|
||||
:alt="
|
||||
t(
|
||||
$t(
|
||||
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherEnd.icon}`
|
||||
)
|
||||
"
|
||||
:title="
|
||||
t(
|
||||
$t(
|
||||
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherEnd.icon}`
|
||||
)
|
||||
"
|
||||
@ -53,8 +53,8 @@
|
||||
<img
|
||||
class="weather-img weather-img-small"
|
||||
src="/img/weather/temperature.svg"
|
||||
:alt="t(`workouts.WEATHER.TEMPERATURE`)"
|
||||
:title="t(`workouts.WEATHER.TEMPERATURE`)"
|
||||
:alt="$t(`workouts.WEATHER.TEMPERATURE`)"
|
||||
:title="$t(`workouts.WEATHER.TEMPERATURE`)"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
@ -69,8 +69,8 @@
|
||||
<img
|
||||
class="weather-img weather-img-small"
|
||||
src="/img/weather/pour-rain.svg"
|
||||
:alt="t(`workouts.WEATHER.HUMIDITY`)"
|
||||
:title="t(`workouts.WEATHER.HUMIDITY`)"
|
||||
:alt="$t(`workouts.WEATHER.HUMIDITY`)"
|
||||
:title="$t(`workouts.WEATHER.HUMIDITY`)"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
@ -85,8 +85,8 @@
|
||||
<img
|
||||
class="weather-img weather-img-small"
|
||||
src="/img/weather/breeze.svg"
|
||||
:alt="t(`workouts.WEATHER.WIND`)"
|
||||
:title="t(`workouts.WEATHER.WIND`)"
|
||||
:alt="$t(`workouts.WEATHER.WIND`)"
|
||||
:title="$t(`workouts.WEATHER.WIND`)"
|
||||
/>
|
||||
</td>
|
||||
<td>{{ Number(workoutObject.weatherStart.wind).toFixed(1) }}m/s</td>
|
||||
@ -99,9 +99,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { IWorkoutObject } from '@/types/workouts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'WorkoutWeather',
|
||||
props: {
|
||||
@ -110,10 +110,6 @@
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div class="workout-detail">
|
||||
<Modal
|
||||
v-if="displayModal"
|
||||
:title="t('common.CONFIRMATION')"
|
||||
:message="t('workouts.WORKOUT_DELETION_CONFIRMATION')"
|
||||
:title="$t('common.CONFIRMATION')"
|
||||
:message="$t('workouts.WORKOUT_DELETION_CONFIRMATION')"
|
||||
@confirmAction="deleteWorkout(workoutObject.workoutId)"
|
||||
@cancelAction="updateDisplayModal(false)"
|
||||
/>
|
||||
@ -36,7 +36,6 @@
|
||||
ref,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
@ -90,7 +89,6 @@
|
||||
setup(props) {
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
function getWorkoutObjectUrl(
|
||||
workout: IWorkout,
|
||||
@ -196,7 +194,6 @@
|
||||
getWorkoutObject(workout.value, segment.value)
|
||||
),
|
||||
displayModal,
|
||||
t,
|
||||
deleteWorkout,
|
||||
updateDisplayModal,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
>
|
||||
<Card>
|
||||
<template #title>{{
|
||||
t(`workouts.${isCreation ? 'ADD' : 'EDIT'}_WORKOUT`)
|
||||
$t(`workouts.${isCreation ? 'ADD' : 'EDIT'}_WORKOUT`)
|
||||
}}</template>
|
||||
<template #content>
|
||||
<div id="workout-form">
|
||||
@ -20,7 +20,7 @@
|
||||
:disabled="loading"
|
||||
@click="updateWithGpx"
|
||||
/>
|
||||
<label for="withGpx">{{ t('workouts.WITH_GPX') }}</label>
|
||||
<label for="withGpx">{{ $t('workouts.WITH_GPX') }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
@ -31,12 +31,12 @@
|
||||
@click="updateWithGpx"
|
||||
/>
|
||||
<label for="withoutGpx">{{
|
||||
t('workouts.WITHOUT_GPX')
|
||||
$t('workouts.WITHOUT_GPX')
|
||||
}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.SPORT', 1) }}: </label>
|
||||
<label> {{ $t('workouts.SPORT', 1) }}: </label>
|
||||
<select
|
||||
id="sport"
|
||||
required
|
||||
@ -54,8 +54,8 @@
|
||||
</div>
|
||||
<div class="form-item" v-if="isCreation && withGpx">
|
||||
<label for="gpxFile">
|
||||
{{ t('workouts.GPX_FILE') }}
|
||||
{{ t('workouts.ZIP_ARCHIVE_DESCRIPTION') }}:
|
||||
{{ $t('workouts.GPX_FILE') }}
|
||||
{{ $t('workouts.ZIP_ARCHIVE_DESCRIPTION') }}:
|
||||
</label>
|
||||
<input
|
||||
id="gpxFile"
|
||||
@ -67,26 +67,28 @@
|
||||
/>
|
||||
<div class="files-help">
|
||||
<div>
|
||||
<strong>{{ t('workouts.GPX_FILE') }}:</strong>
|
||||
<strong>{{ $t('workouts.GPX_FILE') }}:</strong>
|
||||
<ul>
|
||||
<li>{{ t('workouts.MAX_SIZE') }}: {{ fileSizeLimit }}</li>
|
||||
<li>
|
||||
{{ $t('workouts.MAX_SIZE') }}: {{ fileSizeLimit }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>{{ t('workouts.ZIP_ARCHIVE') }}:</strong>
|
||||
<strong>{{ $t('workouts.ZIP_ARCHIVE') }}:</strong>
|
||||
<ul>
|
||||
<li>{{ t('workouts.NO_FOLDER') }}</li>
|
||||
<li>{{ $t('workouts.NO_FOLDER') }}</li>
|
||||
<li>
|
||||
{{ t('workouts.MAX_FILES') }}: {{ gpx_limit_import }}
|
||||
{{ $t('workouts.MAX_FILES') }}: {{ gpx_limit_import }}
|
||||
</li>
|
||||
<li>{{ t('workouts.MAX_SIZE') }}: {{ zipSizeLimit }}</li>
|
||||
<li>{{ $t('workouts.MAX_SIZE') }}: {{ zipSizeLimit }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item" v-else>
|
||||
<label for="title"> {{ t('workouts.TITLE') }}: </label>
|
||||
<label for="title"> {{ $t('workouts.TITLE') }}: </label>
|
||||
<input
|
||||
id="title"
|
||||
name="title"
|
||||
@ -99,7 +101,7 @@
|
||||
<div v-if="!withGpx">
|
||||
<div class="workout-date-duration">
|
||||
<div class="form-item">
|
||||
<label>{{ t('workouts.WORKOUT_DATE') }}:</label>
|
||||
<label>{{ $t('workouts.WORKOUT_DATE') }}:</label>
|
||||
<div class="workout-date-time">
|
||||
<input
|
||||
id="workout-date"
|
||||
@ -121,7 +123,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>{{ t('workouts.DURATION') }}:</label>
|
||||
<label>{{ $t('workouts.DURATION') }}:</label>
|
||||
<div>
|
||||
<input
|
||||
id="workout-duration-hour"
|
||||
@ -162,7 +164,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>{{ t('workouts.DISTANCE') }} (km):</label>
|
||||
<label>{{ $t('workouts.DISTANCE') }} (km):</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
@ -174,7 +176,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.NOTES') }}: </label>
|
||||
<label> {{ $t('workouts.NOTES') }}: </label>
|
||||
<CustomTextArea
|
||||
name="notes"
|
||||
:input="workoutDataObject.notes"
|
||||
@ -189,10 +191,10 @@
|
||||
</div>
|
||||
<div v-else class="form-buttons">
|
||||
<button class="confirm" type="submit" :disabled="loading">
|
||||
{{ t('buttons.SUBMIT') }}
|
||||
{{ $t('buttons.SUBMIT') }}
|
||||
</button>
|
||||
<button class="cancel" @click.prevent="onCancel">
|
||||
{{ t('buttons.CANCEL') }}
|
||||
{{ $t('buttons.CANCEL') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -406,7 +408,6 @@
|
||||
errorMessages,
|
||||
fileSizeLimit,
|
||||
gpx_limit_import,
|
||||
t,
|
||||
translatedSports,
|
||||
withGpx,
|
||||
zipSizeLimit,
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div id="workout-note">
|
||||
<Card>
|
||||
<template #title>{{ t('workouts.NOTES') }}</template>
|
||||
<template #title>{{ $t('workouts.NOTES') }}</template>
|
||||
<template #content>
|
||||
{{ notes && notes !== '' ? notes : t('workouts.NO_NOTES') }}</template
|
||||
{{ notes && notes !== '' ? notes : $t('workouts.NO_NOTES') }}</template
|
||||
>
|
||||
</Card>
|
||||
</div>
|
||||
@ -11,7 +11,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
|
||||
@ -26,10 +25,6 @@
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="workout-segments">
|
||||
<Card>
|
||||
<template #title>{{ t('workouts.SEGMENT', 2) }}</template>
|
||||
<template #title>{{ $t('workouts.SEGMENT', 2) }}</template>
|
||||
<template #content>
|
||||
<ul>
|
||||
<li v-for="(segment, index) in segments" :key="segment.segment_id">
|
||||
@ -13,10 +13,10 @@
|
||||
segmentId: index + 1,
|
||||
},
|
||||
}"
|
||||
>{{ t('workouts.SEGMENT', 1) }} {{ index + 1 }}</router-link
|
||||
>{{ $t('workouts.SEGMENT', 1) }} {{ index + 1 }}</router-link
|
||||
>
|
||||
({{ t('workouts.DISTANCE') }}: {{ segment.distance }} km,
|
||||
{{ t('workouts.DURATION') }}: {{ segment.duration }})
|
||||
({{ $t('workouts.DISTANCE') }}: {{ segment.distance }} km,
|
||||
{{ $t('workouts.DURATION') }}: {{ segment.duration }})
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
@ -26,7 +26,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Card from '@/components/Common/Card.vue'
|
||||
import { IWorkoutSegment } from '@/types/workouts'
|
||||
@ -42,10 +41,6 @@
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="no-workouts box">
|
||||
<div>
|
||||
{{ t('workouts.NO_WORKOUTS') }}
|
||||
{{ $t('workouts.NO_WORKOUTS') }}
|
||||
<router-link to="/workouts/add">
|
||||
{{ t('workouts.UPLOAD_FIRST_WORKOUT') }}
|
||||
{{ $t('workouts.UPLOAD_FIRST_WORKOUT') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@ -11,14 +11,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NoWorkouts',
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
return { t }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -4,18 +4,18 @@
|
||||
<div class="form">
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.FROM') }}: </label>
|
||||
<label> {{ $t('workouts.FROM') }}: </label>
|
||||
<input name="from" type="date" @change="handleFilterChange" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.TO') }}: </label>
|
||||
<label> {{ $t('workouts.TO') }}: </label>
|
||||
<input name="to" type="date" @change="handleFilterChange" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.SPORT', 1) }}:</label>
|
||||
<label> {{ $t('workouts.SPORT', 1) }}:</label>
|
||||
<select name="sport_id" @change="handleFilterChange">
|
||||
<option value="" />
|
||||
<option
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.DISTANCE') }} (km): </label>
|
||||
<label> {{ $t('workouts.DISTANCE') }} (km): </label>
|
||||
<div class="form-inputs-group">
|
||||
<input
|
||||
name="distance_from"
|
||||
@ -40,7 +40,7 @@
|
||||
step="1"
|
||||
@change="handleFilterChange"
|
||||
/>
|
||||
<span>{{ t('workouts.TO') }}</span>
|
||||
<span>{{ $t('workouts.TO') }}</span>
|
||||
<input
|
||||
name="distance_to"
|
||||
type="number"
|
||||
@ -54,7 +54,7 @@
|
||||
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.DURATION') }} (km): </label>
|
||||
<label> {{ $t('workouts.DURATION') }} (km): </label>
|
||||
<div class="form-inputs-group">
|
||||
<input
|
||||
name="duration_from"
|
||||
@ -63,7 +63,7 @@
|
||||
placeholder="hh:mm"
|
||||
type="text"
|
||||
/>
|
||||
<span>{{ t('workouts.TO') }}</span>
|
||||
<span>{{ $t('workouts.TO') }}</span>
|
||||
<input
|
||||
name="duration_to"
|
||||
@change="handleFilterChange"
|
||||
@ -77,7 +77,7 @@
|
||||
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.AVE_SPEED') }} (km): </label>
|
||||
<label> {{ $t('workouts.AVE_SPEED') }} (km): </label>
|
||||
<div class="form-inputs-group">
|
||||
<input
|
||||
min="0"
|
||||
@ -86,7 +86,7 @@
|
||||
step="1"
|
||||
type="number"
|
||||
/>
|
||||
<span>{{ t('workouts.TO') }}</span>
|
||||
<span>{{ $t('workouts.TO') }}</span>
|
||||
<input
|
||||
min="0"
|
||||
name="ave_speed_to"
|
||||
@ -100,7 +100,7 @@
|
||||
|
||||
<div class="form-items-group">
|
||||
<div class="form-item">
|
||||
<label> {{ t('workouts.MAX_SPEED') }} (km): </label>
|
||||
<label> {{ $t('workouts.MAX_SPEED') }} (km): </label>
|
||||
|
||||
<div class="form-inputs-group">
|
||||
<input
|
||||
@ -110,7 +110,7 @@
|
||||
step="1"
|
||||
type="number"
|
||||
/>
|
||||
<span>{{ t('workouts.TO') }}</span>
|
||||
<span>{{ $t('workouts.TO') }}</span>
|
||||
<input
|
||||
min="0"
|
||||
name="max_speed_to"
|
||||
@ -125,7 +125,7 @@
|
||||
|
||||
<div class="form-button">
|
||||
<button class="confirm" @click="onFilter">
|
||||
{{ t('buttons.FILTER') }}
|
||||
{{ $t('buttons.FILTER') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -166,7 +166,7 @@
|
||||
emit('filter', { ...params })
|
||||
}
|
||||
|
||||
return { t, translatedSports, onFilter, handleFilterChange }
|
||||
return { translatedSports, onFilter, handleFilterChange }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -6,19 +6,19 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sport-col" />
|
||||
<th>{{ capitalize(t('workouts.WORKOUT', 1)) }}</th>
|
||||
<th>{{ capitalize(t('workouts.DATE')) }}</th>
|
||||
<th>{{ capitalize(t('workouts.DISTANCE')) }}</th>
|
||||
<th>{{ capitalize(t('workouts.DURATION')) }}</th>
|
||||
<th>{{ capitalize(t('workouts.AVE_SPEED')) }}</th>
|
||||
<th>{{ capitalize(t('workouts.MAX_SPEED')) }}</th>
|
||||
<th>{{ capitalize($t('workouts.WORKOUT', 1)) }}</th>
|
||||
<th>{{ capitalize($t('workouts.DATE')) }}</th>
|
||||
<th>{{ capitalize($t('workouts.DISTANCE')) }}</th>
|
||||
<th>{{ capitalize($t('workouts.DURATION')) }}</th>
|
||||
<th>{{ capitalize($t('workouts.AVE_SPEED')) }}</th>
|
||||
<th>{{ capitalize($t('workouts.MAX_SPEED')) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="workout in workouts" :key="workout.id">
|
||||
<td class="sport-col">
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.SPORT', 1) }}
|
||||
{{ $t('workouts.SPORT', 1) }}
|
||||
</span>
|
||||
<SportImage
|
||||
:title="
|
||||
@ -32,7 +32,7 @@
|
||||
</td>
|
||||
<td class="workout-title">
|
||||
<span class="cell-heading">
|
||||
{{ capitalize(t('workouts.WORKOUT', 1)) }}
|
||||
{{ capitalize($t('workouts.WORKOUT', 1)) }}
|
||||
</span>
|
||||
<router-link
|
||||
class="nav-item"
|
||||
@ -53,7 +53,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.DATE') }}
|
||||
{{ $t('workouts.DATE') }}
|
||||
</span>
|
||||
{{
|
||||
format(
|
||||
@ -64,25 +64,25 @@
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.DISTANCE') }}
|
||||
{{ $t('workouts.DISTANCE') }}
|
||||
</span>
|
||||
{{ Number(workout.distance).toFixed(2) }} km
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.DURATION') }}
|
||||
{{ $t('workouts.DURATION') }}
|
||||
</span>
|
||||
{{ workout.moving }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.AVE_SPEED') }}
|
||||
{{ $t('workouts.AVE_SPEED') }}
|
||||
</span>
|
||||
{{ workout.ave_speed }} km/h
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span class="cell-heading">
|
||||
{{ t('workouts.MAX_SPEED') }}
|
||||
{{ $t('workouts.MAX_SPEED') }}
|
||||
</span>
|
||||
{{ workout.max_speed }} km/h
|
||||
</td>
|
||||
@ -94,7 +94,7 @@
|
||||
<NoWorkouts v-if="workouts.length === 0" />
|
||||
<div v-if="moreWorkoutsExist" class="more-workouts">
|
||||
<button @click="loadMoreWorkouts">
|
||||
{{ t('workouts.LOAD_MORE_WORKOUT') }}
|
||||
{{ $t('workouts.LOAD_MORE_WORKOUT') }}
|
||||
</button>
|
||||
</div>
|
||||
<div id="bottom" />
|
||||
@ -112,9 +112,8 @@
|
||||
watch,
|
||||
onBeforeMount,
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SportImage from '@/components/Common/SportImage/index.vue'
|
||||
import SportImage from '@/components/Common/Images/SportImage/index.vue'
|
||||
import StaticMap from '@/components/Common/StaticMap.vue'
|
||||
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
|
||||
import { WORKOUTS_STORE } from '@/store/constants'
|
||||
@ -147,7 +146,6 @@
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const { t } = useI18n()
|
||||
const workouts: ComputedRef<IWorkout[]> = computed(
|
||||
() => store.getters[WORKOUTS_STORE.GETTERS.USER_WORKOUTS]
|
||||
)
|
||||
@ -189,7 +187,6 @@
|
||||
|
||||
return {
|
||||
moreWorkoutsExist,
|
||||
t,
|
||||
workouts,
|
||||
capitalize,
|
||||
format,
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"CONFIRMATION": "Confirmation",
|
||||
"DAY": "day | days",
|
||||
"HOME": "Home"
|
||||
"HOME": "Home",
|
||||
"HERE": "here"
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
{
|
||||
"CONFIRM_ACCOUNT_DELETION": "Are you sure you want to delete your account? All data will be deleted, this cannot be undone",
|
||||
"EMAIL": "Email",
|
||||
"ENTER_EMAIL": "Enter an email address",
|
||||
"ENTER_PASSWORD": "Enter a password",
|
||||
"ENTER_PASSWORD_CONFIRMATION": "Confirm the password",
|
||||
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
|
||||
"LANGUAGE": "Language",
|
||||
"LOGIN": "Login",
|
||||
"LOGOUT": "Logout",
|
||||
"PASSWORD": "Password",
|
||||
"PASSWORD_CONFIRM": "Confirm Password",
|
||||
"PASSWORD_CONFIRMATION": "Password confirmation",
|
||||
"PASSWORD_FORGOTTEN": "Forgot password?",
|
||||
"PASSWORD_RESET": "Password reset",
|
||||
"PASSWORD_SENT_EMAIL_TEXT": "Check your email. If your address is in our database, you'll received an email with a link to reset your password.",
|
||||
"PASSWORD_UPDATED": "Your password have been updated. Click {0} to log in.",
|
||||
"PROFILE": {
|
||||
"BACK_TO_PROFILE": "Back to profile",
|
||||
"BIO": "Bio",
|
||||
@ -36,6 +44,7 @@
|
||||
},
|
||||
"REGISTER": "Register",
|
||||
"REGISTER_DISABLED": "Sorry, registration is disabled.",
|
||||
"RESET_PASSWORD": "Reset your password",
|
||||
"USER_PICTURE": "user picture",
|
||||
"USERNAME": "Username"
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"CONFIRMATION": "Confirmation",
|
||||
"DAY": "jour | jours",
|
||||
"HOME": "Accueil"
|
||||
"HOME": "Accueil",
|
||||
"HERE": "ici"
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
{
|
||||
"CONFIRM_ACCOUNT_DELETION": "Etes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.",
|
||||
"EMAIL": "Email",
|
||||
"ENTER_EMAIL": "Saisir une adresse email",
|
||||
"ENTER_PASSWORD": "Saisir un mot de passe",
|
||||
"ENTER_PASSWORD_CONFIRMATION": "Confirmer le mot de passe",
|
||||
"INVALID_TOKEN": "Jeton invalide, veullez demander une nouvelle réinitialisation de mot de passe.",
|
||||
"LANGUAGE": "Langue",
|
||||
"LOGIN": "Se connecter",
|
||||
"LOGOUT": "Se déconnecter",
|
||||
"PASSWORD": "Mot de passe",
|
||||
"PASSWORD_CONFIRM": "Confirmation du mot de passe",
|
||||
"PASSWORD_CONFIRMATION": "Confirmation du mot de passe",
|
||||
"PASSWORD_FORGOTTEN": "Mot de passe oublié ?",
|
||||
"PASSWORD_RESET": "Réinitialisation du mot de passe",
|
||||
"PASSWORD_SENT_EMAIL_TEXT": "Vérifiez vore boite mail. Si vote adresse est dans notre base de données, vous recevrez un email avec un lien pour réinitialiser votre mot de passe.",
|
||||
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",
|
||||
"PROFILE": {
|
||||
"BACK_TO_PROFILE": "Revenir au profil",
|
||||
"BIO": "Bio",
|
||||
@ -36,6 +44,7 @@
|
||||
},
|
||||
"REGISTER": "S'inscrire",
|
||||
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
|
||||
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
|
||||
"USER_PICTURE": "photo de l'utilisateur",
|
||||
"USERNAME": "Nom d'utilisateur"
|
||||
}
|
@ -6,6 +6,7 @@ import AddWorkout from '@/views/AddWorkout.vue'
|
||||
import Dashboard from '@/views/DashBoard.vue'
|
||||
import LoginOrRegister from '@/views/LoginOrRegister.vue'
|
||||
import NotFoundView from '@/views/NotFoundView.vue'
|
||||
import PasswordResetView from '@/views/PasswordResetView.vue'
|
||||
import ProfileView from '@/views/ProfileView.vue'
|
||||
import StatisticsView from '@/views/StatisticsView.vue'
|
||||
import EditWorkout from '@/views/workouts/EditWorkout.vue'
|
||||
@ -36,6 +37,30 @@ const routes: Array<RouteRecordRaw> = [
|
||||
component: ProfileView,
|
||||
props: { edition: false, tab: 'PROFILE' },
|
||||
},
|
||||
{
|
||||
path: '/password-reset/sent',
|
||||
name: 'PasswordEmailSent',
|
||||
component: PasswordResetView,
|
||||
props: { action: 'request-sent' },
|
||||
},
|
||||
{
|
||||
path: '/password-reset/request',
|
||||
name: 'PasswordResetRequest',
|
||||
component: PasswordResetView,
|
||||
props: { action: 'reset-request' },
|
||||
},
|
||||
{
|
||||
path: '/password-reset/password-updated',
|
||||
name: 'PasswordUpdated',
|
||||
component: PasswordResetView,
|
||||
props: { action: 'password-updated' },
|
||||
},
|
||||
{
|
||||
path: '/password-reset',
|
||||
name: 'PasswordReset',
|
||||
component: PasswordResetView,
|
||||
props: { action: 'reset' },
|
||||
},
|
||||
{
|
||||
path: '/profile/edit/picture',
|
||||
name: 'UserPictureEdition',
|
||||
@ -100,18 +125,27 @@ const router = createRouter({
|
||||
routes,
|
||||
})
|
||||
|
||||
const pathsWithoutAuthentication = [
|
||||
'/login',
|
||||
'/password-reset',
|
||||
'/password-reset/password-updated',
|
||||
'/password-reset/request',
|
||||
'/password-reset/sent',
|
||||
'/register',
|
||||
]
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
store
|
||||
.dispatch(USER_STORE.ACTIONS.CHECK_AUTH_USER)
|
||||
.then(() => {
|
||||
if (
|
||||
store.getters[USER_STORE.GETTERS.IS_AUTHENTICATED] &&
|
||||
['/login', '/register'].includes(to.path)
|
||||
pathsWithoutAuthentication.includes(to.path)
|
||||
) {
|
||||
return next('/')
|
||||
} else if (
|
||||
!store.getters[USER_STORE.GETTERS.IS_AUTHENTICATED] &&
|
||||
!['/login', '/register'].includes(to.path)
|
||||
!pathsWithoutAuthentication.includes(to.path)
|
||||
) {
|
||||
const path =
|
||||
to.path === '/'
|
||||
|
@ -62,4 +62,6 @@
|
||||
--cell-heading-bg-color: #eeeeee;
|
||||
--cell-heading-color: #696969;
|
||||
|
||||
--svg-filter: drop-shadow(10px 10px 10px var(--app-shadow-color))
|
||||
|
||||
}
|
@ -16,6 +16,8 @@ import { IUserActions, IUserState } from '@/store/modules/user/types'
|
||||
import {
|
||||
ILoginOrRegisterData,
|
||||
IUserDeletionPayload,
|
||||
IUserPasswordPayload,
|
||||
IUserPasswordResetPayload,
|
||||
IUserPayload,
|
||||
IUserPicturePayload,
|
||||
IUserPreferencesPayload,
|
||||
@ -214,4 +216,36 @@ export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
|
||||
context.commit(USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
|
||||
)
|
||||
},
|
||||
[USER_STORE.ACTIONS.SEND_PASSWORD_RESET_REQUEST](
|
||||
context: ActionContext<IUserState, IRootState>,
|
||||
payload: IUserPasswordPayload
|
||||
): void {
|
||||
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||
api
|
||||
.post('auth/password/reset-request', payload)
|
||||
.then((res) => {
|
||||
if (res.data.status === 'success') {
|
||||
router.push('/password-reset/sent')
|
||||
} else {
|
||||
handleError(context, null)
|
||||
}
|
||||
})
|
||||
.catch((error) => handleError(context, error))
|
||||
},
|
||||
[USER_STORE.ACTIONS.RESET_USER_PASSWORD](
|
||||
context: ActionContext<IUserState, IRootState>,
|
||||
payload: IUserPasswordResetPayload
|
||||
): void {
|
||||
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||
api
|
||||
.post('auth/password/update', payload)
|
||||
.then((res) => {
|
||||
if (res.data.status === 'success') {
|
||||
router.push('/password-reset/password-updated')
|
||||
} else {
|
||||
handleError(context, null)
|
||||
}
|
||||
})
|
||||
.catch((error) => handleError(context, error))
|
||||
},
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ export enum UserActions {
|
||||
GET_USER_PROFILE = 'GET_USER_PROFILE',
|
||||
LOGIN_OR_REGISTER = 'LOGIN_OR_REGISTER',
|
||||
LOGOUT = 'LOGOUT',
|
||||
SEND_PASSWORD_RESET_REQUEST = 'SEND_PASSWORD_RESET_REQUEST',
|
||||
RESET_USER_PASSWORD = 'RESET_USER_PASSWORD',
|
||||
UPDATE_USER_PICTURE = 'UPDATE_USER_PICTURE',
|
||||
UPDATE_USER_PROFILE = 'UPDATE_USER_PROFILE',
|
||||
UPDATE_USER_PREFERENCES = 'UPDATE_USER_PREFERENCES',
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
IAuthUserProfile,
|
||||
ILoginOrRegisterData,
|
||||
IUserDeletionPayload,
|
||||
IUserPasswordPayload,
|
||||
IUserPasswordResetPayload,
|
||||
IUserPayload,
|
||||
IUserPicturePayload,
|
||||
IUserPreferencesPayload,
|
||||
@ -55,6 +57,16 @@ export interface IUserActions {
|
||||
payload: IUserPicturePayload
|
||||
): void
|
||||
|
||||
[USER_STORE.ACTIONS.SEND_PASSWORD_RESET_REQUEST](
|
||||
context: ActionContext<IUserState, IRootState>,
|
||||
payload: IUserPasswordPayload
|
||||
): void
|
||||
|
||||
[USER_STORE.ACTIONS.RESET_USER_PASSWORD](
|
||||
context: ActionContext<IUserState, IRootState>,
|
||||
payload: IUserPasswordResetPayload
|
||||
): void
|
||||
|
||||
[USER_STORE.ACTIONS.DELETE_ACCOUNT](
|
||||
context: ActionContext<IUserState, IRootState>,
|
||||
payload: IUserDeletionPayload
|
||||
|
@ -42,6 +42,16 @@ export interface IUserPicturePayload {
|
||||
picture: File
|
||||
}
|
||||
|
||||
export interface IUserPasswordPayload {
|
||||
email: string
|
||||
}
|
||||
|
||||
export interface IUserPasswordResetPayload {
|
||||
password: string
|
||||
password_conf: string
|
||||
token: string
|
||||
}
|
||||
|
||||
export interface IUserDeletionPayload {
|
||||
username: string
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
import BikePic from '@/components/BikePic.vue'
|
||||
import LoginOrRegisterForm from '@/components/User/LoginOrRegisterForm.vue'
|
||||
import LoginOrRegisterForm from '@/components/User/UserAuthForm.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NavBar',
|
||||
|
64
fittrackee_client/src/views/PasswordResetView.vue
Normal file
64
fittrackee_client/src/views/PasswordResetView.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div id="password-reset">
|
||||
<div class="container">
|
||||
<PasswordResetRequest
|
||||
v-if="action.startsWith('reset')"
|
||||
:action="action"
|
||||
:token="token"
|
||||
/>
|
||||
<PasswordEmailSent v-else :action="action" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onBeforeMount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import PasswordEmailSent from '@/components/User/PasswordReset/PasswordActionDone.vue'
|
||||
import PasswordResetRequest from '@/components/User/PasswordReset/PasswordResetForm.vue'
|
||||
export default defineComponent({
|
||||
name: 'PasswordResetView',
|
||||
components: {
|
||||
PasswordEmailSent,
|
||||
PasswordResetRequest,
|
||||
},
|
||||
props: {
|
||||
action: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const token = computed(() => route.query.token)
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (props.action === 'reset' && !token.value) {
|
||||
router.push('/')
|
||||
}
|
||||
})
|
||||
|
||||
return { token }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/scss/base.scss';
|
||||
|
||||
#password-reset {
|
||||
display: flex;
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
|
||||
@media screen and (max-width: $small-limit) {
|
||||
width: 100%;
|
||||
margin: 0 auto 50px auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -11,7 +11,7 @@
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>
|
||||
{{ t(`workouts.${hiddenFilters ? 'DISPLAY' : 'HIDE'}_FILTERS`) }}
|
||||
{{ $t(`workouts.${hiddenFilters ? 'DISPLAY' : 'HIDE'}_FILTERS`) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,7 +71,6 @@
|
||||
authUser,
|
||||
hiddenFilters,
|
||||
params,
|
||||
t,
|
||||
translatedSports,
|
||||
toggleFilters,
|
||||
updateParams,
|
||||
|
@ -976,6 +976,18 @@
|
||||
"@intlify/shared" "9.1.7"
|
||||
"@intlify/vue-devtools" "9.1.7"
|
||||
|
||||
"@intlify/core-base@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.1.9.tgz#e4e8c951010728e4af3a0d13d74cf3f9e7add7f6"
|
||||
integrity sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==
|
||||
dependencies:
|
||||
"@intlify/devtools-if" "9.1.9"
|
||||
"@intlify/message-compiler" "9.1.9"
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/runtime" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
"@intlify/vue-devtools" "9.1.9"
|
||||
|
||||
"@intlify/core@^9.1.6":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core/-/core-9.1.7.tgz#69c00dc31111f1b61d79fbd9ad1838196e73c94a"
|
||||
@ -990,6 +1002,13 @@
|
||||
dependencies:
|
||||
"@intlify/shared" "9.1.7"
|
||||
|
||||
"@intlify/devtools-if@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/devtools-if/-/devtools-if-9.1.9.tgz#a30e1dd1256ff2c5c98d8d75d075384fba898e5d"
|
||||
integrity sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==
|
||||
dependencies:
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@intlify/message-compiler@9.1.7", "@intlify/message-compiler@^9.1.6":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.1.7.tgz#4663fcc2a190f3cc6970e12565c8d6f22beeb719"
|
||||
@ -999,11 +1018,25 @@
|
||||
"@intlify/shared" "9.1.7"
|
||||
source-map "0.6.1"
|
||||
|
||||
"@intlify/message-compiler@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.1.9.tgz#1193cbd224a71c2fb981455b8534a3c766d2948d"
|
||||
integrity sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==
|
||||
dependencies:
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
source-map "0.6.1"
|
||||
|
||||
"@intlify/message-resolver@9.1.7":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-resolver/-/message-resolver-9.1.7.tgz#a95d13866c8de85784358039c8845668152e4162"
|
||||
integrity sha512-WTK+OaXJYjyquLGhuCyDvU2WHkG+kXzXeHagmVFHn+s118Jf2143zzkLLUrapP5CtZ/csuyjmYg7b3xQRQAmvw==
|
||||
|
||||
"@intlify/message-resolver@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-resolver/-/message-resolver-9.1.9.tgz#3155ccd2f5e6d0dc16cad8b7f1d8e97fcda05bfc"
|
||||
integrity sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==
|
||||
|
||||
"@intlify/runtime@9.1.7":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/runtime/-/runtime-9.1.7.tgz#67e0d6b2fd85a5b0b301a151c2f436f93154c3c6"
|
||||
@ -1013,11 +1046,25 @@
|
||||
"@intlify/message-resolver" "9.1.7"
|
||||
"@intlify/shared" "9.1.7"
|
||||
|
||||
"@intlify/runtime@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/runtime/-/runtime-9.1.9.tgz#2c12ce29518a075629efed0a8ed293ee740cb285"
|
||||
integrity sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==
|
||||
dependencies:
|
||||
"@intlify/message-compiler" "9.1.9"
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@intlify/shared@9.1.7", "@intlify/shared@^9.1.6":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.1.7.tgz#e7d8bc90cb59dc17dd7b4c85a73db16fcb7891fc"
|
||||
integrity sha512-zt0zlUdalumvT9AjQNxPXA36UgOndUyvBMplh8uRZU0fhWHAwhnJTcf0NaG9Qvr8I1n3HPSs96+kLb/YdwTavQ==
|
||||
|
||||
"@intlify/shared@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.1.9.tgz#0baaf96128b85560666bec784ffb01f6623cc17a"
|
||||
integrity sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==
|
||||
|
||||
"@intlify/vue-devtools@9.1.7":
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.1.7.tgz#b08d39bb5f21ba9b1954eab9466e9408129425a7"
|
||||
@ -1027,6 +1074,15 @@
|
||||
"@intlify/runtime" "9.1.7"
|
||||
"@intlify/shared" "9.1.7"
|
||||
|
||||
"@intlify/vue-devtools@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz#2be8f4dbe7f7ed4115676eb32348141d411e426b"
|
||||
integrity sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==
|
||||
dependencies:
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/runtime" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@intlify/vue-i18n-loader@^2.1.0":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/vue-i18n-loader/-/vue-i18n-loader-2.1.2.tgz#91a0858e26275dfc2c9c27aef9883028cada45ae"
|
||||
@ -9877,14 +9933,14 @@ vue-i18n@^8.17.0:
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.25.0.tgz#1037d9295fa2845a230b771de473481edb2cfc4c"
|
||||
integrity sha512-ynhcL+PmTxuuSE1T10htiSXzjBozxYIE3ffbM1RfgAkVbr/v1SP+9Mi/7/uv8ZVV1yGuKjFAYp9BXq+X7op6MQ==
|
||||
|
||||
vue-i18n@^9.1.0:
|
||||
version "9.1.7"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.1.7.tgz#6f28dd2135197066508e2e65ab204a019750d773"
|
||||
integrity sha512-ujuuDanoHqtEd4GejWrbG/fXE9nrP51ElsEGxp0WBHfv+/ki0/wyUqkO+4fLikki2obGtXdviTPH0VNpas5K6g==
|
||||
vue-i18n@^9.1.9:
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.1.9.tgz#cb53e06ab5cc5b7eed59332f151caf48d47be9bb"
|
||||
integrity sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==
|
||||
dependencies:
|
||||
"@intlify/core-base" "9.1.7"
|
||||
"@intlify/shared" "9.1.7"
|
||||
"@intlify/vue-devtools" "9.1.7"
|
||||
"@intlify/core-base" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
"@intlify/vue-devtools" "9.1.9"
|
||||
"@vue/devtools-api" "^6.0.0-beta.7"
|
||||
|
||||
"vue-loader-v16@npm:vue-loader@^16.1.0":
|
||||
|
Loading…
Reference in New Issue
Block a user