Skip to content
Snippets Groups Projects
Verified Commit d48546a7 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add mobile view for timetables and improve select for timetables

parent 3f75b026
No related branches found
No related tags found
1 merge request!301New data model based on calendar events
...@@ -26,9 +26,17 @@ export default { ...@@ -26,9 +26,17 @@ export default {
<div class="text-h5 grey--text text--darken-2 mb-2"> <div class="text-h5 grey--text text--darken-2 mb-2">
{{ $t(titleKey) }} {{ $t(titleKey) }}
</div> </div>
<div class="text-body-2 grey--text text--darken-2"> <div
class="text-body-2 grey--text text--darken-2"
v-if="$vuetify.breakpoint.lgAndUp"
>
{{ $t(descriptionKey) }} {{ $t(descriptionKey) }}
</div> </div>
<div v-if="$vuetify.breakpoint.mdAndDown">
<v-btn color="primary" @click="$emit('selectTimetable')" class="mt-4">
{{ $t("chronos.timetable.select") }}
</v-btn>
</div>
</div> </div>
</v-card> </v-card>
</template> </template>
<script>
import timetableTypes from "./timetableTypes";
export default {
name: "SelectTimetable",
props: {
value: {
type: String | null,
required: true,
},
availableTimetables: {
type: Array,
required: true,
},
},
data() {
return {
selected: null,
selectedFull: null,
search: "",
selectedTypes: ["GROUP", "TEACHER", "ROOM"],
types: timetableTypes,
};
},
watch: {
value(val) {
this.selectedFull = val;
this.selected = val.id;
},
selectedFull(val) {
this.$emit("input", val);
},
},
computed: {
availableTimetablesFiltered() {
// Filter timetables by selected types
return this.availableTimetables.filter((timetable) => {
return this.selectedTypes.indexOf(timetable.type) !== -1;
});
},
},
};
</script>
<template>
<div>
<v-card-text class="mb-0">
<!-- Search field for timetables -->
<v-text-field
search
filled
rounded
clearable
autofocus
v-model="search"
:placeholder="$t('chronos.timetable.search')"
prepend-inner-icon="mdi-magnify"
hide-details="auto"
class="mb-2"
/>
<!-- Filter by timetable types -->
<v-btn-toggle v-model="selectedTypes" dense block multiple class="d-flex">
<v-btn
v-for="type in types"
:key="type.id"
class="flex-grow-1"
:value="type.id"
>
{{ type.name }}
</v-btn>
</v-btn-toggle>
</v-card-text>
<!-- Select of available timetables -->
<v-data-iterator
:items="availableTimetablesFiltered"
item-key="id"
:search="search"
single-expand
disable-pagination
>
<template #default="{ items, isExpanded, expand }">
<v-list class="scrollable-list">
<v-list-item-group v-model="selected">
<v-list-item
v-for="item in items"
@click="selectedFull = item"
:value="item.id"
:key="item.id"
>
<v-list-item-icon color="primary">
<v-icon v-if="item.type in types" color="secondary">
{{ types[item.type].icon }}
</v-icon>
<v-icon v-else color="secondary">mdi-grid</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-chevron-right</v-icon>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</template>
</v-data-iterator>
</div>
</template>
<style scoped>
.scrollable-list {
height: 100%;
overflow-y: scroll;
}
</style>
<script> <script>
import { gqlAvailableTimetables } from "./timetables.graphql"; import { gqlAvailableTimetables } from "./timetables.graphql";
import NoTimetableCard from "./NoTimetableCard.vue"; import NoTimetableCard from "./NoTimetableCard.vue";
import SelectTimetable from "./SelectTimetable.vue";
import timetableTypes from "./timetableTypes";
export default { export default {
name: "Timetable", name: "Timetable",
components: { NoTimetableCard }, components: { NoTimetableCard, SelectTimetable },
apollo: { apollo: {
availableTimetables: { availableTimetables: {
query: gqlAvailableTimetables, query: gqlAvailableTimetables,
...@@ -14,43 +16,26 @@ export default { ...@@ -14,43 +16,26 @@ export default {
return { return {
availableTimetables: [], availableTimetables: [],
selected: null, selected: null,
selectedFull: null,
search: "", search: "",
selectedTypes: ["GROUP", "TEACHER", "ROOM"], selectedTypes: ["GROUP", "TEACHER", "ROOM"],
types: { types: timetableTypes,
GROUP: { selectDialog: false,
name: "Groups",
id: "GROUP",
icon: "mdi-account-group-outline",
},
TEACHER: {
name: "Teachers",
id: "TEACHER",
icon: "mdi-account-outline",
},
ROOM: { name: "Rooms", id: "ROOM", icon: "mdi-door" },
},
}; };
}, },
watch: { watch: {
selected(selected) { selected(selected) {
if (selected == null) {
this.selectedFull = null;
}
},
selectedFull(selectedFull) {
// Align navigation with currently selected timetable // Align navigation with currently selected timetable
if (!selectedFull) { if (!selected) {
this.$router.push({ name: "chronos.timetable" }); this.$router.push({ name: "chronos.timetable" });
} else if ( } else if (
selectedFull.objId !== this.$route.params.id || selected.objId !== this.$route.params.id ||
selectedFull.type !== this.$route.params.type selected.type !== this.$route.params.type
) { ) {
this.$router.push({ this.$router.push({
name: "chronos.timetableWithId", name: "chronos.timetableWithId",
params: { params: {
type: selectedFull.type.toLowerCase(), type: selected.type.toLowerCase(),
id: selectedFull.objId, id: selected.objId,
}, },
}); });
} }
...@@ -59,7 +44,7 @@ export default { ...@@ -59,7 +44,7 @@ export default {
methods: { methods: {
findNextTimetable(offset = 1) { findNextTimetable(offset = 1) {
const currentIndex = this.availableTimetablesIds.indexOf( const currentIndex = this.availableTimetablesIds.indexOf(
this.selectedFull.id this.selected.id
); );
const newIndex = currentIndex + offset; const newIndex = currentIndex + offset;
if (newIndex < 0 || newIndex >= this.availableTimetablesIds.length) { if (newIndex < 0 || newIndex >= this.availableTimetablesIds.length) {
...@@ -68,8 +53,7 @@ export default { ...@@ -68,8 +53,7 @@ export default {
return this.availableTimetables[newIndex]; return this.availableTimetables[newIndex];
}, },
selectTimetable(timetable) { selectTimetable(timetable) {
this.selected = timetable.id; this.selected = timetable;
this.selectedFull = timetable;
}, },
}, },
computed: { computed: {
...@@ -100,88 +84,77 @@ export default { ...@@ -100,88 +84,77 @@ export default {
<template> <template>
<div> <div>
<v-row> <v-row>
<v-col cols="2"> <v-dialog
v-model="selectDialog"
fullscreen
hide-overlay
transition="dialog-bottom-transition"
>
<v-card> <v-card>
<v-card-text class="mb-0"> <v-toolbar dark color="primary">
<!-- Search field for timetables --> <v-toolbar-title>{{
<v-text-field $t("chronos.timetable.select")
search }}</v-toolbar-title>
filled <v-spacer></v-spacer>
rounded </v-toolbar>
clearable <select-timetable
autofocus v-model="selected"
v-model="search" @input="selectDialog = false"
:placeholder="$t('chronos.timetable.search')" :availableTimetables="availableTimetables"
prepend-inner-icon="mdi-magnify" />
hide-details="auto" </v-card>
class="mb-2" </v-dialog>
/>
<!-- Filter by timetable types -->
<v-btn-toggle
v-model="selectedTypes"
dense
block
multiple
class="d-flex"
>
<v-btn
v-for="type in types"
:key="type.id"
class="flex-grow-1"
:value="type.id"
>
{{ type.name }}
</v-btn>
</v-btn-toggle>
</v-card-text>
<!-- Select of available timetables --> <v-col md="3" lg="3" xl="2" v-if="$vuetify.breakpoint.lgAndUp">
<v-data-iterator <v-card>
:items="availableTimetablesFiltered" <select-timetable
item-key="id" v-model="selected"
:search="search" :availableTimetables="availableTimetables"
single-expand />
>
<template #default="{ items, isExpanded, expand }">
<v-list>
<v-list-item-group v-model="selected">
<v-list-item
v-for="item in items"
@click="selectedFull = item"
:value="item.id"
:key="item.id"
>
<v-list-item-icon color="primary">
<v-icon v-if="item.type in types" color="secondary">
{{ types[item.type].icon }}
</v-icon>
<v-icon v-else color="secondary">mdi-grid</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-chevron-right</v-icon>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</template>
</v-data-iterator>
</v-card> </v-card>
</v-col> </v-col>
<v-col cols="10" class="full-height"> <v-col sm="12" md="12" lg="9" xl="10" class="full-height">
<!-- No timetable card--> <!-- No timetable card-->
<no-timetable-card v-if="selectedFull == null" /> <no-timetable-card
v-if="selected == null"
@selectTimetable="selectDialog = true"
/>
<!-- Calendar card--> <!-- Calendar card-->
<v-card v-else> <v-card v-else>
<div class="d-flex"> <div class="d-flex flex-column" v-if="$vuetify.breakpoint.smAndDown">
<v-card-title class="pt-2">
<v-btn
icon
:disabled="!prevTimetable"
@click="selectTimetable(prevTimetable)"
:title="$t('chronos.timetable.prev')"
class="mr-1"
>
<v-icon>mdi-chevron-left</v-icon>
</v-btn>
<v-spacer />
<v-chip outlined color="secondary" @click="selectDialog = true">
{{ selected.name }}
<v-icon right>mdi-chevron-down</v-icon>
</v-chip>
<v-spacer />
<v-btn
icon
:disabled="!nextTimetable"
@click="selectTimetable(nextTimetable)"
:title="$t('chronos.timetable.next')"
class="ml-1 float-right"
>
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</v-card-title>
</div>
<div class="d-flex flex-wrap justify-space-between mb-2" v-else>
<v-card-title> <v-card-title>
{{ selectedFull.name }} {{ selected.name }}
</v-card-title> </v-card-title>
<v-spacer />
<div class="pa-2 mt-1"> <div class="pa-2 mt-1">
<v-btn <v-btn
icon icon
...@@ -192,7 +165,7 @@ export default { ...@@ -192,7 +165,7 @@ export default {
<v-icon>mdi-chevron-left</v-icon> <v-icon>mdi-chevron-left</v-icon>
</v-btn> </v-btn>
<v-chip label color="secondary" outlined class="mx-1">{{ <v-chip label color="secondary" outlined class="mx-1">{{
selectedFull.shortName selected.shortName
}}</v-chip> }}</v-chip>
<v-btn <v-btn
icon icon
...@@ -206,7 +179,7 @@ export default { ...@@ -206,7 +179,7 @@ export default {
</div> </div>
<calendar-with-controls <calendar-with-controls
:calendar-feeds="[{ name: 'lesson' }]" :calendar-feeds="[{ name: 'lesson' }]"
:params="{ type: selectedFull.type, id: selectedFull.objId }" :params="{ type: selected.type, id: selected.objId }"
/> />
</v-card> </v-card>
</v-col> </v-col>
......
export default {
GROUP: {
name: "Groups",
id: "GROUP",
icon: "mdi-account-group-outline",
},
TEACHER: {
name: "Teachers",
id: "TEACHER",
icon: "mdi-account-outline",
},
ROOM: { name: "Rooms", id: "ROOM", icon: "mdi-door" },
};
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
}, },
"search": "Search Timetables", "search": "Search Timetables",
"prev": "Previous Timetable", "prev": "Previous Timetable",
"next": "Next Timetable" "next": "Next Timetable",
"select": "Select Timetable"
}, },
"lessons": { "lessons": {
"menu_title_daily": "Daily lessons" "menu_title_daily": "Daily lessons"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment