Client - upgrade Vue to 3.3 and move to Vite

This commit is contained in:
Sam 2023-11-11 15:23:04 +01:00
parent 91455251e1
commit 1befae927d
309 changed files with 6291 additions and 12719 deletions

View File

@ -194,7 +194,7 @@ lint-client:
cd fittrackee_client && $(NPM) lint
lint-client-fix:
cd fittrackee_client && $(NPM) lint-fix
cd fittrackee_client && $(NPM) format
lint-python:
$(PYTEST) --isort --black -m "isort or black" fittrackee e2e --ignore=fittrackee/migrations
@ -233,7 +233,7 @@ serve-dev:
serve-client:
# for dev environments
cd fittrackee_client && PORT=3000 $(NPM) serve
cd fittrackee_client && PORT=3000 $(NPM) dev
serve-python:
# for dev environments
@ -269,6 +269,9 @@ type-check:
echo 'Running mypy...'
$(MYPY) fittrackee
type-check-client:
cd fittrackee_client && $(NPM) type-check
upgrade-db:
$(FTCLI) db upgrade

View File

@ -1,2 +1,2 @@
VUE_APP_API_URL=http://localhost:5000
VITE_APP_API_URL=http://localhost:5000
PORT=3000

View File

@ -0,0 +1,18 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
},
"rules": {
"vue/multi-word-component-names": "off"
}
}

28
fittrackee_client/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,4 +1,5 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
@ -9,4 +10,4 @@
"printWidth": 80,
"endOfLine": "auto",
"vueIndentScriptAndStyle": true
}
}

View File

@ -1,29 +1,46 @@
# fittrackee_client
## Project setup
```
yarn install
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
yarn
```
### Compiles and hot-reloads for development
```
yarn serve
### Compile and Hot-Reload for Development
```sh
yarn dev
```
### Compiles and minifies for production
```
### Type-Check, Compile and Minify for Production
```sh
yarn build
```
### Run your unit tests
```
yarn test:unit
```
### Lint with [ESLint](https://eslint.org/)
### Lints and fixes files
```
```sh
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
}

1
fittrackee_client/env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="static/css/fork-awesome.min.css"/>
<link rel="stylesheet" href="static/css/leaflet.css"/>
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -3,127 +3,63 @@
"version": "0.7.25",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint",
"lint-fix": "vue-cli-service lint --fix",
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\""
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"@tmcw/togeojson": "^5.8.1",
"@vue-leaflet/vue-leaflet": "0.9.0",
"@vue-leaflet/vue-leaflet": "^0.10.1",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.3",
"@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-de": "^3.0.2",
"@zxcvbn-ts/language-en": "^3.0.2",
"@zxcvbn-ts/language-es-es": "^3.0.2",
"@zxcvbn-ts/language-fr": "^3.0.2",
"@zxcvbn-ts/language-it": "^3.0.2",
"@zxcvbn-ts/language-pl": "^3.0.2",
"axios": "^1.5.1",
"axios": "^1.6.1",
"chart.js": "^4.4.0",
"chartjs-plugin-datalabels": "^2.2.0",
"core-js": "^3.33.0",
"date-fns": "2.29.3",
"core-js": "^3.33.2",
"date-fns": "2.30.0",
"date-fns-tz": "^2.0.0",
"leaflet": "^1.9.4",
"linkify-html": "^4.1.1",
"linkifyjs": "^4.1.1",
"register-service-worker": "^1.7.1",
"linkify-html": "^4.1.2",
"linkifyjs": "^4.1.2",
"sanitize-html": "^2.11.0",
"snarkdown": "^2.0.0",
"vue": "3.2.47",
"vue-chart-3": "3.1.1",
"vue": "^3.3.8",
"vue-chart-3": "^3.1.8",
"vue-fullscreen": "^3.1.1",
"vue-i18n": "^9.5.0",
"vue-i18n": "^9.6.5",
"vue-router": "^4.2.5",
"vuex": "^4.1.0"
},
"devDependencies": {
"@intlify/vue-i18n-loader": "^4.2.0",
"@types/chai": "^4.3.6",
"@types/mocha": "^10.0.2",
"@types/sanitize-html": "^2.9.1",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"@vue/cli-plugin-babel": "~5.0.8",
"@vue/cli-plugin-eslint": "~5.0.8",
"@vue/cli-plugin-pwa": "~5.0.8",
"@vue/cli-plugin-router": "~5.0.8",
"@vue/cli-plugin-typescript": "~5.0.8",
"@vue/cli-plugin-unit-mocha": "~5.0.8",
"@vue/cli-plugin-vuex": "~5.0.8",
"@vue/cli-service": "~5.0.8",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.4.1",
"@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.2",
"@types/chai": "^4.3.10",
"@types/mocha": "^10.0.4",
"@types/node": "^20.9.0",
"@types/sanitize-html": "^2.9.4",
"@vitejs/plugin-vue": "^4.4.0",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/tsconfig": "^0.4.0",
"chai": "^4.3.10",
"eslint": "8.42.0",
"eslint-config-prettier": "^8.10.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^2.8.8",
"sass": "^1.68.0",
"sass-loader": "^13.3.2",
"typescript": "5.0.4",
"vue-cli-plugin-i18n": "~2.3.2"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"plugin:import/recommended",
"plugin:import/typescript"
],
"globals": {
"defineProps": "readonly",
"defineEmits": "readonly",
"defineExpose": "readonly",
"withDefaults": "readonly"
},
"settings": {
"import/resolver": "typescript"
},
"parserOptions": {
"ecmaVersion": 2020,
"parser": "@typescript-eslint/parser"
},
"rules": {
"import/order": [
"error",
{
"newlines-between": "always",
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
],
"vue/multi-word-component-names": "off"
},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
"env": {
"mocha": true
}
}
]
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
"npm-run-all2": "^6.1.1",
"prettier": "^3.0.3",
"sass": "^1.69.5",
"typescript": "~5.2.0",
"vite": "^4.4.11",
"vue-tsc": "^1.8.19"
}
}

View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="<%= BASE_URL %>static/css/fork-awesome.min.css"/>
<link rel="stylesheet" href="<%= BASE_URL %>static/css/leaflet.css"/>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -29,13 +29,14 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, ref, onBeforeMount, onMounted } from 'vue'
import { computed, ref, onBeforeMount, onMounted } from 'vue'
import type { ComputedRef } from 'vue'
import Footer from '@/components/Footer.vue'
import NavBar from '@/components/NavBar.vue'
import NoConfig from '@/components/NoConfig.vue'
import { ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import type { TAppConfig } from '@/types/application'
import { useStore } from '@/use/useStore'
import { localeFromLanguage } from '@/utils/locales'

View File

@ -1,4 +1,4 @@
import { AxiosRequestConfig } from 'axios'
import type { AxiosRequestConfig } from 'axios'
export const pendingRequests = new Map()

View File

@ -49,9 +49,7 @@
</div>
<template v-if="appConfig.about">
<p class="about-instance">{{ $t('about.ABOUT_THIS_INSTANCE') }}</p>
<div
v-html="snarkdown(linkifyAndClean(appConfig.about))"
/>
<div v-html="snarkdown(linkifyAndClean(appConfig.about))" />
</template>
</div>
</div>
@ -59,10 +57,11 @@
<script lang="ts" setup>
import snarkdown from 'snarkdown'
import { ComputedRef, computed, capitalize } from 'vue'
import { computed, capitalize } from 'vue'
import type { ComputedRef } from 'vue'
import { ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import type { TAppConfig } from '@/types/application'
import { useStore } from '@/use/useStore'
import { linkifyAndClean } from '@/utils/inputs'
@ -113,7 +112,7 @@
}
.about-instance {
font-weight: bold;
margin-top: $default-margin*3;
margin-top: $default-margin * 3;
}
}
</style>

