Skip to content
Snippets Groups Projects
Forked from Stud.IP / Stud.IP
1670 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
StudipWizardDialog.vue 8.06 KiB
<template>
    <studip-dialog
        :height="height"
        :width="width"
        :title="title"
        :confirmText="confirmText"
        :confirmClass="confirmClass"
        :confirmDisabled="!showConfirm"
        :closeText="closeText"
        :closeClass="closeClass"
        @close="$emit('close')"
        @confirm="confirm"
    >
        <template v-slot:dialogContent>
            <div class="wizard-wrapper">
                <div class="wizard-meta">
                    <studip-icon :shape="activeSlot.icon" :size="96"/>
                    <p class="wizard-description">
                        {{ activeSlot.description }}
                    </p>
                    <p v-if="requirements.length > 0" class="wizard-requirements">
                        <span>{{ $gettext('Bitte geben Sie die folgenden Informationen an:') }}</span>
                        <ul>
                            <li v-for="(requirement, index) in requirements" :key="requirement.slot.name + '_' + index">
                                <button @click="selectSlot(requirement.slot.id)">
                                    <studip-icon
                                        :shape="requirement.slot.icon"
                                        :size="16"
                                        role="clickable"
                                    />{{ requirement.text }}
                                </button>
                            </li>
                        </ul>
                    </p>
                </div>
                <div class="wizard-content-wrapper">
                    <h2>
                        {{ activeSlot.title }}<span v-if="activeSlotRequiered" aria-hidden="true" class="required">*</span>
                    </h2>
                    <ul class="wizard-progress">
                        <li
                            v-for="progress in slots"
                            :key="progress.id"
                            :class="[
                                isValid(progress.id) ? 'valid' : 'invalid',
                                activeId === progress.id ? 'active' : 'inactive',
                                isOptional(progress.id) ? 'optional' : ''
                            ]"
                        >
                            <button
                                ref="tabs"
                                :title="progress.title"
                                role="tab"
                                :aria-selected="activeId === progress.id"
                                :aria-controls="progress.name"
                                :tabindex="0"
                                @click="selectSlot(progress.id)"
                                @keydown.right="nextContent"
                                @keydown.left="prevContent"
                            >
                                <studip-icon
                                    :shape="progress.icon"
                                    :size="24"
                                    :role="isValid(progress.id) ? 'info_alt' : 'clickable'"
                                />
                            </button>
                        </li>
                    </ul>
                    <ul class="wizard-list">
                        <li v-for="slot in slots" :key="slot.id">
                            <div
                                v-show="slot.id === activeId"
                                class="wizard-item"
                                role="tabpanel"
                                :aria-labelledby="slot.name"
                            >
                                <div class="wizard-content">
                                    <slot :name="slot.name" ></slot>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </template>
        <template v-slot:dialogButtonsBefore>
            <button :style="{visibility: hasPrevContent ? 'visible' : 'hidden'}" class="button arr_left" @click="prevContent">
                {{ $gettext('zurück') }}
            </button>
        </template>
        <template v-slot:dialogButtonsAfter>
            <button :style="{visibility: hasNextContent ? 'visible' : 'hidden'}" class="button arr_right" @click="nextContent">
                {{ $gettext('weiter') }}
            </button>
        </template>
    </studip-dialog>
</template>

<script>
import StudipDialog from './StudipDialog.vue'
import StudipIcon from './StudipIcon.vue';
export default {
    name: 'studip-wizard-dialog',
    components: {
        StudipDialog,
        StudipIcon
    },
    props: {
        title: {
            type: String
        },
        confirmText: {
            type: String
        },
        closeText: {
            type: String
        },
        confirmClass: {
            type: String,
            default: 'accept'
        },
        closeClass: {
            type: String,
            default: 'cancel'
        },
        height: {
            type: String,
            default: '640'
        },
        width: {
            type: String,
            default: '900'
        },
        slots: {
            type: Array,
            required: true
        },
        lastRequiredSlotId: {
            type: Number
        },
        requirements: {
            type: Array,
            default: () => []
        }
    },
    data() {
        return {
            activeId: 1,
            visitedIds: [1]
        }
    },
    computed: {
        hasPrevContent() {
            if (this.activeId === 1) {
                return false;
            }

            return true;
        },
        hasNextContent() {
            if (this.activeId === this.slots.length) {
                return false;
            }

            return true;
        },
        showConfirm() {
            let valid = true;
            if (this.lastRequiredSlotId !== undefined) {
                this.slots.every(slot => {
                    if (slot.id > this.lastRequiredSlotId) {
                        return false;
                    }
                    if (!slot.valid) {
                        valid = false;
                    }

                    return true;
                });

                return valid;
            }

            this.slots.forEach( slot => {
                if (!slot.valid) {
                    valid = false;
                }
            });

            return valid;
        },
        activeSlot() {
            return this.slots.filter(slot => this.activeId === slot.id)[0];
        },
        activeSlotRequiered() {
            if (this.lastRequiredSlotId === undefined) {
                return false;
            }

            return this.lastRequiredSlotId >= this.activeSlot.id;
        },
    },
    methods: {
        prevContent() {
            if (!this.hasPrevContent) {
                return;
            } else {
                this.activeId = this.activeId - 1;
                this.$nextTick(() => {
                    this.$refs.tabs[this.activeId - 1].focus();
                });
            }
        },
        nextContent() {
            if (!this.hasNextContent) {
                return;
            } else {
                this.activeId = this.activeId + 1;
                this.$nextTick(() => {
                    this.$refs.tabs[this.activeId - 1].focus();
                });
            }
        },
        selectSlot(id) {
            this.activeId = id;
        },
        isValid(id) {
            const slot = this.slots.find( slot => slot.id === id);
            if (slot) {
                return slot.valid && this.visitedIds.indexOf(id) !== -1;
            }

            return false;
        },
        isOptional(id) {
            if (this.lastRequiredSlotId === undefined) {
                return false;
            }

            return this.lastRequiredSlotId < id;
        },
        confirm() {
            this.$emit('confirm');
        }
    },
    watch: {
        activeId(newVal) {
            if (this.visitedIds.indexOf(newVal) === -1) {
                this.visitedIds.push(newVal);
            }
        }
    }
}
</script>