Merge stable version before large change #16
169
frontend/package-lock.json
generated
169
frontend/package-lock.json
generated
@ -4,7 +4,6 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "frontend",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@capacitor/core": "^4.3.0",
|
||||
@ -13,6 +12,7 @@
|
||||
"@capacitor/push-notifications": "^4.1.0",
|
||||
"@formkit/nuxt": "^1.0.0-beta.11-c95e605",
|
||||
"@nuxtjs/robots": "^3.0.0",
|
||||
"@vueuse/components": "^9.12.0",
|
||||
"@vueuse/firebase": "^9.2.0",
|
||||
"@vueuse/shared": "^9.4.0",
|
||||
"firebase": "^9.14.0",
|
||||
@ -24,7 +24,7 @@
|
||||
"@nuxtjs/plausible": "^0.2.0",
|
||||
"@nuxtjs/tailwindcss": "^6.1.3",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@vueuse/nuxt": "^9.6.0",
|
||||
"nuxt": "^3.0.0-rc.14",
|
||||
"nuxt-icon": "^0.1.7"
|
||||
@ -2899,8 +2899,7 @@
|
||||
"node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
|
||||
},
|
||||
"node_modules/@unhead/dom": {
|
||||
"version": "1.0.4",
|
||||
@ -3234,15 +3233,79 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
|
||||
"integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
|
||||
},
|
||||
"node_modules/@vueuse/components": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/components/-/components-9.12.0.tgz",
|
||||
"integrity": "sha512-U468xbr2PISuWepeOU4J8zkVj0aDhiFe230oDhnIm8mHtcS9gM2vSKTB32InxTs6kVma60yAGdqBySkyFNX/+w==",
|
||||
"dependencies": {
|
||||
"@vueuse/core": "9.12.0",
|
||||
"@vueuse/shared": "9.12.0",
|
||||
"vue-demi": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/components/node_modules/@vueuse/shared": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.12.0.tgz",
|
||||
"integrity": "sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==",
|
||||
"dependencies": {
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/components/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"dev": true,
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.12.0.tgz",
|
||||
"integrity": "sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==",
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"@vueuse/metadata": "9.12.0",
|
||||
"@vueuse/shared": "9.12.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core/node_modules/@vueuse/metadata": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.12.0.tgz",
|
||||
"integrity": "sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core/node_modules/@vueuse/shared": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.12.0.tgz",
|
||||
"integrity": "sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==",
|
||||
"dependencies": {
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
@ -3253,7 +3316,6 @@
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
@ -3410,6 +3472,21 @@
|
||||
"node": "^14.16.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/nuxt/node_modules/@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/nuxt/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
@ -15200,8 +15277,7 @@
|
||||
"@types/web-bluetooth": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
|
||||
},
|
||||
"@unhead/dom": {
|
||||
"version": "1.0.4",
|
||||
@ -15494,23 +15570,60 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
|
||||
"integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
|
||||
},
|
||||
"@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"dev": true,
|
||||
"@vueuse/components": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/components/-/components-9.12.0.tgz",
|
||||
"integrity": "sha512-U468xbr2PISuWepeOU4J8zkVj0aDhiFe230oDhnIm8mHtcS9gM2vSKTB32InxTs6kVma60yAGdqBySkyFNX/+w==",
|
||||
"requires": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"@vueuse/core": "9.12.0",
|
||||
"@vueuse/shared": "9.12.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/shared": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.12.0.tgz",
|
||||
"integrity": "sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==",
|
||||
"requires": {
|
||||
"vue-demi": "*"
|
||||
}
|
||||
},
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vueuse/core": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.12.0.tgz",
|
||||
"integrity": "sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==",
|
||||
"requires": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.12.0",
|
||||
"@vueuse/shared": "9.12.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/metadata": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.12.0.tgz",
|
||||
"integrity": "sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ=="
|
||||
},
|
||||
"@vueuse/shared": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.12.0.tgz",
|
||||
"integrity": "sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==",
|
||||
"requires": {
|
||||
"vue-demi": "*"
|
||||
}
|
||||
},
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
@ -15609,6 +15722,18 @@
|
||||
"untyped": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@vueuse/core": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz",
|
||||
"integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/web-bluetooth": "^0.0.16",
|
||||
"@vueuse/metadata": "9.6.0",
|
||||
"@vueuse/shared": "9.6.0",
|
||||
"vue-demi": "*"
|
||||
}
|
||||
},
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
|
@ -12,7 +12,7 @@
|
||||
"@nuxtjs/plausible": "^0.2.0",
|
||||
"@nuxtjs/tailwindcss": "^6.1.3",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@vueuse/nuxt": "^9.6.0",
|
||||
"nuxt": "^3.0.0-rc.14",
|
||||
"nuxt-icon": "^0.1.7"
|
||||
@ -24,6 +24,7 @@
|
||||
"@capacitor/push-notifications": "^4.1.0",
|
||||
"@formkit/nuxt": "^1.0.0-beta.11-c95e605",
|
||||
"@nuxtjs/robots": "^3.0.0",
|
||||
"@vueuse/components": "^9.12.0",
|
||||
"@vueuse/firebase": "^9.2.0",
|
||||
"@vueuse/shared": "^9.4.0",
|
||||
"firebase": "^9.14.0",
|
||||
|
@ -34,11 +34,17 @@
|
||||
<label class="font-bold">Naam Wedstrijd</label>
|
||||
<input v-model="contest.name" required="true" class="input mb-5 " type="text">
|
||||
|
||||
<label class="font-bold">Type Zwembad</label>
|
||||
<select v-model="contest.type" required="true" class="input mb-5 " type="text">
|
||||
<option value="50m">50 Meter</option>
|
||||
<option value="25m">25 Meter</option>
|
||||
</select>
|
||||
|
||||
<label class="font-bold">Datum</label>
|
||||
<input v-model="contest.date" required="true" class="input w-min hover:cursor-pointer pr-0 mb-5 " type="date">
|
||||
|
||||
<label class="font-bold">Onderdelen</label>
|
||||
<div class="flex flex-col gap-y-5">
|
||||
<div class="flex flex-col gap-y-3">
|
||||
<div v-if="competitors" v-for="event in contest.events" class="container p-2">
|
||||
<div @click="event.open = !event.open" class="flex hover:cursor-pointer">
|
||||
<h2 class="font-bold">{{ event.name }}</h2>
|
||||
@ -103,6 +109,7 @@ const modelData = ref({
|
||||
|
||||
const contest = ref({
|
||||
name: '',
|
||||
type: '',
|
||||
date: '',
|
||||
events: {
|
||||
obstacleSwim: {
|
||||
@ -129,6 +136,12 @@ const contest = ref({
|
||||
id: 'manikinCarryWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
manikinTowWithFins: {
|
||||
open: false,
|
||||
name: '100m Manikin Tow with Fins',
|
||||
id: 'manikinTowWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
superLifesaver: {
|
||||
open: false,
|
||||
name: '200m Super Lifesaver',
|
||||
@ -192,7 +205,7 @@ const submitContestForm = async () => {
|
||||
const docRef = doc(collection(db, 'timings'))
|
||||
batch.set(docRef, {
|
||||
relatiecode: competitor.relatiecode,
|
||||
contest: { name: contest.value.name, date: contest.value.date.toString() },
|
||||
contest: { name: contest.value.name, date: contest.value.date.toString(), type: contest.value.type },
|
||||
event: event.id,
|
||||
time: { minutes: competitor.time.minutes.toString().padStart(2, '0'), seconds: competitor.time.seconds.toString().padStart(2, '0'), milliseconds: competitor.time.milliseconds.toString().padStart(2, '0'), combined: combinedTime },
|
||||
dsq: competitor.dsq,
|
||||
|
229
frontend/pages/wedstrijd/alltimes.vue
Normal file
229
frontend/pages/wedstrijd/alltimes.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<div @click.self="showModel = false" v-if="showModel" class="fixed flex justify-center items-center h-screen w-full bg-black top-0 left-0 z-50 bg-opacity-50" >
|
||||
<form @submit.prevent="submitModalForm" class="dark:bg-neutral-800 bg-neutral-200 p-10 rounded-xl flex flex-col w-full max-w-sm">
|
||||
<h1 class="font-bold text-center text-lg mb-5">Tijd {{ modelData.eventName }}</h1>
|
||||
|
||||
<label class="font-bold">Westrijd</label>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.contest.name" type="text" class="input dark:bg-neutral-700 bg-neutral-300 mb-5" />
|
||||
|
||||
<label class="font-bold">Type zwembad</label>
|
||||
<select :disabled="!userData.wedstrijdAdmin" v-model="modelData.contest.type" required="true" class="input dark:bg-neutral-700 bg-neutral-300 mb-5" type="text">
|
||||
<option value="50m">50 Meter</option>
|
||||
<option value="25m">25 Meter</option>
|
||||
</select>
|
||||
|
||||
<label class="font-bold">Tijd</label>
|
||||
<div class="mb-1">
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.minutes" type="number" step="1" min="0" max="99" placeholder="mm" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
<span class="text-default text-xl font-bold mx-1">:</span>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.seconds" type="number" step="1" min="0" max="99" placeholder="ss" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
<span class="text-default text-xl font-bold mx-1">:</span>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.milliseconds" type="number" step="1" min="0" max="99" placeholder="ms" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mb-5">
|
||||
<input :disabled="!userData.wedstrijdAdmin" type="checkbox" v-model="modelData.dsq" class="mr-1 checkbox">
|
||||
<span class="text-default">Diskwalificatie</span>
|
||||
</div>
|
||||
|
||||
<label class="font-bold">Info </label>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.info" type="text" placeholder="Bijv. Een diskwalificatie" class="input dark:bg-neutral-700 bg-neutral-300 mb-10" />
|
||||
|
||||
<input v-if="userData.wedstrijdAdmin" :disabled="disableButtons" type="submit" class="btn" value="Bewerken" />
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="timings[0]" class="flex flex-col justify-center items-center gap-y-3 px-2 overflow-hidden">
|
||||
<div class="relative">
|
||||
<button @click.stop="showDropdown = !showDropdown" class="btn">Deelnemers <Icon size="1.2em" name="ion:arrow-down-b" /></button>
|
||||
<div v-if="showDropdown" v-on-click-outside.bubble="handleDropdown" class="w-48 mt-2 bg-neutral-800 absolute rounded-lg shadow p-3">
|
||||
<ul class="space-y-2 text-default">
|
||||
<li v-for="competitor in competitors" @click="competitor.checked = !competitor.checked" class="flex gap-x-1 items-center hover:cursor-pointer">
|
||||
<input v-model="competitor.checked" type="checkbox" class="checkbox">
|
||||
<label class="hover:cursor-pointer">{{ competitor.name }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="event in events" class="container w-full max-w-md py-2 px-4">
|
||||
<div @click="event.open = !event.open" class="flex hover:cursor-pointer">
|
||||
<h2 class="font-bold">{{ event.name }}</h2>
|
||||
<span v-if="filteredTimings.filter(a => a.event === event.id).length > 0" class="ml-auto">{{ filteredTimings.filter(a => a.event === event.id)[0].time.minutes }}:{{ timings.filter(a => a.event === event.id)[0].time.seconds }}:{{ timings.filter(a => a.event === event.id)[0].time.milliseconds }}</span>
|
||||
<span v-else class="ml-auto">Geen tijd</span>
|
||||
<Icon size="1.2em" name="ion:arrow-down-b" class="my-auto ml-2 transition-all" :class="{'rotate-180' : event.open }" />
|
||||
</div>
|
||||
<div v-if="event.open" class="mt-2">
|
||||
<table class="table-fixed text-left w-full even:bg-gray-500">
|
||||
<thead class="font-bold">
|
||||
<tr>
|
||||
<th class="w-3/7">Tijd</th>
|
||||
<th class="w-1/7">Datum</th>
|
||||
<th class="w-3/7">Wie</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr @click="handleModel(time, event, index)" v-for="(time, index) in filteredTimings.filter(a => a.event === event.id)" class="even:dark:bg-neutral-700 even:bg-neutral-300 hover:cursor-pointer">
|
||||
<td class="pl-1" :class="time.dsq ? 'line-through' : ''">{{ time.time.minutes }}:{{ time.time.seconds }}:{{ time.time.milliseconds}}</td>
|
||||
<td>{{ time.contest.date }}</td>
|
||||
<td class="overflow-hidden whitespace-nowrap truncate">{{ competitors.filter(a => a.relatiecode === time.relatiecode)[0].name.split(', ')[1] + ' ' + competitors.filter(a => a.relatiecode === time.relatiecode)[0].name.split(', ')[0] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { collection, query, where, getDocs, doc, updateDoc} from "firebase/firestore";
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { vOnClickOutside} from '@vueuse/components'
|
||||
|
||||
definePageMeta({
|
||||
title: 'Eigen Tijden',
|
||||
key: 'back'
|
||||
})
|
||||
|
||||
const { db, userData, competitors } = inject('firebase')
|
||||
const toast = useToast()
|
||||
|
||||
const timings = ref([])
|
||||
const showModel = ref(false)
|
||||
const disableButtons = ref(false)
|
||||
const showDropdown = ref(false)
|
||||
|
||||
const handleDropdown = (x) => {
|
||||
showDropdown.value = false
|
||||
}
|
||||
|
||||
const filteredTimings = computed(() => {
|
||||
return timings.value.filter(a => competitors.value.filter(b => b.checked === true).map(x => x.relatiecode).includes(a.relatiecode))
|
||||
})
|
||||
|
||||
const modelData = ref({
|
||||
time: {
|
||||
minutes: null,
|
||||
seconds: null,
|
||||
milliseconds: null,
|
||||
},
|
||||
dsq: false,
|
||||
info: '',
|
||||
contest: {
|
||||
type: '',
|
||||
name: '',
|
||||
date: '',
|
||||
}
|
||||
})
|
||||
|
||||
const events = ref({
|
||||
obstacleSwim: {
|
||||
open: false,
|
||||
name: '200m Obstacle Swim',
|
||||
id: 'obstacleSwim',
|
||||
competitors: [],
|
||||
},
|
||||
manikinCarry: {
|
||||
open: false,
|
||||
name: '50m Manikin Carry',
|
||||
id: 'manikinCarry',
|
||||
competitors: [],
|
||||
},
|
||||
rescueMedley: {
|
||||
open: false,
|
||||
name: '100m Rescue Medley',
|
||||
id: 'rescueMedley',
|
||||
competitors: [],
|
||||
},
|
||||
manikinCarryWithFins: {
|
||||
open: false,
|
||||
name: '100m Manikin Carry with Fins',
|
||||
id: 'manikinCarryWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
manikinTowWithFins: {
|
||||
open: false,
|
||||
name: '100m Manikin Tow with Fins',
|
||||
id: 'manikinTowWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
superLifesaver: {
|
||||
open: false,
|
||||
name: '200m Super Lifesaver',
|
||||
id: 'superLifesaver',
|
||||
competitors: [],
|
||||
},
|
||||
})
|
||||
|
||||
const getCompetitors = async () => {
|
||||
if (competitors.value[0]) return
|
||||
const querySnapshot = await getDocs(collection(db, "competitors"))
|
||||
querySnapshot.forEach((doc) => {
|
||||
const data = doc.data()
|
||||
data.checked = true
|
||||
competitors.value.push(data)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const citiesRef = collection(db, "timings");
|
||||
|
||||
const q = query(citiesRef);
|
||||
|
||||
const querySnapshot = await getDocs(q);
|
||||
|
||||
querySnapshot.forEach((doc) => {
|
||||
// doc.data() is never undefined for query doc snapshots
|
||||
const data = doc.data()
|
||||
data.id = doc.id
|
||||
|
||||
timings.value.push(data)
|
||||
});
|
||||
|
||||
timings.value = timings.value.sort((a, b) => a.time.combined.localeCompare(b.time.combined))
|
||||
getCompetitors()
|
||||
})
|
||||
|
||||
|
||||
const handleModel = (competitor, e, index) => {
|
||||
modelData.value = competitor
|
||||
modelData.value.index = index
|
||||
modelData.value.eventId = e.id
|
||||
showModel.value = true
|
||||
}
|
||||
|
||||
const submitModalForm = async () => {
|
||||
if (!modelData.value.time.minutes) modelData.value.time.minutes = 0
|
||||
if (!modelData.value.time.seconds) modelData.value.time.seconds = 0
|
||||
if (!modelData.value.time.milliseconds) modelData.value.time.milliseconds = 0
|
||||
const id = modelData.value.id
|
||||
|
||||
delete modelData.value.index
|
||||
delete modelData.value.eventId
|
||||
delete modelData.value.id
|
||||
|
||||
disableButtons.value = true
|
||||
const combinedTime = modelData.value.time.minutes.toString().padStart(2, '0') + modelData.value.time.seconds.toString().padStart(2, '0') + modelData.value.time.milliseconds.toString().padStart(2, '0')
|
||||
modelData.value.time.combinedTime = combinedTime
|
||||
|
||||
const docRef = doc(db, "timings", id);
|
||||
|
||||
console.log(modelData.value)
|
||||
await updateDoc(docRef, modelData.value);
|
||||
|
||||
toast.success('Tijd is bewerkt')
|
||||
showModel.value = false
|
||||
disableButtons.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
</style>
|
@ -6,7 +6,7 @@
|
||||
<Icon class="ml-auto" size="2em" name="ion:arrow-forward"/>
|
||||
</NuxtLink>
|
||||
<div class="divider" />
|
||||
<NuxtLink to="/calendar" class="item-hover py-2 flex items-center">
|
||||
<NuxtLink to="/wedstrijd/alltimes" class="item-hover py-2 flex items-center">
|
||||
<span>Brigade Tijden</span>
|
||||
<Icon class="ml-auto" size="2em" name="ion:arrow-forward"/>
|
||||
</NuxtLink>
|
||||
|
@ -1,5 +1,38 @@
|
||||
<template>
|
||||
<div v-if="timings[0]" class="flex flex-col justify-center items-center gap-y-5 px-2 overflow-hidden">
|
||||
<div @click.self="showModel = false" v-if="showModel" class="fixed flex justify-center items-center h-screen w-full bg-black top-0 left-0 z-50 bg-opacity-50" >
|
||||
<form @submit.prevent="submitModalForm" class="dark:bg-neutral-800 bg-neutral-200 p-10 rounded-xl flex flex-col w-full max-w-sm">
|
||||
<h1 class="font-bold text-center text-lg mb-5">Tijd {{ modelData.eventName }}</h1>
|
||||
|
||||
<label class="font-bold">Westrijd</label>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.contest.name" type="text" class="input dark:bg-neutral-700 bg-neutral-300 mb-5" />
|
||||
|
||||
<label class="font-bold">Type zwembad</label>
|
||||
<select :disabled="!userData.wedstrijdAdmin" v-model="modelData.contest.type" required="true" class="input dark:bg-neutral-700 bg-neutral-300 mb-5" type="text">
|
||||
<option value="50m">50 Meter</option>
|
||||
<option value="25m">25 Meter</option>
|
||||
</select>
|
||||
|
||||
<label class="font-bold">Tijd</label>
|
||||
<div class="mb-1">
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.minutes" type="number" step="1" min="0" max="99" placeholder="mm" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
<span class="text-default text-xl font-bold mx-1">:</span>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.seconds" type="number" step="1" min="0" max="99" placeholder="ss" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
<span class="text-default text-xl font-bold mx-1">:</span>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.time.milliseconds" type="number" step="1" min="0" max="99" placeholder="ms" class="input dark:bg-neutral-700 bg-neutral-300 w-10 text-center p-1" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center mb-5">
|
||||
<input :disabled="!userData.wedstrijdAdmin" type="checkbox" v-model="modelData.dsq" class="mr-1 checkbox">
|
||||
<span class="text-default">Diskwalificatie</span>
|
||||
</div>
|
||||
|
||||
<label class="font-bold">Info </label>
|
||||
<input :disabled="!userData.wedstrijdAdmin" v-model="modelData.info" type="text" placeholder="Bijv. Een diskwalificatie" class="input dark:bg-neutral-700 bg-neutral-300 mb-10" />
|
||||
|
||||
<input v-if="userData.wedstrijdAdmin" :disabled="disableButtons" type="submit" class="btn" value="Bewerken" />
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="timings[0]" class="flex flex-col justify-center items-center gap-y-3 px-2 overflow-hidden">
|
||||
<div v-for="event in events" class="container w-full max-w-md py-2 px-4">
|
||||
<div @click="event.open = !event.open" class="flex hover:cursor-pointer">
|
||||
<h2 class="font-bold">{{ event.name }}</h2>
|
||||
@ -12,15 +45,15 @@
|
||||
<thead class="font-bold">
|
||||
<tr>
|
||||
<th class="w-3/7">Tijd</th>
|
||||
<th class="w-1/7">DSQ</th>
|
||||
<th class="w-3/7">Datum</th>
|
||||
<th class="w-1/7">Datum</th>
|
||||
<th class="w-3/7">Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="time in timings.filter(a => a.event === event.id)" class="even:dark:bg-neutral-700 even:bg-neutral-300 hover:cursor-pointer">
|
||||
<td class="pl-1">{{ time.time.minutes }}:{{ time.time.seconds }}:{{ time.time.milliseconds}}</td>
|
||||
<td>{{ time.dsq}}</td>
|
||||
<tr @click="handleModel(time, event, index)" v-for="(time, index) in timings.filter(a => a.event === event.id)" class="even:dark:bg-neutral-700 even:bg-neutral-300 hover:cursor-pointer">
|
||||
<td class="pl-1" :class="{ 'strikethrough' : time.dsq }">{{ time.time.minutes }}:{{ time.time.seconds }}:{{ time.time.milliseconds}}</td>
|
||||
<td>{{ time.contest.date }}</td>
|
||||
<td>{{ time.contest.type }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -30,7 +63,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { collection, query, where, getDocs } from "firebase/firestore";
|
||||
import { collection, query, where, getDocs, doc, updateDoc} from "firebase/firestore";
|
||||
import { useToast } from 'vue-toastification'
|
||||
|
||||
definePageMeta({
|
||||
title: 'Eigen Tijden',
|
||||
@ -38,8 +72,27 @@ definePageMeta({
|
||||
})
|
||||
|
||||
const { db, userData } = inject('firebase')
|
||||
const toast = useToast()
|
||||
|
||||
const timings = ref([])
|
||||
const showModel = ref(false)
|
||||
const disableButtons = ref(false)
|
||||
|
||||
const modelData = ref({
|
||||
time: {
|
||||
minutes: null,
|
||||
seconds: null,
|
||||
milliseconds: null,
|
||||
},
|
||||
dsq: false,
|
||||
info: '',
|
||||
contest: {
|
||||
type: '',
|
||||
name: '',
|
||||
date: '',
|
||||
}
|
||||
})
|
||||
|
||||
const events = ref({
|
||||
obstacleSwim: {
|
||||
open: false,
|
||||
@ -65,6 +118,12 @@ const events = ref({
|
||||
id: 'manikinCarryWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
manikinTowWithFins: {
|
||||
open: false,
|
||||
name: '100m Manikin Tow with Fins',
|
||||
id: 'manikinTowWithFins',
|
||||
competitors: [],
|
||||
},
|
||||
superLifesaver: {
|
||||
open: false,
|
||||
name: '200m Super Lifesaver',
|
||||
@ -82,9 +141,57 @@ onMounted(async () => {
|
||||
|
||||
querySnapshot.forEach((doc) => {
|
||||
// doc.data() is never undefined for query doc snapshots
|
||||
timings.value.push(doc.data())
|
||||
const data = doc.data()
|
||||
data.id = doc.id
|
||||
|
||||
timings.value.push(data)
|
||||
});
|
||||
|
||||
timings.value = timings.value.sort((a, b) => a.time.combined.localeCompare(b.time.combined))
|
||||
})
|
||||
|
||||
|
||||
const handleModel = (competitor, e, index) => {
|
||||
modelData.value = competitor
|
||||
modelData.value.index = index
|
||||
modelData.value.eventId = e.id
|
||||
showModel.value = true
|
||||
}
|
||||
|
||||
const submitModalForm = async () => {
|
||||
if (!modelData.value.time.minutes) modelData.value.time.minutes = 0
|
||||
if (!modelData.value.time.seconds) modelData.value.time.seconds = 0
|
||||
if (!modelData.value.time.milliseconds) modelData.value.time.milliseconds = 0
|
||||
const id = modelData.value.id
|
||||
|
||||
delete modelData.value.index
|
||||
delete modelData.value.eventId
|
||||
delete modelData.value.id
|
||||
|
||||
disableButtons.value = true
|
||||
const combinedTime = modelData.value.time.minutes.toString().padStart(2, '0') + modelData.value.time.seconds.toString().padStart(2, '0') + modelData.value.time.milliseconds.toString().padStart(2, '0')
|
||||
modelData.value.time.combinedTime = combinedTime
|
||||
|
||||
const docRef = doc(db, "timings", id);
|
||||
|
||||
console.log(modelData.value)
|
||||
await updateDoc(docRef, modelData.value);
|
||||
|
||||
toast.success('Tijd is bewerkt')
|
||||
showModel.value = false
|
||||
disableButtons.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user