View File

@ -73,7 +73,7 @@
:disabled="!edition"
/>
</label>
<label class="about-label" for="about">
<label class="about-label" for="about">
{{ $t('admin.ABOUT.TEXT') }}:
</label>
<span class="textarea-description">
@ -88,7 +88,13 @@
/>
<div
v-else
v-html="snarkdown(linkifyAndClean(appData.about ? appData.about : $t('admin.NO_TEXT_ENTERED')))"
v-html="
snarkdown(
linkifyAndClean(
appData.about ? appData.about : $t('admin.NO_TEXT_ENTERED')
)
)
"
class="textarea-content"
/>
<label class="privacy-policy-label" for="privacy_policy">
@ -106,7 +112,15 @@
/>
<div
v-else
v-html="snarkdown(linkifyAndClean(appData.privacy_policy ? appData.privacy_policy : $t('admin.NO_TEXT_ENTERED')))"
v-html="
snarkdown(
linkifyAndClean(
appData.privacy_policy
? appData.privacy_policy
: $t('admin.NO_TEXT_ENTERED')
)
)
"
class="textarea-content"
/>
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
@ -137,19 +151,12 @@
<script setup lang="ts">
import snarkdown from 'snarkdown'
import {
ComputedRef,
capitalize,
computed,
reactive,
withDefaults,
onBeforeMount,
toRefs,
} from 'vue'
import { capitalize, computed, reactive, onBeforeMount, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { useRouter } from 'vue-router'
import { ROOT_STORE } from '@/store/constants'
import { TAppConfig, TAppConfigForm } from '@/types/application'
import type { TAppConfig, TAppConfigForm } from '@/types/application'
import { useStore } from '@/use/useStore'
import { getFileSizeInMB } from '@/utils/files'
import { linkifyAndClean } from '@/utils/inputs'
@ -187,19 +194,17 @@
function updateForm(appConfig: TAppConfig) {
Object.keys(appData).map((key) => {
['max_single_file_size', 'max_zip_file_size'].includes(key)
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(appData[key] = getFileSizeInMB(appConfig[key]))
: ['about', 'privacy_policy'].includes(key)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
? appData[key] = appConfig[key]!== null
? appConfig[key]
: ''
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
: (appData[key] = appConfig[key])
;['max_single_file_size', 'max_zip_file_size'].includes(key)
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(appData[key] = getFileSizeInMB(appConfig[key]))
: ['about', 'privacy_policy'].includes(key)
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(appData[key] = appConfig[key] !== null ? appConfig[key] : '')
: // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(appData[key] = appConfig[key])
})
}
function onCancel() {
@ -232,7 +237,7 @@
font-style: italic;
}
textarea {
textarea {
margin-bottom: $default-padding;
}
.textarea-description {
@ -242,6 +247,5 @@
margin-bottom: $default-margin;
padding: $default-padding;
}
}
</style>

View File

@ -54,18 +54,18 @@
</template>
<script setup lang="ts">
import { capitalize, onMounted, toRefs, withDefaults } from 'vue'
import { capitalize, onMounted, toRefs } from 'vue'
import AppStatsCards from '@/components/Administration/AppStatsCards.vue'
import Card from '@/components/Common/Card.vue'
import { IAppStatistics, TAppConfig } from '@/types/application'
import type { IAppStatistics, TAppConfig } from '@/types/application'
interface Props {
appConfig: TAppConfig
appStatistics?: IAppStatistics
}
const props = withDefaults(defineProps<Props>(), {
appStatistics: () => ({} as IAppStatistics),
appStatistics: () => ({}) as IAppStatistics,
})
const { appConfig, appStatistics } = toRefs(props)

View File

@ -84,11 +84,12 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed } from 'vue'
import { computed } from 'vue'
import type { ComputedRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { ROOT_STORE, SPORTS_STORE } from '@/store/constants'
import { ITranslatedSport } from '@/types/sports'
import type { ITranslatedSport } from '@/types/sports'
import { useStore } from '@/use/useStore'
import { translateSports } from '@/utils/sports'

View File

@ -134,8 +134,6 @@
<script setup lang="ts">
import {
ComputedRef,
Ref,
computed,
reactive,
watch,
@ -143,15 +141,17 @@
onBeforeMount,
onUnmounted,
} from 'vue'
import { LocationQuery, useRoute, useRouter } from 'vue-router'
import type { ComputedRef, Ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { LocationQuery } from 'vue-router'
import FilterSelects from '@/components/Common/FilterSelects.vue'
import Pagination from '@/components/Common/Pagination.vue'
import UserPicture from '@/components/User/UserPicture.vue'
import UsersNameFilter from '@/components/Users/UsersNameFilter.vue'
import { AUTH_USER_STORE, ROOT_STORE, USERS_STORE } from '@/store/constants'
import { IPagination, TPaginationPayload } from '@/types/api'
import { IAuthUserProfile, IUserProfile } from '@/types/user'
import type { IPagination, TPaginationPayload } from '@/types/api'
import type { IAuthUserProfile, IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { getQuery, sortList } from '@/utils/api'
import { formatDate } from '@/utils/dates'

View File

@ -27,7 +27,7 @@
import { computed, toRefs } from 'vue'
import StatCard from '@/components/Common/StatCard.vue'
import { IAppStatistics } from '@/types/application'
import type { IAppStatistics } from '@/types/application'
import { getReadableFileSize } from '@/utils/files'
interface Props {

View File

@ -15,7 +15,7 @@
</template>
<script setup lang="ts">
import { ref, watch, withDefaults } from 'vue'
import { ref, watch } from 'vue'
interface Props {
name: string

View File

@ -7,9 +7,10 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, toRefs, withDefaults } from 'vue'
import { computed, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { TUnit } from '@/types/units'
import type { TUnit } from '@/types/units'
import { units, convertDistance } from '@/utils/units'
interface Props {

View File

@ -29,7 +29,7 @@
import { ref, toRefs, watch } from 'vue'
import { useRoute } from 'vue-router'
import { IDropdownOption, TDropdownOptions } from '@/types/forms'
import type { IDropdownOption, TDropdownOptions } from '@/types/forms'
interface Props {
options: TDropdownOptions
selected: string

View File

@ -11,7 +11,7 @@
</template>
<script setup lang="ts">
import { toRefs, withDefaults } from 'vue'
import { toRefs } from 'vue'
interface Props {
title: string

View File

@ -45,7 +45,7 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { TPaginationPayload } from '@/types/api'
import type { TPaginationPayload } from '@/types/api'
interface Props {
order_by: string[]

View File

@ -56,7 +56,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'EmailSent',
}

View File

@ -21,7 +21,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'ErrorImg',
}

View File

@ -87,7 +87,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Password',
}

View File

@ -44,7 +44,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'CyclingSport',
}

View File

@ -26,7 +26,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'CyclingTransport',
}

View File

@ -1,38 +1,47 @@
<template>
<svg
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 491.737 491.737"
style="enable-background: new 0 0 491.737 491.737"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<desc
id="cyclingVirtualDescription">
<svg
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 491.737 491.737"
style="enable-background: new 0 0 491.737 491.737"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
>
<desc id="cyclingVirtualDescription">
silhouette of a person riding a bicycle with virtual indicator
</desc>
<path
d="m 321.097,112.359 c 20.973,12.338 47.985,5.315 60.293,-15.652 12.34,-20.973 5.35,-47.974 -15.623,-60.304 -21.009,-12.332 -47.99,-5.317 -60.314,15.65 -12.324,20.983 -5.35,47.974 15.644,60.306 z"
id="path3" /><path
d="m 393.081,264.102 c -2.414,0 -4.8,0.194 -7.169,0.362 l -14.431,-71.605 4.702,-1.757 c 10.666,-3.987 16.093,-15.868 12.098,-26.54 -3.994,-10.681 -15.946,-16.084 -26.531,-12.09 l -51.823,19.38 -2.321,-18.864 c 6.3,-13.193 5.541,-29.78 -4.767,-41.482 -21.224,-24.092 -47.12,-12.508 -55.191,-5.976 l -106.884,86.555 0.016,0.024 c -3.319,2.893 -6.089,6.485 -7.86,10.842 -2.191,5.396 -2.596,11.067 -1.564,16.384 -8.503,0.669 -15.255,7.571 -15.255,16.246 0,9.085 7.346,16.44 16.432,16.48 l -6.797,15.906 c -8.62,-2.465 -17.674,-3.866 -27.066,-3.866 C 44.27,264.102 0,308.354 0,362.754 c 0,54.403 44.27,98.663 98.668,98.663 54.403,0 98.652,-44.26 98.652,-98.663 0,-36.228 -19.683,-67.867 -48.858,-85.024 l 10.957,-25.652 h 17.767 l 60.281,24.462 -32.201,52.773 c -8.297,13.612 -3.994,31.382 9.615,39.685 4.691,2.86 9.878,4.229 15,4.229 9.729,0 19.234,-4.929 24.677,-13.838 l 29.339,-48.095 19.072,11.511 c -5.447,12.227 -8.54,25.726 -8.54,39.95 0,54.403 44.254,98.663 98.652,98.663 54.402,0 98.656,-44.26 98.656,-98.663 0,-54.401 -44.254,-98.653 -98.656,-98.653 z M 98.668,436.671 c -40.756,0 -73.923,-33.161 -73.923,-73.917 0,-40.756 33.167,-73.909 73.923,-73.909 5.944,0 11.649,0.896 17.188,2.224 L 95.38,338.962 c -11.758,1.619 -20.843,11.598 -20.843,23.792 0,13.323 10.808,24.132 24.13,24.132 8.767,0 16.367,-4.745 20.589,-11.76 h 52.065 c -5.926,34.862 -36.133,61.545 -72.653,61.545 z m 72.654,-86.288 h -52.065 c -0.355,-0.588 -0.708,-1.176 -1.112,-1.732 l 20.476,-47.901 c 17.058,11.026 29.172,28.845 32.701,49.633 z m 125.459,-60.208 7.666,-12.564 c 4.416,-7.233 5.431,-16.038 2.774,-24.084 -2.661,-8.046 -8.718,-14.515 -16.562,-17.704 l -52.725,-21.395 32.443,-26.281 1.804,14.691 c 0.756,6.267 4.366,11.841 9.761,15.12 3.271,1.981 6.979,2.988 10.698,2.988 2.435,0 4.88,-0.435 7.218,-1.306 l 48.15,-18.001 13.627,67.691 c -18.268,6.162 -34.117,17.51 -45.848,32.314 z m 78.615,47.458 -38.003,-22.94 c 7.877,-9.118 17.787,-16.319 29.205,-20.734 z m 17.685,99.038 c -40.757,0 -73.907,-33.161 -73.907,-73.917 0,-9.544 1.965,-18.597 5.268,-26.983 l 44.541,26.888 c 0,0.032 -0.016,0.064 -0.016,0.095 0,13.323 10.808,24.132 24.114,24.132 13.322,0 24.118,-10.81 24.118,-24.132 0,-10.478 -6.721,-19.307 -16.06,-22.64 l -10.277,-51.043 c 0.756,-0.024 1.463,-0.226 2.22,-0.226 40.757,0 73.911,33.153 73.911,73.909 -10e-4,40.756 -33.155,73.917 -73.912,73.917 z"
id="path5" />
<g
id="g10174"
transform="rotate(-45,60.058765,120.50397)"><path
d="m 100.16593,30.670651 c -5.521751,5.521749 -5.521751,14.11256 0,19.638597 17.79324,17.793301 28.22948,42.342094 28.22948,67.502302 0,25.77277 -9.81917,49.70354 -27.61257,67.50231 -5.521761,5.52175 -5.521761,14.11256 0,19.63859 2.45267,2.45269 6.13811,4.29754 9.81916,4.29754 3.68106,0 7.36234,-1.22848 9.81921,-4.29754 23.31927,-23.31932 36.20348,-54.00119 36.20348,-87.1365 0,-33.134258 -12.88856,-63.816092 -36.20348,-87.136525 -6.14243,-5.530298 -14.73279,-5.530298 -20.25443,-0.0085 z"
id="path3370"
style="stroke-width:1.09578" /><path
d="m 83.597679,66.875252 c -5.52175,-5.521722 -14.11255,-5.521722 -19.63857,0 -5.52175,5.521756 -5.52175,14.11259 0,19.6386 8.59071,8.5907 12.88856,19.638598 12.88856,31.294418 0,11.66021 -4.90967,23.31931 -12.88856,31.29441 -5.52175,5.52175 -5.52175,14.11256 0,19.63859 2.45267,2.45269 6.13812,4.29754 9.81917,4.29754 3.68105,0 7.36233,-1.22847 9.81917,-4.29754 13.50002,-13.50004 21.479501,-31.91025 20.862591,-50.93191 0.61209,-19.026028 -6.750211,-37.431868 -20.862591,-50.93189 z"
id="path3372"
style="stroke-width:1.09578" /><path
d="m 54.143079,118.42081 c 0,11.86074 -9.61798,21.47512 -21.4795,21.47512 -11.861488,0 -21.4795,-9.61372 -21.4795,-21.47512 0,-11.86141 9.618012,-21.479498 21.4795,-21.479498 11.86152,0 21.4795,9.618008 21.4795,21.479498"
id="path3378"
style="stroke-width:1.09578" /></g></svg>
d="m 321.097,112.359 c 20.973,12.338 47.985,5.315 60.293,-15.652 12.34,-20.973 5.35,-47.974 -15.623,-60.304 -21.009,-12.332 -47.99,-5.317 -60.314,15.65 -12.324,20.983 -5.35,47.974 15.644,60.306 z"
id="path3"
/>
<path
d="m 393.081,264.102 c -2.414,0 -4.8,0.194 -7.169,0.362 l -14.431,-71.605 4.702,-1.757 c 10.666,-3.987 16.093,-15.868 12.098,-26.54 -3.994,-10.681 -15.946,-16.084 -26.531,-12.09 l -51.823,19.38 -2.321,-18.864 c 6.3,-13.193 5.541,-29.78 -4.767,-41.482 -21.224,-24.092 -47.12,-12.508 -55.191,-5.976 l -106.884,86.555 0.016,0.024 c -3.319,2.893 -6.089,6.485 -7.86,10.842 -2.191,5.396 -2.596,11.067 -1.564,16.384 -8.503,0.669 -15.255,7.571 -15.255,16.246 0,9.085 7.346,16.44 16.432,16.48 l -6.797,15.906 c -8.62,-2.465 -17.674,-3.866 -27.066,-3.866 C 44.27,264.102 0,308.354 0,362.754 c 0,54.403 44.27,98.663 98.668,98.663 54.403,0 98.652,-44.26 98.652,-98.663 0,-36.228 -19.683,-67.867 -48.858,-85.024 l 10.957,-25.652 h 17.767 l 60.281,24.462 -32.201,52.773 c -8.297,13.612 -3.994,31.382 9.615,39.685 4.691,2.86 9.878,4.229 15,4.229 9.729,0 19.234,-4.929 24.677,-13.838 l 29.339,-48.095 19.072,11.511 c -5.447,12.227 -8.54,25.726 -8.54,39.95 0,54.403 44.254,98.663 98.652,98.663 54.402,0 98.656,-44.26 98.656,-98.663 0,-54.401 -44.254,-98.653 -98.656,-98.653 z M 98.668,436.671 c -40.756,0 -73.923,-33.161 -73.923,-73.917 0,-40.756 33.167,-73.909 73.923,-73.909 5.944,0 11.649,0.896 17.188,2.224 L 95.38,338.962 c -11.758,1.619 -20.843,11.598 -20.843,23.792 0,13.323 10.808,24.132 24.13,24.132 8.767,0 16.367,-4.745 20.589,-11.76 h 52.065 c -5.926,34.862 -36.133,61.545 -72.653,61.545 z m 72.654,-86.288 h -52.065 c -0.355,-0.588 -0.708,-1.176 -1.112,-1.732 l 20.476,-47.901 c 17.058,11.026 29.172,28.845 32.701,49.633 z m 125.459,-60.208 7.666,-12.564 c 4.416,-7.233 5.431,-16.038 2.774,-24.084 -2.661,-8.046 -8.718,-14.515 -16.562,-17.704 l -52.725,-21.395 32.443,-26.281 1.804,14.691 c 0.756,6.267 4.366,11.841 9.761,15.12 3.271,1.981 6.979,2.988 10.698,2.988 2.435,0 4.88,-0.435 7.218,-1.306 l 48.15,-18.001 13.627,67.691 c -18.268,6.162 -34.117,17.51 -45.848,32.314 z m 78.615,47.458 -38.003,-22.94 c 7.877,-9.118 17.787,-16.319 29.205,-20.734 z m 17.685,99.038 c -40.757,0 -73.907,-33.161 -73.907,-73.917 0,-9.544 1.965,-18.597 5.268,-26.983 l 44.541,26.888 c 0,0.032 -0.016,0.064 -0.016,0.095 0,13.323 10.808,24.132 24.114,24.132 13.322,0 24.118,-10.81 24.118,-24.132 0,-10.478 -6.721,-19.307 -16.06,-22.64 l -10.277,-51.043 c 0.756,-0.024 1.463,-0.226 2.22,-0.226 40.757,0 73.911,33.153 73.911,73.909 -10e-4,40.756 -33.155,73.917 -73.912,73.917 z"
id="path5"
/>
<g id="g10174" transform="rotate(-45,60.058765,120.50397)">
<path
d="m 100.16593,30.670651 c -5.521751,5.521749 -5.521751,14.11256 0,19.638597 17.79324,17.793301 28.22948,42.342094 28.22948,67.502302 0,25.77277 -9.81917,49.70354 -27.61257,67.50231 -5.521761,5.52175 -5.521761,14.11256 0,19.63859 2.45267,2.45269 6.13811,4.29754 9.81916,4.29754 3.68106,0 7.36234,-1.22848 9.81921,-4.29754 23.31927,-23.31932 36.20348,-54.00119 36.20348,-87.1365 0,-33.134258 -12.88856,-63.816092 -36.20348,-87.136525 -6.14243,-5.530298 -14.73279,-5.530298 -20.25443,-0.0085 z"
id="path3370"
style="stroke-width: 1.09578"
/>
<path
d="m 83.597679,66.875252 c -5.52175,-5.521722 -14.11255,-5.521722 -19.63857,0 -5.52175,5.521756 -5.52175,14.11259 0,19.6386 8.59071,8.5907 12.88856,19.638598 12.88856,31.294418 0,11.66021 -4.90967,23.31931 -12.88856,31.29441 -5.52175,5.52175 -5.52175,14.11256 0,19.63859 2.45267,2.45269 6.13812,4.29754 9.81917,4.29754 3.68105,0 7.36233,-1.22847 9.81917,-4.29754 13.50002,-13.50004 21.479501,-31.91025 20.862591,-50.93191 0.61209,-19.026028 -6.750211,-37.431868 -20.862591,-50.93189 z"
id="path3372"
style="stroke-width: 1.09578"
/>
<path
d="m 54.143079,118.42081 c 0,11.86074 -9.61798,21.47512 -21.4795,21.47512 -11.861488,0 -21.4795,-9.61372 -21.4795,-21.47512 0,-11.86141 9.618012,-21.479498 21.4795,-21.479498 11.86152,0 21.4795,9.618008 21.4795,21.479498"
id="path3378"
style="stroke-width: 1.09578"
/>
</g>
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'CyclingVirtual',
}

View File

@ -31,7 +31,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Hiking',
}

View File

@ -44,7 +44,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'MountainBiking',
}

View File

@ -64,7 +64,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'MountainBikingElectric',
}

