Merge stable version before large change #16
@ -34,4 +34,4 @@
|
|||||||
.text-default {
|
.text-default {
|
||||||
@apply dark:text-gray-300 text-gray-900
|
@apply dark:text-gray-300 text-gray-900
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,123 +1,138 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-5 mx-auto p-2 w-full max-w-md">
|
<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 v-if="!newEvent" @submit.prevent="saveEmail" class="flex flex-col">
|
<form @submit.prevent="submitModelForm" class="dark:bg-neutral-800 bg-neutral-200 p-10 rounded-xl flex flex-col w-full max-w-sm">
|
||||||
<label class="font-bold">Naam Wedstrijd</label>
|
<h1 class="font-bold text-center text-lg mb-5">Deelnemer Toevoegen</h1>
|
||||||
<input v-model="contest.name" required="true" class="input mb-5 " type="text">
|
|
||||||
|
<label class="font-bold text-default">Deelnemer</label>
|
||||||
|
<select :disabled="modelData.edit" required v-model="modelData.relatiecode" class="input dark:bg-neutral-700 bg-neutral-300 mb-5">
|
||||||
|
<option v-if="!modelData.edit" v-for="user in competitors.filter(x => !contest.events[modelData.event].competitors.map(y => y.relatiecode).includes(x.relatiecode))" :value="user.relatiecode">{{ user.name}} ({{ user.relatiecode }})</option>
|
||||||
|
<option v-else v-for="user in competitors" :value="user.relatiecode">{{ user.name}} ({{ user.relatiecode }})</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<label class="font-bold">Datum</label>
|
<label class="font-bold text-default">Tijd</label>
|
||||||
<input v-model="contest.date" required="true" class="input w-min hover:cursor-pointer pr-0 mb-5 " type="date">
|
<div class="mb-1">
|
||||||
|
<input 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 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 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 type="checkbox" v-model="modelData.dsq" class="mr-1 checkbox">
|
||||||
|
<span class="text-default">Diskwalificatie</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label class="font-bold">Onderdelen</label>
|
<label class="font-bold">Info (Optioneel)</label>
|
||||||
<button @click="newEvent = true" class="item-hover border-dashed border-2 container text-center font-bold border-neutral-500 mb-3">Onderdeel Toevoegen</button>
|
<input v-model="modelData.info" type="text" placeholder="Bijv. Een diskwalificatie" class="input dark:bg-neutral-700 bg-neutral-300 mb-10" />
|
||||||
<div class="flex flex-col gap-y-5 mb-5">
|
|
||||||
<div v-for="(event, index) in contest.events" :key="index" class="container p-2 flex flex-col gap-y-3">
|
|
||||||
<h2 class="text-center text-primary font-bold text-lg">{{ event.type }}</h2>
|
|
||||||
<table class="table-fixed text-left odd:bg-blue-500">
|
|
||||||
<thead class="font-bold">
|
|
||||||
<tr>
|
|
||||||
<th class="w-3/6">Naam</th>
|
|
||||||
<th class="w-2/6">Tijd</th>
|
|
||||||
<th class="w-1/6">DSQ</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="competitor in event.competitors" class="even:dark:bg-neutral-700 even:bg-neutral-300">
|
|
||||||
<td>{{ competitors.find(x => x.relatiecode === competitor.relatiecode ).name }}</td>
|
|
||||||
<td>{{ competitor.time.minute}}:{{ competitor.time.seconds }}:{{ competitor.time.milliseconds }}</td>
|
|
||||||
<td>{{ competitor.dsq }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full flex flex-wrap justify-between">
|
<input type="submit" class="btn" :value="modelData.edit ? 'Bewerken' : 'Toevoegen'" />
|
||||||
<input :disabled="disableButtons" type="submit" value="Wedstrijd Toevoegen" class="btn w-full sm:w-48 mb-1">
|
</form>
|
||||||
<button @click="resetContest" class="hover:underline font-bold w-full sm:w-max sm:ml-auto">Reset</button>
|
</div>
|
||||||
</div>
|
<div class="flex flex-col gap-5 mx-auto p-2 w-full max-w-md">
|
||||||
</form>
|
<form @submit.prevent="submitContestForm" class="flex flex-col">
|
||||||
<form v-else @submit.prevent="addEvent" class="flex flex-col">
|
<label class="font-bold">Naam Wedstrijd</label>
|
||||||
<label class="font-bold">Onderdeel</label>
|
<input v-model="contest.name" required="true" class="input mb-5 " type="text">
|
||||||
<select v-model="tempEvent.type" class="input mb-5">
|
|
||||||
<option value="200m-Obstacle-Swim">200m Obstacle Swim (Hindernis)</option>
|
|
||||||
<option value="50m-Manikin-Carry">50m Manikin Carry (Popvervoeren)</option>
|
|
||||||
<option value="100m-Rescue-Medley">100m Rescue Medley (Reddingswissel)</option>
|
|
||||||
<option value="100m-Manikin-Carry-with-Fins">100m Manikin Carry with Fins (Popvervoeren met finnen)</option>
|
|
||||||
<option value="100m-Manikin-Tow-with-Fins">100m Manikin Tow with Fins (Lifesaver)</option>
|
|
||||||
<option value="200m-Super-Lifesaver">200m Super Lifesaver</option>
|
|
||||||
<option value="Line-Throw">Line Throw</option>
|
|
||||||
<option value="4x25m-Manikin-Relay">4x25m Manikin Relay (Popvervoeren)</option>
|
|
||||||
<option value="4x50m-Obstacle-Relay">4x50m Obstacle Relay (Hindernis)</option>
|
|
||||||
<option value="4x50m-Medley-Relay">4x50m Medley Relay (Torpedoboei)</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="font-bold">Deelnemers</label>
|
<label class="font-bold">Datum</label>
|
||||||
<button @click="tempEvent.competitors.unshift({ relatiecode: '', dsq: false, info: '', time: { minute: null, seconds: null, milliseconds: null }})" type="button" class="item-hover border-dashed border-2 container text-center font-bold border-neutral-500 mb-3">Deelnemer Toevoegen</button>
|
<input v-model="contest.date" required="true" class="input w-min hover:cursor-pointer pr-0 mb-5 " type="date">
|
||||||
<div class="flex flex-col gap-y-3 mb-5">
|
|
||||||
<div v-for="(competitor, index) in tempEvent.competitors" :key="index">
|
|
||||||
<div class="container flex flex-col p-4">
|
|
||||||
<label class="font-bold">Deelnemer</label>
|
|
||||||
<select v-model="competitor.relatiecode" class="input dark:bg-neutral-700 bg-neutral-300 mb-5">
|
|
||||||
<option v-for="user in competitors" :value="user.relatiecode">{{ user.name}} ({{ user.relatiecode }})</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="font-bold">Tijd</label>
|
<label class="font-bold">Onderdelen</label>
|
||||||
<div class="flex dark:bg-neutral-700 bg-neutral-300 gap-x-2 w-min rounded mb-2">
|
<div class="flex flex-col gap-y-5">
|
||||||
<select v-model="competitor.time.minute" class="input pl-3 pr-8 bg-opacity-0 shadow-none ">
|
<div v-if="competitors" v-for="event in contest.events" class="container p-2">
|
||||||
<option value="null" disabled selected>mm</option>
|
<div @click="event.open = !event.open" class="flex hover:cursor-pointer">
|
||||||
<option v-for="n in 60" :value="n < 11 ? `0${n-1}` : `${n-1}`">{{ n < 11 ? `0${n-1}` : `${n-1}` }}</option>
|
<h2 class="font-bold">{{ event.name }}</h2>
|
||||||
</select>
|
<Icon size="1.2em" name="ion:arrow-down-b" class="ml-auto my-auto mr-2 transition-all" :class="{'rotate-180' : event.open }" />
|
||||||
<span class="my-auto text-xl">:</span>
|
</div>
|
||||||
<select v-model="competitor.time.seconds" class="input pl-2 pr-8 bg-opacity-0 shadow-none ">
|
<div v-if="event.open" class="mt-2">
|
||||||
<option value="null" disabled selected>ss</option>
|
<table class="table-fixed text-left w-full even:bg-gray-500">
|
||||||
<option v-for="n in 60" :value="n < 11 ? `0${n-1}` : `${n-1}`">{{ n < 11 ? `0${n-1}` : `${n-1}`}}</option>
|
<thead class="font-bold">
|
||||||
</select>
|
<tr>
|
||||||
<span class="my-auto text-xl">:</span>
|
<th class="w-3/6">Naam</th>
|
||||||
<select v-model="competitor.time.milliseconds" class="input pl-2 pr-8 bg-opacity-0 shadow-none ">
|
<th class="w-2/6">Tijd</th>
|
||||||
<option value="null" disabled selected>ms</option>
|
<th class="w-1/6">DSQ</th>
|
||||||
<option v-for="n in 100" :value="n < 11 ? `0${n-1}` : `${n-1}`">{{ n < 11 ? `0${n-1}` : `${n-1}` }}</option>
|
</tr>
|
||||||
</select>
|
</thead>
|
||||||
</div>
|
<tbody>
|
||||||
<div class="flex items-center mb-5">
|
<tr @click="handleModel(competitor, event.id, true, index)" v-for="(competitor, index) in event.competitors" class="even:dark:bg-neutral-700 even:bg-neutral-300 hover:cursor-pointer">
|
||||||
<input type="checkbox" v-model="competitor.dsq" class="mr-1 checkbox">
|
<td class="py-1 pl-1">{{ competitors.find(x => x.relatiecode === competitor.relatiecode ).name }}</td>
|
||||||
<span>Diskwalificatie</span>
|
<td>{{ competitor.time.minutes.toString().padStart(2, '0') }}:{{ competitor.time.seconds.toString().padStart(2, '0') }}:{{ competitor.time.milliseconds.toString().padStart(2, '0') }}</td>
|
||||||
</div>
|
<td>{{ competitor.dsq }}</td>
|
||||||
|
</tr>
|
||||||
<label class="font-bold">Info (Optioneel)</label>
|
<tr v-if="competitors.filter(x => !event.competitors.map(y => y.relatiecode).includes(x.relatiecode)).length > 0" class="even:dark:bg-neutral-700 even:bg-neutral-300">
|
||||||
<input v-model="competitor.info" type="text" placeholder="Bijv. Een diskwalificatie" class="input dark:bg-neutral-700 bg-neutral-300" />
|
<td @click="handleModel(null, event.id)" class="hover:cursor-pointer py-1 pl-1">+ Deelnemer toevoegen</td>
|
||||||
</div>
|
<td></td>
|
||||||
</div>
|
<td></td>
|
||||||
</div>
|
</tr>
|
||||||
<div class="w-full flex flex-wrap justify-between">
|
</tbody>
|
||||||
<input :disabled="disableButtons" type="submit" value="Onderdeel Toevoegen" class="btn w-full sm:w-48 mb-1">
|
</table>
|
||||||
<button @click="backEvent" class="hover:underline font-bold w-full sm:w-max sm:ml-auto">Cancel</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
<input type="submit" class="btn mt-10 px-5 w-min mx-auto" value="Wedstrijd toevoegen" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<span class="whitespace-pre">{{ contest }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getDocs, collection } from "firebase/firestore"
|
import { getDocs, collection, writeBatch, doc } from "firebase/firestore"
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: 'Wedstrijd Toevoegen'
|
title: 'Wedstrijd Toevoegen',
|
||||||
|
key: 'back'
|
||||||
})
|
})
|
||||||
|
|
||||||
const { userData, db, competitors } = inject('firebase')
|
const { userData, db, competitors } = inject('firebase')
|
||||||
|
|
||||||
const disableButtons = ref(false)
|
const showModel = ref(false)
|
||||||
const router = useRouter()
|
|
||||||
const newEvent = ref(false)
|
const modelData = ref({
|
||||||
|
relatiecode: '',
|
||||||
|
time: {
|
||||||
|
minutes: null,
|
||||||
|
seconds: null,
|
||||||
|
milliseconds: null,
|
||||||
|
},
|
||||||
|
dsq: false,
|
||||||
|
info: '',
|
||||||
|
})
|
||||||
|
|
||||||
const contest = ref({
|
const contest = ref({
|
||||||
name: '',
|
name: '',
|
||||||
date: null,
|
date: '',
|
||||||
events: [],
|
events: {
|
||||||
})
|
obstacleSwim: {
|
||||||
|
open: false,
|
||||||
const tempEvent = ref({
|
name: '200m Obstacle Swim',
|
||||||
type: '',
|
id: 'obstacleSwim',
|
||||||
competitors: []
|
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: [],
|
||||||
|
},
|
||||||
|
superLifesaver: {
|
||||||
|
open: false,
|
||||||
|
name: '200m Super Lifesaver',
|
||||||
|
id: 'superLifesaver',
|
||||||
|
competitors: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const getCompetitors = async () => {
|
const getCompetitors = async () => {
|
||||||
@ -128,18 +143,76 @@ const getCompetitors = async () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const addEvent = () => {
|
const handleModel = (competitor, event, edit, index) => {
|
||||||
newEvent.value = false
|
if(!competitor) competitor = {
|
||||||
contest.value.events.unshift(tempEvent.value)
|
relatiecode: '',
|
||||||
tempEvent.value = { type: '', competitors: []}
|
time: {
|
||||||
|
minutes: null,
|
||||||
|
seconds: null,
|
||||||
|
milliseconds: null,
|
||||||
|
},
|
||||||
|
dsq: false,
|
||||||
|
info: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
modelData.value = competitor
|
||||||
|
modelData.value.event = event
|
||||||
|
modelData.value.edit = edit
|
||||||
|
modelData.value.index = index
|
||||||
|
showModel.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const backEvent = () => {
|
const submitModelForm = () => {
|
||||||
newEvent.value = false
|
if (!modelData.value.time.minutes) modelData.value.time.minutes = 0
|
||||||
tempEvent.value = { type: '', competitors: []}
|
if (!modelData.value.time.seconds) modelData.value.time.seconds = 0
|
||||||
|
if (!modelData.value.time.milliseconds) modelData.value.time.milliseconds = 0
|
||||||
|
const index = modelData.value.index
|
||||||
|
const edit = modelData.value.edit
|
||||||
|
|
||||||
|
delete modelData.value.index
|
||||||
|
delete modelData.value.edit
|
||||||
|
|
||||||
|
if (!edit) contest.value.events[modelData.value.event].competitors.push(modelData.value)
|
||||||
|
|
||||||
|
showModel.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitContestForm = async () => {
|
||||||
|
const batch = writeBatch(db)
|
||||||
|
|
||||||
|
Object.values(contest.value.events).forEach(event => {
|
||||||
|
event.competitors.forEach(competitor => {
|
||||||
|
const combinedTime = competitor.time.minutes.toString() + competitor.time.seconds.toString() + competitor.time.milliseconds.toString()
|
||||||
|
|
||||||
|
const docRef = doc(collection(db, 'timings'))
|
||||||
|
batch.set(docRef, {
|
||||||
|
relatiecode: competitor.relatiecode,
|
||||||
|
contest: { name: contest.value.name, date: contest.value.date.toString() },
|
||||||
|
event: event.id,
|
||||||
|
time: { minutes: competitor.time.minutes, seconds: competitor.time.seconds, milliseconds: competitor.time.milliseconds, combined: combinedTime },
|
||||||
|
dsq: competitor.dsq,
|
||||||
|
info: competitor.info || ''
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await batch.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getCompetitors()
|
getCompetitors()
|
||||||
})
|
})
|
||||||
</script>
|
</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