Merge pull request #245 from jat255/add_date_formats
Add ability to customize format used to display dates throughout the app
This commit is contained in:
commit
c4bb41caf8
20
Makefile
20
Makefile
@ -42,6 +42,9 @@ clean-install: clean
|
||||
rm -rf dist/
|
||||
|
||||
## Docker commands for evaluation purposes
|
||||
docker-bandit:
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_BANDIT) -r fittrackee -c pyproject.toml
|
||||
|
||||
docker-build:
|
||||
docker-compose -f docker-compose-dev.yml build fittrackee
|
||||
|
||||
@ -50,11 +53,15 @@ docker-build-all: docker-build docker-build-client
|
||||
docker-build-client:
|
||||
docker-compose -f docker-compose-dev.yml build fittrackee_client
|
||||
|
||||
docker-check-all: docker-bandit docker-lint-all docker-type-check docker-test-client docker-test-python
|
||||
|
||||
docker-init: docker-run docker-init-db docker-restart docker-run-workers
|
||||
|
||||
docker-init-db:
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee docker/init-database.sh
|
||||
|
||||
docker-lint-all: docker-lint-client docker-lint-python
|
||||
|
||||
docker-lint-client:
|
||||
docker-compose -f docker-compose-dev.yml up -d fittrackee_client
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee_client yarn lint
|
||||
@ -65,12 +72,18 @@ docker-lint-python: docker-run
|
||||
docker-logs:
|
||||
docker-compose -f docker-compose-dev.yml logs --follow
|
||||
|
||||
docker-migrate-db:
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_FLASK) db migrate --directory $(DOCKER_MIGRATIONS)
|
||||
|
||||
docker-rebuild:
|
||||
docker-compose -f docker-compose-dev.yml build --no-cache
|
||||
|
||||
docker-restart:
|
||||
docker-compose -f docker-compose-dev.yml restart fittrackee
|
||||
|
||||
docker-revision:
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_FLASK) db revision --directory $(DOCKER_MIGRATIONS) --message $(MIGRATION_MESSAGE)
|
||||
|
||||
docker-run-all: docker-run docker-run-workers
|
||||
|
||||
docker-run:
|
||||
@ -104,9 +117,16 @@ docker-test-e2e: docker-run
|
||||
docker-test-python: docker-run
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee docker/test-python.sh $(PYTEST_ARGS)
|
||||
|
||||
docker-type-check:
|
||||
echo 'Running mypy in docker...'
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_MYPY) fittrackee
|
||||
|
||||
docker-up:
|
||||
docker-compose -f docker-compose-dev.yml up fittrackee
|
||||
|
||||
docker-upgrade-db:
|
||||
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_FTCLI) db upgrade
|
||||
|
||||
downgrade-db:
|
||||
$(FLASK) db downgrade --directory $(MIGRATIONS)
|
||||
|
||||
|
@ -27,6 +27,14 @@ BANDIT = $(VENV)/bin/bandit
|
||||
PYBABEL = $(VENV)/bin/pybabel
|
||||
FTCLI = $(VENV)/bin/ftcli
|
||||
|
||||
# Docker env
|
||||
export DOCKER_APP_DIR = /usr/src/app
|
||||
export DOCKER_MIGRATIONS = $(DOCKER_APP_DIR)/fittrackee/migrations
|
||||
export DOCKER_FLASK = /usr/local/bin/flask
|
||||
export DOCKER_FTCLI = /usr/local/bin/ftcli
|
||||
export DOCKER_BANDIT = /usr/local/bin/bandit
|
||||
export DOCKER_MYPY = /usr/local/bin/mypy
|
||||
|
||||
# Node env
|
||||
NODE_MODULES = $(PWD)/fittrackee_client/node_modules
|
||||
NPM ?= yarn
|
||||
|
2
fittrackee/dist/index.html
vendored
2
fittrackee/dist/index.html
vendored
@ -1 +1 @@
|
||||
<!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"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.e9c5b3a5.js"></script><script defer="defer" src="/static/js/app.f492102f.js"></script><link href="/static/css/app.eee1934d.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!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"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.a306e708.js"></script><script defer="defer" src="/static/js/app.2c35ea55.js"></script><link href="/static/css/app.a67ca8d9.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
2
fittrackee/dist/service-worker.js
vendored
2
fittrackee/dist/service-worker.js
vendored
File diff suppressed because one or more lines are too long
2
fittrackee/dist/service-worker.js.map
vendored
2
fittrackee/dist/service-worker.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[328],{6e3:function(t,e,i){i.r(e),i.d(e,{default:function(){return _}});var a=i(6252),n=i(2262),s=i(8273),c=i(5801),r=i(9917);const S=t=>((0,a.dD)("data-v-64629971"),t=t(),(0,a.Cn)(),t),l={id:"admin",class:"view"},p={key:0,class:"container"},u=S((()=>(0,a._)("div",{id:"bottom"},null,-1)));var T=(0,a.aZ)({__name:"AdminView",setup(t){const e=(0,r.o)(),i=(0,a.Fl)((()=>e.getters[c.SY.GETTERS.APP_CONFIG])),S=(0,a.Fl)((()=>e.getters[c.SY.GETTERS.APP_STATS])),T=(0,a.Fl)((()=>e.getters[c.YN.GETTERS.IS_ADMIN])),d=(0,a.Fl)((()=>e.getters[c.YN.GETTERS.USER_LOADING]));return(0,a.wF)((()=>e.dispatch(c.SY.ACTIONS.GET_APPLICATION_STATS))),(t,e)=>{const c=(0,a.up)("router-view");return(0,a.wg)(),(0,a.iD)("div",l,[(0,n.SU)(d)?(0,a.kq)("",!0):((0,a.wg)(),(0,a.iD)("div",p,[(0,n.SU)(T)?((0,a.wg)(),(0,a.j4)(c,{key:0,appConfig:(0,n.SU)(i),appStatistics:(0,n.SU)(S)},null,8,["appConfig","appStatistics"])):((0,a.wg)(),(0,a.j4)(s.Z,{key:1})),u]))])}}}),d=i(3744);const o=(0,d.Z)(T,[["__scopeId","data-v-64629971"]]);var _=o}}]);
|
||||
//# sourceMappingURL=admin.ab9e5f5f.js.map
|
||||
//# sourceMappingURL=admin.3b0b84c0.js.map
|
@ -1 +1 @@
|
||||
{"version":3,"file":"static/js/admin.ab9e5f5f.js","mappings":"mOAGA,MAAMA,EAAeC,KAAMC,EAAAA,EAAAA,IAAa,mBAAmBD,EAAEA,KAAIE,EAAAA,EAAAA,MAAcF,GACzEG,EAAa,CACjBC,GAAI,QACJC,MAAO,QAEHC,EAAa,CACjBC,IAAK,EACLF,MAAO,aAEHG,EAA2BT,GAAa,KAAmBU,EAAAA,EAAAA,GAAoB,MAAO,CAAEL,GAAI,UAAY,MAAO,KAUrH,OAA4BM,EAAAA,EAAAA,IAAiB,CAC3CC,OAAQ,YACRC,MAAMC,GAEN,MAAMC,GAAQC,EAAAA,EAAAA,KAERC,GAAqCC,EAAAA,EAAAA,KACzC,IAAMH,EAAMI,QAAQC,EAAAA,GAAAA,QAAAA,cAEhBC,GAA6CH,EAAAA,EAAAA,KACjD,IAAMH,EAAMI,QAAQC,EAAAA,GAAAA,QAAAA,aAEhBE,GAAuCJ,EAAAA,EAAAA,KAC3C,IAAMH,EAAMI,QAAQI,EAAAA,GAAAA,QAAAA,YAEhBC,GAAoCN,EAAAA,EAAAA,KACxC,IAAMH,EAAMI,QAAQI,EAAAA,GAAAA,QAAAA,gBAKxB,OAFEE,EAAAA,EAAAA,KAAc,IAAMV,EAAMW,SAASN,EAAAA,GAAAA,QAAAA,yBAE9B,CAACO,EAAUC,KAChB,MAAMC,GAAyBC,EAAAA,EAAAA,IAAkB,eAEjD,OAAQC,EAAAA,EAAAA,OAAcC,EAAAA,EAAAA,IAAoB,MAAO5B,EAAY,EACzD6B,EAAAA,EAAAA,IAAOT,IAWLU,EAAAA,EAAAA,IAAoB,IAAI,KAVvBH,EAAAA,EAAAA,OAAcC,EAAAA,EAAAA,IAAoB,MAAOzB,EAAY,EACnD0B,EAAAA,EAAAA,IAAOX,KACHS,EAAAA,EAAAA,OAAcI,EAAAA,EAAAA,IAAaN,EAAwB,CAClDrB,IAAK,EACLS,WAAWgB,EAAAA,EAAAA,IAAOhB,GAClBI,eAAeY,EAAAA,EAAAA,IAAOZ,IACrB,KAAM,EAAG,CAAC,YAAa,qBACzBU,EAAAA,EAAAA,OAAcI,EAAAA,EAAAA,IAAaC,EAAAA,EAAU,CAAE5B,IAAK,KACjDC,MAVR,CAeD,I,UCvDD,MAAM4B,GAA2B,OAAgB,EAAQ,CAAC,CAAC,YAAY,qBAEvE,O","sources":["webpack://fittrackee_client/./src/views/AdminView.vue?67de","webpack://fittrackee_client/./src/views/AdminView.vue"],"sourcesContent":["import { defineComponent as _defineComponent } from 'vue'\nimport { unref as _unref, resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementVNode as _createElementVNode, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-64629971\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n id: \"admin\",\n class: \"view\"\n}\nconst _hoisted_2 = {\n key: 0,\n class: \"container\"\n}\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { id: \"bottom\" }, null, -1))\n\nimport { computed, ComputedRef, onBeforeMount } from 'vue'\n\n import NotFound from '@/components/Common/NotFound.vue'\n import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'\n import { TAppConfig, IAppStatistics } from '@/types/application'\n import { useStore } from '@/use/useStore'\n\n \nexport default /*#__PURE__*/_defineComponent({\n __name: 'AdminView',\n setup(__props) {\n\n const store = useStore()\n\n const appConfig: ComputedRef<TAppConfig> = computed(\n () => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]\n )\n const appStatistics: ComputedRef<IAppStatistics> = computed(\n () => store.getters[ROOT_STORE.GETTERS.APP_STATS]\n )\n const isAuthUserAmin: ComputedRef<boolean> = computed(\n () => store.getters[AUTH_USER_STORE.GETTERS.IS_ADMIN]\n )\n const userLoading: ComputedRef<boolean> = computed(\n () => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]\n )\n\n onBeforeMount(() => store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_STATS))\n\nreturn (_ctx: any,_cache: any) => {\n const _component_router_view = _resolveComponent(\"router-view\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n (!_unref(userLoading))\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_2, [\n (_unref(isAuthUserAmin))\n ? (_openBlock(), _createBlock(_component_router_view, {\n key: 0,\n appConfig: _unref(appConfig),\n appStatistics: _unref(appStatistics)\n }, null, 8, [\"appConfig\", \"appStatistics\"]))\n : (_openBlock(), _createBlock(NotFound, { key: 1 })),\n _hoisted_3\n ]))\n : _createCommentVNode(\"\", true)\n ]))\n}\n}\n\n})","import script from \"./AdminView.vue?vue&type=script&setup=true&lang=ts\"\nexport * from \"./AdminView.vue?vue&type=script&setup=true&lang=ts\"\n\nimport \"./AdminView.vue?vue&type=style&index=0&id=64629971&lang=scss&scoped=true\"\n\nimport exportComponent from \"/mnt/data-lnx/Devs/00_Perso/FitTrackee/fittrackee_client/node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['__scopeId',\"data-v-64629971\"]])\n\nexport default __exports__"],"names":["_withScopeId","n","_pushScopeId","_popScopeId","_hoisted_1","id","class","_hoisted_2","key","_hoisted_3","_createElementVNode","_defineComponent","__name","setup","__props","store","useStore","appConfig","computed","getters","ROOT_STORE","appStatistics","isAuthUserAmin","AUTH_USER_STORE","userLoading","onBeforeMount","dispatch","_ctx","_cache","_component_router_view","_resolveComponent","_openBlock","_createElementBlock","_unref","_createCommentVNode","_createBlock","NotFound","__exports__"],"sourceRoot":""}
|
||||
{"version":3,"file":"static/js/admin.3b0b84c0.js","mappings":"mOAGA,MAAMA,EAAeC,KAAMC,EAAAA,EAAAA,IAAa,mBAAmBD,EAAEA,KAAIE,EAAAA,EAAAA,MAAcF,GACzEG,EAAa,CACjBC,GAAI,QACJC,MAAO,QAEHC,EAAa,CACjBC,IAAK,EACLF,MAAO,aAEHG,EAA2BT,GAAa,KAAmBU,EAAAA,EAAAA,GAAoB,MAAO,CAAEL,GAAI,UAAY,MAAO,KAUrH,OAA4BM,EAAAA,EAAAA,IAAiB,CAC3CC,OAAQ,YACRC,MAAMC,GAEN,MAAMC,GAAQC,EAAAA,EAAAA,KAERC,GAAqCC,EAAAA,EAAAA,KACzC,IAAMH,EAAMI,QAAQC,EAAAA,GAAAA,QAAAA,cAEhBC,GAA6CH,EAAAA,EAAAA,KACjD,IAAMH,EAAMI,QAAQC,EAAAA,GAAAA,QAAAA,aAEhBE,GAAuCJ,EAAAA,EAAAA,KAC3C,IAAMH,EAAMI,QAAQI,EAAAA,GAAAA,QAAAA,YAEhBC,GAAoCN,EAAAA,EAAAA,KACxC,IAAMH,EAAMI,QAAQI,EAAAA,GAAAA,QAAAA,gBAKxB,OAFEE,EAAAA,EAAAA,KAAc,IAAMV,EAAMW,SAASN,EAAAA,GAAAA,QAAAA,yBAE9B,CAACO,EAAUC,KAChB,MAAMC,GAAyBC,EAAAA,EAAAA,IAAkB,eAEjD,OAAQC,EAAAA,EAAAA,OAAcC,EAAAA,EAAAA,IAAoB,MAAO5B,EAAY,EACzD6B,EAAAA,EAAAA,IAAOT,IAWLU,EAAAA,EAAAA,IAAoB,IAAI,KAVvBH,EAAAA,EAAAA,OAAcC,EAAAA,EAAAA,IAAoB,MAAOzB,EAAY,EACnD0B,EAAAA,EAAAA,IAAOX,KACHS,EAAAA,EAAAA,OAAcI,EAAAA,EAAAA,IAAaN,EAAwB,CAClDrB,IAAK,EACLS,WAAWgB,EAAAA,EAAAA,IAAOhB,GAClBI,eAAeY,EAAAA,EAAAA,IAAOZ,IACrB,KAAM,EAAG,CAAC,YAAa,qBACzBU,EAAAA,EAAAA,OAAcI,EAAAA,EAAAA,IAAaC,EAAAA,EAAU,CAAE5B,IAAK,KACjDC,MAVR,CAeD,I,UCvDD,MAAM4B,GAA2B,OAAgB,EAAQ,CAAC,CAAC,YAAY,qBAEvE,O","sources":["webpack://fittrackee_client/./src/views/AdminView.vue?67de","webpack://fittrackee_client/./src/views/AdminView.vue"],"sourcesContent":["import { defineComponent as _defineComponent } from 'vue'\nimport { unref as _unref, resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementVNode as _createElementVNode, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-64629971\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n id: \"admin\",\n class: \"view\"\n}\nconst _hoisted_2 = {\n key: 0,\n class: \"container\"\n}\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { id: \"bottom\" }, null, -1))\n\nimport { computed, ComputedRef, onBeforeMount } from 'vue'\n\n import NotFound from '@/components/Common/NotFound.vue'\n import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'\n import { TAppConfig, IAppStatistics } from '@/types/application'\n import { useStore } from '@/use/useStore'\n\n \nexport default /*#__PURE__*/_defineComponent({\n __name: 'AdminView',\n setup(__props) {\n\n const store = useStore()\n\n const appConfig: ComputedRef<TAppConfig> = computed(\n () => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]\n )\n const appStatistics: ComputedRef<IAppStatistics> = computed(\n () => store.getters[ROOT_STORE.GETTERS.APP_STATS]\n )\n const isAuthUserAmin: ComputedRef<boolean> = computed(\n () => store.getters[AUTH_USER_STORE.GETTERS.IS_ADMIN]\n )\n const userLoading: ComputedRef<boolean> = computed(\n () => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]\n )\n\n onBeforeMount(() => store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_STATS))\n\nreturn (_ctx: any,_cache: any) => {\n const _component_router_view = _resolveComponent(\"router-view\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n (!_unref(userLoading))\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_2, [\n (_unref(isAuthUserAmin))\n ? (_openBlock(), _createBlock(_component_router_view, {\n key: 0,\n appConfig: _unref(appConfig),\n appStatistics: _unref(appStatistics)\n }, null, 8, [\"appConfig\", \"appStatistics\"]))\n : (_openBlock(), _createBlock(NotFound, { key: 1 })),\n _hoisted_3\n ]))\n : _createCommentVNode(\"\", true)\n ]))\n}\n}\n\n})","import script from \"./AdminView.vue?vue&type=script&setup=true&lang=ts\"\nexport * from \"./AdminView.vue?vue&type=script&setup=true&lang=ts\"\n\nimport \"./AdminView.vue?vue&type=style&index=0&id=64629971&lang=scss&scoped=true\"\n\nimport exportComponent from \"/mnt/data-lnx/Devs/00_Perso/FitTrackee/fittrackee_client/node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['__scopeId',\"data-v-64629971\"]])\n\nexport default __exports__"],"names":["_withScopeId","n","_pushScopeId","_popScopeId","_hoisted_1","id","class","_hoisted_2","key","_hoisted_3","_createElementVNode","_defineComponent","__name","setup","__props","store","useStore","appConfig","computed","getters","ROOT_STORE","appStatistics","isAuthUserAmin","AUTH_USER_STORE","userLoading","onBeforeMount","dispatch","_ctx","_cache","_component_router_view","_resolveComponent","_openBlock","_createElementBlock","_unref","_createCommentVNode","_createBlock","NotFound","__exports__"],"sourceRoot":""}
|
2
fittrackee/dist/static/js/app.2c35ea55.js
vendored
Normal file
2
fittrackee/dist/static/js/app.2c35ea55.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/app.2c35ea55.js.map
vendored
Normal file
1
fittrackee/dist/static/js/app.2c35ea55.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.f492102f.js
vendored
2
fittrackee/dist/static/js/app.f492102f.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[845],{4264:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});r(7658);var n=r(6252),a=r(2262),s=r(3577),u=r(2201),o=r(7167),i=r(5801),c=r(9917);const l={key:0,id:"account-confirmation",class:"center-card with-margin"},E={class:"error-message"};var _=(0,n.aZ)({__name:"AccountConfirmationView",setup(e){const t=(0,u.yj)(),r=(0,u.tv)(),_=(0,c.o)(),d=(0,n.Fl)((()=>_.getters[i.SY.GETTERS.ERROR_MESSAGES])),S=(0,n.Fl)((()=>t.query.token));function m(){S.value?_.dispatch(i.YN.ACTIONS.CONFIRM_ACCOUNT,{token:S.value}):r.push("/")}return(0,n.wF)((()=>m())),(0,n.Ah)((()=>_.commit(i.SY.MUTATIONS.EMPTY_ERROR_MESSAGES))),(e,t)=>{const r=(0,n.up)("router-link");return(0,a.SU)(d)?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(o.Z),(0,n._)("p",E,[(0,n._)("span",null,(0,s.zw)(e.$t("error.SOMETHING_WRONG"))+".",1),(0,n.Wm)(r,{class:"links",to:"/account-confirmation/resend"},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.$t("buttons.ACCOUNT-CONFIRMATION-RESEND"))+"? ",1)])),_:1})])])):(0,n.kq)("",!0)}}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-785df978"]]);var m=S},8160:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});r(7658);var n=r(6252),a=r(2262),s=r(3577),u=r(2201),o=r(7167),i=r(5801),c=r(9917);const l={key:0,id:"email-update",class:"center-card with-margin"},E={class:"error-message"};var _=(0,n.aZ)({__name:"EmailUpdateView",setup(e){const t=(0,u.yj)(),r=(0,u.tv)(),_=(0,c.o)(),d=(0,n.Fl)((()=>_.getters[i.YN.GETTERS.AUTH_USER_PROFILE])),S=(0,n.Fl)((()=>_.getters[i.YN.GETTERS.IS_AUTHENTICATED])),m=(0,n.Fl)((()=>_.getters[i.SY.GETTERS.ERROR_MESSAGES])),p=(0,n.Fl)((()=>t.query.token));function R(){p.value?_.dispatch(i.YN.ACTIONS.CONFIRM_EMAIL,{token:p.value,refreshUser:S.value}):r.push("/")}return(0,n.wF)((()=>R())),(0,n.Ah)((()=>_.commit(i.SY.MUTATIONS.EMPTY_ERROR_MESSAGES))),(0,n.YP)((()=>m.value),(e=>{d.value.username&&e&&r.push("/")})),(e,t)=>{const r=(0,n.up)("router-link"),u=(0,n.up)("i18n-t");return(0,a.SU)(m)&&!(0,a.SU)(d).username?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(o.Z),(0,n._)("p",E,[(0,n._)("span",null,(0,s.zw)(e.$t("error.SOMETHING_WRONG"))+".",1),(0,n._)("span",null,[(0,n.Wm)(u,{keypath:"user.PROFILE.ERRORED_EMAIL_UPDATE"},{default:(0,n.w5)((()=>[(0,n.Wm)(r,{to:"/login"},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.$t("user.LOG_IN")),1)])),_:1})])),_:1})])])])):(0,n.kq)("",!0)}}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-8c2ec9ce"]]);var m=S},6266:function(e,t,r){r.r(t),r.d(t,{default:function(){return d}});var n=r(6252),a=r(2262),s=r(5801),u=r(9917);const o=e=>((0,n.dD)("data-v-05463732"),e=e(),(0,n.Cn)(),e),i={key:0,id:"profile",class:"container view"},c=o((()=>(0,n._)("div",{id:"bottom"},null,-1)));var l=(0,n.aZ)({__name:"ProfileView",setup(e){const t=(0,u.o)(),r=(0,n.Fl)((()=>t.getters[s.YN.GETTERS.AUTH_USER_PROFILE]));return(e,t)=>{const s=(0,n.up)("router-view");return(0,a.SU)(r).username?((0,n.wg)(),(0,n.iD)("div",i,[(0,n.Wm)(s,{user:(0,a.SU)(r)},null,8,["user"]),c])):(0,n.kq)("",!0)}}}),E=r(3744);const _=(0,E.Z)(l,[["__scopeId","data-v-05463732"]]);var d=_},9453:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});var n=r(6252),a=r(2262),s=r(2201),u=r(2179),o=r(7408),i=r(5801),c=r(9917);const l={key:0,id:"user",class:"view"},E={class:"box"};var _=(0,n.aZ)({__name:"UserView",props:{fromAdmin:{type:Boolean}},setup(e){const t=e,{fromAdmin:r}=(0,a.BK)(t),_=(0,s.yj)(),d=(0,c.o)(),S=(0,n.Fl)((()=>d.getters[i.RT.GETTERS.USER]));return(0,n.wF)((()=>{_.params.username&&"string"===typeof _.params.username&&d.dispatch(i.RT.ACTIONS.GET_USER,_.params.username)})),(0,n.Jd)((()=>{d.dispatch(i.RT.ACTIONS.EMPTY_USER)})),(e,t)=>(0,a.SU)(S).username?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(u.Z,{user:(0,a.SU)(S)},null,8,["user"]),(0,n._)("div",E,[(0,n.Wm)(o.Z,{user:(0,a.SU)(S),"from-admin":(0,a.SU)(r)},null,8,["user","from-admin"])])])):(0,n.kq)("",!0)}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-af7007f4"]]);var m=S}}]);
|
||||
//# sourceMappingURL=profile.dd30724d.js.map
|
||||
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[845],{4264:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});r(7658);var n=r(6252),a=r(2262),s=r(3577),u=r(2201),o=r(7167),i=r(5801),c=r(9917);const l={key:0,id:"account-confirmation",class:"center-card with-margin"},E={class:"error-message"};var _=(0,n.aZ)({__name:"AccountConfirmationView",setup(e){const t=(0,u.yj)(),r=(0,u.tv)(),_=(0,c.o)(),d=(0,n.Fl)((()=>_.getters[i.SY.GETTERS.ERROR_MESSAGES])),S=(0,n.Fl)((()=>t.query.token));function m(){S.value?_.dispatch(i.YN.ACTIONS.CONFIRM_ACCOUNT,{token:S.value}):r.push("/")}return(0,n.wF)((()=>m())),(0,n.Ah)((()=>_.commit(i.SY.MUTATIONS.EMPTY_ERROR_MESSAGES))),(e,t)=>{const r=(0,n.up)("router-link");return(0,a.SU)(d)?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(o.Z),(0,n._)("p",E,[(0,n._)("span",null,(0,s.zw)(e.$t("error.SOMETHING_WRONG"))+".",1),(0,n.Wm)(r,{class:"links",to:"/account-confirmation/resend"},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.$t("buttons.ACCOUNT-CONFIRMATION-RESEND"))+"? ",1)])),_:1})])])):(0,n.kq)("",!0)}}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-785df978"]]);var m=S},8160:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});r(7658);var n=r(6252),a=r(2262),s=r(3577),u=r(2201),o=r(7167),i=r(5801),c=r(9917);const l={key:0,id:"email-update",class:"center-card with-margin"},E={class:"error-message"};var _=(0,n.aZ)({__name:"EmailUpdateView",setup(e){const t=(0,u.yj)(),r=(0,u.tv)(),_=(0,c.o)(),d=(0,n.Fl)((()=>_.getters[i.YN.GETTERS.AUTH_USER_PROFILE])),S=(0,n.Fl)((()=>_.getters[i.YN.GETTERS.IS_AUTHENTICATED])),m=(0,n.Fl)((()=>_.getters[i.SY.GETTERS.ERROR_MESSAGES])),p=(0,n.Fl)((()=>t.query.token));function R(){p.value?_.dispatch(i.YN.ACTIONS.CONFIRM_EMAIL,{token:p.value,refreshUser:S.value}):r.push("/")}return(0,n.wF)((()=>R())),(0,n.Ah)((()=>_.commit(i.SY.MUTATIONS.EMPTY_ERROR_MESSAGES))),(0,n.YP)((()=>m.value),(e=>{d.value.username&&e&&r.push("/")})),(e,t)=>{const r=(0,n.up)("router-link"),u=(0,n.up)("i18n-t");return(0,a.SU)(m)&&!(0,a.SU)(d).username?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(o.Z),(0,n._)("p",E,[(0,n._)("span",null,(0,s.zw)(e.$t("error.SOMETHING_WRONG"))+".",1),(0,n._)("span",null,[(0,n.Wm)(u,{keypath:"user.PROFILE.ERRORED_EMAIL_UPDATE"},{default:(0,n.w5)((()=>[(0,n.Wm)(r,{to:"/login"},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.$t("user.LOG_IN")),1)])),_:1})])),_:1})])])])):(0,n.kq)("",!0)}}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-8c2ec9ce"]]);var m=S},6266:function(e,t,r){r.r(t),r.d(t,{default:function(){return d}});var n=r(6252),a=r(2262),s=r(5801),u=r(9917);const o=e=>((0,n.dD)("data-v-05463732"),e=e(),(0,n.Cn)(),e),i={key:0,id:"profile",class:"container view"},c=o((()=>(0,n._)("div",{id:"bottom"},null,-1)));var l=(0,n.aZ)({__name:"ProfileView",setup(e){const t=(0,u.o)(),r=(0,n.Fl)((()=>t.getters[s.YN.GETTERS.AUTH_USER_PROFILE]));return(e,t)=>{const s=(0,n.up)("router-view");return(0,a.SU)(r).username?((0,n.wg)(),(0,n.iD)("div",i,[(0,n.Wm)(s,{user:(0,a.SU)(r)},null,8,["user"]),c])):(0,n.kq)("",!0)}}}),E=r(3744);const _=(0,E.Z)(l,[["__scopeId","data-v-05463732"]]);var d=_},9453:function(e,t,r){r.r(t),r.d(t,{default:function(){return m}});var n=r(6252),a=r(2262),s=r(2201),u=r(2179),o=r(1585),i=r(5801),c=r(9917);const l={key:0,id:"user",class:"view"},E={class:"box"};var _=(0,n.aZ)({__name:"UserView",props:{fromAdmin:{type:Boolean}},setup(e){const t=e,{fromAdmin:r}=(0,a.BK)(t),_=(0,s.yj)(),d=(0,c.o)(),S=(0,n.Fl)((()=>d.getters[i.RT.GETTERS.USER]));return(0,n.wF)((()=>{_.params.username&&"string"===typeof _.params.username&&d.dispatch(i.RT.ACTIONS.GET_USER,_.params.username)})),(0,n.Jd)((()=>{d.dispatch(i.RT.ACTIONS.EMPTY_USER)})),(e,t)=>(0,a.SU)(S).username?((0,n.wg)(),(0,n.iD)("div",l,[(0,n.Wm)(u.Z,{user:(0,a.SU)(S)},null,8,["user"]),(0,n._)("div",E,[(0,n.Wm)(o.Z,{user:(0,a.SU)(S),"from-admin":(0,a.SU)(r)},null,8,["user","from-admin"])])])):(0,n.kq)("",!0)}}),d=r(3744);const S=(0,d.Z)(_,[["__scopeId","data-v-af7007f4"]]);var m=S}}]);
|
||||
//# sourceMappingURL=profile.23749cd8.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[193],{7885:function(e,s,t){t.r(s),t.d(s,{default:function(){return A}});var a=t(6252),r=t(2262),l=t(3577),o=(t(7658),t(9150)),n=t(4998);const c={class:"chart-menu"},i={class:"chart-arrow"},u={class:"time-frames custom-checkboxes-group"},d={class:"time-frames-checkboxes custom-checkboxes"},p=["id","name","checked","onInput"],m={class:"chart-arrow"};var v=(0,a.aZ)({__name:"StatsMenu",emits:["arrowClick","timeFrameUpdate"],setup(e,{emit:s}){const t=(0,r.iH)("month"),o=["week","month","year"];function n(e){t.value=e,s("timeFrameUpdate",e)}return(e,r)=>((0,a.wg)(),(0,a.iD)("div",c,[(0,a._)("div",i,[(0,a._)("i",{class:"fa fa-chevron-left","aria-hidden":"true",onClick:r[0]||(r[0]=e=>s("arrowClick",!0))})]),(0,a._)("div",u,[(0,a._)("div",d,[((0,a.wg)(),(0,a.iD)(a.HY,null,(0,a.Ko)(o,(s=>(0,a._)("div",{class:"time-frame custom-checkbox",key:s},[(0,a._)("label",null,[(0,a._)("input",{type:"radio",id:s,name:s,checked:t.value===s,onInput:e=>n(s)},null,40,p),(0,a._)("span",null,(0,l.zw)(e.$t(`statistics.TIME_FRAMES.${s}`)),1)])]))),64))])]),(0,a._)("div",m,[(0,a._)("i",{class:"fa fa-chevron-right","aria-hidden":"true",onClick:r[1]||(r[1]=e=>s("arrowClick",!1))})])]))}}),k=t(3744);const _=(0,k.Z)(v,[["__scopeId","data-v-22d55de2"]]);var S=_,w=t(631);const f={class:"sports-menu"},h=["id","name","checked","onInput"],U={class:"sport-label"};var b=(0,a.aZ)({__name:"StatsSportsMenu",props:{userSports:null,selectedSportIds:{default:()=>[]}},emits:["selectedSportIdsUpdate"],setup(e,{emit:s}){const t=e,{t:n}=(0,o.QT)(),c=(0,a.f3)("sportColors"),{selectedSportIds:i}=(0,r.BK)(t),u=(0,a.Fl)((()=>(0,w.xH)(t.userSports,n)));function d(e){s("selectedSportIdsUpdate",e)}return(e,s)=>{const t=(0,a.up)("SportImage");return(0,a.wg)(),(0,a.iD)("div",f,[((0,a.wg)(!0),(0,a.iD)(a.HY,null,(0,a.Ko)((0,r.SU)(u),(e=>((0,a.wg)(),(0,a.iD)("label",{type:"checkbox",key:e.id,style:(0,l.j5)({color:e.color?e.color:(0,r.SU)(c)[e.label]})},[(0,a._)("input",{type:"checkbox",id:e.id,name:e.label,checked:(0,r.SU)(i).includes(e.id),onInput:s=>d(e.id)},null,40,h),(0,a.Wm)(t,{"sport-label":e.label,color:e.color},null,8,["sport-label","color"]),(0,a._)("span",U,(0,l.zw)(e.translatedLabel),1)],4)))),128))])}}});const I=b;var g=I,T=t(9318);const y={key:0,id:"user-statistics"};var C=(0,a.aZ)({__name:"index",props:{sports:null,user:null},setup(e){const s=e,{t:t}=(0,o.QT)(),{sports:l,user:c}=(0,r.BK)(s),i=(0,r.iH)("month"),u=(0,r.iH)(v(i.value)),d=(0,a.Fl)((()=>(0,w.xH)(s.sports,t))),p=(0,r.iH)(_(s.sports));function m(e){i.value=e,u.value=v(i.value)}function v(e){return(0,T.aZ)(new Date,e,s.user.weekm)}function k(e){u.value=(0,T.FN)(u.value,e,s.user.weekm)}function _(e){return e.map((e=>e.id))}function f(e){p.value.includes(e)?p.value=p.value.filter((s=>s!==e)):p.value.push(e)}return(0,a.YP)((()=>s.sports),(e=>{p.value=_(e)})),(e,s)=>(0,r.SU)(d)?((0,a.wg)(),(0,a.iD)("div",y,[(0,a.Wm)(S,{onTimeFrameUpdate:m,onArrowClick:k}),(0,a.Wm)(n.Z,{sports:(0,r.SU)(l),user:(0,r.SU)(c),chartParams:u.value,"displayed-sport-ids":p.value,fullStats:!0},null,8,["sports","user","chartParams","displayed-sport-ids"]),(0,a.Wm)(g,{"selected-sport-ids":p.value,"user-sports":(0,r.SU)(l),onSelectedSportIdsUpdate:f},null,8,["selected-sport-ids","user-sports"])])):(0,a.kq)("",!0)}});const F=(0,k.Z)(C,[["__scopeId","data-v-30799d13"]]);var Z=F,x=t(5630),D=t(5801),H=t(9917);const E={id:"statistics",class:"view"},R={key:0,class:"container"};var W=(0,a.aZ)({__name:"StatisticsView",setup(e){const s=(0,H.o)(),t=(0,a.Fl)((()=>s.getters[D.YN.GETTERS.AUTH_USER_PROFILE])),o=(0,a.Fl)((()=>s.getters[D.O8.GETTERS.SPORTS].filter((e=>t.value.sports_list.includes(e.id)))));return(e,s)=>{const n=(0,a.up)("Card");return(0,a.wg)(),(0,a.iD)("div",E,[(0,r.SU)(t).username?((0,a.wg)(),(0,a.iD)("div",R,[(0,a.Wm)(n,null,{title:(0,a.w5)((()=>[(0,a.Uk)((0,l.zw)(e.$t("statistics.STATISTICS")),1)])),content:(0,a.w5)((()=>[(0,a.Wm)(Z,{class:(0,l.C_)({"stats-disabled":0===(0,r.SU)(t).nb_workouts}),user:(0,r.SU)(t),sports:(0,r.SU)(o)},null,8,["class","user","sports"])])),_:1}),0===(0,r.SU)(t).nb_workouts?((0,a.wg)(),(0,a.j4)(x.Z,{key:0})):(0,a.kq)("",!0)])):(0,a.kq)("",!0)])}}});const P=(0,k.Z)(W,[["__scopeId","data-v-2e341d4e"]]);var A=P}}]);
|
||||
//# sourceMappingURL=statistics.9cd652fd.js.map
|
||||
//# sourceMappingURL=statistics.eaf4afd3.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/workouts.f4402b84.js.map
vendored
Normal file
1
fittrackee/dist/static/js/workouts.f4402b84.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,31 @@
|
||||
"""Add date_format for date display to user preferences in DB
|
||||
|
||||
Revision ID: bf13b8f5589d
|
||||
Revises: 84d840ce853b
|
||||
Create Date: 2022-10-25 18:53:59.378423
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'bf13b8f5589d'
|
||||
down_revision = '5b936821326d'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(
|
||||
'users', sa.Column('date_format', sa.String(length=50), nullable=True)
|
||||
)
|
||||
op.execute("UPDATE users SET date_format = 'MM/dd/yyyy'")
|
||||
op.alter_column('users', 'date_format', nullable=False)
|
||||
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('users', 'date_format')
|
||||
# ### end Alembic commands ###
|
@ -235,6 +235,27 @@ class TestUserRegistration(ApiTestCaseMixin):
|
||||
assert data['status'] == 'success'
|
||||
assert 'auth_token' not in data
|
||||
|
||||
def test_it_creates_user_with_default_date_format(
|
||||
self, app: Flask
|
||||
) -> None:
|
||||
client = app.test_client()
|
||||
username = self.random_string()
|
||||
|
||||
client.post(
|
||||
'/api/auth/register',
|
||||
data=json.dumps(
|
||||
dict(
|
||||
username=username,
|
||||
email=self.random_email(),
|
||||
password=self.random_string(),
|
||||
)
|
||||
),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
new_user = User.query.filter_by(username=username).first()
|
||||
assert new_user.date_format == 'MM/dd/yyyy'
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'input_language,expected_language',
|
||||
[('en', 'en'), ('fr', 'fr'), ('invalid', 'en'), (None, 'en')],
|
||||
@ -1394,6 +1415,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
||||
language=input_language,
|
||||
imperial_units=True,
|
||||
display_ascent=False,
|
||||
date_format='yyyy-MM-dd',
|
||||
)
|
||||
),
|
||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||
@ -1407,6 +1429,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
||||
assert data['data']['imperial_units'] is True
|
||||
assert data['data']['language'] == expected_language
|
||||
assert data['data']['timezone'] == 'America/New_York'
|
||||
assert data['data']['date_format'] == 'yyyy-MM-dd'
|
||||
assert data['data']['weekm'] is True
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -173,6 +173,7 @@ def register_user() -> Union[Tuple[Dict, int], HttpResponse]:
|
||||
if not user:
|
||||
new_user = User(username=username, email=email, password=password)
|
||||
new_user.timezone = 'Europe/Paris'
|
||||
new_user.date_format = 'MM/dd/yyyy'
|
||||
new_user.confirmation_token = secrets.token_urlsafe(30)
|
||||
new_user.language = language
|
||||
db.session.add(new_user)
|
||||
@ -780,6 +781,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
"bio": null,
|
||||
"birth_date": null,
|
||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||
"date_format": "MM/dd/yyyy",
|
||||
"display_ascent": true,
|
||||
"email": "sam@example.com",
|
||||
"first_name": null,
|
||||
@ -854,6 +856,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
}
|
||||
|
||||
:<json boolean display_ascent: display highest ascent records and total
|
||||
:<json string date_format: the format used to display dates in the app
|
||||
:<json boolean imperial_units: display distance in imperial units
|
||||
:<json string language: language preferences
|
||||
:<json string timezone: user time zone
|
||||
@ -874,6 +877,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
# get post data
|
||||
post_data = request.get_json()
|
||||
user_mandatory_data = {
|
||||
'date_format',
|
||||
'display_ascent',
|
||||
'imperial_units',
|
||||
'language',
|
||||
@ -883,6 +887,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
if not post_data or not post_data.keys() >= user_mandatory_data:
|
||||
return InvalidPayloadErrorResponse()
|
||||
|
||||
date_format = post_data.get('date_format')
|
||||
display_ascent = post_data.get('display_ascent')
|
||||
imperial_units = post_data.get('imperial_units')
|
||||
language = get_language(post_data.get('language'))
|
||||
@ -890,6 +895,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
weekm = post_data.get('weekm')
|
||||
|
||||
try:
|
||||
auth_user.date_format = date_format
|
||||
auth_user.display_ascent = display_ascent
|
||||
auth_user.imperial_units = imperial_units
|
||||
auth_user.language = language
|
||||
|
@ -33,6 +33,7 @@ class User(BaseModel):
|
||||
bio = db.Column(db.String(200), nullable=True)
|
||||
picture = db.Column(db.String(255), nullable=True)
|
||||
timezone = db.Column(db.String(50), nullable=True)
|
||||
date_format = db.Column(db.String(50), nullable=True)
|
||||
# does the week start Monday?
|
||||
weekm = db.Column(db.Boolean, default=False, nullable=False)
|
||||
workouts = db.relationship(
|
||||
@ -190,6 +191,7 @@ class User(BaseModel):
|
||||
serialized_user = {
|
||||
**serialized_user,
|
||||
**{
|
||||
'date_format': self.date_format,
|
||||
'display_ascent': self.display_ascent,
|
||||
'imperial_units': self.imperial_units,
|
||||
'language': self.language,
|
||||
|
@ -62,9 +62,10 @@
|
||||
{{ $t('user.PROFILE.REGISTRATION_DATE') }}
|
||||
</span>
|
||||
{{
|
||||
format(
|
||||
getDateWithTZ(user.created_at, authUser.timezone),
|
||||
'dd/MM/yyyy HH:mm'
|
||||
formatDate(
|
||||
user.created_at,
|
||||
authUser.timezone,
|
||||
authUser.date_format
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
@ -130,7 +131,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import {
|
||||
ComputedRef,
|
||||
Ref,
|
||||
@ -152,7 +152,7 @@
|
||||
import { IAuthUserProfile, IUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getQuery, sortList } from '@/utils/api'
|
||||
import { getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
const store = useStore()
|
||||
const route = useRoute()
|
||||
|
@ -86,7 +86,7 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
span {
|
||||
padding: 2px 5px;
|
||||
padding: 2px;
|
||||
}
|
||||
.record-type {
|
||||
flex-grow: 1;
|
||||
@ -94,7 +94,12 @@
|
||||
.record-value {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
padding-right: $default-padding * 2;
|
||||
padding-right: $default-padding;
|
||||
}
|
||||
.record-date {
|
||||
white-space: nowrap;
|
||||
min-width: 30%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@
|
||||
translateSports(props.sports, t),
|
||||
props.user.timezone,
|
||||
props.user.imperial_units,
|
||||
props.user.display_ascent
|
||||
props.user.display_ascent,
|
||||
props.user.date_format
|
||||
)
|
||||
)
|
||||
</script>
|
||||
|
@ -130,6 +130,8 @@
|
||||
import { TAppConfig } from '@/types/application'
|
||||
import { IAuthUserProfile, IUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { formatDate, getDateFormat } from '@/utils/dates'
|
||||
import { localeFromLanguage } from '@/utils/locales'
|
||||
|
||||
interface Props {
|
||||
user: IUserProfile
|
||||
@ -142,17 +144,28 @@
|
||||
const store = useStore()
|
||||
|
||||
const { user, fromAdmin } = toRefs(props)
|
||||
const language: ComputedRef<string> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
|
||||
)
|
||||
const authUser: ComputedRef<IAuthUserProfile> = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.AUTH_USER_PROFILE]
|
||||
)
|
||||
const registrationDate = computed(() =>
|
||||
props.user.created_at
|
||||
? format(new Date(props.user.created_at), 'dd/MM/yyyy HH:mm')
|
||||
? formatDate(
|
||||
props.user.created_at,
|
||||
authUser.value.timezone,
|
||||
authUser.value.date_format
|
||||
)
|
||||
: ''
|
||||
)
|
||||
const birthDate = computed(() =>
|
||||
props.user.birth_date
|
||||
? format(new Date(props.user.birth_date), 'dd/MM/yyyy')
|
||||
? format(
|
||||
new Date(props.user.birth_date),
|
||||
`${getDateFormat(authUser.value.date_format, language.value)}`,
|
||||
{ locale: localeFromLanguage[language.value] }
|
||||
)
|
||||
: ''
|
||||
)
|
||||
const isSuccess = computed(
|
||||
|
@ -2,9 +2,11 @@
|
||||
<div id="user-preferences" class="description-list">
|
||||
<dl>
|
||||
<dt>{{ $t('user.PROFILE.LANGUAGE') }}:</dt>
|
||||
<dd>{{ language }}</dd>
|
||||
<dd>{{ userLanguage }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.TIMEZONE') }}:</dt>
|
||||
<dd>{{ timezone }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.DATE_FORMAT') }}:</dt>
|
||||
<dd>{{ getDateFormat(date_format, appLanguage) }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}:</dt>
|
||||
<dd>{{ $t(`user.PROFILE.${fistDayOfWeek}`) }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.UNITS.LABEL') }}:</dt>
|
||||
@ -28,9 +30,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ComputedRef } from 'vue'
|
||||
|
||||
import { ROOT_STORE } from '@/store/constants'
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getDateFormat } from '@/utils/dates'
|
||||
import { languageLabels } from '@/utils/locales'
|
||||
|
||||
interface Props {
|
||||
@ -38,7 +43,12 @@
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const language = computed(() =>
|
||||
const store = useStore()
|
||||
|
||||
const appLanguage: ComputedRef<string> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
|
||||
)
|
||||
const userLanguage = computed(() =>
|
||||
props.user.language
|
||||
? languageLabels[props.user.language]
|
||||
: languageLabels['en']
|
||||
@ -47,6 +57,9 @@
|
||||
const timezone = computed(() =>
|
||||
props.user.timezone ? props.user.timezone : 'Europe/Paris'
|
||||
)
|
||||
const date_format = computed(() =>
|
||||
props.user.date_format ? props.user.date_format : 'MM/dd/yyyy'
|
||||
)
|
||||
const display_ascent = computed(() =>
|
||||
props.user.display_ascent ? 'DISPLAYED' : 'HIDDEN'
|
||||
)
|
||||
|
@ -65,11 +65,12 @@
|
||||
import { ComputedRef, computed, reactive, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { IUserProfile, IUserPayload } from '@/types/user'
|
||||
import { IUserProfile, IUserPayload, IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
interface Props {
|
||||
user: IUserProfile
|
||||
user: IAuthUserProfile
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
@ -84,7 +85,11 @@
|
||||
})
|
||||
const registrationDate = computed(() =>
|
||||
props.user.created_at
|
||||
? format(new Date(props.user.created_at), 'dd/MM/yyyy HH:mm')
|
||||
? formatDate(
|
||||
props.user.created_at,
|
||||
props.user.timezone,
|
||||
props.user.date_format
|
||||
)
|
||||
: ''
|
||||
)
|
||||
const loading = computed(
|
||||
|
@ -23,6 +23,22 @@
|
||||
@updateTimezone="updateTZ"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-items">
|
||||
{{ $t('user.PROFILE.DATE_FORMAT') }}
|
||||
<select
|
||||
id="date_format"
|
||||
v-model="userForm.date_format"
|
||||
:disabled="loading"
|
||||
>
|
||||
<option
|
||||
v-for="dateFormat in dateFormatOptions"
|
||||
:value="dateFormat.value"
|
||||
:key="dateFormat.value"
|
||||
>
|
||||
{{ dateFormat.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="form-items form-checkboxes">
|
||||
<span class="checkboxes-label">
|
||||
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
|
||||
@ -106,6 +122,7 @@
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { availableDateFormatOptions } from '@/utils/dates'
|
||||
import { availableLanguages } from '@/utils/locales'
|
||||
|
||||
interface Props {
|
||||
@ -120,6 +137,7 @@
|
||||
imperial_units: false,
|
||||
language: '',
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'dd/MM/yyyy',
|
||||
weekm: false,
|
||||
})
|
||||
const weekStart = [
|
||||
@ -158,6 +176,13 @@
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
)
|
||||
const dateFormatOptions = computed(() =>
|
||||
availableDateFormatOptions(
|
||||
new Date().toUTCString(),
|
||||
props.user.timezone,
|
||||
userForm.language
|
||||
)
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.user) {
|
||||
@ -170,6 +195,7 @@
|
||||
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
||||
userForm.language = user.language ? user.language : 'en'
|
||||
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
||||
userForm.date_format = user.date_format ? user.date_format : 'dd/MM/yyyy'
|
||||
userForm.weekm = user.weekm ? user.weekm : false
|
||||
}
|
||||
function updateProfile() {
|
||||
|
@ -50,9 +50,10 @@
|
||||
<dt>{{ capitalize($t('oauth2.APP.ISSUE_AT')) }}:</dt>
|
||||
<dd>
|
||||
{{
|
||||
format(
|
||||
getDateWithTZ(client.issued_at, authUser.timezone),
|
||||
'dd/MM/yyyy HH:mm'
|
||||
formatDate(
|
||||
client.issued_at,
|
||||
authUser.timezone,
|
||||
authUser.date_format
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
@ -105,7 +106,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import {
|
||||
ComputedRef,
|
||||
Ref,
|
||||
@ -124,7 +124,7 @@
|
||||
import { IOAuth2Client } from '@/types/oauth'
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
interface Props {
|
||||
authUser: IAuthUserProfile
|
||||
|
@ -9,9 +9,10 @@
|
||||
<span class="app-issued-at">
|
||||
{{ $t('oauth2.APP.ISSUE_AT') }}
|
||||
{{
|
||||
format(
|
||||
getDateWithTZ(client.issued_at, authUser.timezone),
|
||||
'dd/MM/yyyy HH:mm'
|
||||
formatDate(
|
||||
client.issued_at,
|
||||
authUser.timezone,
|
||||
authUser.date_format
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
@ -34,7 +35,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import { ComputedRef, computed, onBeforeMount, toRefs, watch } from 'vue'
|
||||
import { LocationQuery, useRoute } from 'vue-router'
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
import { IAuthUserProfile } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { defaultPage, getNumberQueryValue } from '@/utils/api'
|
||||
import { getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
interface Props {
|
||||
authUser: IAuthUserProfile
|
||||
|
@ -29,10 +29,7 @@
|
||||
class="workout-date"
|
||||
v-if="workout.workout_date && user"
|
||||
:title="
|
||||
format(
|
||||
getDateWithTZ(workout.workout_date, user.timezone),
|
||||
'dd/MM/yyyy HH:mm'
|
||||
)
|
||||
formatDate(workout.workout_date, user.timezone, user.date_format)
|
||||
"
|
||||
>
|
||||
{{
|
||||
@ -141,7 +138,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Locale, format, formatDistance } from 'date-fns'
|
||||
import { Locale, formatDistance } from 'date-fns'
|
||||
import { ComputedRef, computed, toRefs, withDefaults } from 'vue'
|
||||
|
||||
import StaticMap from '@/components/Common/StaticMap.vue'
|
||||
@ -151,7 +148,7 @@
|
||||
import { IUserProfile } from '@/types/user'
|
||||
import { IWorkout } from '@/types/workouts'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
|
||||
interface Props {
|
||||
user: IUserProfile
|
||||
|
@ -131,7 +131,8 @@
|
||||
getDateWithTZ(
|
||||
props.workoutData.workout.workout_date,
|
||||
props.authUser.timezone
|
||||
)
|
||||
),
|
||||
props.authUser.date_format
|
||||
)
|
||||
return {
|
||||
ascent: segment ? segment.ascent : workout.ascent,
|
||||
|
@ -84,9 +84,10 @@
|
||||
{{ $t('workouts.DATE') }}
|
||||
</span>
|
||||
{{
|
||||
format(
|
||||
getDateWithTZ(workout.workout_date, user.timezone),
|
||||
'dd/MM/yyyy HH:mm'
|
||||
formatDate(
|
||||
workout.workout_date,
|
||||
user.timezone,
|
||||
user.date_format
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
@ -162,7 +163,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import {
|
||||
ComputedRef,
|
||||
Ref,
|
||||
@ -186,7 +186,7 @@
|
||||
import { IWorkout, TWorkoutsPayload } from '@/types/workouts'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getQuery, sortList, workoutsPayloadKeys } from '@/utils/api'
|
||||
import { getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
import { getSportColor, getSportLabel } from '@/utils/sports'
|
||||
import { convertDistance } from '@/utils/units'
|
||||
import { defaultOrder } from '@/utils/workouts'
|
||||
|
@ -52,6 +52,7 @@
|
||||
"BACK_TO_PROFILE": "Zurück zum Profil",
|
||||
"BIO": "Biographie",
|
||||
"BIRTH_DATE": "Geburtsdatum",
|
||||
"DATE_FORMAT": "Datumsanzeigeformat",
|
||||
"EDIT": "Profil bearbeiten",
|
||||
"EDIT_PREFERENCES": "Einstellungen ändern",
|
||||
"EDIT_SPORTS_PREFERENCES": "Einstellungen für Sportarten ändern",
|
||||
|
@ -52,6 +52,7 @@
|
||||
"BACK_TO_PROFILE": "Back to profile",
|
||||
"BIO": "Bio",
|
||||
"BIRTH_DATE": "Birth date",
|
||||
"DATE_FORMAT": "Date display format",
|
||||
"EDIT": "Edit profile",
|
||||
"EDIT_PREFERENCES": "Edit preferences",
|
||||
"EDIT_SPORTS_PREFERENCES": "Edit sports preferences",
|
||||
|
@ -52,6 +52,7 @@
|
||||
"BACK_TO_PROFILE": "Revenir au profil",
|
||||
"BIO": "Bio",
|
||||
"BIRTH_DATE": "Date de naissance",
|
||||
"DATE_FORMAT": "Format d'affichage de la date",
|
||||
"EDIT": "Modifier le profil",
|
||||
"EDIT_PREFERENCES": "Modifier les préférences",
|
||||
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
|
||||
|
@ -29,6 +29,7 @@ export interface IAuthUserProfile extends IUserProfile {
|
||||
imperial_units: boolean
|
||||
language: string | null
|
||||
timezone: string
|
||||
date_format: string
|
||||
weekm: boolean
|
||||
}
|
||||
|
||||
@ -64,6 +65,7 @@ export interface IUserPreferencesPayload {
|
||||
imperial_units: boolean
|
||||
language: string
|
||||
timezone: string
|
||||
date_format: string
|
||||
weekm: boolean
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,11 @@ import {
|
||||
} from 'date-fns'
|
||||
import { utcToZonedTime } from 'date-fns-tz'
|
||||
|
||||
import createI18n from '@/i18n'
|
||||
import { localeFromLanguage } from '@/utils/locales'
|
||||
|
||||
const { locale } = createI18n.global
|
||||
|
||||
export const getStartDate = (
|
||||
duration: string,
|
||||
day: Date,
|
||||
@ -70,11 +75,70 @@ export const formatWorkoutDate = (
|
||||
if (!dateFormat) {
|
||||
dateFormat = 'yyyy/MM/dd'
|
||||
}
|
||||
dateFormat = getDateFormat(dateFormat, locale.value)
|
||||
if (!timeFormat) {
|
||||
timeFormat = 'HH:mm'
|
||||
}
|
||||
return {
|
||||
workout_date: format(dateTime, dateFormat),
|
||||
workout_date: format(dateTime, dateFormat, {
|
||||
locale: localeFromLanguage[locale.value],
|
||||
}),
|
||||
workout_time: format(dateTime, timeFormat),
|
||||
}
|
||||
}
|
||||
|
||||
const availableDateFormats = [
|
||||
'MM/dd/yyyy',
|
||||
'dd/MM/yyyy',
|
||||
'yyyy-MM-dd',
|
||||
'date_string',
|
||||
]
|
||||
const dateStringFormats: Record<string, string> = {
|
||||
de: 'do MMM yyyy',
|
||||
en: 'MMM. do, yyyy',
|
||||
fr: 'd MMM yyyy',
|
||||
}
|
||||
|
||||
export const getDateFormat = (dateFormat: string, language: string): string => {
|
||||
return dateFormat === 'date_string' ? dateStringFormats[language] : dateFormat
|
||||
}
|
||||
|
||||
export const formatDate = (
|
||||
dateString: string,
|
||||
timezone: string,
|
||||
dateFormat: string,
|
||||
withTime = true,
|
||||
language: string | null = null
|
||||
): string => {
|
||||
if (!language) {
|
||||
language = locale.value
|
||||
}
|
||||
return format(
|
||||
getDateWithTZ(dateString, timezone),
|
||||
`${getDateFormat(dateFormat, language)}${withTime ? ' HH:mm' : ''}`,
|
||||
{ locale: localeFromLanguage[language] }
|
||||
)
|
||||
}
|
||||
|
||||
export const availableDateFormatOptions = (
|
||||
inputDate: string,
|
||||
timezone: string,
|
||||
language: string | null = null
|
||||
) => {
|
||||
const l: string = language ? language : locale.value
|
||||
const options: Record<string, string>[] = []
|
||||
availableDateFormats.map((df) => {
|
||||
const dateFormat = getDateFormat(df, l)
|
||||
options.push({
|
||||
label: `${dateFormat} - ${formatDate(
|
||||
inputDate,
|
||||
timezone,
|
||||
dateFormat,
|
||||
false,
|
||||
l
|
||||
)}`,
|
||||
value: df,
|
||||
})
|
||||
})
|
||||
return options
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
import createI18n from '@/i18n'
|
||||
import { ITranslatedSport } from '@/types/sports'
|
||||
import { TUnit } from '@/types/units'
|
||||
import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
|
||||
import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates'
|
||||
import { formatDate, getDateFormat } from '@/utils/dates'
|
||||
import { convertDistance, units } from '@/utils/units'
|
||||
|
||||
const { locale } = createI18n.global
|
||||
|
||||
export const formatRecord = (
|
||||
record: IRecord,
|
||||
tz: string,
|
||||
useImperialUnits: boolean
|
||||
useImperialUnits: boolean,
|
||||
date_format: string
|
||||
): Record<string, string | number> => {
|
||||
const distanceUnitFrom: TUnit = 'km'
|
||||
const distanceUnitTo: TUnit = useImperialUnits
|
||||
@ -53,8 +57,7 @@ export const formatRecord = (
|
||||
)
|
||||
}
|
||||
return {
|
||||
workout_date: formatWorkoutDate(getDateWithTZ(record.workout_date, tz))
|
||||
.workout_date,
|
||||
workout_date: formatDate(record.workout_date, tz, date_format, false),
|
||||
workout_id: record.workout_id,
|
||||
id: record.id,
|
||||
record_type: record.record_type,
|
||||
@ -73,9 +76,11 @@ export const getRecordsBySports = (
|
||||
translatedSports: ITranslatedSport[],
|
||||
tz: string,
|
||||
useImperialUnits: boolean,
|
||||
display_ascent: boolean
|
||||
): IRecordsBySports =>
|
||||
records
|
||||
display_ascent: boolean,
|
||||
date_format: string
|
||||
): IRecordsBySports => {
|
||||
date_format = getDateFormat(date_format, locale.value)
|
||||
return records
|
||||
.filter((r) => (display_ascent ? true : r.record_type !== 'HA'))
|
||||
.reduce((sportList: IRecordsBySports, record) => {
|
||||
const sport = translatedSports.find((s) => s.id === record.sport_id)
|
||||
@ -88,8 +93,9 @@ export const getRecordsBySports = (
|
||||
}
|
||||
}
|
||||
sportList[sport.translatedLabel].records.push(
|
||||
formatRecord(record, tz, useImperialUnits)
|
||||
formatRecord(record, tz, useImperialUnits, date_format)
|
||||
)
|
||||
}
|
||||
return sportList
|
||||
}, {})
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ import {
|
||||
incrementDate,
|
||||
getStartDate,
|
||||
formatWorkoutDate,
|
||||
formatDate,
|
||||
availableDateFormatOptions,
|
||||
getDateFormat,
|
||||
} from '@/utils/dates'
|
||||
|
||||
describe('startDate (week starting Sunday)', () => {
|
||||
@ -240,3 +243,158 @@ describe('formatWorkoutDate', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('formatDate', () => {
|
||||
const dateString = 'Tue, 01 Nov 2022 00:00:00 GMT'
|
||||
|
||||
const testsParams = [
|
||||
{
|
||||
description:
|
||||
'format date for "Europe/Paris" timezone and "dd/MM/yyyy" format (with time)',
|
||||
inputParams: {
|
||||
timezone: 'Europe/Paris',
|
||||
dateFormat: 'dd/MM/yyyy',
|
||||
withTime: true,
|
||||
},
|
||||
expectedDate: '01/11/2022 01:00',
|
||||
},
|
||||
{
|
||||
description:
|
||||
'format date for "America/New_York" timezone and "MM/dd/yyyy" format (w/o time)',
|
||||
inputParams: {
|
||||
timezone: 'America/New_York',
|
||||
dateFormat: 'MM/dd/yyyy',
|
||||
withTime: false,
|
||||
},
|
||||
expectedDate: '10/31/2022',
|
||||
},
|
||||
]
|
||||
testsParams.map((testParams) => {
|
||||
it(testParams.description, () => {
|
||||
assert.deepEqual(
|
||||
formatDate(
|
||||
dateString,
|
||||
testParams.inputParams.timezone,
|
||||
testParams.inputParams.dateFormat,
|
||||
testParams.inputParams.withTime
|
||||
),
|
||||
testParams.expectedDate
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('formatDate (w/ default value)', () => {
|
||||
it('format date for "Europe/Paris" timezone and "dd/MM/yyyy" format', () => {
|
||||
assert.deepEqual(
|
||||
formatDate('Tue, 01 Nov 2022 00:00:00 GMT', 'Europe/Paris', 'yyyy-MM-dd'),
|
||||
'2022-11-01 01:00'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getDateFormat', () => {
|
||||
const testsParams = [
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'dd/MM/yyyy',
|
||||
language: 'en',
|
||||
},
|
||||
expectedFormat: 'dd/MM/yyyy',
|
||||
},
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'MM/dd/yyyy',
|
||||
language: 'en',
|
||||
},
|
||||
expectedFormat: 'MM/dd/yyyy',
|
||||
},
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'yyyy-MM-dd',
|
||||
language: 'en',
|
||||
},
|
||||
expectedFormat: 'yyyy-MM-dd',
|
||||
},
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'date_string',
|
||||
language: 'en',
|
||||
},
|
||||
expectedFormat: 'MMM. do, yyyy',
|
||||
},
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'date_string',
|
||||
language: 'fr',
|
||||
},
|
||||
expectedFormat: 'd MMM yyyy',
|
||||
},
|
||||
{
|
||||
inputParams: {
|
||||
dateFormat: 'date_string',
|
||||
language: 'de',
|
||||
},
|
||||
expectedFormat: 'do MMM yyyy',
|
||||
},
|
||||
]
|
||||
testsParams.map((testParams) => {
|
||||
it(`get date format for "${testParams.inputParams.language}" and "${testParams.inputParams.dateFormat}" `, () => {
|
||||
assert.deepEqual(
|
||||
getDateFormat(
|
||||
testParams.inputParams.dateFormat,
|
||||
testParams.inputParams.language
|
||||
),
|
||||
testParams.expectedFormat
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('availableDateFormatOptions', () => {
|
||||
const inputDate = `Sun, 9 Oct 2022 18:18:41 GMT`
|
||||
const inputTimezone = `Europe/Paris`
|
||||
|
||||
const testsParams = [
|
||||
{
|
||||
inputLanguage: 'en',
|
||||
expectedOptions: [
|
||||
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
|
||||
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
|
||||
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
|
||||
{ label: 'MMM. do, yyyy - Oct. 9th, 2022', value: 'date_string' },
|
||||
],
|
||||
},
|
||||
{
|
||||
inputLanguage: 'fr',
|
||||
expectedOptions: [
|
||||
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
|
||||
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
|
||||
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
|
||||
{ label: 'd MMM yyyy - 9 oct. 2022', value: 'date_string' },
|
||||
],
|
||||
},
|
||||
{
|
||||
inputLanguage: 'de',
|
||||
expectedOptions: [
|
||||
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
|
||||
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
|
||||
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
|
||||
{ label: 'do MMM yyyy - 9. Okt. 2022', value: 'date_string' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
testsParams.map((testParams) => {
|
||||
it(`returns available options for ${testParams.inputLanguage} locale`, () => {
|
||||
assert.deepEqual(
|
||||
availableDateFormatOptions(
|
||||
inputDate,
|
||||
inputTimezone,
|
||||
testParams.inputLanguage
|
||||
),
|
||||
testParams.expectedOptions
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -19,6 +19,7 @@ describe('formatRecord', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 9,
|
||||
@ -41,6 +42,7 @@ describe('formatRecord', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/MM/dd'
|
||||
},
|
||||
expected: {
|
||||
id: 10,
|
||||
@ -63,6 +65,7 @@ describe('formatRecord', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/MM/dd'
|
||||
},
|
||||
expected: {
|
||||
id: 11,
|
||||
@ -85,12 +88,13 @@ describe('formatRecord', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'dd/MM/yyyy'
|
||||
},
|
||||
expected: {
|
||||
id: 12,
|
||||
record_type: 'MS',
|
||||
value: '18 km/h',
|
||||
workout_date: '2019/07/08',
|
||||
workout_date: '08/07/2019',
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
},
|
||||
@ -107,12 +111,13 @@ describe('formatRecord', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'MMM. do, yyyy'
|
||||
},
|
||||
expected: {
|
||||
id: 13,
|
||||
record_type: 'HA',
|
||||
value: '100 m',
|
||||
workout_date: '2019/07/07',
|
||||
workout_date: 'Jul. 7th, 2019',
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
},
|
||||
@ -123,7 +128,8 @@ describe('formatRecord', () => {
|
||||
formatRecord(
|
||||
testParams.inputParams.record,
|
||||
testParams.inputParams.timezone,
|
||||
false
|
||||
false,
|
||||
testParams.inputParams.date_format
|
||||
),
|
||||
testParams.expected
|
||||
)
|
||||
@ -146,6 +152,7 @@ describe('formatRecord after conversion', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 9,
|
||||
@ -168,12 +175,13 @@ describe('formatRecord after conversion', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 10,
|
||||
record_type: 'FD',
|
||||
value: '11.185 mi',
|
||||
workout_date: '2019/07/08',
|
||||
workout_date: '2019/08/07',
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
},
|
||||
@ -190,6 +198,7 @@ describe('formatRecord after conversion', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 11,
|
||||
@ -212,12 +221,13 @@ describe('formatRecord after conversion', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 12,
|
||||
record_type: 'MS',
|
||||
value: '11.18 mi/h',
|
||||
workout_date: '2019/07/08',
|
||||
workout_date: '2019/08/07',
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
},
|
||||
@ -234,6 +244,7 @@ describe('formatRecord after conversion', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
timezone: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
id: 13,
|
||||
@ -250,7 +261,8 @@ describe('formatRecord after conversion', () => {
|
||||
formatRecord(
|
||||
testParams.inputParams.record,
|
||||
testParams.inputParams.timezone,
|
||||
true
|
||||
true,
|
||||
testParams.inputParams.date_format
|
||||
),
|
||||
testParams.expected
|
||||
)
|
||||
@ -272,7 +284,8 @@ describe('formatRecord (invalid record type)', () => {
|
||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||
},
|
||||
'Europe/Paris',
|
||||
false
|
||||
false,
|
||||
'yyyy/dd/MM'
|
||||
)
|
||||
).to.throw(
|
||||
'Invalid record type, expected: "AS", "FD", "HA", "LD", "MD", got: "M"'
|
||||
@ -287,6 +300,7 @@ describe('getRecordsBySports', () => {
|
||||
input: {
|
||||
records: [],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {},
|
||||
},
|
||||
@ -305,6 +319,7 @@ describe('getRecordsBySports', () => {
|
||||
},
|
||||
],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
'Cycling (Sport)': {
|
||||
@ -355,6 +370,7 @@ describe('getRecordsBySports', () => {
|
||||
},
|
||||
],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
'Cycling (Sport)': {
|
||||
@ -385,7 +401,7 @@ describe('getRecordsBySports', () => {
|
||||
id: 10,
|
||||
record_type: 'FD',
|
||||
value: '18 km',
|
||||
workout_date: '2019/07/08',
|
||||
workout_date: '2019/08/07',
|
||||
workout_id: 'n6JcLPQt3QtZWFfiSnYm4C',
|
||||
},
|
||||
],
|
||||
@ -401,7 +417,8 @@ describe('getRecordsBySports', () => {
|
||||
translatedSports,
|
||||
testParams.input.tz,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
testParams.input.date_format
|
||||
),
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
@ -418,6 +435,7 @@ describe('getRecordsBySports after conversion', () => {
|
||||
input: {
|
||||
records: [],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {},
|
||||
},
|
||||
@ -436,6 +454,7 @@ describe('getRecordsBySports after conversion', () => {
|
||||
},
|
||||
],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
'Cycling (Sport)': {
|
||||
@ -486,6 +505,7 @@ describe('getRecordsBySports after conversion', () => {
|
||||
},
|
||||
],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
'Cycling (Sport)': {
|
||||
@ -516,7 +536,7 @@ describe('getRecordsBySports after conversion', () => {
|
||||
id: 10,
|
||||
record_type: 'FD',
|
||||
value: '11.185 mi',
|
||||
workout_date: '2019/07/08',
|
||||
workout_date: '2019/08/07',
|
||||
workout_id: 'n6JcLPQt3QtZWFfiSnYm4C',
|
||||
},
|
||||
],
|
||||
@ -532,7 +552,8 @@ describe('getRecordsBySports after conversion', () => {
|
||||
translatedSports,
|
||||
testParams.input.tz,
|
||||
true,
|
||||
true
|
||||
true,
|
||||
testParams.input.date_format
|
||||
),
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
@ -549,6 +570,7 @@ describe('getRecordsBySports with HA record', () => {
|
||||
input: {
|
||||
records: [],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {},
|
||||
},
|
||||
@ -576,6 +598,7 @@ describe('getRecordsBySports with HA record', () => {
|
||||
},
|
||||
],
|
||||
tz: 'Europe/Paris',
|
||||
date_format: 'yyyy/dd/MM'
|
||||
},
|
||||
expected: {
|
||||
'Cycling (Sport)': {
|
||||
@ -602,7 +625,8 @@ describe('getRecordsBySports with HA record', () => {
|
||||
translatedSports,
|
||||
testParams.input.tz,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
testParams.input.date_format
|
||||
),
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
|
Loading…
Reference in New Issue
Block a user