View File

@ -50,7 +50,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Mountaineering',
}

View File

@ -138,7 +138,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'OpenWaterSwimming',
}

View File

@ -33,7 +33,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Paragliding',
}

View File

@ -31,7 +31,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Rowing',
}

View File

@ -31,7 +31,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Running',
}

View File

@ -35,7 +35,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'SkiingAlpine',
}

View File

@ -31,7 +31,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'SkiingCrossCountry',
}

View File

@ -55,7 +55,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Snowshoes',
}

View File

@ -37,7 +37,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Trail',
}

View File

@ -25,7 +25,7 @@
</svg>
</template>
<script>
<script lang="ts">
export default {
name: 'Walking',
}

View File

@ -38,14 +38,8 @@
</template>
<script setup lang="ts">
import {
ComputedRef,
computed,
onUnmounted,
onMounted,
toRefs,
withDefaults,
} from 'vue'
import { computed, onUnmounted, onMounted, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { ROOT_STORE } from '@/store/constants'
import { useStore } from '@/use/useStore'

View File

@ -8,7 +8,8 @@
</template>
<script setup lang="ts">
import { Ref, onMounted, ref, toRefs, withDefaults, onUnmounted } from 'vue'
import { onMounted, ref, toRefs, onUnmounted } from 'vue'
import type { Ref } from 'vue'
import Error from '@/components/Common/Error.vue'
interface Props {

View File

@ -51,9 +51,9 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { IPagination, TPaginationPayload } from '@/types/api'
import { IOauth2ClientsPayload } from '@/types/oauth'
import { TWorkoutsPayload } from '@/types/workouts'
import type { IPagination, TPaginationPayload } from '@/types/api'
import type { IOauth2ClientsPayload } from '@/types/oauth'
import type { TWorkoutsPayload } from '@/types/workouts'
import { rangePagination } from '@/utils/api'
interface Props {

View File

@ -30,7 +30,8 @@
</template>
<script setup lang="ts">
import { Ref, ref, toRefs, watch, withDefaults } from 'vue'
import { ref, toRefs, watch } from 'vue'
import type { Ref } from 'vue'
import PasswordStrength from '@/components/Common/PasswordStength.vue'

View File

@ -29,15 +29,8 @@
<script setup lang="ts">
import { zxcvbn } from '@zxcvbn-ts/core'
import {
ComputedRef,
Ref,
computed,
ref,
onBeforeMount,
toRefs,
watch,
} from 'vue'
import { computed, ref, onBeforeMount, toRefs, watch } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { useStore } from '@/use/useStore'

View File

@ -23,9 +23,9 @@
</template>
<script setup lang="ts">
import { toRefs, withDefaults } from 'vue'
import { toRefs } from 'vue'
import { IWorkout } from '@/types/workouts'
import type { IWorkout } from '@/types/workouts'
import { getApiUrl } from '@/utils'
interface Props {

View File

@ -5,13 +5,14 @@
</template>
<script lang="ts">
import { ChartOptions, LayoutItem } from 'chart.js'
import { PropType, computed, defineComponent } from 'vue'
import type { ChartOptions, LayoutItem } from 'chart.js'
import { computed, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { BarChart, useBarChart } from 'vue-chart-3'
import { useI18n } from 'vue-i18n'
import { IChartDataset } from '@/types/chart'
import { TStatisticsDatasetKeys } from '@/types/statistics'
import type { IChartDataset } from '@/types/chart'
import type { TStatisticsDatasetKeys } from '@/types/statistics'
import { formatTooltipValue } from '@/utils/tooltip'
export default defineComponent({

View File

@ -81,28 +81,20 @@
<script lang="ts">
import { format } from 'date-fns'
import {
ComputedRef,
PropType,
Ref,
computed,
defineComponent,
ref,
watch,
onBeforeMount,
} from 'vue'
import { computed, defineComponent, ref, watch, onBeforeMount } from 'vue'
import type { ComputedRef, PropType, Ref } from 'vue'
import Chart from '@/components/Common/StatsChart/Chart.vue'
import { STATS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import {
import type { ISport } from '@/types/sports'
import type {
IStatisticsChartData,
TStatisticsDatasetKeys,
IStatisticsDateParams,
TStatisticsFromApi,
IStatisticsParams,
} from '@/types/statistics'
import { IAuthUserProfile } from '@/types/user'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { formatStats } from '@/utils/statistics'

View File

@ -33,14 +33,15 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, ref, onBeforeMount, toRefs } from 'vue'
import { computed, ref, onBeforeMount, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import WorkoutCard from '@/components/Workout/WorkoutCard.vue'
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
import { WORKOUTS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import { IUserProfile } from '@/types/user'
import { IWorkout } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user'
import type { IWorkout } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import { defaultOrder } from '@/utils/workouts'

View File

@ -26,11 +26,12 @@
<script setup lang="ts">
import { addDays, format, isSameDay, isSameMonth, isToday } from 'date-fns'
import { Ref, ref, toRefs, watch, onMounted } from 'vue'
import { ref, toRefs, watch, onMounted } from 'vue'
import type { Ref } from 'vue'
import CalendarWorkouts from '@/components/Dashboard/UserCalendar/CalendarWorkouts.vue'
import { ISport } from '@/types/sports'
import { IWorkout } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IWorkout } from '@/types/workouts'
import { getDateWithTZ } from '@/utils/dates'
interface Props {

View File

@ -7,7 +7,8 @@
</template>
<script setup lang="ts">
import { Locale, format, addDays } from 'date-fns'
import { format, addDays } from 'date-fns'
import type { Locale } from 'date-fns'
interface Props {
startDate: Date

View File

@ -21,7 +21,8 @@
</template>
<script setup lang="ts">
import { Locale, format } from 'date-fns'
import { format } from 'date-fns'
import type { Locale } from 'date-fns'
import { toRefs } from 'vue'
interface Props {

View File

@ -30,7 +30,7 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { IWorkout } from '@/types/workouts'
import type { IWorkout } from '@/types/workouts'
interface Props {
displayHARecord: boolean
workout: IWorkout

View File

@ -41,8 +41,8 @@
import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
import CalendarWorkoutsChart from '@/components/Dashboard/UserCalendar/CalendarWorkoutsChart.vue'
import { ISport } from '@/types/sports'
import { IWorkout } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IWorkout } from '@/types/workouts'
import { getSportColor, getSportLabel, sportIdColors } from '@/utils/sports'
import { getDonutDatasets } from '@/utils/workouts'

View File

@ -28,8 +28,8 @@
import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
import DonutChart from '@/components/Dashboard/UserCalendar/DonutChart.vue'
import { ISport } from '@/types/sports'
import { IWorkout } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IWorkout } from '@/types/workouts'
import { getSportColor, getSportLabel } from '@/utils/sports'
interface Props {
@ -88,7 +88,8 @@
.more-workouts {
background: whitesmoke;
border-radius: 4px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2),
box-shadow:
0 4px 8px 0 rgba(0, 0, 0, 0.2),
0 6px 20px 0 rgba(0, 0, 0, 0.19);
position: absolute;
top: 52px;

View File

@ -26,16 +26,18 @@
</template>
<script setup lang="ts">
import { Locale, addMonths, format, subMonths } from 'date-fns'
import { ComputedRef, computed, ref, toRefs, onBeforeMount } from 'vue'
import { addMonths, format, subMonths } from 'date-fns'
import type { Locale } from 'date-fns'
import { computed, ref, toRefs, onBeforeMount } from 'vue'
import type { ComputedRef } from 'vue'
import CalendarCells from '@/components/Dashboard/UserCalendar/CalendarCells.vue'
import CalendarDays from '@/components/Dashboard/UserCalendar/CalendarDays.vue'
import CalendarHeader from '@/components/Dashboard/UserCalendar/CalendarHeader.vue'
import { ROOT_STORE, WORKOUTS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import { IAuthUserProfile } from '@/types/user'
import { IWorkout, TWorkoutsPayload } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IAuthUserProfile } from '@/types/user'
import type { IWorkout, TWorkoutsPayload } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import { getCalendarStartAndEnd } from '@/utils/dates'
import { defaultOrder } from '@/utils/workouts'

View File

@ -20,8 +20,8 @@
import { toRefs } from 'vue'
import StatChart from '@/components/Common/StatsChart/index.vue'
import { ISport } from '@/types/sports'
import { IUserProfile } from '@/types/user'
import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user'
interface Props {
sports: ISport[]

View File

@ -35,7 +35,7 @@
import { toRefs } from 'vue'
import { useI18n } from 'vue-i18n'
import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
import type { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
import { sortRecords } from '@/utils/records'
interface Props {

View File

@ -24,8 +24,8 @@
import { useI18n } from 'vue-i18n'
import RecordsCard from '@/components/Dashboard/UserRecords/RecordsCard.vue'
import { ISport } from '@/types/sports'
import { IAuthUserProfile } from '@/types/user'
import type { ISport } from '@/types/sports'
import type { IAuthUserProfile } from '@/types/user'
import { getRecordsBySports } from '@/utils/records'
import { translateSports } from '@/utils/sports'

View File

@ -31,12 +31,13 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, toRefs } from 'vue'
import { computed, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { useI18n } from 'vue-i18n'
import StatCard from '@/components/Common/StatCard.vue'
import { TUnit } from '@/types/units'
import { IAuthUserProfile } from '@/types/user'
import type { TUnit } from '@/types/units'
import type { IAuthUserProfile } from '@/types/user'
import { convertDistance, units } from '@/utils/units'
interface Props {
user: IAuthUserProfile
@ -56,17 +57,28 @@
: distanceUnitFrom
const totalDistance: ComputedRef<number> = computed(() =>
user.value.imperial_units
? convertDistance(user.value.total_distance, distanceUnitFrom, distanceUnitTo, 2)
: parseFloat(user.value.total_distance.toFixed(2)))
? convertDistance(
user.value.total_distance,
distanceUnitFrom,
distanceUnitTo,
2
)
: parseFloat(user.value.total_distance.toFixed(2))
)
const ascentUnitFrom: TUnit = 'm'
const ascentUnitTo: TUnit = user.value.imperial_units
? units[ascentUnitFrom].defaultTarget
: ascentUnitFrom
const totalAscent: ComputedRef<number> = computed(() =>
user.value.imperial_units
? convertDistance(user.value.total_ascent, ascentUnitFrom, ascentUnitTo, 2)
: parseFloat(user.value.total_ascent.toFixed(2)))
? convertDistance(
user.value.total_ascent,
ascentUnitFrom,
ascentUnitTo,
2
)
: parseFloat(user.value.total_ascent.toFixed(2))
)
function get_duration(total_duration: ComputedRef<string>) {
const duration = total_duration.value.match(/day/g)

View File

@ -93,12 +93,13 @@
</template>
<script setup lang="ts">
import { ComputedRef, Ref, computed, ref, capitalize } from 'vue'
import { computed, ref, capitalize } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import UserPicture from '@/components/User/UserPicture.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IDropdownOption } from '@/types/forms'
import { IAuthUserProfile } from '@/types/user'
import type { IDropdownOption } from '@/types/forms'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { availableLanguages } from '@/utils/locales'

View File

@ -25,11 +25,12 @@
<script lang="ts" setup>
import snarkdown from 'snarkdown'
import { ComputedRef, capitalize, computed } from 'vue'
import { capitalize, computed } from 'vue'
import type { ComputedRef } from 'vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { IAuthUserProfile } from '@/types/user'
import type { TAppConfig } from '@/types/application'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { dateStringFormats, formatDate } from '@/utils/dates'
import { linkifyAndClean } from '@/utils/inputs'

View File

@ -10,16 +10,13 @@
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
@import '~@/scss/vars.scss';
.privacy-policy-message {
background: var(--alert-background-color);
color: var(--alert-color);
border-radius: $border-radius;
padding: $default-padding $default-padding*2;
padding: $default-padding $default-padding * 2;
}
</style>

View File

@ -8,7 +8,7 @@
>
<input
type="checkbox"
:id="sport.id"
:id="`${sport.id}`"
:name="sport.label"
:checked="selectedSportIds.includes(sport.id)"
@input="updateSelectedSportIds(sport.id)"
@ -20,10 +20,11 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, inject, withDefaults, toRefs } from 'vue'
import { computed, inject, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { ISport, ITranslatedSport } from '@/types/sports'
import type { ISport, ITranslatedSport } from '@/types/sports'
import { translateSports } from '@/utils/sports'
interface Props {
@ -38,7 +39,7 @@
const { t } = useI18n()
const sportColors = inject('sportColors')
const sportColors: Record<string, string> | undefined = inject('sportColors')
const { selectedSportIds } = toRefs(props)
const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() =>
translateSports(props.userSports, t)

View File

@ -22,15 +22,16 @@
</template>
<script setup lang="ts">
import { ComputedRef, Ref, computed, ref, toRefs, watch } from 'vue'
import { computed, ref, toRefs, watch } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import StatChart from '@/components/Common/StatsChart/index.vue'
import StatsMenu from '@/components/Statistics/StatsMenu.vue'
import SportsMenu from '@/components/Statistics/StatsSportsMenu.vue'
import { ISport, ITranslatedSport } from '@/types/sports'
import { IStatisticsDateParams } from '@/types/statistics'
import { IAuthUserProfile } from '@/types/user'
import type { ISport, ITranslatedSport } from '@/types/sports'
import type { IStatisticsDateParams } from '@/types/statistics'
import type { IAuthUserProfile } from '@/types/user'
import { translateSports } from '@/utils/sports'
import { getStatsDateParams, updateChartParams } from '@/utils/statistics'

View File

@ -10,7 +10,7 @@
</template>
<script setup lang="ts">
import { toRefs, withDefaults } from 'vue'
import { toRefs } from 'vue'
import UserAuthForm from '@/components/User/UserAuthForm.vue'

View File

@ -34,11 +34,12 @@
</template>
<script setup lang="ts">
import { computed, ComputedRef, toRefs } from 'vue'
import { computed, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import UserPicture from '@/components/User/UserPicture.vue'
import { AUTH_USER_STORE } from '@/store/constants'
import { IAuthUserProfile, IUserProfile } from '@/types/user'
import type { IAuthUserProfile, IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
interface Props {

View File

@ -120,20 +120,12 @@
<script setup lang="ts">
import { format } from 'date-fns'
import {
ComputedRef,
Ref,
computed,
ref,
toRefs,
withDefaults,
watch,
onUnmounted,
} from 'vue'
import { computed, ref, toRefs, watch, onUnmounted } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import { AUTH_USER_STORE, ROOT_STORE, USERS_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { IAuthUserProfile, IUserProfile } from '@/types/user'
import type { TAppConfig } from '@/types/application'
import type { IAuthUserProfile, IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { formatDate, getDateFormat } from '@/utils/dates'
import { localeFromLanguage } from '@/utils/locales'

View File

@ -56,10 +56,11 @@
</template>
<script setup lang="ts">
import { computed, ComputedRef } from 'vue'
import { computed } from 'vue'
import type { ComputedRef } from 'vue'
import { ROOT_STORE } from '@/store/constants'
import { IAuthUserProfile } from '@/types/user'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { getDateFormat } from '@/utils/dates'
import { languageLabels } from '@/utils/locales'

View File

@ -13,7 +13,7 @@
import UserHeader from '@/components/User/ProfileDisplay/UserHeader.vue'
import UserProfileTabs from '@/components/User/UserProfileTabs.vue'
import { IUserProfile } from '@/types/user'
import type { IUserProfile } from '@/types/user'
interface Props {
user: IUserProfile

View File

@ -28,7 +28,8 @@
</template>
<script setup lang="ts">
import { Ref, ref, toRefs, watch, withDefaults } from 'vue'
import { ref, toRefs, watch } from 'vue'
import type { Ref } from 'vue'
import { timeZones } from '@/utils/timezone'

View File

@ -105,8 +105,6 @@
<script setup lang="ts">
import { isBefore, subDays } from 'date-fns'
import {
ComputedRef,
Ref,
computed,
reactive,
ref,
@ -115,12 +113,13 @@
watch,
onUnmounted,
} from 'vue'
import type { ComputedRef, Ref } from 'vue'
import authApi from '@/api/authApi'
import PasswordInput from '@/components/Common/PasswordInput.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import {
import type { TAppConfig } from '@/types/application'
import type {
IAuthUserProfile,
IUserAccountPayload,
IExportRequest,

View File

@ -62,10 +62,15 @@
<script setup lang="ts">
import { format } from 'date-fns'
import { ComputedRef, computed, reactive, onMounted, onUnmounted } from 'vue'
import { computed, reactive, onMounted, onUnmounted } from 'vue'
import type { ComputedRef } from 'vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IUserProfile, IUserPayload, IAuthUserProfile } from '@/types/user'
import type {
IUserProfile,
IUserPayload,
IAuthUserProfile,
} from '@/types/user'
import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates'

View File

@ -33,12 +33,13 @@
</template>
<script setup lang="ts">
import { ComputedRef, Ref, computed, ref, toRefs, onUnmounted } from 'vue'
import { computed, ref, toRefs, onUnmounted } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import UserPicture from '@/components/User/UserPicture.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { IUserProfile } from '@/types/user'
import type { TAppConfig } from '@/types/application'
import type { IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { getReadableFileSize } from '@/utils/files'

View File

@ -165,11 +165,12 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, reactive, onMounted, onUnmounted } from 'vue'
import { computed, reactive, onMounted, onUnmounted } from 'vue'
import type { ComputedRef } from 'vue'
import TimezoneDropdown from '@/components/User/ProfileEdition/TimezoneDropdown.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
import type { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { availableDateFormatOptions } from '@/utils/dates'
import { availableLanguages } from '@/utils/locales'

View File

@ -17,10 +17,7 @@
<div class="policy-content">
<PrivacyPolicy />
</div>
<label
for="accepted_policy"
class="accepted_policy"
>
<label for="accepted_policy" class="accepted_policy">
<input
type="checkbox"
id="accepted_policy"
@ -49,11 +46,12 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, ref, onUnmounted, toRefs } from 'vue'
import { computed, ref, onUnmounted, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import PrivacyPolicy from '@/components/PrivacyPolicy.vue'
import {AUTH_USER_STORE, ROOT_STORE} from '@/store/constants'
import { IAuthUserProfile } from '@/types/user'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
interface Props {
@ -67,11 +65,12 @@
const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
)
const acceptedPolicy= ref(false)
const acceptedPolicy = ref(false)
function onSubmit() {
store.dispatch(
AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY, acceptedPolicy.value
AUTH_USER_STORE.ACTIONS.ACCEPT_PRIVACY_POLICY,
acceptedPolicy.value
)
}
@ -93,14 +92,14 @@
.policy-content {
height: 500px;
border:1px solid #ccc;
border: 1px solid #ccc;
overflow: auto;
margin: $default-margin;
border-radius: $border-radius;
@media screen and (max-width: $small-limit) {
margin: $default-margin 0;
font-size: .9em;
font-size: 0.9em;
}
.privacy-policy-text {

View File

@ -22,7 +22,7 @@
import UserProfileTabs from '@/components/User/UserProfileTabs.vue'
import { AUTH_USER_STORE } from '@/store/constants'
import { IUserProfile } from '@/types/user'
import type { IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
interface Props {
@ -34,7 +34,14 @@
const store = useStore()
const { user, tab } = toRefs(props)
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS', 'PRIVACY-POLICY']
const tabs = [
'PROFILE',
'ACCOUNT',
'PICTURE',
'PREFERENCES',
'SPORTS',
'PRIVACY-POLICY',
]
const loading = computed(
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
)

View File

@ -89,8 +89,8 @@
import { computed, reactive } from 'vue'
import { OAUTH2_STORE } from '@/store/constants'
import { IOAuth2ClientPayload } from '@/types/oauth'
import { IAuthUserProfile } from '@/types/user'
import type { IOAuth2ClientPayload } from '@/types/oauth'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { admin_oauth2_scopes, oauth2_scopes } from '@/utils/oauth'

View File

@ -39,11 +39,12 @@
</template>
<script setup lang="ts">
import { computed, ComputedRef, onBeforeMount } from 'vue'
import { computed, onBeforeMount } from 'vue'
import type { ComputedRef } from 'vue'
import { useRoute } from 'vue-router'
import { OAUTH2_STORE, ROOT_STORE } from '@/store/constants'
import { IOAuth2Client } from '@/types/oauth'
import type { IOAuth2Client } from '@/types/oauth'
import { useStore } from '@/use/useStore'
const route = useRoute()

View File

@ -110,17 +110,15 @@
<script setup lang="ts">
import {
ComputedRef,
Ref,
capitalize,
computed,
onBeforeMount,
toRefs,
ref,
onUnmounted,
withDefaults,
watch,
} from 'vue'
import type { ComputedRef, Ref } from 'vue'
import { useRoute } from 'vue-router'
import { OAUTH2_STORE, ROOT_STORE } from '@/store/constants'

View File

@ -37,14 +37,16 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, onBeforeMount, toRefs, watch } from 'vue'
import { LocationQuery, useRoute } from 'vue-router'
import { computed, onBeforeMount, toRefs, watch } from 'vue'
import type { ComputedRef } from 'vue'
import { useRoute } from 'vue-router'
import type { LocationQuery } from 'vue-router'
import Pagination from '@/components/Common/Pagination.vue'
import { OAUTH2_STORE } from '@/store/constants'
import { IPagination } from '@/types/api'
import { IOAuth2Client, IOauth2ClientsPayload } from '@/types/oauth'
import { IAuthUserProfile } from '@/types/user'
import type { IPagination } from '@/types/api'
import type { IOAuth2Client, IOauth2ClientsPayload } from '@/types/oauth'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { defaultPage, getNumberQueryValue } from '@/utils/api'
import { formatDate } from '@/utils/dates'

View File

@ -8,7 +8,7 @@
import { onUnmounted, toRefs } from 'vue'
import { OAUTH2_STORE, ROOT_STORE } from '@/store/constants'
import { IAuthUserProfile } from '@/types/user'
import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
interface Props {

View File

@ -163,22 +163,14 @@
</template>
<script setup lang="ts">
import {
ComputedRef,
computed,
onUnmounted,
reactive,
ref,
toRefs,
watch,
withDefaults,
} from 'vue'
import { computed, onUnmounted, reactive, ref, toRefs, watch } from 'vue'
import type { ComputedRef } from 'vue'
import { useRoute } from 'vue-router'
import PasswordInput from '@/components/Common/PasswordInput.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { ILoginRegisterFormData } from '@/types/user'
import type { TAppConfig } from '@/types/application'
import type { ILoginRegisterFormData } from '@/types/user'
import { useStore } from '@/use/useStore'
interface Props {
@ -197,7 +189,7 @@
username: '',
email: '',
password: '',
accepted_policy: false
accepted_policy: false,
})
const buttonText: ComputedRef<string> = computed(() =>
getButtonText(props.action)
@ -336,7 +328,7 @@
.accepted_policy {
display: flex;
align-items: center;
font-size: .85em;
font-size: 0.85em;
font-weight: normal;
}
}

View File

@ -15,7 +15,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { IUserProfile } from '@/types/user'
import type { IUserProfile } from '@/types/user'
import { getApiUrl } from '@/utils'
interface Props {

View File

@ -26,7 +26,7 @@
</template>
<script setup lang="ts">
import { onMounted, toRefs, withDefaults } from 'vue'
import { onMounted, toRefs } from 'vue'
interface Props {
tabs: string[]

View File

@ -165,12 +165,13 @@
</template>
<script setup lang="ts">
import { ComputedRef, computed, inject, reactive, toRefs, watch } from 'vue'
import { computed, inject, reactive, toRefs, watch } from 'vue'
import type { ComputedRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { AUTH_USER_STORE, ROOT_STORE, SPORTS_STORE } from '@/store/constants'
import { ISport, ITranslatedSport } from '@/types/sports'
import { IUserProfile, IUserSportPreferencesPayload } from '@/types/user'
import type { ISport, ITranslatedSport } from '@/types/sports'
import type { IUserProfile, IUserSportPreferencesPayload } from '@/types/user'
import { useStore } from '@/use/useStore'
import { translateSports } from '@/utils/sports'

View File

@ -138,15 +138,17 @@
</template>
<script setup lang="ts">
import { Locale, formatDistance } from 'date-fns'
import { ComputedRef, computed, toRefs, withDefaults } from 'vue'
import { formatDistance } from 'date-fns'
import type { Locale } from 'date-fns'
import { computed, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import StaticMap from '@/components/Common/StaticMap.vue'
import UserPicture from '@/components/User/UserPicture.vue'
import { ROOT_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import { IUserProfile } from '@/types/user'
import { IWorkout } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user'
import type { IWorkout } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates'
@ -157,8 +159,8 @@
sport?: ISport
}
const props = withDefaults(defineProps<Props>(), {
workout: () => ({} as IWorkout),
sport: () => ({} as ISport),
workout: () => ({}) as IWorkout,
sport: () => ({}) as ISport,
})
const store = useStore()

View File

@ -19,7 +19,7 @@
import { toRefs } from 'vue'
import { useI18n } from 'vue-i18n'
import { IWeather } from '@/types/workouts'
import type { IWeather } from '@/types/workouts'
import { getWindSpeed } from '@/utils/units'
import { convertDegreeToDirection } from '@/utils/weather'

View File

@ -100,8 +100,8 @@
import { toRefs } from 'vue'
import authApi from '@/api/authApi'
import { ISport } from '@/types/sports'
import { IWorkoutObject } from '@/types/workouts'
import type { ISport } from '@/types/sports'
import type { IWorkoutObject } from '@/types/workouts'
interface Props {
sport: ISport

View File

@ -51,15 +51,16 @@
</template>
<script setup lang="ts">
import { ChartData, ChartOptions } from 'chart.js'
import { ComputedRef, computed, ref, toRefs } from 'vue'
import type { ChartData, ChartOptions } from 'chart.js'
import { computed, ref, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import { LineChart, useLineChart } from 'vue-chart-3'
import { useI18n } from 'vue-i18n'
import { htmlLegendPlugin } from '@/components/Workout/WorkoutDetail/WorkoutChart/legend'
import { TUnit } from '@/types/units'
import { IAuthUserProfile } from '@/types/user'
import {
import type { TUnit } from '@/types/units'
import type { IAuthUserProfile } from '@/types/user'
import type {
IWorkoutChartData,
IWorkoutData,
TCoordinates,

View File

@ -1,4 +1,5 @@
import { Chart, LegendItem } from 'chart.js'
import { Chart } from 'chart.js'
import type { LegendItem } from 'chart.js'
const getOrCreateLegendList = (id: string): HTMLUListElement => {
const legendContainer = document.getElementById(id)

View File

@ -114,7 +114,7 @@
import WorkoutRecord from '@/components/Workout/WorkoutDetail/WorkoutRecord.vue'
import WorkoutWeather from '@/components/Workout/WorkoutDetail/WorkoutWeather.vue'
import { IWorkoutObject } from '@/types/workouts'
import type { IWorkoutObject } from '@/types/workouts'
interface Props {
workoutObject: IWorkoutObject

View File

@ -14,7 +14,7 @@
import { LIcon, LMarker } from '@vue-leaflet/vue-leaflet'
import { toRefs } from 'vue'
import { TCoordinates } from '@/types/workouts'
import type { TCoordinates } from '@/types/workouts'
interface Props {
markerCoordinates: TCoordinates

View File

@ -16,6 +16,7 @@
:zoomAnimation="false"
ref="workoutMap"
@ready="fitBounds(bounds)"
:use-global-leaflet="false"
>
<LControlLayers />
<LControl
@ -90,14 +91,15 @@
LMarker,
LTileLayer,
} from '@vue-leaflet/vue-leaflet'
import { ComputedRef, computed, ref, toRefs, withDefaults } from 'vue'
import { computed, ref, toRefs } from 'vue'
import type { ComputedRef } from 'vue'
import 'leaflet/dist/leaflet.css'
import CustomMarker from '@/components/Workout/WorkoutDetail/WorkoutMap/CustomMarker.vue'
import { ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { GeoJSONData } from '@/types/geojson'
import { IWorkoutData, TCoordinates } from '@/types/workouts'
import type { TAppConfig } from '@/types/application'
import type { GeoJSONData } from '@/types/geojson'
import type { IWorkoutData, TCoordinates } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import { getApiUrl } from '@/utils'
@ -106,7 +108,7 @@
markerCoordinates?: TCoordinates
}
const props = withDefaults(defineProps<Props>(), {
markerCoordinates: () => ({} as TCoordinates),
markerCoordinates: () => ({}) as TCoordinates,
})
const store = useStore()

View File

@ -16,7 +16,7 @@
</template>
<script setup lang="ts">
import { toRefs, withDefaults } from 'vue'
import { toRefs } from 'vue'
import { linkifyAndClean } from '@/utils/inputs'

View File

@ -15,7 +15,7 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { IWorkoutObject } from '@/types/workouts'
import type { IWorkoutObject } from '@/types/workouts'
interface Props {
recordType: string

View File

@ -31,7 +31,7 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { IWorkoutSegment } from '@/types/workouts'
import type { IWorkoutSegment } from '@/types/workouts'
interface Props {
segments: IWorkoutSegment[]

Some files were not shown because too many files have changed in this diff Show More