Skip to content
Snippets Groups Projects
CoursewareShelfDialogCopy.vue 17.2 KiB
Newer Older
<template>
    <studip-wizard-dialog
        :title="$gettext('Lernmaterial kopieren')"
        :confirmText="$gettext('Kopieren')"
        :closeText="$gettext('Abbrechen')"
        :lastRequiredSlotId="2"
        :requirements="requirements"
        :slots="wizardSlots"
        @close="close"
        @confirm="copy"
    >
        <template v-slot:source>
            <form class="default" @submit.prevent="">
                <fieldset class="radiobutton-set">
                    <template v-if="inCourseContext">
                        <input
                            id="cw-shelf-copy-source-self"
                            type="radio"
                            v-model="source"
                            value="self"
                            :aria-description="text.sourceSelf"
                        />
                        <label @click="source = 'self'" for="cw-shelf-copy-source-self">
Ron Lucke's avatar
Ron Lucke committed
                            <div class="icon"><studip-icon shape="seminar" :size="32"/></div>
                            <div class="text">{{ text.sourceSelf }}</div>
Ron Lucke's avatar
Ron Lucke committed
                            <studip-icon shape="radiobutton-unchecked" :size="24" class="unchecked" />
                            <studip-icon shape="check-circle" :size="24" class="check" />
                        </label>
                    </template>
                    <input
                        id="cw-shelf-copy-source-courses"
                        type="radio"
                        v-model="source"
                        value="courses"
                        :aria-description="text.sourceCourses"
                    />
                    <label @click="source = 'courses'" for="cw-shelf-copy-source-courses">
Ron Lucke's avatar
Ron Lucke committed
                        <div class="icon"><studip-icon shape="seminar" :size="32"/></div>
                        <div class="text">{{ text.sourceCourses }}</div>
Ron Lucke's avatar
Ron Lucke committed
                        <studip-icon shape="radiobutton-unchecked" :size="24" class="unchecked" />
                        <studip-icon shape="check-circle" :size="24" class="check" />
                    </label>
                    <input
                        id="cw-shelf-copy-source-users"
                        type="radio"
                        v-model="source"
                        value="users"
                        :aria-description="text.sourceUsers"
                    />
                    <label @click="source = 'users'" for="cw-shelf-copy-source-users">
Ron Lucke's avatar
Ron Lucke committed
                        <div class="icon"><studip-icon shape="content" :size="32"/></div>
                        <div class="text">{{ text.sourceUsers }}</div>
Ron Lucke's avatar
Ron Lucke committed
                        <studip-icon shape="radiobutton-unchecked" :size="24" class="unchecked" />
                        <studip-icon shape="check-circle" :size="24" class="check" />
Ron Lucke's avatar
Ron Lucke committed
                <template v-if="source === 'courses'">
                    <label>
                        <span>{{ $gettext('Semester') }}</span><span aria-hidden="true"></span>
                        <select v-model="selectedSemester">
                            <option value="all">{{ $gettext('Alle Semester') }}</option>
                            <option v-for="semester in semesterMap" :key="semester.id" :value="semester.id">
                                {{ semester.attributes.title }}
                            </option>
                        </select>
                    </label>
                    <label>
                        <span>{{ $gettext('Veranstaltung') }}</span><span aria-hidden="true" class="wizard-required">*</span>
                        <studip-select
                            v-if="filteredCourses.length !== 0 && !loadingCourses"
                            :options="filteredCourses"
                            :clearable="false"
                            :reduce="option => option.id"
Ron Lucke's avatar
Ron Lucke committed
                            :getOptionLabel="option => option.attributes.title"
Ron Lucke's avatar
Ron Lucke committed
                            v-model="selectedRange"
                        >
                            <template #open-indicator="selectAttributes">
                                <span v-bind="selectAttributes"
Ron Lucke's avatar
Ron Lucke committed
                                    ><studip-icon shape="arr_1down" :size="10"
