Skip to content
Snippets Groups Projects

Resolve "Frontend for Models"

Merged Julian requested to merge 1-frontend-for-models into master
Compare and Show latest version
8 files
+ 385
1
Compare changes
  • Side-by-side
  • Inline
Files
8
<template>
<div id="slot-container">
<!-- <v-hover v-slot="{ hover }">-->
<!-- <v-card elevation="0">-->
<!-- <v-card-title>-->
<!-- <validity-range-field-->
<!-- solo-->
<!-- hide-details-->
<!-- v-model="internalValidityRange"-->
<!-- :loading="$apollo.queries.currentValidityRange.loading"-->
<!-- />-->
<!-- <v-btn-->
<!-- v-if="canAddDay('A_0')"-->
<!-- v-show="hover"-->
<!-- color="secondary"-->
<!-- fab-->
<!-- dark-->
<!-- small-->
<!-- absolute-->
<!-- right-->
<!-- style="right: calc(-20px - 0.5rem)"-->
<!-- >-->
<!-- <v-icon>mdi-plus</v-icon>-->
<!-- </v-btn>-->
<!-- </v-card-title>-->
<!-- </v-card>-->
<!-- </v-hover>-->
<v-hover
v-for="weekday in weekdays"
:style="{
gridColumn: weekday,
}"
v-slot="{ hover }"
>
<v-card :loading="$apollo.queries.items.loading">
<v-card-title class="d-flex flex-wrap justify-space-between align-center fill-height">
<span>{{ $t("weekdays." + weekday) }}</span>
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<v-btn
disabled
icon
v-bind="attrs"
v-on="on"
v-show="hover"
>
<v-icon>$deleteContent</v-icon>
</v-btn>
</template>
<span v-t="'actions.delete'"></span>
</v-tooltip>
<v-menu offset-y>
<template #activator="{ on: menu, attrs }">
<v-tooltip bottom>
<template #activator="{ on: tooltip }">
<v-btn
icon
v-bind="attrs"
v-on="{ ...tooltip, ...menu }"
:loading="loading[weekday]"
v-show="hover"
>
<v-icon>mdi-application-export</v-icon>
</v-btn>
</template>
<span v-t="'actions.copy_to_day'"></span>
</v-tooltip>
</template>
<v-list>
<v-list-item
v-for="(item, index) in weekdays.filter(day => day !== weekday)"
:key="index"
link
>
<v-list-item-title @click="copyTo(weekday, item)">{{ $t("weekdays." + item) }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn
v-if="canAddDay(left(weekday))"
v-show="hover"
color="secondary"
fab
dark
small
absolute
left
style="left: calc(-20px - 0.5rem)"
@click="add(left(weekday))"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
<v-btn
v-if="canAddDay(right(weekday))"
v-show="hover"
color="secondary"
fab
dark
small
absolute
right
style="right: calc(-20px - 0.5rem)"
@click="add(right(weekday))"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-card-title>
</v-card>
</v-hover>
<template
v-for="slot in slots"
>
<slot-card
:item="slot"
:disabled="$apollo.queries.items.loading"
/>
</template>
</div>
</template>
<script>
import {createBreakSlot, deleteBreakSlots} from "../break.graphql";
import {
slots,
createSlot,
deleteSlot,
deleteSlots,
updateSlots,
} from "../slot.graphql";
import {currentValidityRange} from "../validityRange.graphql";
import ValidityRangeField from "../ValidityRangeField.vue";
import SecondaryActionButton from "aleksis.core/components/generic/buttons/SecondaryActionButton.vue";
import SlotCard from "./SlotCard.vue";
export default {
name: "LessonRaster",
components: {SlotCard, SecondaryActionButton, ValidityRangeField},
apollo: {
items: {
query: slots,
variables() {
return {
filters: JSON.stringify({
"validity_range__id": this.internalValidityRange.id
})
}
},
result(data) {
this.weekdays = Array.from(new Set(data.data.items.map(slot => slot.weekday)));
},
skip() {
return this.internalValidityRange === null;
}
},
currentValidityRange: {
query: currentValidityRange,
result(data) {
this.internalValidityRange = data.data.currentValidityRange;
}
}
},
data() {
return {
weekdays: [],
internalValidityRange: null,
loading: {}
}
},
computed: {
slots() {
return this.items;
},
columns() {
return this.weekdays.map(
day => `[${day}] 1fr`
).join(" ");
}
},
methods: {
canAddDay(weekday) {
if (!weekday) {
return false;
}
return !this.weekdays.includes(weekday);
},
add(weekday) {
if (!this.weekdays.includes(weekday)) {
this.weekdays.push(weekday)
this.weekdays.sort();
}
},
right(weekday) {
return weekday === "A_6" ? null : weekday.replace(/\d+$/, (match) => parseInt(match) + 1);
},
left(weekday) {
return weekday === "A_0" ? null : weekday.replace(/\d+$/, (match) => parseInt(match) - 1);
},
async copyTo(src, dest) {
this.loading[src] = true;
const slotsToDelete = this.items
.filter(slot => slot.weekday === dest && slot.model === "Slot")
.map(slot => slot.id);
const breaksToDelete = this.items
.filter(slot => slot.weekday === dest && slot.model === "Break")
.map(slot => slot.id);
// As there is an error when deleting breaks and normal slots in one action, we delete them separately
await Promise.all([
this.$apollo.mutate({
mutation: deleteSlots,
variables: {
ids: slotsToDelete
},
}),
this.$apollo.mutate({
mutation: deleteBreakSlots,
variables: {
ids: breaksToDelete
},
}),
]
);
await Promise.all(
this.items
.filter(slot => slot.weekday === src)
.map(slot => {
this.$apollo.mutate({
mutation: slot.model === "Slot" ? createSlot : createBreakSlot,
variables: {
input: {
name: slot.name,
validityRange: slot.validityRange.id,
weekday: parseInt(dest[2]),
period: slot.period,
timeStart: slot.timeStart,
timeEnd: slot.timeEnd,
}
},
})
})
)
await this.$apollo.queries.items.refetch();
this.loading[src] = false;
}
},
}
</script>
<style scoped>
#slot-container {
display: grid;
grid-template-columns: v-bind(columns);
grid-auto-rows: 1fr auto;
gap: 1rem;
overflow-x: scroll;
margin: -1em;
padding: 1em;
}
</style>
\ No newline at end of file
Loading