miniplan/public/src/components/TablePlan.vue
2023-09-17 10:19:43 +02:00

293 lines
6.4 KiB
Vue

<script setup lang="ts">
import {API} from "@/views/api";
import {onMounted, reactive, ref} from "vue";
import type {Gottesdienst, Mark, PlanModel, SimplifiedMinistrant} from "@/models/models";
import Input from "@/components/Input.vue";
const props = defineProps<{
gottesdienste: Gottesdienst[],
ministranten: SimplifiedMinistrant[]
marks: Mark[],
editable: number[]
edit: boolean
}>()
const emit = defineEmits(["toggleMark", "added", "delete", "endEdit"])
const data = reactive({
godi: {}
})
onMounted(() => {
window.addEventListener("keypress", ev => {
if(ev.key == "Enter" && props.edit){
emit("added", data.godi, () => {
data.godi = {}
})
}
})
})
function getIconForMark(gid, mid) {
const mark = getMark(gid, mid).value
switch (mark) {
case -1:
return "remove";
case 0:
return "question_mark";
// return ""
case 1:
return "close"
}
return ""
}
function getClassForMark(gid, mid) {
const mark = getMark(gid, mid).value
switch (mark) {
case -1:
return "minus";
case 0:
return "neutral";
case 1:
return "cross"
}
return ""
}
function getHintForMark(gid, mid) {
const mark = getMark(gid, mid).value
switch (mark) {
case -1:
return "Ich kann nicht";
case 0:
return "Egal";
case 1:
return "Ich komme"
}
}
function two(s) {
return (s < 10 ? "0" : "") + s
}
function formatDay(time) {
let date = new Date(time)
return two(date.getDate()) + "." + two(date.getMonth()) + "."
}
function formatTime(time) {
let date = new Date(time)
return two(date.getHours()) + ":" + two(date.getMinutes())
}
function formatWeekday(time) {
let date = new Date(time)
switch (date.getDay()) {
case 1:
return "Mo";
case 2:
return "Di";
case 3:
return "Mi";
case 4:
return "Do";
case 5:
return "Fr";
case 6:
return "Sa";
case 0:
return "So"
}
}
function getMark(gid, mid) {
const mark = props.marks.find(mark => mark.mid == mid && mark.gid == gid)
return mark ? mark : {gid, mid, value: 0}
}
function getMinistrantClasses(mini: SimplifiedMinistrant) {
return {
edit: props.editable.includes(mini.id)
}
}
</script>
<template>
<table>
<thead>
<tr v-if="props.edit">
<th></th>
<th v-for="godi in props.gottesdienste"><i @click="$emit('delete', godi.id)">delete</i></th>
<th><i @click="$emit('endEdit')">close</i></th>
</tr>
<tr>
<th></th>
<th v-for="godi in props.gottesdienste">{{ godi.name }}</th>
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.name"/></th>
</tr>
<tr class="bold">
<th>Datum</th>
<th v-for="godi in props.gottesdienste">{{ formatDay(godi.date) }}</th>
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.date" type="date"/></th>
</tr>
<tr>
<th>Uhrzeit</th>
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.date) }}</th>
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.time" type="time"/></th>
</tr>
<tr class="bold">
<th>Anwesenheit</th>
<th v-for="godi in props.gottesdienste">{{ formatTime(godi.attendance) }}</th>
<th class="edit" v-if="props.edit"><Input v-model:value="data.godi.attendance" type="time"/></th>
</tr>
<tr>
<th>Wochentag</th>
<th v-for="godi in props.gottesdienste">{{ formatWeekday(godi.date) }}</th>
<th class="edit" v-if="props.edit"></th>
</tr>
</thead>
<tbody>
<tr v-for="mini in props.ministranten" class="ministrant" :class="getMinistrantClasses(mini)">
<td class="name">{{ mini.id }} {{ mini.firstname }} {{ mini.lastname }}</td>
<td
v-for="godi in props.gottesdienste"
class="mark"
:class="getClassForMark(godi.id, mini.id)"
@click="$emit('toggleMark', godi.id, mini.id)">
<i class="icon"> {{ getIconForMark(godi.id, mini.id) }} </i><br>
<span class="hint">{{ getHintForMark(godi.id, mini.id) }}</span>
</td>
<td class="edit" v-if="props.edit"></td>
</tr>
</tbody>
</table>
</template>
<style scoped lang="less">
table {
border-spacing: 0;
}
tr{
th{
font-weight: 400;
&.edit{
text-align: start;
}
}
&.bold th{
font-weight: 700;
}
}
td {
background: #ffffff;
}
td:first-child, th:first-child {
padding: 6px 60px 6px 12px;
text-align: left;
}
td:nth-child(2n), th:nth-child(2n){
background: #8ce081;
}
.mark {
text-align: center;
vertical-align: center;
justify-content: center;
align-items: center;
min-width: 100px;
height: 20px;
user-select: none;
i {
border-radius: 100%;
padding: 1px;
font-size: 22px;
margin: 2px;
}
&.minus {
background: #fdd5d5;
color: #690b0b;
i {
}
}
&.cross {
background: #d1fcd1;
color: #045b04;
i {
}
}
&.neutral i {
opacity: 0;
color: #9f9f9f;
font-variation-settings: "wght" 350;
mix-blend-mode: difference;
}
.hint {
margin-top: 4px;
opacity: 0.7;
display: none;
font-size: 14px;
//mix-blend-mode: difference;
}
}
.ministrant.edit {
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
z-index: 10;
position: relative;
td {
padding-top: 10px;
padding-bottom: 10px;
}
.mark{
cursor: pointer;
&.neutral i {
opacity: 0.5;
}
.hint {
display: inline-block;
}
}
}
td, th {
--color-outline: #908888;
border-right: 1px solid var(--color-outline);
border-bottom: 1px solid var(--color-outline);
}
td:first-child, th:first-child {
border-right: 2px solid #575757;
}
thead tr:last-child th, tr:nth-child(5n) td {
border-bottom: 2px solid #575757;
}
</style>