Ron Lucke's avatar
Ron Lucke committed
                                /></span>
                            </template>
                        </studip-select>
                        <p v-if="loadingCourses">
                            {{$gettext('Lade Veranstaltungen…')}}
                        </p>
                        <p v-if="filteredCourses.length === 0 && !loadingCourses">
                            {{$gettext('Es wurden keine geeigneten Veranstaltungen gefunden.')}}
                        </p>
                    </label>
                </template>

            </form>
        </template>
        <template v-slot:unit>
            <form class="default" @submit.prevent="">
                <fieldset v-if="units.length !== 0" class="radiobutton-set">
                    <template v-for="unit in units">
                        <input
                            :id="'cw-shelf-copy-unit-' + unit.id"
                            type="radio"
                            v-model="selectedUnit"
                            :checked="unit.id === selectedUnitId"
                            :value="unit"
                            :key="'radio-' + unit.id"
                            :aria-description="unit.element.attributes.title"
                        />
                        <label @click="selectedUnit = unit" :key="'label-' + unit.id" :for="'cw-shelf-copy-unit-' + unit.id">
Ron Lucke's avatar
Ron Lucke committed
                            <div class="icon"><studip-icon shape="courseware" :size="32"/></div>
                            <div class="text">{{ unit.element.attributes.title }}</div>
Ron Lucke's avatar
Ron Lucke committed
                            <studip-icon shape="radiobutton-unchecked" :size="24" class="unchecked" />
                            <studip-icon shape="check-circle" :size="24" class="check" />
                        </label>
                    </template>
                </fieldset>
                <courseware-companion-box
                    v-else
                    mood="sad"
                    :msgCompanion="$gettext('Für die gewählte Quelle stehen keine Lernmaterialien zur Verfügung.')"
                />
            </form>
        </template>
        <template v-slot:edit>
            <form v-if="selectedUnit" class="default" @submit.prevent="">
                <label>
                    {{$gettext('Titel')}}
                    <input type="text" v-model="modifiedTitle" :placeholder="selectedUnitTitle" name="title" />
                </label>
                <label>
                    {{$gettext('Farbe')}}
                    <studip-select
                        v-model="modifiedColor"
                        :options="colors"
                        :reduce="(color) => color.class"
                        :clearable="false"
                        label="class"
                    >
                        <template #open-indicator="selectAttributes">
                            <span v-bind="selectAttributes"
Ron Lucke's avatar
Ron Lucke committed
                                ><studip-icon shape="arr_1down" :size="10"
                            /></span>
                        </template>
                        <template #no-options>
                            {{ $gettext('Es steht keine Auswahl zur Verfügung.') }}
                        </template>
                        <template #selected-option="{ name, hex }">
                            <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                            ><span>{{ name }}</span>
                        </template>
                        <template #option="{ name, hex }">
                            <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                            ><span>{{ name }}</span>
                        </template>
                    </studip-select>
                </label>
                <label>
                    {{$gettext('Beschreibung')}}
                    <textarea v-model="modifiedDescription" :placeholder="selectedUnitDescription" />
                </label>
            </form>
            <courseware-companion-box
                    v-else
                    mood="pointing"
                    :msgCompanion="$gettext('Bitte wählen Sie ein Lernmaterial aus.')"
                />
        </template>
    </studip-wizard-dialog>
</template>

<script>
import CoursewareCompanionBox from '../layouts/CoursewareCompanionBox.vue';
import colorMixin from '@/vue/mixins/courseware/colors.js';
import StudipSelect from '../../StudipSelect.vue';
import StudipWizardDialog from '../../StudipWizardDialog.vue';

import { mapActions, mapGetters } from 'vuex'

export default {
    name: 'courseware-shelf-dialog-copy',
    mixins: [colorMixin],
    components: {
        CoursewareCompanionBox,
        StudipWizardDialog,
        StudipSelect,
    },
    data() {
        return {
            wizardSlots: [
                { id: 1, valid: false, name: 'source', title: this.$gettext('Quelle'), icon: 'source',
                  description: this.$gettext('Wählen Sie hier den Ort in Stud.IP aus, an dem sich das zu kopierende Lernmaterial befindet.') },
                { id: 2, valid: false, name: 'unit', title: this.$gettext('Lernmaterial'), icon: 'courseware',
                  description: this.$gettext('Wählen Sie hier das gewünschte Lernmaterial aus der Liste aus. Eine Auswahl wird durch einen grauen Hintergrund und einen Kontrollhaken angezeigt.') },
Ron Lucke's avatar
Ron Lucke committed
                { id: 3, valid: true, name: 'edit', title: this.$gettext('Anpassen'), icon: 'edit', target: 'title',
                  description: this.$gettext('Sie können hier die Daten des zu kopierenden Lernmaterials anpassen. Eine Anpassung ist optional, Sie können das Lernmaterial auch unverändert kopieren.') },
            ],
            source: '',
            loadingCourses: false,
            courses: [],
Ron Lucke's avatar
Ron Lucke committed
            semesterMap: [],
            selectedSemester: 'all',
            selectedRange: '',
            loadingUnits: false,
            selectedUnit: null,
            selectedUnitElement: null,
            modifiedTitle: '',
            modifiedColor: '',
            modifiedDescription: '',

            requirements: [],
            text: {
                source: this.$gettext('Quelle'),
                unit: this.$gettext('Lernmaterial'),
                sourceSelf: this.$gettext('Diese Veranstaltung'),
                sourceCourses: this.$gettext('Veranstaltung'),
                sourceUsers: this.$gettext('Arbeitsplatz'),

            }
        }
    },
    computed: {
        ...mapGetters({
            userId: 'userId',
            coursewareUnits: 'courseware-units/all',
Ron Lucke's avatar
Ron Lucke committed
            semesterById: 'semesters/byId',
            structuralElementById: 'courseware-structural-elements/byId',
            context: 'context'
        }),
        colors() {
            return this.mixinColors.filter(color => color.darkmode);
        },
        units() {
            let units = this.coursewareUnits.filter(unit => unit.relationships.range.data.id === this.selectedRange);
            units.forEach(unit => {
                unit.element = this.getUnitElement(unit);
            });

            if (this.inCourseContext) {
                units = units.filter(unit => unit.element.attributes.purpose !== 'template');
            }

            return units;
        },
        selectedUnitId() {
            return this.selectedUnit?.id;
        },
        inCourseContext() {
            return this.context.type === 'courses';
        },
        selectedUnitTitle() {
            return this.selectedUnitElement.attributes.title ?? '';
        },
        selectedUnitDescription() {
            return this.selectedUnitElement.attributes.payload.description ?? '';
Ron Lucke's avatar
Ron Lucke committed
        },
        filteredCourses() {
Ron Lucke's avatar
Ron Lucke committed
            const courses = this.courses.filter((course) => { return course.id !== this.context.id });
Ron Lucke's avatar
Ron Lucke committed
            if (this.selectedSemester === 'all') {
                return courses;
            } else {
                return courses.filter((course) => {
                    return course.relationships['start-semester'].data.id === this.selectedSemester;
                });
            }
        }
    },
    async mounted() {
        this.initWizardData();
    },
    methods: {
        ...mapActions({
            companionSuccess: 'companionSuccess',
            loadCourseUnits: 'loadCourseUnits',
            loadUsersCourses: 'loadUsersCourses',
Ron Lucke's avatar
Ron Lucke committed
            loadSemester: 'semesters/loadById',
            loadUserUnits: 'loadUserUnits',
            setShowUnitCopyDialog: 'setShowUnitCopyDialog',
            copyUnit: 'copyUnit',
        }),
        initWizardData() {
            this.source = this.inCourseContext ? 'self' : 'users';
            this.selectedRange = '';
            this.selectedUnit = null;
        },
        close() {
            this.setShowUnitCopyDialog(false);
            this.initWizardData();
        },
        getUnitElement(unit) {
            return this.structuralElementById({id: unit.relationships['structural-element'].data.id});
        },
        async copy() {
            if (this.selectedUnit) {
                const element = this.getUnitElement(this.selectedUnit);
                const modified = {
                        title: this.modifiedTitle !== '' ? this.modifiedTitle : this.selectedUnitTitle,
                        color: this.modifiedColor,
                        description: this.modifiedDescription !== '' ? this.modifiedDescription : this.selectedUnitDescription
                }
                await this.copyUnit({ unitId: this.selectedUnit.id, modified: modified });
                this.companionSuccess({ info: this.$gettext('Lernmaterial kopiert.') });
                this.close();
            }
        },
        async updateCourses() {
            this.loadingCourses = true;
            this.courses = await this.loadUsersCourses({ userId: this.userId, withCourseware: true });
Ron Lucke's avatar
Ron Lucke committed
            this.loadSemesterMap();
Ron Lucke's avatar
Ron Lucke committed
        loadSemesterMap() {
            let view = this;
            let semesters = [];
            this.courses.every(course => {
                let semId = course.relationships['start-semester'].data.id;
                if(!semesters.includes(semId)) {
                    semesters.push(semId);
                }
                return true;
            });
            semesters.every(semester => {
                view.loadSemester({id: semester}).then( () => {
                    view.semesterMap.push(view.semesterById({id: semester}));
Ron Lucke's avatar
Ron Lucke committed
                    view.semesterMap.sort((a, b) => new Date(b.attributes.start) - new Date(a.attributes.start));
Ron Lucke's avatar
Ron Lucke committed
                });
                return true;
            });
        },
        async updateCourseUnits(cid) {
            this.loadingUnits = true;
            await this.loadCourseUnits(cid);
            this.loadingUnits = false;
        },
        setElementData() {
            this.selectedUnitElement = this.getUnitElement(this.selectedUnit);
            this.modifiedTitle = this.selectedUnitElement.attributes.title;
            this.modifiedColor = this.selectedUnitElement.attributes.payload.color;
            this.modifiedDescription = this.selectedUnitElement.attributes.payload.description;
        },
        resetElementData() {
            this.modifiedTitle = '';
            this.modifiedColor = '';
            this.modifiedDescription = '';
        },
        validateSelection() {
            this.requirements = [];
            if (this.selectedRange === '') {
                this.requirements.push({slot: this.wizardSlots[0], text: this.text.source });
            }
            if (this.selectedUnit === null) {
                this.requirements.push({slot: this.wizardSlots[1], text: this.text.unit });
            }
        }
    },
    watch: {
        selectedUnit(newUnit) {
            this.validateSelection();
            const slot = this.wizardSlots[1];
            if (newUnit !== null) {
                slot.valid = true;
                this.setElementData();
            } else {
                slot.valid = false;
                this.resetElementData();
            }
        },
        selectedRange(newRid) {
            this.selectedUnit = null;
            this.validateSelection();
            const slot = this.wizardSlots[0];
            
            if (newRid !== '') {
                slot.valid = true;
                if (this.source === 'courses' || this.source === 'self') {
                    this.updateCourseUnits(newRid);
                }
                if (this.source === 'users') {
                    this.loadUserUnits(newRid);
                }
            } else {
                slot.valid = false;
            }
        },
        source(newSource) {
            switch (newSource) {
                case 'self':
                    this.selectedRange = this.context.id;
                    break;
                case 'courses':
                    this.selectedRange = '';
                    this.updateCourses();
                    break;
                case 'users':
                    this.selectedRange = this.userId;
                    break;
            }
Ron Lucke's avatar
Ron Lucke committed
        },
        selectedSemester(newSemester) {
            this.selectedRange = '';
Ron Lucke's avatar
Ron Lucke committed
</script>