- Complete GGZ Ecademy Nuxt.js user portal - Learning products browser and management - Member management interface - User authentication and roles - Multi-language support (NL/EN) - Vuex store for state management - Component-based architecture
This commit is contained in:
18
components/Admin/3110/Footer.vue
Normal file
18
components/Admin/3110/Footer.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<v-footer app class="grey--text overline" id="admin-footer">
|
||||
<span class="mr-2">3110</span>
|
||||
<span>© Turning thougts into pixels</span>
|
||||
<!-- <span>{{ new Date().getFullYear() }}</span> -->
|
||||
<v-spacer />
|
||||
<v-btn text small class="grey--text">General terms</v-btn>
|
||||
<v-btn text small class="grey--text">Privacy Settings</v-btn>
|
||||
<v-btn text small class="grey--text">Help</v-btn>
|
||||
</v-footer>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#admin-footer {
|
||||
border-top: 1px solid #dfdbe3 !important;
|
||||
z-index: 4
|
||||
}
|
||||
</style>
|
||||
213
components/Admin/LeftMenu.vue
Normal file
213
components/Admin/LeftMenu.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<v-list class="pa-4">
|
||||
<div class="mt-4 mb-10 d-flex">
|
||||
<v-btn fab text class="mr-6" @click="$emit('close-left-menu')">
|
||||
<v-icon x-small>icon-close</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<router-link :to="localePath('/manager')">
|
||||
<app-logo width="180" />
|
||||
</router-link>
|
||||
|
||||
<v-spacer />
|
||||
</div>
|
||||
|
||||
<v-list-group
|
||||
v-for="item in items"
|
||||
:key="item.title"
|
||||
v-model="item.active"
|
||||
:prepend-icon="item.icon"
|
||||
no-action
|
||||
color="accent"
|
||||
append-icon=""
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle v-text="item.title"></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-for="subItem in item.items">
|
||||
<v-list-item
|
||||
nuxt
|
||||
@click
|
||||
exact
|
||||
:key="subItem.title"
|
||||
:to="localePath(subItem.to)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle v-text="subItem.title"></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list-group>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Util from '~/util'
|
||||
import AppLogo from '~/components/Logo'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AppLogo,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
drawer: null,
|
||||
item: 1,
|
||||
roles: [],
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.roles = this.$auth.user.roles.map(({ name }) => name);
|
||||
},
|
||||
|
||||
methods: {
|
||||
shouldShowItemByAllowRules(allowRules) {
|
||||
for (const allowRule of allowRules) {
|
||||
if (!this.checkAllowRule(allowRule)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
checkAllowRule(allowRule) {
|
||||
if (Array.isArray(allowRule)) {
|
||||
return Util.findCommonValuesInArray(allowRule, this.roles);
|
||||
} else if ('boolean' === typeof allowRule) {
|
||||
return allowRule;
|
||||
} else {
|
||||
throw new Error('Unexpected allow rule');
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
userIsOnlyMemberEditor() {
|
||||
return this.$store.getters.isOnlyMemberEditor;
|
||||
},
|
||||
|
||||
items() {
|
||||
const itemsArray = [
|
||||
{
|
||||
icon: 'icon-learningproducts',
|
||||
title: this.$t('learning.products'),
|
||||
allowed: [['super_admin', 'admin', 'operator']],
|
||||
items: [
|
||||
{
|
||||
title: this.$t('learning.all_products'),
|
||||
to: '/manager/learning/',
|
||||
allowed: [['super_admin', 'admin', 'operator', 'user']],
|
||||
},
|
||||
{
|
||||
title: this.$t('learning.filters.title'),
|
||||
to: '/manager/learning/filters',
|
||||
allowed: [['super_admin', 'admin', 'operator']],
|
||||
},
|
||||
{
|
||||
title: this.$t('learning.synonyms'),
|
||||
to: '/manager/learning/synonyms/',
|
||||
allowed: [['super_admin', 'admin', 'operator']],
|
||||
},
|
||||
{
|
||||
title: this.$t('learning.quality_standards'),
|
||||
to: '/manager/learning/quality-standards/',
|
||||
allowed: [['super_admin', 'admin', 'operator']],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'icon-members',
|
||||
title: this.$t('auth.account.management'),
|
||||
allowed: [['super_admin']],
|
||||
items: [
|
||||
{
|
||||
title: this.$t('learning.manage'),
|
||||
to: '/manager/accounts/',
|
||||
allowed: [['super_admin', 'admin']],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'icon-members',
|
||||
title: this.$t('members.management'),
|
||||
allowed: [
|
||||
['super_admin', 'admin', 'operator', 'user'],
|
||||
!this.userIsOnlyMemberEditor,
|
||||
],
|
||||
items: [
|
||||
{
|
||||
title: 'Ledencontrole',
|
||||
to: '/manager/members/control',
|
||||
allowed: [['super_admin', 'admin']],
|
||||
},
|
||||
{
|
||||
title: this.$store.getters.isSuperAdminOrAdmin
|
||||
? this.$t('learning.manage')
|
||||
: 'Alle leden',
|
||||
to: '/manager/members/',
|
||||
allowed: [['super_admin', 'admin', 'operator', 'user']],
|
||||
},
|
||||
{
|
||||
title: 'Branches',
|
||||
to: '/manager/members/branches',
|
||||
allowed: [['super_admin', 'admin']],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'icon-members',
|
||||
title: this.$t('members.managementinfo'),
|
||||
allowed: [['super_admin', 'admin', 'operator']],
|
||||
items: [
|
||||
{
|
||||
title: this.$t('members.report'),
|
||||
to: '/manager/members/report',
|
||||
allowed: [['member']],
|
||||
},
|
||||
{
|
||||
title: this.$t('members.manage'),
|
||||
to: '/manager/members/managementinfo',
|
||||
allowed: [['super_admin', 'admin']],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
icon: 'icon-attributes',
|
||||
title: 'Lidmaatschapgegevens',
|
||||
allowed: [this.userIsOnlyMemberEditor],
|
||||
items: [{
|
||||
title: 'Bekijken',
|
||||
to: '/manager/members',
|
||||
}],
|
||||
},
|
||||
{
|
||||
icon: 'icon-managementinfo',
|
||||
title: 'Managementinformatie',
|
||||
allowed: [this.userIsOnlyMemberEditor],
|
||||
items: [{
|
||||
title: this.$t('members.report'),
|
||||
to: '/manager/members/report',
|
||||
}],
|
||||
},
|
||||
];
|
||||
|
||||
return itemsArray.filter(item => {
|
||||
if (!('allowed' in item)) {
|
||||
return true;
|
||||
} else if (Array.isArray(item.allowed)) {
|
||||
return this.shouldShowItemByAllowRules(item.allowed);
|
||||
} else {
|
||||
throw new Error('Expected allow ruleset to be an array');
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
85
components/Admin/Welcome.vue
Normal file
85
components/Admin/Welcome.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<v-card class="pa-6" :color="$vuetify.theme.dark ? 'primary' : 'txt'" flat>
|
||||
<v-card-title class="white--text lighten-1 font-weight-bold"
|
||||
>{{ $t('general.hi') }}
|
||||
{{ $auth.user.first_name | capitalize }}!</v-card-title
|
||||
>
|
||||
<v-card-text class="white--text text font-weight-light">
|
||||
<span v-if="hasNotifications">
|
||||
{{ $t('general.dashboard.current') }}
|
||||
<span
|
||||
class="warning--text mx-1"
|
||||
@click.stop="
|
||||
$store.commit('navigation/SWITCH_RIGHT_DRAWER', {
|
||||
component: 'Notifications',
|
||||
})
|
||||
"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
>{{ notifications.length }} {{ $t('rightMenu.notes') }}</span
|
||||
>
|
||||
{{ $t('general.dashboard.require') }}<br
|
||||
/></span>
|
||||
|
||||
<span v-if="$store.getters.isMember">
|
||||
Goed om je te zien. Update de lidmaatschapgegevens of bekijk de management informatie via de tegels hieronder of via het menu.</span>
|
||||
|
||||
<span v-else>Welkom in je dashboard van MijnGGZEcademy. Klik op onderstaande tegels of navigeer via het menu linksboven in je scherm.<br /><br />
|
||||
Succes!</span>
|
||||
|
||||
<span v-if="$auth.user.last_login_at">
|
||||
De laatste keer heb je ingelogd op
|
||||
{{ formatDate($auth.user.last_login_at) }}. Fijne dag!
|
||||
</span>
|
||||
</v-card-text>
|
||||
<v-img
|
||||
class="img plant"
|
||||
:src="require(`@/assets/img/plant.png`)"
|
||||
contain
|
||||
></v-img>
|
||||
<v-img
|
||||
class="img cat"
|
||||
:src="require(`@/assets/img/cat.png`)"
|
||||
contain
|
||||
></v-img>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
import nl from 'dayjs/locale/nl'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
notifications() {
|
||||
return this.$store.getters.notifications
|
||||
},
|
||||
hasNotifications() {
|
||||
return this.$store.getters.hasNotifications
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
dayjs.locale('nl')
|
||||
return dayjs(date).format('dddd D MMMM YYYY').toLowerCase()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text {
|
||||
width: 650px;
|
||||
color: white !important;
|
||||
}
|
||||
.img {
|
||||
position: absolute;
|
||||
}
|
||||
.plant {
|
||||
right: -35px;
|
||||
top: -21px;
|
||||
}
|
||||
.cat {
|
||||
right: 150px;
|
||||
top: -96px;
|
||||
}
|
||||
</style>
|
||||
6
components/Admin/ggz/Footer/Copyright.vue
Normal file
6
components/Admin/ggz/Footer/Copyright.vue
Normal file
@@ -0,0 +1,6 @@
|
||||
<template class="m-12">
|
||||
<span class="ml-19" style="text-transform: none !important; letter-spacing: normal !important; font-size: 12px; color: #bac7cb;"
|
||||
>© {{ new Date().getFullYear() }} MijnGGZEcademy is onderdeel van GGZ
|
||||
Ecademy Coöperatie U.A.</span
|
||||
>
|
||||
</template>
|
||||
21
components/Admin/ggz/Footer/Footer.vue
Normal file
21
components/Admin/ggz/Footer/Footer.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<v-footer app class="overline" color="primary" height="60">
|
||||
<span class="grey--text"> <Copyright /> </span>
|
||||
<v-spacer />
|
||||
<v-btn text x-small href="https://www.ggzecademy.nl" target="_blank"
|
||||
>ggzecademy.nl</v-btn
|
||||
>
|
||||
<v-btn text x-small href="https://portaal.ggzecademy.nl" target="_blank">centraal leerplatform</v-btn>
|
||||
<v-btn text x-small href="https://support.ggzecademy.nl" target="_blank">support platform</v-btn>
|
||||
</v-footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Copyright from '@/components/Admin/ggz/Footer/Copyright'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Copyright,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
285
components/Auth/Auth.vue
Normal file
285
components/Auth/Auth.vue
Normal file
@@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<v-form ref="form" v-model="valid" lazy-validation>
|
||||
<v-card tile flat class="mb-6 d-flex flex-column fill-height" width="400">
|
||||
<v-card-title class="txt--text">
|
||||
<h2 class="mt-4" v-if="isLogin">{{ $t('auth.login.title') }}</h2>
|
||||
<h2 class="mt-4" v-if="isForgotten">
|
||||
{{ $t('auth.password_forgotten.title') }}
|
||||
</h2>
|
||||
<h2 class="mt-4" v-if="isReset">
|
||||
{{ $t('auth.password_reset.title') }}
|
||||
</h2>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="txt--text">
|
||||
<span v-if="isLogin">{{ $t('auth.login.text') }}</span>
|
||||
<span v-if="isForgotten">{{ $t('auth.password_forgotten.text') }}</span>
|
||||
<span v-if="isReset">{{ $t('auth.password_reset.text') }}</span>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text class="secondary--text" v-if="errors">
|
||||
<errors-list :errors="errors" />
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
name="email"
|
||||
prepend-inner-icon="icon-user"
|
||||
type="text"
|
||||
color="accent"
|
||||
outlined
|
||||
required
|
||||
lines
|
||||
:placeholder="$t('auth.email')"
|
||||
v-model="email"
|
||||
:rules="rules.email"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
id="password"
|
||||
name="password"
|
||||
:placeholder="$t('auth.password')"
|
||||
prepend-inner-icon="icon-password"
|
||||
type="password"
|
||||
color="accent"
|
||||
outlined
|
||||
v-model="password"
|
||||
:rules="rules.password"
|
||||
v-if="isLogin || isReset"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
id="password_confirmation"
|
||||
name="password_confirmation"
|
||||
placeholder="Wachtwoord bevestiging"
|
||||
prepend-inner-icon="icon-password"
|
||||
type="password"
|
||||
outlined
|
||||
v-model="passwordConfirmation"
|
||||
:rules="rules.password_confirmation"
|
||||
v-if="isReset"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
block
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
depressed
|
||||
v-if="isLogin"
|
||||
@click="validate"
|
||||
:disabled="!valid"
|
||||
>{{ $t('auth.login.cta') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
block
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
depressed
|
||||
v-if="isForgotten"
|
||||
@click="validate"
|
||||
:disabled="!valid"
|
||||
>{{ $t('auth.password_forgotten.cta') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
block
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
depressed
|
||||
v-if="isReset"
|
||||
@click="validate"
|
||||
:disabled="!valid || !isValidToken"
|
||||
>{{ $t('auth.password_reset.cta') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
|
||||
<v-card-actions class="d-flex justify-space-between" v-if="isLogin">
|
||||
<!-- <v-checkbox
|
||||
on-icon="icon-selectionbox-checked"
|
||||
off-icon="icon-selectionbox"
|
||||
style="margin-left: 10px;"
|
||||
v-model="check"
|
||||
:label="$t('auth.keep_logged')"
|
||||
value="secondary"
|
||||
rounded
|
||||
></v-checkbox> -->
|
||||
<nuxt-link
|
||||
class="info--text"
|
||||
:to="localePath('/auth/password-forgotten')"
|
||||
>{{ $t('auth.password_forgotten.question') }}</nuxt-link
|
||||
>
|
||||
</v-card-actions>
|
||||
|
||||
<!-- <v-card-actions class="d-flex justify-space-between" v-if="!isLogin">
|
||||
<nuxt-link
|
||||
class="info--text"
|
||||
:to="localePath('/auth/login')"
|
||||
>{{ $t('auth.account.question') }}</nuxt-link>
|
||||
</v-card-actions> -->
|
||||
</v-card>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import errorsList from '@/components/UI/ErrorsList/ErrorsList'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
errorsList,
|
||||
},
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'login',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
valid: true,
|
||||
check: true,
|
||||
email: '',
|
||||
errors: null,
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
rules: {
|
||||
email: [
|
||||
(v) => !!v || this.$t('auth.validation.email.required'),
|
||||
(v) => v.length <= 50 || this.$t('auth.validation.email.max_length'),
|
||||
(v) =>
|
||||
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
v
|
||||
) || this.$t('auth.validation.email.invalid'),
|
||||
],
|
||||
password: [
|
||||
(v) => !!v || this.$t('auth.validation.password.required'),
|
||||
(v) =>
|
||||
(v && v.length >= 8) ||
|
||||
this.$t('auth.validation.password.min_length'),
|
||||
(v) =>
|
||||
(v && v.length <= 20) ||
|
||||
this.$t('auth.validation.password.max_min_length'),
|
||||
],
|
||||
password_confirmation: [
|
||||
(v) =>
|
||||
v === this.password ||
|
||||
this.$t('auth.validation.password.confirmation'),
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLogin() {
|
||||
return this.mode === 'login'
|
||||
},
|
||||
isForgotten() {
|
||||
return this.mode === 'password-forgotten'
|
||||
},
|
||||
isReset() {
|
||||
return this.mode === 'password-reset'
|
||||
},
|
||||
isValidToken() {
|
||||
return this.$route.query.token.length === 64 && this.$route.query.token
|
||||
},
|
||||
hasErrors() {
|
||||
return this.backendErrors.length > 0
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
async validate() {
|
||||
if (!this.$refs.form.validate()) return
|
||||
if (this.isLogin) await this.login()
|
||||
if (this.isForgotten) await this.askToResetPassword()
|
||||
if (this.isReset) await this.resetPassword()
|
||||
},
|
||||
// reset() {
|
||||
// this.$refs.form.reset()
|
||||
// },
|
||||
// resetValidation() {
|
||||
// this.$refs.form.resetValidation()
|
||||
// },
|
||||
async login() {
|
||||
try {
|
||||
await this.$auth.loginWith('local', {
|
||||
data: {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
},
|
||||
})
|
||||
this.$router.push('/manager')
|
||||
} catch (error) {
|
||||
this.errors = error.response.data.errors
|
||||
this.$notifier.showMessage({
|
||||
content: error.response.data.message,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
},
|
||||
async askToResetPassword() {
|
||||
if (!this.isForgotten) return
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('auth/password/email', {
|
||||
email: this.email,
|
||||
})
|
||||
this.$notifier.showMessage({
|
||||
content: this.$t('auth.notifications.request_accepted'),
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
this.errors = error.response.data.errors
|
||||
this.$notifier.showMessage({
|
||||
content: error.response.data.error,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async resetPassword() {
|
||||
if (!this.isReset) return
|
||||
if (!this.isValidToken) return
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('auth/password/reset', {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
password_confirmation: this.passwordConfirmation,
|
||||
token: this.$route.query.token,
|
||||
})
|
||||
this.$notifier.showMessage({
|
||||
content: this.$t('auth.notifications.password_changed'),
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
|
||||
this.$router.push('/auth/login')
|
||||
|
||||
} catch (error) {
|
||||
this.errors = error.response.data.errors
|
||||
this.$notifier.showMessage({
|
||||
content: error.response.data.error,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info--text {
|
||||
text-decoration: none;
|
||||
}
|
||||
.v-card__title,
|
||||
.v-card__text {
|
||||
word-break: normal;
|
||||
}
|
||||
</style>
|
||||
57
components/Card.vue
Normal file
57
components/Card.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-card flat :elevation="hover ? 8 : 0" @click.prevent="$router.push(route)" color="primary">
|
||||
<v-card-text class="d-flex justify-space-between">
|
||||
<div class="d-flex">
|
||||
<v-avatar
|
||||
size="60"
|
||||
:color="hover ? 'accent' : 'deep-orange lighten-5'"
|
||||
>
|
||||
<v-icon :color="hover ? 'white' : 'accent'">{{ icon }}</v-icon>
|
||||
</v-avatar>
|
||||
|
||||
<div v-if="count" class="mx-6 txt--text">
|
||||
<v-card-title class="font-weight-bold my-0 pa-0">
|
||||
{{ count }}
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="count" class="my-0 pa-0">
|
||||
{{ label }}
|
||||
</v-card-subtitle>
|
||||
</div>
|
||||
|
||||
<div v-else class="mx-6 txt--text d-flex align-center">
|
||||
<v-card-title class="my-0 pa-0 text-subtitle-1">
|
||||
{{ label }}
|
||||
</v-card-title>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot></slot>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
route: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
66
components/ComponentsBar/ComponentsBar.vue
Normal file
66
components/ComponentsBar/ComponentsBar.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<v-toolbar dense flat>
|
||||
<v-overflow-btn
|
||||
:items="components"
|
||||
item-text="name"
|
||||
return-object
|
||||
v-model="componentSelected"
|
||||
label="Select Component"
|
||||
hide-details
|
||||
class="pa-0"
|
||||
flat
|
||||
></v-overflow-btn>
|
||||
<v-btn text @click="addComponent">
|
||||
<v-icon small>icon-add</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: Number
|
||||
},
|
||||
model: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
componentSelected: '',
|
||||
components: []
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.getComponents()
|
||||
},
|
||||
methods: {
|
||||
async getComponents() {
|
||||
try {
|
||||
const response = await this.$axios.get(`/components`)
|
||||
this.components = response.data
|
||||
} catch (error) {
|
||||
console.log('TCL: getComponents -> error', error)
|
||||
}
|
||||
},
|
||||
async addComponent() {
|
||||
const data = {
|
||||
model: this.model,
|
||||
model_id: this.id,
|
||||
component_id: this.componentSelected.id
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('/components/attach', data)
|
||||
const modelReturned = response.data;
|
||||
|
||||
this.componentSelected = null
|
||||
} catch (error) {
|
||||
console.log('TCL: addComponent -> error', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
108
components/ComponentsListToggler/ComponentsListToggler.vue
Normal file
108
components/ComponentsListToggler/ComponentsListToggler.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<v-card class="mx-auto" tile>
|
||||
<v-toolbar color="error" dark flat>
|
||||
<v-toolbar-title>Components</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn depressed color="white" light :to="localePath('/manager/components/create')" text>
|
||||
<v-icon small>icon-add</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-text>
|
||||
<v-list>
|
||||
<v-list-item-group
|
||||
v-model="selected"
|
||||
multiple
|
||||
active-class="pink--text"
|
||||
@change="syncComponents"
|
||||
>
|
||||
<template v-for="(item, index) in components">
|
||||
<v-list-item :key="item.name" :value="item.id">
|
||||
<template v-slot:default="{ active, toggle }">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.name"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action>
|
||||
<v-switch :value="isAdded(item.id)" :disabled="loading" />
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider v-if="index + 1 < components.length" :key="index"></v-divider>
|
||||
</template>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
model_id: {
|
||||
type: Number
|
||||
},
|
||||
model: {
|
||||
type: String
|
||||
},
|
||||
componentsAttachedIds: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
components: [],
|
||||
selected: [],
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
componentsAttachedIds() {
|
||||
this.copyComponentsIds()
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.getComponents()
|
||||
this.copyComponentsIds()
|
||||
},
|
||||
methods: {
|
||||
copyComponentsIds() {
|
||||
this.selected = [...this.componentsAttachedIds]
|
||||
},
|
||||
|
||||
isAdded(componentId) {
|
||||
return this.componentsAttachedIds.includes(componentId)
|
||||
},
|
||||
|
||||
async getComponents() {
|
||||
try {
|
||||
this.loading = true
|
||||
const response = await this.$axios.get(`/components`)
|
||||
this.components = response.data
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('TCL: getComponents -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
async syncComponents() {
|
||||
this.loading = true
|
||||
const data = {
|
||||
model: this.model,
|
||||
model_id: this.model_id,
|
||||
components_ids: this.selected
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('/components/sync', data)
|
||||
this.$emit('reload-resource')
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('TCL: syncComponents -> error', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
58
components/CurrentDateTime/CurrentDateTime.vue
Normal file
58
components/CurrentDateTime/CurrentDateTime.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div class="d-flex">
|
||||
<small class="my-4 font-weight-light mr-4 txt--text">
|
||||
<v-icon size="12" color="teal" class="icon-checkmark mr-2" v-if="showIcon"></v-icon>
|
||||
{{ timestamp }}</small
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timestamp: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setInterval(this.getNow, 1000)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getNow() {
|
||||
const months = [
|
||||
this.$t('general.date.january'),
|
||||
this.$t('general.date.february'),
|
||||
this.$t('general.date.march'),
|
||||
this.$t('general.date.april'),
|
||||
this.$t('general.date.may'),
|
||||
this.$t('general.date.june'),
|
||||
this.$t('general.date.july'),
|
||||
this.$t('general.date.august'),
|
||||
this.$t('general.date.september'),
|
||||
this.$t('general.date.october'),
|
||||
this.$t('general.date.november'),
|
||||
this.$t('general.date.december'),
|
||||
]
|
||||
const now = new Date()
|
||||
const day = now.getDate()
|
||||
const month = now.getMonth()
|
||||
const year = now.getFullYear()
|
||||
|
||||
let h = now.getHours() < 10 ? '0' + now.getHours() : now.getHours()
|
||||
let m = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes()
|
||||
|
||||
const date = `${day} ${months[month]} ${year}`
|
||||
const time = `${h}:${m}`
|
||||
this.timestamp = `${date}`
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
123
components/DynamicComponents/Calendar.vue
Normal file
123
components/DynamicComponents/Calendar.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-sheet tile height="54" color="grey lighten-3" class="d-flex">
|
||||
<v-btn icon class="ma-2" @click="$refs.calendar.prev()">
|
||||
<v-icon x-small>icon-dropdown-left</v-icon>
|
||||
</v-btn>
|
||||
<v-select v-model="type" :items="types" dense outlined hide-details class="ma-2" label="type"></v-select>
|
||||
<v-select
|
||||
v-model="mode"
|
||||
:items="modes"
|
||||
dense
|
||||
outlined
|
||||
hide-details
|
||||
label="event-overlap-mode"
|
||||
class="ma-2"
|
||||
></v-select>
|
||||
<v-select
|
||||
v-model="weekday"
|
||||
:items="weekdays"
|
||||
dense
|
||||
outlined
|
||||
hide-details
|
||||
label="weekdays"
|
||||
class="ma-2"
|
||||
></v-select>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon class="ma-2" @click="$refs.calendar.next()">
|
||||
<v-icon x-small>icon-dropdown-right</v-icon>
|
||||
</v-btn>
|
||||
</v-sheet>
|
||||
<v-sheet height="600">
|
||||
<v-calendar
|
||||
ref="calendar"
|
||||
v-model="value"
|
||||
:weekdays="weekday"
|
||||
:type="type"
|
||||
:events="events"
|
||||
:event-overlap-mode="mode"
|
||||
:event-overlap-threshold="30"
|
||||
:event-color="getEventColor"
|
||||
@change="getEvents"
|
||||
></v-calendar>
|
||||
</v-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
type: 'month',
|
||||
types: ['month', 'week', 'day', '4day'],
|
||||
mode: 'stack',
|
||||
modes: ['stack', 'column'],
|
||||
weekday: [0, 1, 2, 3, 4, 5, 6],
|
||||
weekdays: [
|
||||
{ text: 'Sun - Sat', value: [0, 1, 2, 3, 4, 5, 6] },
|
||||
{ text: 'Mon - Sun', value: [1, 2, 3, 4, 5, 6, 0] },
|
||||
{ text: 'Mon - Fri', value: [1, 2, 3, 4, 5] },
|
||||
{ text: 'Mon, Wed, Fri', value: [1, 3, 5] }
|
||||
],
|
||||
value: '',
|
||||
events: [],
|
||||
colors: [
|
||||
'blue',
|
||||
'indigo',
|
||||
'deep-purple',
|
||||
'cyan',
|
||||
'green',
|
||||
'orange',
|
||||
'grey darken-1'
|
||||
],
|
||||
names: [
|
||||
'Meeting',
|
||||
'Holiday',
|
||||
'PTO',
|
||||
'Travel',
|
||||
'Event',
|
||||
'Birthday',
|
||||
'Conference',
|
||||
'Party'
|
||||
]
|
||||
}),
|
||||
methods: {
|
||||
getEvents({ start, end }) {
|
||||
const events = []
|
||||
|
||||
const min = new Date(`${start.date}T00:00:00`)
|
||||
const max = new Date(`${end.date}T23:59:59`)
|
||||
const days = (max.getTime() - min.getTime()) / 86400000
|
||||
const eventCount = this.rnd(days, days + 20)
|
||||
|
||||
for (let i = 0; i < eventCount; i++) {
|
||||
const allDay = this.rnd(0, 3) === 0
|
||||
const firstTimestamp = this.rnd(min.getTime(), max.getTime())
|
||||
const first = new Date(firstTimestamp - (firstTimestamp % 900000))
|
||||
const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
|
||||
const second = new Date(first.getTime() + secondTimestamp)
|
||||
|
||||
events.push({
|
||||
name: this.names[this.rnd(0, this.names.length - 1)],
|
||||
start: this.formatDate(first, !allDay),
|
||||
end: this.formatDate(second, !allDay),
|
||||
color: this.colors[this.rnd(0, this.colors.length - 1)]
|
||||
})
|
||||
}
|
||||
|
||||
this.events = events
|
||||
},
|
||||
getEventColor(event) {
|
||||
return event.color
|
||||
},
|
||||
rnd(a, b) {
|
||||
return Math.floor((b - a + 1) * Math.random()) + a
|
||||
},
|
||||
formatDate(a, withTime) {
|
||||
return withTime
|
||||
? `${a.getFullYear()}-${a.getMonth() +
|
||||
1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}`
|
||||
: `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
30
components/DynamicComponents/Card.vue
Normal file
30
components/DynamicComponents/Card.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<v-card class="mx-auto my-12" max-width="374">
|
||||
<v-img height="250" :src="data.image" cover></v-img>
|
||||
|
||||
<v-card-title>{{data.title}}</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-row align="center" class="mx-0">
|
||||
<v-rating :value="4.5" color="amber" dense half-increments readonly size="14"></v-rating>
|
||||
|
||||
<div class="grey--text ml-4">4.5 (413)</div>
|
||||
</v-row>
|
||||
|
||||
<div class="my-4 subtitle-1 black--text">$ • Italian, Cafe</div>
|
||||
|
||||
<div>Small plates, salads & sandwiches - an intimate setting with 12 indoor seats plus patio seating.</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
data: Object
|
||||
},
|
||||
data: () => ({}),
|
||||
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
47
components/DynamicComponents/Carousel.vue
Normal file
47
components/DynamicComponents/Carousel.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<v-carousel>
|
||||
<v-carousel-item
|
||||
v-for="(item,i) in items"
|
||||
:key="i"
|
||||
:src="item"
|
||||
reverse-transition="fade-transition"
|
||||
transition="fade-transition"
|
||||
>
|
||||
<v-row class="fill-height" align="center" justify="center">
|
||||
<div class="display-3">Title</div>
|
||||
</v-row>
|
||||
|
||||
<!-- <div class="display-3 pa-4">Title</div> -->
|
||||
</v-carousel-item>
|
||||
</v-carousel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
data: Object
|
||||
},
|
||||
|
||||
computed: {
|
||||
items() {
|
||||
// Returns an array with all the imageX fields
|
||||
|
||||
// Iterate data where key === image__ and return the value;
|
||||
let filtered_keys = (obj, filter) => {
|
||||
let key,
|
||||
keys = []
|
||||
for (key in obj)
|
||||
if (obj.hasOwnProperty(key) && filter.test(key)) keys.push(key)
|
||||
return keys
|
||||
}
|
||||
|
||||
const keys = filtered_keys(this.data, /img_carousel_/)
|
||||
|
||||
return keys.map(key => {
|
||||
if (this.data[key]) return this.data[key]
|
||||
return null
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
59
components/Event/Event.vue
Normal file
59
components/Event/Event.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<v-card class="mx-auto my-12" max-width="374">
|
||||
<v-img height="250" src="https://cdn.vuetifyjs.com/images/cards/cooking.png"></v-img>
|
||||
|
||||
<v-card-title>Cafe Badilico</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-row align="center" class="mx-0">
|
||||
<v-rating :value="4.5" color="amber" dense half-increments readonly size="14"></v-rating>
|
||||
|
||||
<div class="grey--text ml-4">4.5 (413)</div>
|
||||
</v-row>
|
||||
|
||||
<div class="my-4 subtitle-1 black--text">$ • Italian, Cafe</div>
|
||||
|
||||
<div>Small plates, salads & sandwiches an inteimate setting with 12 indoor seats plus patio seating.</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider class="mx-4"></v-divider>
|
||||
|
||||
<v-card-title>Tonight's availability</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-chip-group v-model="selection" active-class="deep-purple accent-4 white--text" column>
|
||||
<v-chip>5:30PM</v-chip>
|
||||
|
||||
<v-chip>7:30PM</v-chip>
|
||||
|
||||
<v-chip>8:00PM</v-chip>
|
||||
|
||||
<v-chip>9:00PM</v-chip>
|
||||
</v-chip-group>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn color="deep-purple accent-4" text @click="reserve">Reserve</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
loading: false,
|
||||
selection: 1
|
||||
}),
|
||||
|
||||
methods: {
|
||||
reserve() {
|
||||
this.loading = true
|
||||
|
||||
setTimeout(() => (this.loading = false), 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
42
components/Hero/Hero.vue
Normal file
42
components/Hero/Hero.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<v-container fluid>
|
||||
<v-card tile flat>
|
||||
<v-img
|
||||
class="white--text"
|
||||
gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)"
|
||||
height="480px"
|
||||
:lazy-src="require('@/assets/img/newsletter.jpg')"
|
||||
>
|
||||
<div class="d-flex justify-space-between flex-column fill-height">
|
||||
<span class="display-1 ma-4 pa-4">In the mood for black and yellow..</span>
|
||||
<div class="d-flex justify-space-between ma-4 pa-4">
|
||||
<v-btn
|
||||
v-for="(btn, i) in buttons"
|
||||
:key="i"
|
||||
tile
|
||||
depressed
|
||||
light
|
||||
class="px-6"
|
||||
color="#ffcc00"
|
||||
x-large
|
||||
>{{btn.label}}</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-img>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
buttons: [
|
||||
{ label: 'Sierkussens', link: '' },
|
||||
{ label: 'Vloerkleden', link: '' },
|
||||
{ label: 'Salontafels', link: '' },
|
||||
{ label: 'Banken', link: '' },
|
||||
{ label: 'Leeslampen', link: '' }
|
||||
]
|
||||
})
|
||||
}
|
||||
</script>
|
||||
100
components/Info/Cookies.vue
Normal file
100
components/Info/Cookies.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="text">
|
||||
<h2>Wat zijn cookies?</h2>
|
||||
<p>Een cookie is een simpel, klein bestand dat met pagina’s van deze wordt meegestuurd. Een cookie wordt door uw browser op de harde schrijf van uw apparaat opgeslagen. Sommige van deze cookies zijn nodig om de site te laten werken; andere helpen ons de website te verbeteren en gebruiksvriendelijker te maken. De met behulp van de cookies opgeslagen informatie kan bij een volgend bezoek weer naar onze servers teruggestuurd worden.</p>
|
||||
<p>Cookies hebben veel verschillende functies. Ze helpen ons bijvoorbeeld om jouw gegevens (zoals authenticatiegegevens), andere essentiële informatie en voorkeuren te onthouden. Cookies kunnen ons ook helpen om onze website te analyseren en kunnen ons in staat stellen om jou bepaalde inhoud aan te bevelen waarvan wij denken dat deze voor jou het meest relevant is.</p>
|
||||
<p>GGZ Ecademy maakt ook gebruik van technieken die vergelijkbaar zijn met cookies, zoals link-tracking. Bij link-tracking worden bepaalde elementen toegevoegd aan een URL, zodat wij u kunnen herkennen als u vanuit onze e-mails doorklikt naar onze website. Hierna zullen cookies en vergelijkbare technieken samen (“Cookies”) worden genoemd.</p>
|
||||
<p>
|
||||
Bepaalde cookies bevatten persoonsgegevens. Meer informatie over welke persoonsgegevens we precies voor welke doeleinden verwerken, kun je vinden in onze
|
||||
<a
|
||||
href="https://ggzecademy.nl/privacy/"
|
||||
>privacyverklaring</a>.
|
||||
</p>
|
||||
<h2>Wat voor soort cookies en andere trackingtechnologieën gebruiken wij?</h2>
|
||||
<p>Over het algemeen voeren onze cookies en soortgelijke volgtechnologieën de volgende verschillende functies uit:</p>
|
||||
<h3>Essentiële / functionele cookies</h3>
|
||||
<p>Deze cookies zijn essentieel voor de kernactiviteit van onze website en worden automatisch ingeschakeld wanneer je de website gebruikt. We slaan je machtigingsinstelling ook op in een cookie om dit te onthouden voor toekomstige bezoeken.</p>
|
||||
<p>Concreet gebruiken wij de volgende essentiële /functionele cookies:</p>
|
||||
<h4>
|
||||
<em>
|
||||
<strong>GGZ Ecademy</strong>
|
||||
</em>
|
||||
</h4>
|
||||
<p>
|
||||
Wie: ggzecademy.nl
|
||||
<br />Doel: het onthouden van een gegeven akkoord op de cookieverklaring, reeds gesloten pop-ups en waar de gebruiker zich bevindt op niveau hoofdstructuur (scholen, instellingen, lid worden).
|
||||
<br />Cookies: Cookie_notice_accepted, Popup-extra-info-closed, Ggzroot
|
||||
<br />Welke persoonsgegevens: met deze cookie worden geen persoonsgegevens verwerkt.
|
||||
<br />Bewaartermijn: 7 dagen
|
||||
<br />Type cookie: functioneel
|
||||
</p>
|
||||
<h3>Analytische cookies</h3>
|
||||
<p>Deze cookies helpen de prestaties van de website te verbeteren en zorgen voor een betere gebruikerservaring. Dit stelt ons in staat om je een hoogwaardige ervaring te bieden door onze website en inhoud aan te passen en snel problemen te identificeren en op te lossen. We gebruiken bijvoorbeeld prestatiecookies om bij te houden welke pagina’s het populairst zijn, welke methode van koppeling tussen pagina’s het meest effectief is en om te bepalen waarom sommige pagina’s foutmeldingen ontvangen. Je kunt ervoor kiezen deze cookies uit te schakelen. De statistieken en overige rapportages zijn niet te herleiden tot individuele personen.</p>
|
||||
<p>Concreet gebruiken wij de volgende analytische cookies:</p>
|
||||
<p>
|
||||
<em>
|
||||
<strong>Google Analytics</strong>
|
||||
</em>
|
||||
<br />Wie: ggzecademy.nl
|
||||
<br />Doel: het analyseren van het gebruik van onze website en diensten en het verbeteren van onze website en diensten.
|
||||
<br />Cookies: _utma, _utmb, _utmc, _utmv, _ga, _gat_[tracker]
|
||||
<br />Welke persoonsgegevens: wij zien enkel globale statistieken en geanonimiseerde gegevens. Google Analytics software verwerkt uw gegevens om tot deze statistieken te komen. Zo verwerkt Google Analytics o.a. van welke website u afkomstig bent, naar welke pagina of website u surft, uw klikgedrag en gebruik van onze website en gegevens over het apparaat waarmee u onze website bezoekt (zoals besturingssysteem, schermresolutie, algemene locatie (tot op stadsniveau), geslacht, taal, sessieduur, browserinformatie). Uw data wordt niet met Google gedeeld.
|
||||
<br />Bewaartermijn: 24 maanden
|
||||
<br />Type cookie: analytisch
|
||||
</p>
|
||||
<h3>Marketing en tracking cookies</h3>
|
||||
<p>We werken samen met derden om advertenties op onze website weer te geven of om onze advertenties op andere sites te beheren. Indien je ons toestemming geeft voor het plaatsen van marketing en/of tracking cookies, dan kan die derde technologieën zoals cookies of vergelijkbare technologieën gebruiken om informatie te verzamelen over jouw activiteiten op deze website en andere sites om je reclame te bieden op basis van jouw browse-activiteiten en interesses. Je kan gegeven toestemming altijd intrekken door je cookie instellingen aan te passen.</p>
|
||||
<p>Concreet gebruiken wij de volgende marketing en tracking cookies:</p>
|
||||
<p>
|
||||
<em>
|
||||
<strong>Facebook & Instagram</strong>
|
||||
</em>
|
||||
<br />Wie: ggzecademy.nl
|
||||
<br />Doel: Facebook gebruikt deze cookies om conversie van posts en advertenties op onze website te meten.
|
||||
<br />Cookies: fbp, fbc, locale, c_user, csm, datr, fr, lu, xs, pk, s, p, act, x-src, presence
|
||||
<br />Welke persoonsgegevens: wij verwerken uw User ID, IP-adres en de datum dat u onze website heeft bezocht. De cookie wordt geplaatst via Google Tag Manager.
|
||||
<br />Bewaartermijn: tot 1 jaar na uw bezoek aan onze website
|
||||
<br />Type cookie: tracking pixel
|
||||
</p>
|
||||
<p>
|
||||
<em>
|
||||
<strong>LinkedIn</strong>
|
||||
</em>
|
||||
<br />Wie: ggzecademy.nl
|
||||
<br />Doel: LinkedIn gebruikt deze cookies om conversie van posts en advertenties op onze website te meten.
|
||||
<br />Cookies: lidc, bcookie, bscookie, L1c, BizoID, BizoData, BizoUserMatchHistory, BizoNetworkPartnerIndex
|
||||
<br />Welke persoonsgegevens: wij verwerken uw browser ID en hoe u met advertenties van/op LinkedIn omgaat.
|
||||
<br />Bewaartermijn: tot 1 jaar na uw bezoek aan onze website
|
||||
<br />Type cookie: tracking
|
||||
</p>
|
||||
<p>
|
||||
<em>
|
||||
<strong>Twitter</strong>
|
||||
</em>
|
||||
<br />Wie: ggzecademy.nl
|
||||
<br />Doel: deze cookie worden gebruikt om conversie van tweets en advertenties op onze website te meten.
|
||||
<br />Cookies: muc
|
||||
<br />Welke persoonsgegevens: wij verwerken enkel anonieme conversie informatie over u.
|
||||
<br />Bewaartermijn: tot 2 jaar na uw bezoek aan onze website
|
||||
<br />Type cookie: tracking
|
||||
</p>
|
||||
<h2>Derden</h2>
|
||||
<p>Onze websites kunnen knoppen, widgets, hulpmiddelen of inhoud bevatten die linken naar services van andere bedrijven (bijvoorbeeld een Facebook-knop ‘Vind ik leuk’ of de knop ‘Delen’). We kunnen informatie verzamelen over jouw gebruik van deze functies. Wanneer je deze knoppen, gereedschappen of inhoud ziet of gebruikt, of als je een webpagina bekijkt die deze bevat, kan bovendien bepaalde informatie uit je browser automatisch naar het andere bedrijf worden verzonden. Lees het privacybeleid van dat bedrijf voor meer informatie.</p>
|
||||
<h2>Hoe kan ik cookies beheren?</h2>
|
||||
<p>Als je cookies wilt accepteren of weigeren, dan kan je dat regelen via het hulpmiddel voor toestemmingsinstellingen op onze website. Deze tool wordt automatisch geladen bij het eerste bezoek van de site.</p>
|
||||
<p>Wij geven u de keuze om Cookies te accepteren of weigeren (met uitzondering van functionele cookies). Daarnaast kunt u ook uw web browser instellingen aanpassen om cookies te weigeren. Hierdoor kan het zijn dat onze website niet meer volledig functioneert.</p>
|
||||
<p>We stellen de essentiële / vereiste cookies in, zodat we jouw keuzes kunnen onthouden wanneer je de website de volgende keer vanuit dezelfde browser bezoekt.</p>
|
||||
<p>Versie 1.0 – 03 oktober 2019</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text {
|
||||
text-align: justify;
|
||||
text-justify: inter-word;
|
||||
}
|
||||
</style>
|
||||
28
components/Info/Disclaimer.vue
Normal file
28
components/Info/Disclaimer.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="text">
|
||||
<p>GGZ Ecademy Coöperatie U.A. (Kamer van Koophandel: 59018062), hierna te noemen GGZ Ecademy, verleent u hierbij toegang tot www.ggzecademy.nl (“de Website”).</p>
|
||||
<p>Op het gebruik van deze website (www.ggzecademy.nl) zijn onderstaande gebruiksvoorwaarden van toepassing. Door gebruik te maken van deze website, wordt u geacht kennis te hebben genomen van de gebruiksvoorwaarden en deze te hebben aanvaard.</p>
|
||||
<h2>Gebruik van informatie</h2>
|
||||
<p>GGZ Ecademy streeft ernaar op deze website altijd juiste en actuele informatie aan te bieden. Hoewel deze informatie met de grootst mogelijke zorgvuldigheid is samengesteld, staat GGZ Ecademy niet in voor de volledigheid, juistheid of actualiteit van de informatie. De juridische informatie op de website is van algemene aard en kan niet worden beschouwd als een vervangen van juridisch advies.</p>
|
||||
<p>Aan de informatie kunnen geen rechten worden ontleend. GGZ Ecademy aanvaardt geen aansprakelijkheid voor schade die voortvloeit uit het gebruik van de informatie of de website en evenmin voor het niet goed functioneren van de website. Op basis van het verzenden en ontvangen van informatie via de website of via e-mail kan niet zonder meer een relatie tussen GGZ Ecademy en de gebruiker van de website ontstaan.</p>
|
||||
<h2>Auteursrechten</h2>
|
||||
<p>Alle rechten van intellectuele eigendom betreffende deze materialen liggen bij GGZ Ecademy of haar licentiegevers. Kopiëren, verspreiden en elk ander gebruik van deze materialen is niet toegestaan zonder schriftelijke toestemming van GGZ Ecademy, behoudens en slechts voor zover anders bepaald in regelingen van dwingend recht (zoals citaatrecht), tenzij bij specifieke materialen anders aangegeven is.</p>
|
||||
<h2>E-mail</h2>
|
||||
<p>GGZ Ecademy garandeert niet dat aan haar gezonden e-mails worden ontvangen of verwerkt, omdat tijdige ontvangst van e-mails niet kan worden gegarandeerd. Ook de veiligheid van het e-mailverkeer kan niet volledig worden gegarandeerd door de hieraan verbonden veiligheidsrisico’s. Door zonder encryptie of wachtwoordbeveiliging per e-mail met GGZ Ecademy te corresponderen, accepteert u dit risico.</p>
|
||||
<h2>Hyperlinks</h2>
|
||||
<p>Deze website kan hyperlinks bevatten naar websites van derden. GGZ Ecademy heeft geen invloed op websites van derden en is niet verantwoordelijk voor de beschikbaarheid of inhoud daarvan. GGZ Ecademy aanvaardt dan ook geen aansprakelijkheid voor schade die voortvloeit uit het gebruik van websites van derden.</p>
|
||||
<h2>Overig</h2>
|
||||
<p>Deze disclaimer kan van tijd tot tijd wijzigen. De laatste wijziging was op 9 juni 2019.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text {
|
||||
text-align: justify;
|
||||
text-justify: inter-word;
|
||||
}
|
||||
</style>
|
||||
338
components/Info/Privacy.vue
Normal file
338
components/Info/Privacy.vue
Normal file
@@ -0,0 +1,338 @@
|
||||
<template>
|
||||
<div class="text">
|
||||
<h2>1. Wie zijn wij?</h2>
|
||||
<p>GGZ Ecademy Coöperatie U.A. (‘GGZ Ecademy’) is een Nederlands bedrijf. Wij zijn actief in de Europese Economische Ruimte (EER) en wij bewaren onze gegevens op servers in de EER, tenzij anders aangegeven.</p>
|
||||
<p>
|
||||
Wij verwerken uw persoonsgegevens als u gebruik maakt van onze dienstverlening, applicaties, websites en software. Dit noemen wij hierna de “Dienst”. In deze privacyverklaring vatten wij samen wanneer en hoe wij uw persoonsgegevens verzamelen, gebruiken en beveiligen. Wij zullen een onderscheid maken tussen persoonsgegevens die we verzamelen voor ons Centrale Leerplatform (het CLP) en de persoonsgegevens die we verzamelen voor de algemene website
|
||||
<a
|
||||
href="https://www.ggzecademy.nl"
|
||||
>https://www.ggzecademy.nl</a>.
|
||||
</p>
|
||||
<h2>2. Algemeen</h2>
|
||||
<p>Wij kunnen bepalingen van deze privacyverklaring wijzigen. Als wij dat doen, dan laten wij u dat weten. Toch raden wij u aan af en toe zelf te controleren of de privacyverklaring is gewijzigd.</p>
|
||||
<h2>3. Welke persoonsgegevens verzamelen we en voor welke doeleinden?</h2>
|
||||
<p>Er zijn een aantal manieren waarop wij uw persoonsgegevens kunnen verzamelen. In deze paragraaf leggen wij u uit welke persoonsgegevens wij van u kunnen verzamelen. De persoonsgegevens zijn gesorteerd naar de website en het CLP en vervolgens nader gesorteerd naar de verschillende verwerkingsdoelen. Naast ieder doel staat hoe lang de persoonsgegevens voor dat doel worden bewaard. Indien zich wijzigingen voordoen in wettelijke bewaartermijnen, dan gaan die voor op de bewaartermijnen die in deze privacyverklaring worden genoemd.</p>
|
||||
<h3>
|
||||
3.1 Persoonsgegevens die we verwerken indien u
|
||||
<a
|
||||
href="https://www.ggzecademy.nl"
|
||||
>https://www.ggzecademy.nl</a> bezoekt
|
||||
</h3>
|
||||
<p>De volgende persoonsgegevens zijn rechtstreeks door ons verzameld of rechtstreeks door u aan ons aangeleverd bij uw gebruik van onze website.</p>
|
||||
<p>
|
||||
<u>a. Verwerkingen die noodzakelijk zijn voor leveren van onze dienstverlening en het uitvoeren van overeenkomsten</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Indien u deelneemt aan de redactieraad: wij bewaren de persoonsgegevens voor dit doeleinde zolang u deelneemt aan de redactieraad en tot 2 jaar nadat u de redactieraad hebt verlaten</u>
|
||||
<br />• uw naam
|
||||
<br />• uw privé en/of zakelijk e-mailadres (o.a. voor het opnemen van contact)
|
||||
<br />• uw telefoonnummer (werk of privé)
|
||||
<br />• uw werkgever
|
||||
<br />• uw werk-gerelateerde functie
|
||||
<br />• uw curriculum vitae
|
||||
<br />• uw specialisme (optioneel)
|
||||
<br />• uw toelichting in het open vlak
|
||||
</li>
|
||||
<li>
|
||||
<u>Indien u zich aanmeldt voor een training: wij bewaren de persoonsgegevens voor dit doeleinde tot 2 jaar nadat de training is afgerond</u>
|
||||
<br />• uw naam
|
||||
<br />• uw e-mailadres
|
||||
<br />• uw telefoonnummer
|
||||
<br />• de organisatie waar u werkzaam bent
|
||||
<br />• overige persoonsgegevens die u invult bij het aanmelden voor een training
|
||||
</li>
|
||||
</ol>
|
||||
<p>Indien u gebruik wilt maken van de betreffende dienst, moet u deze persoonsgegevens verplicht aan ons verstrekken of door ons laten verzamelen. De reden hiervoor is dat wij deze gegevens nodig hebben om de dienst te leveren.</p>
|
||||
<p>
|
||||
<u>b. Verwerkingen voor het behartigen van onze gerechtvaardigde belangen</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Het verbeteren van onze dienstverlening: wij bewaren de persoonsgegevens voor dit doeleinde maximaal gedurende 24 maanden nadat zij zijn verzameld</u>
|
||||
<br />• een nummer om u te identificeren op onze diensten (user- of sessie-ID)
|
||||
<br />• gegevens over uw browser en apparaat waarmee u onze website bezoekt, zoals besturingssysteem en schermgrootte
|
||||
<br />• hoe lang u onze website bezoekt
|
||||
<br />• datum en tijdstip van bezoek
|
||||
<br />• welke zoekopdracht u onze website geeft
|
||||
<br />• hoe u op onze website terecht bent gekomenDe gegevens die wij verwerken voor het verbeteren van onze dienstverlening zijn in de regel niet te herleiden tot een individu.
|
||||
</li>
|
||||
<li>
|
||||
<u>Het veilig houden van de Dienst: wij bewaren de persoonsgegevens voor dit doeleinde maximaal 6 maanden nadat zij zijn verzameld</u>
|
||||
<br />• uw IP-adres
|
||||
<br />• een nummer om uw apparaat te identificeren op onze diensten (device-ID)
|
||||
<br />• een nummer om u te identificeren op onze diensten (user- of sessie-ID)
|
||||
<br />• het door u gebruikte besturingssysteem
|
||||
</li>
|
||||
<li>
|
||||
<u>Indien u bij ons solliciteert (ook indien u solliciteert voor de redactieraad): wij bewaren de persoonsgegevens voor dit doeleinde tot maximaal 4 weken na het eindigen van de sollicitatieprocedure, of tot maximaal 1 jaar na het eindigen van de sollicitatieprocedure indien u daarom verzoekt</u>• uw naam
|
||||
<br />• uw adres
|
||||
<br />• uw e-mailadres
|
||||
<br />• uw telefoonnummer
|
||||
<br />• uw werkgever en werk-gerelateerde functie (indien u solliciteert voor de redactieraad)
|
||||
<br />• uw motivatiebrief en curriculum vitae en de daarin verwerkte gegevens (zoals uw foto, opleidingen, stages, werkervaring en trainingen)
|
||||
<br />• gegevens over uw beschikbaarheid
|
||||
<br />• overige gegevens die u in het kader van uw sollicitatie hebt verstrekt
|
||||
</li>
|
||||
</ol>
|
||||
<p>Wij verwerken deze persoonsgegevens op basis van een belangenafweging. Wilt u de gegevens onder b, onder 1, 2 of 3 niet verstrekken, dan vragen wij u ons dit te laten weten onder vermelding van uw motivering. Wij zullen uw motivering meenemen en nogmaals de belangenafweging maken. Indien wij na de nieuwe belangenafweging tot de conclusie komen dat u uw persoonsgegevens toch dient te verstrekken, dan kunt u onze Dienst niet gebruiken indien u weigert de persoonsgegevens te verstrekken. Meer informatie over uw rechten kunt u hieronder onder het kopje ‘Uw rechten’ lezen.</p>
|
||||
<p>
|
||||
<u>c. Verwerking met uw toestemming</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Om u (op uw verzoek) te informeren over de door u gevolgde dienst of andere diensten van GGZ Ecademy door het sturen van nieuwsbrieven: wij bewaren de persoonsgegevens voor dit doeleinde totdat u zich uitschrijft</u>
|
||||
<br />• uw naam
|
||||
<br />• uw e-mailadres
|
||||
</li>
|
||||
<li>
|
||||
<u>Om u op uw verzoek te informeren en te antwoorden op uw vragen: wij bewaren de persoonsgegevens voor dit doeleinde tot maximaal twee jaar nadat wij voor het laatst e-mailcontact met u hebben gehad</u>
|
||||
<br />• uw naam
|
||||
<br />• de organisatie waar u werkzaam bent
|
||||
<br />• uw e-mailadres
|
||||
<br />• overige persoonsgegevens die u invult bij het opnemen van contact met GGZ Ecademy
|
||||
</li>
|
||||
<li>
|
||||
<u>Om advertenties over onze diensten te bieden op (andere) websites en om met advertentiepartners af te rekenen door conversie te meten: wij bewaren de persoonsgegevens voor dit doeleinde tot twee jaar nadat u voor het laatste onze website heeft bezocht</u>
|
||||
<br />• uw user-ID
|
||||
<br />• uw browser-ID
|
||||
<br />• uw IP-adres
|
||||
</li>
|
||||
</ol>
|
||||
<p>Wij kunnen tevens in algemene zin zien uit welke plaatsen onze bezoekers komen, welk geslacht ze hebben, tot welke inkomenscategorie ze behoren etc. Onderstaande gegevens zijn in beginsel geanonimiseerd en kunnen wij niet tot u persoonlijk herleiden. Het gaat om de volgende gegevens:</p>
|
||||
<ul>
|
||||
<li>uw locatie (tot op het niveau van de stad)</li>
|
||||
<li>uw taalinstellingen</li>
|
||||
<li>uw geslacht</li>
|
||||
<li>het bedrijf waar u werkt en gegevens over uw bedrijf</li>
|
||||
<li>uw functie</li>
|
||||
<li>tot welke inkomenscategorie u behoort</li>
|
||||
<li>wanneer u onze website heeft bezocht</li>
|
||||
<li>hoe u met onze advertenties omgaat</li>
|
||||
</ul>
|
||||
<p>U bent niet verplicht om deze persoonsgegevens aan ons te verstrekken. Indien u de persoonsgegevens niet aan ons verstrekt, dan heeft dit geen negatieve gevolgen voor uw gebruik van de Dienst. U kunt de Dienst dus gewoon blijven gebruiken. Wij verwerken deze persoonsgegevens alleen als u daarvoor toestemming heeft gegeven en ze worden ook pas verwerkt als u daadwerkelijk toestemming heeft gegeven of zelf de persoonsgegevens heeft verstrekt.</p>
|
||||
<h3>3.2 Persoonsgegevens die we verwerken indien u gebruik maakt van het CLP</h3>
|
||||
<p>
|
||||
De volgende persoonsgegevens zijn rechtstreeks door ons verzameld of rechtstreeks door u aan ons aangeleverd indien u het CLP gebruikt.
|
||||
<br />
|
||||
<u></u>
|
||||
</p>
|
||||
<p>
|
||||
<u>a. Administratieverplichtingen (wettelijke grondslag): wij bewaren de persoonsgegevens voor dit doeleinde maximaal 10 jaar</u>
|
||||
</p>
|
||||
<ul>
|
||||
<li>uw naam (enkel van leden)</li>
|
||||
<li>uw adres (enkel van leden)</li>
|
||||
<li>btw-identificatienummer (enkel van leden)</li>
|
||||
</ul>
|
||||
<p>Indien u gebruik wilt maken van onze Dienst, moet u deze persoonsgegevens verplicht aan ons verstrekken. De reden hiervoor is dat wij deze gegevens nodig hebben om te voldoen aan onze wettelijke verplichtingen.</p>
|
||||
<p>
|
||||
<u>b. Verwerkingen die noodzakelijk zijn voor het uitvoeren van een overeenkomst die u gesloten heeft (het aanbieden van het CLP),</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Algemeen: wij bewaren de persoonsgegevens voor dit doeleinde maximaal tot 2 jaar nadat u voor het laatst het CLP heeft gebruikt</u>
|
||||
<br />• uw naam
|
||||
<br />• uw privé en/of zakelijk e-mailadres (o.a. voor het opnemen van contact over het CLP)
|
||||
<br />• uw wachtwoord
|
||||
<br />• uw telefoonnummer (werk en privé)
|
||||
<br />• uw werkgever
|
||||
<br />• uw werk-gerelateerde functie
|
||||
<br />• uw systeemrol (bijvoorbeeld auteur, ontwerper, begeleider, student, beheerder)
|
||||
<br />• uw geboortedatum
|
||||
<br />• uw leerresultaten
|
||||
<br />• uw redenen voor een verzoek om toegang tot een specifieke leeromgeving te krijgen
|
||||
<br />• de overige persoonsgegevens die u invult bij het opnemen van contact met GGZ Ecademy
|
||||
<br />• mogelijke video-opnames bij events (wij zullen proberen u zo min mogelijk in beeld te brengen)
|
||||
</li>
|
||||
</ol>
|
||||
<p>Indien u gebruik wilt maken van onze Dienst, moet u deze persoonsgegevens verplicht aan ons verstrekken of door ons laten verzamelen. De reden hiervoor is dat deze persoonsgegevens nodig zijn om de Dienst aan u te kunnen leveren.</p>
|
||||
<p>
|
||||
<u>c. Verwerkingen voor het behartigen van onze gerechtvaardigde belangen</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Het verbeteren van onze dienstverlening, indien u deelneemt aan een vorm van evaluatie wij bewaren de persoonsgegevens voor dit doeleinde maximaal tot 2 jaar nadat de evaluatie heeft plaatsgevonden</u>
|
||||
<br />• het door u gevolgde leertraject
|
||||
<br />• (overige) ingevulde informatie bij het evaluatieformulier of vermeld tijdens een evaluatiegesprek
|
||||
<br />• uw werkgever
|
||||
</li>
|
||||
<li>
|
||||
<u>Het veilig houden van het CLP: wij bewaren de persoonsgegevens voor dit doeleinde maximaal 6 maanden nadat zij zijn verzameld</u>
|
||||
<br />• uw IP-adres
|
||||
<br />• een nummer om uw apparaat te identificeren op onze diensten (device-ID)
|
||||
<br />• een nummer om u te identificeren op onze diensten (user- of sessie-ID)
|
||||
<br />• het door u gebruikte besturingssysteem
|
||||
<br />• tijd, datum en plaats van inloggen
|
||||
</li>
|
||||
<li>
|
||||
<u>Om u te informeren over andere diensten van GGZ Ecademy: wij bewaren de persoonsgegevens voor dit doeleinde totdat u zich uitschrijft</u>
|
||||
<br />• uw e-mailadres (indien u dit verschaft bij het invullen van het evaluatieformulier)
|
||||
</li>
|
||||
</ol>
|
||||
<p>Wij verwerken deze persoonsgegevens op basis van een belangenafweging. Wilt u de gegevens onder c, onder 1 of 2 niet verstrekken, dan vragen wij u ons dit te laten weten onder vermelding van uw motivering. Wij zullen uw motivering meenemen en nogmaals de belangenafweging maken. Indien wij na de nieuwe belangenafweging tot de conclusie komen dat u uw persoonsgegevens toch dient te verstrekken, dan kunt u onze Dienst niet gebruiken indien u weigert de persoonsgegevens te verstrekken. Meer informatie over uw rechten kunt u hieronder onder het kopje ‘Uw rechten’ lezen.</p>
|
||||
<p>
|
||||
U kunt uzelf afmelden voor de verwerking genoemd onder c, onder 3 door de afmeldinginstructies te volgen die bij elke marketing e-mail zijn opgenomen. Als u zich afmeldt, dan heeft dit geen gevolg voor onze mogelijkheden om u belangrijke e-mails te sturen over de Dienst en uw account. Daarnaast heeft het geen gevolg voor onze mogelijkheid om uw persoonsgegevens te gebruiken zoals wij hebben beschreven in deze privacyverklaring.
|
||||
<br />
|
||||
<u></u>
|
||||
</p>
|
||||
<p>
|
||||
<u>d. Verwerking met uw toestemming</u>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<u>Om u (op uw verzoek) te informeren over de door u gevolgde dienst of andere diensten van GGZ Ecademy: wij bewaren de persoonsgegevens voor dit doeleinde totdat u zich uitschrijft</u>
|
||||
<br />• uw naam
|
||||
<br />• de organisatie waar u werkzaam bent
|
||||
<br />• uw e-mailadres
|
||||
</li>
|
||||
<li>
|
||||
<u>Om u op uw verzoek te informeren en te antwoorden op uw vragen: wij bewaren de persoonsgegevens voor dit doeleinde tot maximaal twee jaar nadat wij voor het laatst e-mailcontact met u hebben gehad</u>
|
||||
<br />• uw naam
|
||||
<br />• de organisatie waar u werkzaam bent
|
||||
<br />• uw e-mailadres
|
||||
<br />• overige persoonsgegevens die u invult bij het opnemen van contact met GGZ Ecademy
|
||||
</li>
|
||||
<li>
|
||||
<u>Vrijwillig ingevulde informatie in onze leeromgeving(en)/op onze websites om in contact te komen met andere cursisten of om beter te kunnen communiceren (ten behoeve van social-learning): wij bewaren de persoonsgegevens voor dit doeleinde maximaal tot 2 jaar nadat u voor het laatst het CLP heeft gebruikt</u>
|
||||
<br />• uw Twitter profiellink
|
||||
<br />• uw Skypenaam
|
||||
<br />• uw LinkedIn profiellink
|
||||
<br />• uw Facebook profiellink
|
||||
<br />• uw adres
|
||||
<br />• uw taal
|
||||
<br />• uw biografie en overige achtergrondinformatie
|
||||
<br />• uw foto
|
||||
<br />• door u opgegeven tags
|
||||
</li>
|
||||
<li>
|
||||
<u>Opleidingsportfolio (gebruik van het opleidingsportfolio is geheel vrijblijvend): wij bewaren de persoonsgegevens voor dit doeleinde maximaal tot 2 jaar nadat u voor het laatst het CLP heeft gebruikt</u>
|
||||
<br />• uw naam
|
||||
<br />• de door u gevolgde opleidingen
|
||||
<br />• overige ingevulde informatie
|
||||
</li>
|
||||
</ol>
|
||||
<p>U bent niet verplicht om deze persoonsgegevens aan ons te verstrekken. Indien u de persoonsgegevens niet aan ons verstrekt, dan heeft dit geen negatieve gevolgen voor uw gebruik van de Dienst. U kunt de Dienst dus gewoon blijven gebruiken. Wij verwerken deze persoonsgegevens alleen als u daarvoor toestemming heeft gegeven en ze worden ook pas verwerkt als u daadwerkelijk toestemming heeft gegeven of zelf de persoonsgegevens heeft verstrekt.</p>
|
||||
<h2>4. Delen van persoonsgegevens</h2>
|
||||
<p>Wij verkopen of verhandelen geen persoonlijke informatie van u aan anderen. Dit is alleen anders als wij dit hebben aangegeven in deze privacyverklaring.</p>
|
||||
<h3>4.1 Delen met verwerkers</h3>
|
||||
<p>Wij kunnen anderen vragen om te helpen bij het verlenen van de Dienst. Het kan voorkomen dat deze derden hierdoor uw persoonsgegevens verwerken. Deze derden worden in deze privacyverklaring verder “Verwerker” genoemd. Met deze Verwerkers sluiten wij verwerkersovereenkomsten.</p>
|
||||
<p>Wij maken gebruik van de volgende soorten Verwerkers:</p>
|
||||
<ul>
|
||||
<li>opslag van (persoons)gegevens en database beheer en onderhoud;</li>
|
||||
<li>website en software ontwikkelaars die onze producten maken, verbeteren, uitbreiden en onderhouden;</li>
|
||||
<li>onderzoeksbureaus en analytische software om onze dienstverlening te verbeteren (o.a. privacy-vriendelijk ingesteld Google Analytics waardoor geen persoonsgegevens met Google gedeeld worden);</li>
|
||||
<li>hosting provider(s);</li>
|
||||
<li>marketingbureau(s) om de website te monitoren;</li>
|
||||
<li>aanbieders van relatiebeheer software, en;</li>
|
||||
<li>beheerders van video’s en opslag daarvan.</li>
|
||||
</ul>
|
||||
<p>In sommige gevallen kan de Verwerker uw persoonsgegevens namens ons verzamelen. Wij informeren Verwerkers dat zij persoonsgegevens die zij van ons verkrijgen alleen mogen gebruiken om het verlenen van de Dienst mogelijk te maken. Verwerkers mogen deze gegevens niet gebruiken om reclame te maken.</p>
|
||||
<p>Als u zelf aanvullende informatie aan deze verwerkers verstrekt, dan zijn wij hiervoor niet verantwoordelijk. Het is verstandig om uzelf goed te informeren over de Verwerker en zijn bedrijf, voordat u uw persoonsgegevens verstrekt.</p>
|
||||
<h3>4.2 Delen met uw toestemming</h3>
|
||||
<p>Wij kunnen ook persoonsgegevens delen met anderen als u ons daarvoor toestemming geeft. We kunnen bijvoorbeeld met andere partijen samenwerken om u specifieke diensten of aanbiedingen aan te bieden. Als u zich inschrijft voor deze diensten of marketingaanbiedingen, dan kunnen wij uw naam of contactgegevens verstrekken als die nodig zijn om die dienst te verlenen of contact met u op te nemen.</p>
|
||||
<h3>4.3 Onze wettelijke verantwoordelijkheid</h3>
|
||||
<p>Wij mogen ook persoonsgegevens met derden delen indien dit:</p>
|
||||
<ol>
|
||||
<li>redelijkerwijs noodzakelijk of passend is om te voldoen aan wettelijke verplichtingen;</li>
|
||||
<li>nodig is om te voldoen aan wettelijke verzoeken van autoriteiten;</li>
|
||||
<li>nodig is om op eventuele aanspraken te reageren;</li>
|
||||
<li>nodig is om de rechten, eigendom of veiligheid van ons, onze gebruikers, onze medewerkers of het publiek te</li>
|
||||
<li>beschermen;</li>
|
||||
<li>nodig is om onszelf of onze gebruikers te beschermen tegen frauduleus, beledigend, ongepast of onwettig gebruik van de Dienst.</li>
|
||||
</ol>
|
||||
<p>Wij zullen u onmiddellijk op de hoogte stellen indien een overheidsinstantie een verzoek doet dat betrekking heeft op uw persoonsgegevens, tenzij wij dit niet mogen op grond van de wet.</p>
|
||||
<h3>4.4 Fusie of verkoop (deel) van de onderneming</h3>
|
||||
<p>Het kan voorkomen dat wij uw persoonsgegevens openbaar maken, delen of overdragen als wij een gedeelte van ons bedrijf overdragen. Voorbeelden hiervan zijn (onderhandelingen over) een fusie, verkoop van onderdelen van de onderneming of het verkrijgen van financiering. Wij zullen uiteraard proberen de impact voor u zoveel mogelijk te beperken door persoonsgegevens alleen over te dragen als dat noodzakelijk is.</p>
|
||||
<h2>5. Bescherming van persoonsgegevens</h2>
|
||||
<p>Wij vinden het belangrijk om uw persoonsgegevens zorgvuldig te behandelen en beveiligingen. Wij hebben daarom passende technische en organisatorische beveiligingsmaatregelen genomen om uw persoonsgegevens te beveiligen. Wij hebben in ieder geval de volgende maatregelen genomen:</p>
|
||||
<ul>
|
||||
<li>We hebben fysieke en elektronische maatregelen ingevoerd die zijn ontworpen om onbevoegde toegang, verlies of misbruik van persoonsgegevens zoveel mogelijk te voorkomen.</li>
|
||||
<li>We gebruiken TLS (Transport Layer Security)-technologie om transmissie van gevoelige informatie of persoonsgegevens naar ons te versleutelen, zoals accountwachtwoorden en andere identificeerbare informatie over betalingen.</li>
|
||||
<li>Waar redelijkerwijs mogelijk worden back-ups van persoonsgegevens gemaakt.</li>
|
||||
<li>Gevoelige informatie wordt versleuteld opgeslagen als dat mogelijk is.</li>
|
||||
<li>Kwetsbaarheden in de software worden zo snel als redelijkerwijs mogelijk aangepakt.</li>
|
||||
</ul>
|
||||
<p>Wij willen u er wel graag op wijzen dat absolute veiligheid voor het verzenden van persoonsgegevens via het internet of het opslaan van persoonsgegevens niet altijd gegarandeerd kan worden.</p>
|
||||
<h2>6. Links naar sites van derden</h2>
|
||||
<p>Onze Diensten kunnen links bevatten naar andere websites en diensten. Daarnaast kan onze Dienst ook zijn voorzien van advertenties van derden. Websites en diensten van derden kunnen informatie over u bijhouden. We hebben geen controle over deze sites of hun activiteiten. Als u uw persoonsgegevens verstrekt aan derden, dan zijn wij hierbij niet betrokken. In dat geval is het privacybeleid van deze derde partij van toepassing. Wij zijn niet verantwoordelijk voor de inhoud van het privacybeleid van deze partijen en de manier waarop deze partijen omgaan met persoonsgegevens. Wij raden u aan om hun privacy- en beveiligingspraktijken en hun beleid te bestuderen voordat u persoonsgegevens aan ze verstrekt.</p>
|
||||
<h2>7. Uw rechten</h2>
|
||||
<p>Privacywetgeving geeft u bepaalde rechten met betrekking tot uw eigen persoonsgegevens. De rechten die wij hieronder omschrijven zijn geen absolute rechten. Wij zullen altijd een afweging maken of wij redelijkerwijs aan uw verzoek kunnen voldoen. Lukt dit niet, of zou het bijvoorbeeld ten koste gaan van de privacy van anderen, dan kunnen wij uw verzoek weigeren. Indien wij een verzoek weigeren, laten wij dit gemotiveerd weten.</p>
|
||||
<p>
|
||||
<u>Recht op inzage</u>
|
||||
</p>
|
||||
<p>U heeft het recht om op te vragen welke persoonsgegevens wij van u verwerken. U kunt ons ook vragen om inzicht te geven in de verwerkingsdoeleinden, betrokken categorieën van persoonsgegevens, de (categorieën van) ontvangers van persoonsgegevens, de bewaartermijn, de bron van de gegevens en of wij wel of niet gebruikmaken van geautomatiseerde besluitvorming.</p>
|
||||
<p>U mag ook vragen om een kopie van uw persoonsgegevens die door ons worden verwerkt. Wilt u bijkomende kopieën? Dan kunnen wij daarvoor een redelijke vergoeding in rekening brengen.</p>
|
||||
<p>
|
||||
<u>Recht op rectificatie</u>
|
||||
</p>
|
||||
<p>
|
||||
Indien de door ons over u verwerkte persoonsgegevens onjuist of onvolledig zijn, kan u ons verzoeken de persoonsgegevens aan te passen of aan te vullen.
|
||||
<br />Indien wij uw verzoek inwilligen, zullen wij, voor zover dat redelijkerwijs mogelijk is, de partijen aan wie wij gegevens verstrekken daarover inlichten.
|
||||
</p>
|
||||
<p>
|
||||
<u>Recht op het wissen van gegevens</u>
|
||||
</p>
|
||||
<p>Wilt u niet meer dat wij bepaalde persoonsgegevens van u verwerken? Dan kunt u ons verzoeken om bepaalde (of alle) persoonsgegevens over u te wissen. Of wij gegevens zullen wissen, hangt af van het verwerkingsdoeleinde. Gegevens die wij verwerken op grond van een wettelijke plicht of voor het uitvoeren van de overeenkomst, wissen wij alleen indien de persoonsgegevens niet langer noodzakelijk zijn. Indien wij gegevens verwerken op grond van het gerechtvaardigd belang, dan wissen wij gegevens alleen indien uw belang zwaarder weegt dan dat van ons. Wij zullen deze afweging maken. Verwerken we de gegevens op grond van toestemming, dan wissen wij de gegevens slechts indien u de toestemming intrekt. Hebben wij per ongeluk gegevens onrechtmatig verwerkt of schrijft een specifieke wet voor dat wij gegevens moeten wissen? Dan zullen wij de gegevens wissen. Als de gegevens nodig zijn voor de afhandeling van een gerechtelijke procedure of een (juridisch) geschil, dan wissen wij de persoonsgegevens pas na afloop van de procedure of het geschil.</p>
|
||||
<p>Indien wij uw verzoek inwilligen, zullen wij, voor zover dat redelijkerwijs mogelijk is, de partijen aan wie wij gegevens verstrekken daarover inlichten.</p>
|
||||
<p>
|
||||
<u>Beperking van de verwerking</u>
|
||||
</p>
|
||||
<p>Als u de juistheid van door ons verwerkte persoonsgegevens betwist, als u meent dat wij uw persoonsgegevens onrechtmatig hebben verwerkt, indien wij de gegevens niet meer nodig hebben of indien u bezwaar heeft gemaakt tegen de verwerking, kunt u ons tevens verzoeken om de verwerking van die persoonsgegevens te beperken. Bijvoorbeeld gedurende de tijd die wij nodig hebben om uw betwisting of bezwaar te beoordelen, of indien reeds duidelijk is dat voor verdere verwerking van die persoonsgegevens geen rechtmatige grondslag (meer) bestaat, maar u er toch belang bij heeft dat wij de persoonsgegevens nog niet wissen. Als wij de verwerking van uw persoonsgegevens op uw verzoek beperken, mogen wij die gegevens nog wel gebruiken voor de afhandeling van een gerechtelijke procedure of een (juridisch) geschil.</p>
|
||||
<p>
|
||||
<u>Recht op overdraagbaarheid</u>
|
||||
</p>
|
||||
<p>Op uw verzoek kunnen wij de gegevens die wij verwerken voor het uitvoeren van de overeenkomst of op grond van uw toestemming en die automatisch verwerkt worden, overdragen aan u of een andere door u aan te wijzen partij. Een dergelijk verzoek kunt u met redelijke tussenpozen doen.</p>
|
||||
<p>
|
||||
<u>Geautomatiseerde individuele besluitvorming</u>
|
||||
</p>
|
||||
<p>Wij nemen geen besluiten die uitsluitend zijn gebaseerd op geautomatiseerde verwerkingen.</p>
|
||||
<p>
|
||||
<u>Recht van bezwaar en het intrekken van toestemming</u>
|
||||
</p>
|
||||
<p>Indien wij gegevens verwerken op grond van een gerechtvaardigd belang, mag u bezwaar maken tegen de verwerking. Indien wij gegevens verwerken op grond van uw toestemming, dan mag u die toestemming intrekken. Voor meer informatie verwijzen wij u graag naar de betreffende verwerkingsdoeleinden hierboven.</p>
|
||||
<p>
|
||||
<u>Het uitoefenen van uw rechten</u>
|
||||
</p>
|
||||
<p>
|
||||
U kunt een verzoek tot inzage, correctie, verwijdering, gegevensoverdraging van uw persoonsgegevens of verzoek tot intrekking van uw toestemming of bezwaar op de verwerking van uw persoonsgegevens sturen naar
|
||||
<a
|
||||
href="https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=privacy@ggzecademy.nl"
|
||||
target="_blank"
|
||||
>privacy@ggzecademy.nl</a>.
|
||||
</p>
|
||||
<p>Om misbruik te voorkomen vragen wij u, bij een schriftelijk verzoek tot inzage, aanpassing of verwijdering, u adequaat te identificeren. Dit kunt u doen door een kopie van een geldig legitimatiebewijs mee te sturen. Vergeet niet om op de kopie uw BSN én pasfoto af te schermen.</p>
|
||||
<p>We streven ernaar om uw verzoek, klacht of bezwaar binnen een maand te verwerken. Als het niet mogelijk is om binnen een maand een beslissing te nemen, zullen we u op de hoogte brengen van de redenen voor de vertraging en van het tijdstip waarop de beslissing naar verwachting zal worden verstrekt (niet langer dan 3 maanden na ontvangst).</p>
|
||||
<p>
|
||||
<u>Autoriteit Persoonsgegevens</u>
|
||||
</p>
|
||||
<p>
|
||||
Heeft u een klacht over onze verwerking van uw persoonsgegevens? Neem dan contact met ons op. Wij helpen u natuurlijk graag verder. Mocht u er desondanks toch niet samen met ons uitkomen, dan heeft u op grond van de privacywetgeving ook het recht om een klacht in te dienen bij de privacytoezichthouder, de Autoriteit Persoonsgegevens. U kunt hiervoor contact opnemen met de Autoriteit Persoonsgegevens via
|
||||
<a
|
||||
href="https://autoriteitpersoonsgegevens.nl/"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>https://autoriteitpersoonsgegevens.nl/</a>.
|
||||
</p>
|
||||
<h2>8. Contact</h2>
|
||||
<p>
|
||||
Als u vragen, problemen of opmerkingen heeft over deze privacyverklaring of onze gegevensverwerkingen, dan kunt u contact met ons opnemen via e-mail op
|
||||
<a
|
||||
href="https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=privacy@ggzecademy.nl"
|
||||
target="_blank"
|
||||
>privacy@ggzecademy.nl</a>.
|
||||
</p>
|
||||
<p>Versie 2.1 – d.d. 1 oktober 2019</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text {
|
||||
text-align: justify;
|
||||
text-justify: inter-word;
|
||||
}
|
||||
</style>
|
||||
50
components/Learning/BrowserColumns.vue
Normal file
50
components/Learning/BrowserColumns.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="text-center">
|
||||
<v-btn text x-small :disabled="isFirstPage" @click="changePage('previous')">
|
||||
<v-icon x-small>icon-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<small class="mx-2">
|
||||
{{ `${page} / ${totalPages}` }}
|
||||
</small>
|
||||
|
||||
<v-btn text x-small :disabled="isLastPage" @click="changePage('next')">
|
||||
<v-icon x-small>icon-arrow-right</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<!-- Debugging -->
|
||||
<!-- <ul>
|
||||
<li v-for="(column, i) in subset" :key="`column-dyn${i}`">
|
||||
{{ column }}
|
||||
</li>
|
||||
</ul> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Inspiration: https://github.com/byteboomers/vue-lpage
|
||||
export default {
|
||||
computed: {
|
||||
page() {
|
||||
return this.$store.state.columnBrowser.page
|
||||
},
|
||||
isFirstPage() {
|
||||
return this.$store.getters['columnBrowser/isFirstPage']
|
||||
},
|
||||
isLastPage() {
|
||||
return this.$store.getters['columnBrowser/isLastPage']
|
||||
},
|
||||
totalPages() {
|
||||
return this.$store.getters['columnBrowser/totalPages']
|
||||
},
|
||||
subset() {
|
||||
return this.$store.getters['columnBrowser/subset']
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
changePage(direction) {
|
||||
this.$store.dispatch('columnBrowser/changePage', direction)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
505
components/Learning/CoursesTable.vue
Normal file
505
components/Learning/CoursesTable.vue
Normal file
@@ -0,0 +1,505 @@
|
||||
<template>
|
||||
<div>
|
||||
<a target="_blank" href="/" id="root_url" v-show="false"></a>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:options="coursesTableOptions"
|
||||
:items="products"
|
||||
:footer-props="{ itemsPerPageOptions: [10, 25, 50, 100, -1] }"
|
||||
@update:options="handleChangesOnOptions"
|
||||
class="pa-4 secondary"
|
||||
>
|
||||
<!-- Translates dynamically headers -->
|
||||
<template v-for="h in headers" v-slot:[`header.${h.value}`]="{ header }">
|
||||
{{ $t(h.text) }}
|
||||
|
||||
<div
|
||||
v-if="h.value === 'actions'"
|
||||
:key="`column-browser-${h.text}`"
|
||||
class="text-center"
|
||||
>
|
||||
<browser-columns />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.cover="{ item }">
|
||||
<v-img
|
||||
:alt="item.title"
|
||||
lazy-src="/images/product-placeholder.jpg"
|
||||
:src="computeImage(item)"
|
||||
contain
|
||||
height="60px"
|
||||
width="110px"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template class="d-flex flex-column" v-slot:item.title="{ item }">
|
||||
<div>
|
||||
<span>
|
||||
<span
|
||||
v-if="!item.published && !item.deleted_at"
|
||||
class="info--text font-weight-thin font-italic"
|
||||
>{{ $t('general.draft') | capitalize }}</span
|
||||
>
|
||||
<span v-if="item.deleted_at" class="error--text font-italic">{{
|
||||
$t('general.deleted') | capitalize
|
||||
}}</span>
|
||||
</span>
|
||||
<span>
|
||||
<filter-items-resolver
|
||||
filterTitle="category"
|
||||
:filters="item.filters"
|
||||
/>
|
||||
|
||||
<filter-items-resolver gratisMode :filters="item.filters" />
|
||||
</span>
|
||||
</div>
|
||||
<strong>{{ item.title | truncate(29) }}</strong>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.status="{ item }">
|
||||
<filter-items-resolver filterTitle="status" :filters="item.filters" />
|
||||
</template>
|
||||
|
||||
<template v-slot:item.product_type="{ item }">
|
||||
<filter-items-resolver
|
||||
filterTitle="product_type"
|
||||
:filters="item.filters"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.course="{ item }">
|
||||
<filter-items-resolver filterTitle="course" :filters="item.filters" />
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
class="mx-4 white--text"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
nuxt
|
||||
small
|
||||
:to="localePath(`/manager/learning/${item.slug}`)"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu
|
||||
offset-y
|
||||
close-on-content-click
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
class="menu-btn"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item
|
||||
:to="localePath(`/manager/learning/${item.slug}?edit`)"
|
||||
nuxt
|
||||
>
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="clone(item.id)" v-if="publishedSelected">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-duplicate</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.duplicate') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<!-- <v-list-item>
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-download</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.download') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
@click="shareUrl(localePath(`/manager/learning/${item.slug}`))"
|
||||
>
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-share</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.share') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item> -->
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialog">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{
|
||||
$t('learning.product_overview.delete_confirmation', {
|
||||
productName: item.title,
|
||||
})
|
||||
}}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteProduct(item.id)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="close"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue2Filters from 'vue2-filters'
|
||||
import FilterItemsResolver from '~/components/Learning/FilterItemsResolver'
|
||||
import BrowserColumns from '~/components/Learning/BrowserColumns'
|
||||
|
||||
export default {
|
||||
mixins: [Vue2Filters.mixin],
|
||||
props: {
|
||||
published: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
drafts: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
deleted: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
selector: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
FilterItemsResolver,
|
||||
BrowserColumns,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
page: 1,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialog(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
noImage() {
|
||||
return require(`@/assets/img/no_image.png`)
|
||||
},
|
||||
headers() {
|
||||
return this.$store.getters.columnsSortedSubset
|
||||
},
|
||||
columns() {
|
||||
return this.$store.state.learning.columns
|
||||
},
|
||||
products() {
|
||||
if (!['published', 'drafts', 'deleted'].includes(this.selector)) return []
|
||||
return this[this.selector]
|
||||
},
|
||||
publishedSelected() {
|
||||
return this.selector === 'published'
|
||||
},
|
||||
draftsSelected() {
|
||||
return this.selector === 'drafts'
|
||||
},
|
||||
deletedSelected() {
|
||||
return this.selector === 'deleted'
|
||||
},
|
||||
coursesTableOptions() {
|
||||
return this.$store.state.learning.coursesTableOptions
|
||||
},
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
// If cols preferences saved in localstorage
|
||||
if (localStorage.getItem('learning_products_cols')) {
|
||||
// Get them
|
||||
const colsLocalPreferences = JSON.parse(
|
||||
localStorage.getItem('learning_products_cols')
|
||||
)
|
||||
|
||||
// Local copy and extract values to sort columns
|
||||
let colsRestored = [...this.columns]
|
||||
const colsLocalPreferencesValues = colsLocalPreferences.map(
|
||||
({ value }) => value
|
||||
)
|
||||
|
||||
// Sort by local preferences
|
||||
colsRestored.sort(
|
||||
(a, b) =>
|
||||
colsLocalPreferencesValues.indexOf(a.value) -
|
||||
colsLocalPreferencesValues.indexOf(b.value)
|
||||
)
|
||||
|
||||
// update visibility by local preferences
|
||||
colsLocalPreferences.forEach((col) => {
|
||||
if (col.hasOwnProperty('display')) {
|
||||
const colIndex = colsRestored.findIndex(
|
||||
(el) => el.value === col.value
|
||||
)
|
||||
|
||||
colsRestored[colIndex] = {
|
||||
...colsRestored[colIndex],
|
||||
display: col.display,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Send to Store
|
||||
await this.$store.dispatch('learning/setColumns', colsRestored)
|
||||
}
|
||||
|
||||
// Initialize columns ordered
|
||||
if (this.$store.state.learning.columnsSorted.length <= 0) {
|
||||
await this.$store.dispatch('learning/setColumns')
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
// Get datatable options from localstorage if present
|
||||
if (
|
||||
localStorage.getItem(
|
||||
`courses_table_options_user${this.$store.getters.loggedInUser.id || ''}`
|
||||
)
|
||||
) {
|
||||
const options = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`courses_table_options_user${
|
||||
this.$store.getters.loggedInUser.id || ''
|
||||
}`
|
||||
)
|
||||
)
|
||||
|
||||
this.$store.commit('learning/SET_COURSES_TABLE_OPTIONS', options)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialog = false
|
||||
},
|
||||
|
||||
save() {
|
||||
this.close()
|
||||
},
|
||||
|
||||
computeImage(item) {
|
||||
if (item.cover.full) return item.cover.full
|
||||
if (item.video) return '/images/video-placeholder.jpg'
|
||||
return '/images/product-placeholder.jpg'
|
||||
},
|
||||
|
||||
async clone(productId) {
|
||||
if (!productId) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No product to clone selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
const response = await this.$axios.post('/learning-products/clone', {
|
||||
product_id: productId,
|
||||
})
|
||||
this.$emit('reload-learning-products')
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Product cloned in Drafts`,
|
||||
color: 'success',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
} catch (error) {
|
||||
console.log('clone -> error', error)
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to clone the selected product`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async deleteProduct(productId) {
|
||||
if (!productId) return
|
||||
this.dialog = false
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
await this.$store.dispatch('learning/deleteProduct', productId)
|
||||
this.$router.push(this.localePath('/manager/learning'))
|
||||
},
|
||||
|
||||
async shareUrl(url) {
|
||||
if (!url) return
|
||||
|
||||
const root_url = document.getElementById('root_url').href
|
||||
|
||||
// Remove last slash from root url
|
||||
const full_url = `${root_url.slice(0, -1)}${url}`
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(full_url)
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Url Copied in clipboard `,
|
||||
color: 'success',
|
||||
icon: 'mdi-check',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('shareUrl -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
async handleChangesOnOptions(options) {
|
||||
this.$store.commit('learning/SET_COURSES_TABLE_OPTIONS', options)
|
||||
await localStorage.setItem(
|
||||
`courses_table_options_user${
|
||||
this.$store.getters.loggedInUser.id || ''
|
||||
}`,
|
||||
JSON.stringify(options)
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
table tr a.v-btn {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover a.v-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
.v-list-item:hover >>> .v-list-item__icon i,
|
||||
.v-list-item:hover >>> .v-list-item__content .v-list-item__subtitle {
|
||||
color: var(--v-info-base) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header th:last-child,
|
||||
.v-data-table >>> .v-data-table-header th:nth-child(3) {
|
||||
position: relative;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header th:last-child::before,
|
||||
.v-data-table >>> .v-data-table-header th:nth-child(3)::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
height: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header tr th {
|
||||
border-bottom: none !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.v-data-table td .menu-btn {
|
||||
background-color: unset !important;
|
||||
}
|
||||
.v-data-table >>> td {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
.v-data-table >>> thead th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.v-data-table >>> td:first-child {
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
.v-data-table >>> td:last-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.v-data-table >>> td:first-child .v-image {
|
||||
margin-right: -18px;
|
||||
}
|
||||
.v-data-table >>> td:last-child,
|
||||
.v-data-table >>> td:nth-child(3) {
|
||||
position: relative;
|
||||
}
|
||||
.v-data-table >>> td:last-child::before,
|
||||
.v-data-table >>> td:nth-child(3)::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
height: 60px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table__divider {
|
||||
border-right: none !important;
|
||||
}
|
||||
</style>
|
||||
73
components/Learning/FilterItemsResolver.vue
Normal file
73
components/Learning/FilterItemsResolver.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<span>
|
||||
<span v-if="hasFilterItems && !gratisMode">
|
||||
<small
|
||||
v-for="({ filter_item }, i) in filterItemResolved"
|
||||
:key="`column-filter_item-${filter_item.id}`"
|
||||
>
|
||||
<v-icon
|
||||
:color="filter_item.color"
|
||||
class="mx-1"
|
||||
size="10"
|
||||
v-if="filter_item.color"
|
||||
>mdi-circle</v-icon
|
||||
>
|
||||
<span v-if="filter_item.title">{{ filter_item.title }}</span>
|
||||
<span v-if="filter_item.subtitle">{{ filter_item.subtitle }}</span>
|
||||
{{ filterItemResolved.length - 1 === i ? '' : '-' }}
|
||||
</small>
|
||||
</span>
|
||||
|
||||
<span v-if="gratisMode && isGratis">
|
||||
<v-icon class="mx-1" color="accent" x-small>mdi-star</v-icon>
|
||||
<span class="accent--text">Gratis</span>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
filterTitle: {
|
||||
type: String,
|
||||
default: 'type',
|
||||
},
|
||||
filters: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
gratisMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
filterItemResolved() {
|
||||
// return this.$store.getters.filterItemsResolved(
|
||||
// this.filterTitle,
|
||||
// this.filters
|
||||
// )
|
||||
|
||||
const filter = this.$store.getters.getFilterByTitle(this.filterTitle)
|
||||
return this.filters.filter((f) => f.filter_item.filter_id === filter.id)
|
||||
},
|
||||
hasFilterItems() {
|
||||
return this.filterItemResolved.length > 0
|
||||
},
|
||||
isGratis() {
|
||||
return this.filterItemResolved.find(
|
||||
(f) => f.filter_item.title === 'Gratis'
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
small span {
|
||||
font-size: 15.75px;
|
||||
}
|
||||
.mdi-star {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
</style>
|
||||
43
components/Learning/Filters.vue
Normal file
43
components/Learning/Filters.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<v-chip
|
||||
class="mr-4 mb-2 txt--text font-weight-bold px-6"
|
||||
color="primary"
|
||||
v-for="filter in filters"
|
||||
:key="filter.title"
|
||||
@click.stop="
|
||||
$store.commit('navigation/SWITCH_RIGHT_DRAWER', {
|
||||
component: 'FiltersMenu',
|
||||
subMenu: filter.title,
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ $t(`learning.filters.${filter.title}`) | capitalize }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
class="mr-4 mb-2 txt--text font-weight-bold px-6"
|
||||
color="primary"
|
||||
@click.stop="
|
||||
$store.commit('navigation/SWITCH_RIGHT_DRAWER', {
|
||||
component: 'Settings',
|
||||
subMenu: 'filters',
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ $t('learning.filters.more') }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
this.$store.dispatch('learning/setFilters')
|
||||
},
|
||||
computed: {
|
||||
filters() {
|
||||
return this.$store.state.learning.filters.slice(0, 5)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
25
components/Learning/FiltersSelected.vue
Normal file
25
components/Learning/FiltersSelected.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<v-btn
|
||||
x-small
|
||||
depressed
|
||||
text
|
||||
v-for="(filter, i) in $store.getters.filtersSelected"
|
||||
:key="`filter-check${i}`"
|
||||
@click="removeFilterItemFromSelected(filter)"
|
||||
>
|
||||
<v-icon class="mx-1" color="success">icon-checkmark</v-icon>
|
||||
{{ $store.getters.getFilterItemById(filter).title | capitalize }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
removeFilterItemFromSelected(filterItemId) {
|
||||
this.$store.commit('learning/REMOVE_SELECTED_FILTER', filterItemId)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
53
components/Learning/ProductCard/ProductCard.vue
Normal file
53
components/Learning/ProductCard/ProductCard.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<v-card class="mx-auto" max-width="400" tile nuxt :to="slug">
|
||||
<v-list-item>
|
||||
<!-- <v-list-item-avatar color="grey"></v-list-item-avatar> -->
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
<v-chip class="ma-2" color="primary">
|
||||
{{ course }}
|
||||
</v-chip>
|
||||
</v-list-item-subtitle>
|
||||
<v-list-item-title>{{ title }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-img :src="cover" class="my-5" />
|
||||
|
||||
<!-- <v-card-title class="pb-0">{{ title }}</v-card-title> -->
|
||||
|
||||
<!-- <v-card-text class="primary--text">
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores
|
||||
officiis pariatur aliquid id ipsam magnam neque quo dicta veritatis
|
||||
iusto.
|
||||
</div>
|
||||
</v-card-text> -->
|
||||
|
||||
<v-card-actions class="d-flex flex-column">
|
||||
<v-btn color="orange" text> Share </v-btn>
|
||||
|
||||
<v-btn color="orange" text> Explore </v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
cover: {
|
||||
type: String,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
course: {
|
||||
type: String,
|
||||
},
|
||||
gratis: {},
|
||||
slug: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
604
components/Learning/ProductOverview/Accreditation.vue
Normal file
604
components/Learning/ProductOverview/Accreditation.vue
Normal file
@@ -0,0 +1,604 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.accreditation')">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="accreditations"
|
||||
:options="options"
|
||||
hide-default-footer
|
||||
item-key="accreditation"
|
||||
flat
|
||||
v-if="hasAccreditations"
|
||||
>
|
||||
<!-- Translates dynamically headers -->
|
||||
<template v-for="h in headers" v-slot:[`header.${h.value}`]="{ header }">
|
||||
{{ h.text ? $t(`learning.accreditation.${h.text}`) : '' }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.register="{ item }">
|
||||
{{ getFilterItem('register', item).title }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.date_start="{ item }">
|
||||
{{ formatDate(item.date_start) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.date_end="{ item }">
|
||||
{{ formatDate(item.date_end) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="
|
||||
editMode && ($store.getters.isAdmin || $store.getters.isOperator)
|
||||
"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialogDelete">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{ $t('learning.delete_accreditation_confirmation') }}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogAccreditation"
|
||||
max-width="75%"
|
||||
v-if="editMode && ($store.getters.isAdmin || $store.getters.isOperator)"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="cta-secondary my-10"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
@click="resetAccreditationsFilters"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
|
||||
{{ $t('learning.add_new_accreditation') }}</v-btn
|
||||
>
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t(`learning.filters.register`)
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="register"
|
||||
:editMode="editMode"
|
||||
target="accreditations"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-text-field
|
||||
v-model="editedItem.credits"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.accreditation_period')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9" class="d-flex pl-2">
|
||||
<v-menu
|
||||
ref="menuStart"
|
||||
v-model="menuStart"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
margin-top="20px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`accreditation-start-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedStart"
|
||||
append-icon="icon-events"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
readonly
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="editedItem.date_start"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
locale="nl-NL"
|
||||
>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text @click="menuStart = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
@click="$refs.menuStart.save(editedItem.date_start)"
|
||||
>OK</v-btn
|
||||
>
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
<span class="mx-5 my-3 font-weight-bold">
|
||||
tot
|
||||
</span>
|
||||
<v-menu
|
||||
ref="menuEnd"
|
||||
v-model="menuEnd"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`accreditation-end-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedEnd"
|
||||
append-icon="icon-events"
|
||||
readonly
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="editedItem.date_end"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
locale="nl-NL"
|
||||
>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text @click="menuEnd = false">Cancel</v-btn>
|
||||
<v-btn text @click="$refs.menuEnd.save(editedItem.date_end)"
|
||||
>OK</v-btn
|
||||
>
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editMode">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="save"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw product kiest u eerst voor 'Opslaan' om
|
||||
deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import universalFilterSelector from '@/components/UniversalFilterSelector/UniversalFilterSelector'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
universalFilterSelector,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'register', value: 'register' },
|
||||
{ text: 'credits', value: 'credits' },
|
||||
{ text: 'date_start', value: 'date_start' },
|
||||
{ text: 'date_end', value: 'date_end' },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
accreditationEditMode: false,
|
||||
dialogAccreditation: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {
|
||||
date_start: '',
|
||||
date_end: '',
|
||||
credits: '',
|
||||
},
|
||||
defaultItem: {
|
||||
date_start: '',
|
||||
date_end: '',
|
||||
credits: '',
|
||||
},
|
||||
loading: false,
|
||||
date: null,
|
||||
menuStart: false,
|
||||
menuEnd: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
remote() {
|
||||
return this.$store.state.learning.remote
|
||||
},
|
||||
local() {
|
||||
return this.$store.state.learning.local
|
||||
},
|
||||
accreditations() {
|
||||
if (!this.local || !Array.isArray(this.local.accreditations)) return []
|
||||
return this.local.accreditations
|
||||
},
|
||||
hasAccreditations() {
|
||||
if (!this.accreditations) return false
|
||||
return this.accreditations.length > 0
|
||||
},
|
||||
formTitle() {
|
||||
return this.editedIndex === -1
|
||||
? this.$t('learning.new_accreditation')
|
||||
: this.$t('learning.edit_accreditation')
|
||||
},
|
||||
accreditationsFiltersSelected() {
|
||||
return this.$store.state.learning.accreditationsFiltersSelected
|
||||
},
|
||||
computedDateFormattedStart() {
|
||||
return this.formatDate(this.editedItem.date_start)
|
||||
},
|
||||
computedDateFormattedEnd() {
|
||||
return this.formatDate(this.editedItem.date_end)
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogAccreditation(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getFilterItem(filterTitle, accreditation) {
|
||||
const filter = this.$store.getters.getFilterByTitle(filterTitle)
|
||||
|
||||
const arrayTmp = []
|
||||
if (!accreditation.filters) return {}
|
||||
accreditation.filters.forEach((f) => {
|
||||
const filterItemTmp = this.$store.getters.getFilterItemById(
|
||||
f.filter_item_id
|
||||
)
|
||||
arrayTmp.push(filterItemTmp)
|
||||
})
|
||||
|
||||
const filterItem = arrayTmp.find((e) => e.filter_id === filter.id)
|
||||
return filterItem || {}
|
||||
},
|
||||
formatDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [year, month, day, time] = date.replace(' ', '-').split('-')
|
||||
return `${day}/${month}/${year}`
|
||||
},
|
||||
|
||||
resetAccreditationsFilters() {
|
||||
this.$store.commit('learning/RESET_ACCREDITATIONS_FILTERS')
|
||||
},
|
||||
|
||||
setAccreditationsFilters(item) {
|
||||
item.filters.forEach(async (f) => {
|
||||
const filterItem = this.$store.getters.getFilterItemById(
|
||||
f.filter_item_id
|
||||
)
|
||||
|
||||
await this.$store.commit('learning/UPDATE_FILTERS', {
|
||||
filterId: filterItem.filter_id,
|
||||
target: 'accreditations',
|
||||
value: f.filter_item_id,
|
||||
})
|
||||
})
|
||||
|
||||
this.editedIndex = this.accreditations.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
close() {
|
||||
this.dialogAccreditation = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
})
|
||||
},
|
||||
|
||||
setFiltersSelectedInEditedItem() {
|
||||
let accreditationFiltersItemsIds = []
|
||||
|
||||
for (const [key, value] of Object.entries(
|
||||
this.accreditationsFiltersSelected
|
||||
)) {
|
||||
accreditationFiltersItemsIds.push(value)
|
||||
}
|
||||
|
||||
this.editedItem['filter_items'] = accreditationFiltersItemsIds
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.setAccreditationsFilters(item)
|
||||
this.dialogAccreditation = true
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No accredication to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$axios.delete(`/accreditations/${item.id}`)
|
||||
|
||||
this.$store.commit('learning/DELETE_ACCREDITATION_LOCAL', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogAccreditation = false
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Accreditation deleted`,
|
||||
color: 'success',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
} catch (error) {
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to delete the selected accreditation`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
// Edit mode
|
||||
if (this.editedIndex > -1) {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
this.setFiltersSelectedInEditedItem()
|
||||
|
||||
const response = await this.$axios.post(
|
||||
'/accreditations',
|
||||
this.editedItem
|
||||
)
|
||||
|
||||
this.$store.commit('learning/EDIT_ACCREDITATION_LOCAL', {
|
||||
index: this.editedIndex,
|
||||
accreditation: response.data,
|
||||
})
|
||||
|
||||
this.dialogAccreditation = false
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Accreditation stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogAccreditation = false
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the accreditation`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
// Create new mode
|
||||
} else {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
this.setFiltersSelectedInEditedItem()
|
||||
|
||||
const response = await this.$axios.post(
|
||||
'/accreditations',
|
||||
this.editedItem
|
||||
)
|
||||
|
||||
this.dialog = false
|
||||
|
||||
this.$store.commit('learning/ADD_ACCREDITATION_LOCAL', response.data)
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Accreditation stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogAccreditation = false
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the accreditation`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
this.close()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-application >>> .v-menu__content{
|
||||
top: 230px !important;
|
||||
}
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 242px !important;
|
||||
}
|
||||
</style>
|
||||
262
components/Learning/ProductOverview/Administration.vue
Normal file
262
components/Learning/ProductOverview/Administration.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.administration')">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Van leden voor leden</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9" class="mb-4 d-flex flex-column">
|
||||
<div class="pb-0 mb-0 d-flex">
|
||||
<v-switch
|
||||
:disabled="!editMode"
|
||||
inset
|
||||
class="my-3 toggle"
|
||||
v-model="for_members"
|
||||
/>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.owner')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="owner"
|
||||
:placeholder="$t('learning.product_overview.placeholder.description')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.partner')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="partner"
|
||||
:placeholder="$t('learning.product_overview.placeholder.description')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Leverancier
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="supplier"
|
||||
:placeholder="$t('learning.product_overview.placeholder.description')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.contract_agreements')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<quill-editor
|
||||
v-model="contract_agreements"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
@focus="isEditorFocused = true"
|
||||
@blur="isEditorFocused = false"
|
||||
@change="onEditorChange()"
|
||||
:class="{ focused: isEditorFocused }"
|
||||
v-if="editMode"
|
||||
/>
|
||||
|
||||
<span v-html="contract_agreements" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Prognose gebruik aantal leden
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="prognosis_members"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Prognose gebruik aantal deelnemers
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="prognosis_attendees"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
quillEditor,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEditorFocused: false,
|
||||
editorOption: {
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ size: ['small', false, 'large'] }],
|
||||
['bold', 'italic'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
['link'],
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.learning.local
|
||||
},
|
||||
owner: {
|
||||
get() {
|
||||
return this.local.owner || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'owner',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
partner: {
|
||||
get() {
|
||||
return this.local.partner || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'partner',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
supplier: {
|
||||
get() {
|
||||
return this.local.supplier || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'supplier',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
contract_agreements: {
|
||||
get() {
|
||||
return this.local.contract_agreements || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'contract_agreements',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
prognosis_members: {
|
||||
get() {
|
||||
return this.local.prognosis_members || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'prognosis_members',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
prognosis_attendees: {
|
||||
get() {
|
||||
return this.local.prognosis_attendees || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'prognosis_attendees',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
for_members: {
|
||||
get() {
|
||||
return this.local.for_members
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'for_members',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onEditorChange() {
|
||||
if (!this.isEditorFocused) this.isEditorFocused = true
|
||||
// console.log('editor change!', editor)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
603
components/Learning/ProductOverview/Basic.vue
Normal file
603
components/Learning/ProductOverview/Basic.vue
Normal file
@@ -0,0 +1,603 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.basic')">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.title')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="title"
|
||||
:rules="rules.title"
|
||||
:placeholder="$t('learning.product_overview.placeholder.titel')"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
required
|
||||
error
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode"></v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.code')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="code"
|
||||
:placeholder="$t('learning.product_overview.placeholder.productcode')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
:rules="rules.code"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Van leden voor leden</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9" class="mb-4 d-flex flex-column">
|
||||
<div class="pb-0 mb-0 d-flex">
|
||||
<v-switch
|
||||
:disabled="!editMode"
|
||||
inset
|
||||
class="my-3 toggle"
|
||||
v-model="for_members"
|
||||
/>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black"> Url </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="url"
|
||||
:placeholder="$t('learning.product_overview.placeholder.url')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.status')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector filterTitle="status" :editMode="editMode" />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Tegel afbeelding
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<vue-dropzone
|
||||
ref="imgDropZoneTile"
|
||||
class="cta-secondary my-4"
|
||||
id="customdropzoneTile"
|
||||
:options="dropzoneOptions"
|
||||
@vdropzone-complete="afterCompleteTile"
|
||||
v-if="editMode"
|
||||
/>
|
||||
|
||||
<v-img
|
||||
:src="tileComputed || noImage"
|
||||
:lazy-src="noImage"
|
||||
contain
|
||||
v-cloak
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode" class="mt-12">
|
||||
{{ $t('learning.product_overview.allowed') }} <br />
|
||||
{{ $t('learning.product_overview.allowed2') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('general.image')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<vue-dropzone
|
||||
ref="imgDropZoneCover"
|
||||
class="cta-secondary my-4"
|
||||
id="customdropzone"
|
||||
:options="dropzoneOptions"
|
||||
@vdropzone-complete="afterCompleteCover"
|
||||
v-if="editMode"
|
||||
/>
|
||||
|
||||
<v-img
|
||||
:src="coverComputed || noImage"
|
||||
:lazy-src="noImage"
|
||||
contain
|
||||
v-cloak
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode" class="mt-12">
|
||||
{{ $t('learning.product_overview.allowed') }} <br />
|
||||
{{ $t('learning.product_overview.allowed2') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Video</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<v-text-field
|
||||
v-model="video"
|
||||
prepend-inner-icon="mdi-youtube"
|
||||
:placeholder="$t('learning.product_overview.placeholder.trailer')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-if="editMode"
|
||||
class="youtube"
|
||||
/>
|
||||
|
||||
<iframe
|
||||
v-if="video"
|
||||
width="100%"
|
||||
height="480"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
marginheight="0"
|
||||
marginwidth="0"
|
||||
:src="video"
|
||||
allowfullscreen
|
||||
msallowfullscreen
|
||||
allow="fullscreen"
|
||||
></iframe>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
{{ $t('learning.product_overview.allowed_trailer') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.duration')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="lead_time"
|
||||
:placeholder="$t('learning.product_overview.duration')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.level') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
id="level"
|
||||
filterTitle="level"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
SEO Title
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="seo_title"
|
||||
:placeholder="$t('learning.product_overview.placeholder.seo_title')"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
:rules="rules.seo_title"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Meta description
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-textarea
|
||||
v-model="meta_description"
|
||||
:placeholder="
|
||||
$t('learning.product_overview.placeholder.meta_description')
|
||||
"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
></v-textarea>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Synoniemen
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<synonyms-selector :editMode="editMode" />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import universalFilterSelector from '@/components/UniversalFilterSelector/UniversalFilterSelector'
|
||||
import synonymsSelector from '@/components/Learning/SynonymsSelector'
|
||||
import vueDropzone from 'vue2-dropzone'
|
||||
import 'vue2-dropzone/dist/vue2Dropzone.min.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
vueDropzone,
|
||||
universalFilterSelector,
|
||||
synonymsSelector,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
date: new Date().toISOString().substr(0, 7),
|
||||
menu: false,
|
||||
modal: false,
|
||||
dialog: false,
|
||||
valid: true,
|
||||
lazy: false,
|
||||
loading: false,
|
||||
dropzoneOptions: {
|
||||
url: 'https://httpbin.org/post',
|
||||
maxFilesize: 1.2, // MB
|
||||
maxFiles: 1,
|
||||
thumbnailWidth: 150,
|
||||
thumbnailHeight: 150,
|
||||
addRemoveLinks: true,
|
||||
acceptedFiles: '.jpg, .jpeg, .png',
|
||||
dictDefaultMessage: `<p><i class='icon icon-image mr-2'></i> Upload afbeelding</p>`,
|
||||
},
|
||||
images: [],
|
||||
rules: {
|
||||
// title: [(v) => 'De titel is verplicht'],
|
||||
// code: [(v) => !!v || 'De productcode is verplicht'],
|
||||
// seo_title: [(v) => !!v || 'De SEO-titel is verplicht'],
|
||||
title: [(v) => 'De titel is verplicht'],
|
||||
code: [(v) => 'De productcode is verplicht'],
|
||||
seo_title: [(v) => 'De SEO-titel is verplicht'],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.getters.localProduct
|
||||
},
|
||||
|
||||
title: {
|
||||
get() {
|
||||
return this.local.title
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', { field: 'title', value })
|
||||
},
|
||||
},
|
||||
code: {
|
||||
get() {
|
||||
return this.local.code
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', { field: 'code', value })
|
||||
},
|
||||
},
|
||||
|
||||
for_members: {
|
||||
get() {
|
||||
return this.local.for_members
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'for_members',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
status: {
|
||||
get() {
|
||||
return this.local.status
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', { field: 'status', value })
|
||||
},
|
||||
},
|
||||
video: {
|
||||
get() {
|
||||
return this.local.video
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', { field: 'video', value })
|
||||
},
|
||||
},
|
||||
lead_time: {
|
||||
get() {
|
||||
return this.local.lead_time
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'lead_time',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
seo_title: {
|
||||
get() {
|
||||
return this.local.seo_title
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'seo_title',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
meta_description: {
|
||||
get() {
|
||||
return this.local.meta_description
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'meta_description',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
url: {
|
||||
get() {
|
||||
return this.local.url
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'url',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
level: {
|
||||
get() {
|
||||
return this.local.level
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'level',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
levelItems() {
|
||||
if (!this.$store.getters.filters.length > 0) return []
|
||||
return this.$store.getters.filters.find(
|
||||
(filter) => filter.title === 'level'
|
||||
).items
|
||||
},
|
||||
|
||||
cover() {
|
||||
return this.local.cover
|
||||
},
|
||||
|
||||
coverComputed() {
|
||||
if (this.$store.state.learning.cover.url)
|
||||
return this.$store.state.learning.cover.url
|
||||
if (this.local.cover) return this.local.cover.full
|
||||
return null
|
||||
},
|
||||
|
||||
tile() {
|
||||
return this.local.tile
|
||||
},
|
||||
|
||||
tileComputed() {
|
||||
if (this.$store.state.learning.tile.url)
|
||||
return this.$store.state.learning.tile.url
|
||||
if (this.local.tile) return this.local.tile.full
|
||||
return null
|
||||
},
|
||||
noImage() {
|
||||
return require(`@/assets/img/no_image.png`)
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
async afterCompleteTile(file) {
|
||||
if (file === undefined) return
|
||||
if (file.name.lastIndexOf('.') <= 0) return
|
||||
|
||||
if (file.size > 2000000) {
|
||||
this.$notifier.showMessage({
|
||||
content: `Exceeded Max filesize`,
|
||||
color: 'error',
|
||||
icon: 'mdi-alert-circle',
|
||||
})
|
||||
this.$store.commit('learning/RESET_TILE')
|
||||
return
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
try {
|
||||
const fr = new FileReader()
|
||||
fr.readAsDataURL(file)
|
||||
fr.addEventListener('load', () => {
|
||||
this.$store.commit('learning/UPDATE_TILE', {
|
||||
name: file.name,
|
||||
url: fr.result,
|
||||
file: file,
|
||||
})
|
||||
})
|
||||
this.isLoading = false
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
this.$refs.imgDropZoneTile.removeFile(file)
|
||||
},
|
||||
|
||||
async afterCompleteCover(file) {
|
||||
if (file === undefined) return
|
||||
if (file.name.lastIndexOf('.') <= 0) return
|
||||
|
||||
if (file.size > 2000000) {
|
||||
this.$notifier.showMessage({
|
||||
content: `Exceeded Max filesize`,
|
||||
color: 'error',
|
||||
icon: 'mdi-alert-circle',
|
||||
})
|
||||
this.$store.commit('learning/RESET_COVER')
|
||||
return
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
try {
|
||||
const fr = new FileReader()
|
||||
fr.readAsDataURL(file)
|
||||
fr.addEventListener('load', () => {
|
||||
this.$store.commit('learning/UPDATE_COVER', {
|
||||
name: file.name,
|
||||
url: fr.result,
|
||||
file: file,
|
||||
})
|
||||
})
|
||||
this.isLoading = false
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
this.$refs.imgDropZoneCover.removeFile(file)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#level >>> .v-input__slot .v-select__slot {
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.image-div {
|
||||
display: flex;
|
||||
margin: 25px;
|
||||
}
|
||||
.image {
|
||||
max-width: 250px;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
#customdropzone {
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
#customdropzone >>> .icon {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
#customdropzone >>> p {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mt-12 {
|
||||
margin-top: 35px !important;
|
||||
}
|
||||
|
||||
.v-input >>> .v-text-field__slot input {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
.v-input >>> .v-text-field__slot textarea {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
|
||||
.youtube >>> .v-input__icon--prepend-inner i {
|
||||
color: #e64e0f !important;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.youtube >>> .v-text-field__slot {
|
||||
border-left: 1px solid var(--v-lines-base) !important;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.youtube >>> .v-input__icon--prepend-inner {
|
||||
margin: auto 14px auto 10px;
|
||||
}
|
||||
</style>
|
||||
181
components/Learning/ProductOverview/Links.vue
Normal file
181
components/Learning/ProductOverview/Links.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.links')">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('general.sharepoint')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
prepend-inner-icon="icon-sharepoint"
|
||||
v-model="sharepoint_link"
|
||||
placeholder="https://sharepoint.com/"
|
||||
outlined
|
||||
flat
|
||||
class="links"
|
||||
v-if="editMode"
|
||||
></v-text-field>
|
||||
<v-btn
|
||||
v-if="!editMode && sharepoint_link"
|
||||
:href="sharepoint_link"
|
||||
target="_blank"
|
||||
text
|
||||
link
|
||||
|
||||
><v-icon left>icon-sharepoint</v-icon> {{ sharepoint_link }}</v-btn
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<!-- <v-subheader v-if="editMode">{{ $t('general.add_link') }}</v-subheader> -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('general.support_site')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="support_link"
|
||||
prepend-inner-icon="icon-link"
|
||||
placeholder="https://support.ggzecademy.nl/"
|
||||
outlined
|
||||
flat
|
||||
class="links"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<v-btn
|
||||
v-if="!editMode && support_link"
|
||||
:href="support_link"
|
||||
link
|
||||
text
|
||||
target="_blank"
|
||||
|
||||
><v-icon left>icon-link</v-icon>{{ support_link }}</v-btn
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<!-- <v-subheader v-if="editMode">{{ $t('general.add_link') }}</v-subheader> -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('general.support_tickets')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="support_tickets_link"
|
||||
prepend-inner-icon="icon-link"
|
||||
placeholder="https://support.ggzecademy.nl/"
|
||||
outlined
|
||||
flat
|
||||
class="links"
|
||||
v-if="editMode"
|
||||
></v-text-field>
|
||||
<v-btn
|
||||
v-if="!editMode && support_tickets_link"
|
||||
:href="support_tickets_link"
|
||||
text
|
||||
target="_blank"
|
||||
link
|
||||
><v-icon left>icon-link</v-icon>{{ support_tickets_link }}</v-btn
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<!-- <v-subheader v-if="editMode">{{ $t('general.add_link') }}</v-subheader> -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.learning.local
|
||||
},
|
||||
sharepoint_link: {
|
||||
get() {
|
||||
return this.local.sharepoint_link || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'sharepoint_link',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
support_link: {
|
||||
get() {
|
||||
return this.local.support_link || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'support_link',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
support_tickets_link: {
|
||||
get() {
|
||||
return this.local.support_tickets_link || ''
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'support_tickets_link',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-input__icon--prepend .v-icon {
|
||||
font-size: 15px !important;
|
||||
}
|
||||
.links >>> .v-input__icon--prepend-inner {
|
||||
margin: auto 12px;
|
||||
}
|
||||
.links >>> .v-input__icon--prepend-inner i {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
.links >>> .v-input__icon--prepend-inner .icon-sharepoint {
|
||||
color: dodgerblue !important;
|
||||
}
|
||||
|
||||
.links >>> .v-text-field__slot {
|
||||
border-left: 1px solid var(--v-lines-base) !important;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.links >>> .v-input__slot:hover .v-text-field__slot {
|
||||
border-color: var(--v-secAccent-base) !important;
|
||||
}
|
||||
.row{
|
||||
overflow: hidden;
|
||||
}
|
||||
.row >>> div:nth-child(3) .v-subheader {
|
||||
color: var(--v-tertiary-base) !important;
|
||||
}
|
||||
</style>
|
||||
859
components/Learning/ProductOverview/Notifications.vue
Normal file
859
components/Learning/ProductOverview/Notifications.vue
Normal file
@@ -0,0 +1,859 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.notifications')">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="notifications"
|
||||
:options="options"
|
||||
hide-default-footer
|
||||
item-key="notification"
|
||||
flat
|
||||
v-if="hasNotifications"
|
||||
>
|
||||
<template v-slot:item.date="{ item }">{{
|
||||
formatDate(item.date)
|
||||
}}</template>
|
||||
|
||||
<template v-slot:item.sent="{ item }">
|
||||
<v-icon color="teal" class="icon-checkmark" v-if="item.sent"></v-icon>
|
||||
<v-icon color="red" class="icon-close" size="8" v-else></v-icon>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
class="mx-4 white--text button-hover"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
small
|
||||
@click="viewItem(item)"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="
|
||||
editMode && ($store.getters.isAdmin || $store.getters.isOperator)
|
||||
"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.edit') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialogDelete">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.delete') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{
|
||||
$t('learning.product_overview.delete_confirmation', {
|
||||
productName: item.subject,
|
||||
})
|
||||
}}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogNotification"
|
||||
max-width="75%"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editMode"
|
||||
class="my-10 cta-secondary"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
@click="notificationEditMode = true"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
{{ $t('learning.add_new_notification') }}
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.actions.date_time')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="8" class="d-flex">
|
||||
<v-menu
|
||||
ref="menuDate"
|
||||
v-model="menuDate"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`notification-date-${Math.random()}`"
|
||||
v-model="computedDateFormatted"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
readonly
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="editedItem.date"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
locale="nl-NL"
|
||||
>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text @click="menuDate = false">Cancel</v-btn>
|
||||
<v-btn text @click="$refs.menuDate.save(editedItem.date)"
|
||||
>OK</v-btn
|
||||
>
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
<span class="mx-5 my-3 font-weight-bold">{{
|
||||
$t('learning.actions.at')
|
||||
}}</span>
|
||||
<v-menu
|
||||
ref="menuTime"
|
||||
v-model="menuTime"
|
||||
:close-on-content-click="false"
|
||||
:nudge-right="40"
|
||||
:return-value.sync="editedItem.time"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
max-width="290px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`notification-time-${Math.random()}`"
|
||||
v-model="editedItem.time"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
|
||||
<v-time-picker
|
||||
v-if="menuTime"
|
||||
v-model="editedItem.time"
|
||||
full-width
|
||||
format="24hr"
|
||||
@click:minute="$refs.menuTime.save(editedItem.time)"
|
||||
></v-time-picker>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black"></v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.actions.mail_addresses')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="8" class="d-flex">
|
||||
<v-combobox
|
||||
v-model="editedItem.emails"
|
||||
hide-selected
|
||||
label="Add emails here"
|
||||
multiple
|
||||
chips
|
||||
solo
|
||||
:disabled="!editModeComputed"
|
||||
>
|
||||
<template
|
||||
v-slot:selection="{ attrs, item, parent, selected }"
|
||||
>
|
||||
<v-chip
|
||||
v-bind="attrs"
|
||||
:input-value="selected"
|
||||
small
|
||||
:close="editModeComputed"
|
||||
@click:close="parent.selectItem(item)"
|
||||
>
|
||||
<span class="pr-2">{{ item }}</span>
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black"></v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.actions.users')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="8" class="d-flex users">
|
||||
<v-autocomplete
|
||||
v-model="editedItem.users"
|
||||
:items="users"
|
||||
chips
|
||||
color="blue-grey lighten-2"
|
||||
item-text="fullName"
|
||||
item-value="id"
|
||||
multiple
|
||||
hide-selected
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
>
|
||||
<template v-slot:selection="data">
|
||||
<v-chip
|
||||
v-bind="data.attrs"
|
||||
:input-value="data.id"
|
||||
:close="editModeComputed"
|
||||
@click="data.select"
|
||||
@click:close="removeUser(data.item.id)"
|
||||
>{{ data.item.fullName }}</v-chip
|
||||
>
|
||||
</template>
|
||||
<template v-slot:item="data">
|
||||
<template>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title
|
||||
v-html="data.item.fullName"
|
||||
></v-list-item-title>
|
||||
<!-- <v-list-item-subtitle
|
||||
v-html="data.item.group"
|
||||
></v-list-item-subtitle>-->
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
</template>
|
||||
</v-autocomplete>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="12" md="2"></v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.actions.subject')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="8" class="d-flex">
|
||||
<v-text-field
|
||||
v-model="editedItem.subject"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black"></v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.actions.message')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="8">
|
||||
<quill-editor
|
||||
class="quill primary"
|
||||
:options="editorOption"
|
||||
v-model="editedItem.message"
|
||||
style="width: 100%"
|
||||
v-if="editModeComputed"
|
||||
/>
|
||||
<span v-html="editedItem.message" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="2">
|
||||
<v-subheader class="txt--text font-weight-black"></v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editModeComputed">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="save"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw product kiest u eerst voor 'Opslaan' om
|
||||
deze functie te activeren.
|
||||
</p>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>In the picture</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9" class="mb-4 d-flex flex-column">
|
||||
<div class="pb-0 mb-0 d-flex">
|
||||
<v-switch
|
||||
:disabled="!editMode"
|
||||
inset
|
||||
class="toggle my-3"
|
||||
v-model="in_the_picture"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
:value="computedInThePicDateFormattedStart"
|
||||
readonly
|
||||
prepend-inner-icon="icon-events"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:flat="!editMode"
|
||||
/>
|
||||
<span class="mx-5 my-3 font-weight-bold"> tot </span>
|
||||
<v-text-field
|
||||
:value="computedInThePicDateFormattedEnd"
|
||||
readonly
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:flat="!editMode"
|
||||
append-icon="icon-events"
|
||||
/>
|
||||
</div>
|
||||
<v-date-picker
|
||||
v-if="$store.getters.isSuperAdminOrAdmin"
|
||||
v-model="dates"
|
||||
no-title
|
||||
:disabled="!editMode"
|
||||
flat
|
||||
first-day-of-week="1"
|
||||
range
|
||||
full-width
|
||||
locale="nl-NL"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
quillEditor,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
users: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
picker: new Date(Date.now() - new Date().getTimezoneOffset() * 60000)
|
||||
.toISOString()
|
||||
.substr(0, 10),
|
||||
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'subject', value: 'subject' },
|
||||
{ text: 'date', value: 'date' },
|
||||
{ text: 'time', value: 'time' },
|
||||
{ text: 'sent', value: 'sent' },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
loading: false,
|
||||
dialogNotification: false,
|
||||
dialogDelete: false,
|
||||
|
||||
editedIndex: -1,
|
||||
editedItem: {
|
||||
date: '',
|
||||
time: null,
|
||||
emails: [],
|
||||
users: [],
|
||||
subject: '',
|
||||
message: '',
|
||||
},
|
||||
defaultItem: {
|
||||
date: '',
|
||||
time: null,
|
||||
emails: [],
|
||||
users: [],
|
||||
subject: '',
|
||||
message: '',
|
||||
},
|
||||
content: 'Write here your content...',
|
||||
editorOption: {
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ size: ['small', false, 'large'] }],
|
||||
['bold', 'italic'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
['link'],
|
||||
],
|
||||
},
|
||||
},
|
||||
notificationEditMode: false,
|
||||
autoUpdate: true,
|
||||
isUpdating: false,
|
||||
activator: null,
|
||||
attach: null,
|
||||
editing: null,
|
||||
index: -1,
|
||||
date: null,
|
||||
menu: false,
|
||||
menuStart: false,
|
||||
menuEnd: false,
|
||||
menuDate: false,
|
||||
menuTime: false,
|
||||
menu2: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
dates: [],
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogNotification(val) {
|
||||
val || this.close()
|
||||
},
|
||||
dates(val) {
|
||||
// If the second date is earlier than the first, switch them
|
||||
if (val.length === 2 && val[1] < val[0]) this.dates.reverse()
|
||||
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'in_the_picture_start',
|
||||
value: val[0] || null,
|
||||
})
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'in_the_picture_end',
|
||||
value: val[1] || null,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.getters.localProduct
|
||||
},
|
||||
notifications() {
|
||||
if (!this.local || !Array.isArray(this.local.notifications)) return []
|
||||
return this.local.notifications
|
||||
},
|
||||
hasNotifications() {
|
||||
return this.notifications.length > 0
|
||||
},
|
||||
formTitle() {
|
||||
return this.editedIndex === -1
|
||||
? 'Nieuwe notificatie'
|
||||
: 'Bewerken notificatie'
|
||||
},
|
||||
editModeComputed() {
|
||||
return this.notificationEditMode && this.editMode
|
||||
},
|
||||
computedDateFormatted() {
|
||||
return this.formatDate(this.editedItem.date)
|
||||
},
|
||||
computedInThePicDateFormattedStart() {
|
||||
return this.formatDate(this.in_the_picture_start)
|
||||
},
|
||||
computedInThePicDateFormattedEnd() {
|
||||
return this.formatDate(this.in_the_picture_end)
|
||||
},
|
||||
in_the_picture: {
|
||||
get() {
|
||||
return this.local.in_the_picture
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'in_the_picture',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
in_the_picture_start() {
|
||||
return this.local.in_the_picture_start
|
||||
},
|
||||
in_the_picture_end() {
|
||||
return this.local.in_the_picture_end
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
assignItemToEdited(item) {
|
||||
this.editedIndex = this.notifications.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
|
||||
if (typeof this.editedItem.users === 'string') {
|
||||
this.editedItem.users = JSON.parse(this.editedItem.users)
|
||||
}
|
||||
if (typeof this.editedItem.emails === 'string') {
|
||||
this.editedItem.emails = JSON.parse(this.editedItem.emails)
|
||||
}
|
||||
},
|
||||
formatDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [year, month, day, time] = date.replace(' ', '-').split('-')
|
||||
return `${day}/${month}/${year}`
|
||||
},
|
||||
|
||||
viewItem(item) {
|
||||
this.editedIndex = this.notifications.indexOf(item)
|
||||
this.notificationEditMode = false
|
||||
this.assignItemToEdited(item)
|
||||
this.dialogNotification = true
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.notificationEditMode = true
|
||||
this.assignItemToEdited(item)
|
||||
this.dialogNotification = true
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No notificaion to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$axios.delete(
|
||||
`/learning-products/notifications/${item.id}`
|
||||
)
|
||||
|
||||
this.$store.commit('learning/DELETE_COURSE_NOTIFICATION_LOCAL', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogNotification = false
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Notification deleted`,
|
||||
color: 'success',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
} catch (error) {
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to delete the selected notification`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
// Edit mode
|
||||
if (this.editedIndex > -1) {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
this.editedItem.sent = 0
|
||||
|
||||
const response = await this.$axios.post(
|
||||
'/learning-products/notifications',
|
||||
this.editedItem
|
||||
)
|
||||
|
||||
this.$store.commit('learning/EDIT_COURSE_NOTIFICATION_LOCAL', {
|
||||
index: this.editedIndex,
|
||||
notification: response.data,
|
||||
})
|
||||
|
||||
this.dialogAccreditation = false
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Notification stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogNotification = false
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the notification`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
// Create new mode
|
||||
} else {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
let data = { ...this.editedItem }
|
||||
data['emails'] = JSON.stringify(data['emails'])
|
||||
data['users'] = JSON.stringify(data['users'])
|
||||
|
||||
const response = await this.$axios.post(
|
||||
'/learning-products/notifications',
|
||||
data
|
||||
)
|
||||
|
||||
this.dialog = false
|
||||
|
||||
this.$store.commit(
|
||||
'learning/ADD_COURSE_NOTIFICATION_LOCAL',
|
||||
response.data
|
||||
)
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Notifican stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogAccreditation = false
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the notification`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.dialogNotification = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
})
|
||||
},
|
||||
edit(index, item) {
|
||||
if (!this.editing) {
|
||||
this.editing = item
|
||||
this.index = index
|
||||
} else {
|
||||
this.editing = null
|
||||
this.index = -1
|
||||
}
|
||||
},
|
||||
|
||||
removeUser(userId) {
|
||||
const index = this.editedItem.users.indexOf(userId)
|
||||
|
||||
if (index >= 0) {
|
||||
let arrayUsers = [...this.editedItem.users]
|
||||
arrayUsers.splice(index, 1)
|
||||
this.editedItem.users = [...arrayUsers]
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i,
|
||||
.font-weight-bold {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-card >>> .in_the_picture {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
max-height: 68% !important;
|
||||
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
|
||||
table tr .button-hover.v-btn {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover .button-hover.v-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
.v-autocomplete__content {
|
||||
top: 532px !important;
|
||||
left: 507px !important;
|
||||
}
|
||||
|
||||
.v-autocomplete__content >>> .v-list .v-list-item:first-child {
|
||||
pointer-events: auto !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
.v-autocomplete__content
|
||||
.v-list
|
||||
.v-list-item:first-child
|
||||
.v-list-item__content {
|
||||
border-bottom: 0px solid var(--v-search-base) !important;
|
||||
padding-bottom: unset !important;
|
||||
}
|
||||
.v-autocomplete__content .v-list {
|
||||
padding: 6px !important;
|
||||
}
|
||||
.v-autocomplete__content .v-list .v-list-item:first-child .v-list-item__title {
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
.v-text-field.v-text-field--solo >>> .v-input__append-inner {
|
||||
align-self: baseline;
|
||||
}
|
||||
.v-text-field.v-text-field--solo >>> .v-input__slot {
|
||||
padding: 8px 12px !important;
|
||||
}
|
||||
.v-text-field.v-text-field--solo >>> .v-input__icon--append {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
168
components/Learning/ProductOverview/Organize.vue
Normal file
168
components/Learning/ProductOverview/Organize.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<accordion-card
|
||||
:title="$t('learning.product_overview.organize')"
|
||||
id="organize"
|
||||
>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.type') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="type"
|
||||
filterType="checkbox"
|
||||
:editMode="editMode"
|
||||
/>
|
||||
<!-- v-if="isFilterTypeEmpty" -->
|
||||
<small class="error--text">Het type is verplicht</small>
|
||||
<br />
|
||||
<br />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
{{ $t('learning.more_options_selectable') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.product_type') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
class="producttype"
|
||||
filterTitle="product_type"
|
||||
filterType="mixed"
|
||||
:editMode="editMode"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.category') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="category"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.theme') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="theme"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.course') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="course"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.audience') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="audience"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
{{ $t('learning.more_options_selectable') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.filters.quality_standards') | capitalize
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<universalFilterSelector
|
||||
filterTitle="quality_standards"
|
||||
:editMode="editMode"
|
||||
filterType="mixed"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
{{ $t('learning.more_options_selectable') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import universalFilterSelector from '@/components/UniversalFilterSelector/UniversalFilterSelector'
|
||||
// import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
universalFilterSelector,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isFilterTypeEmpty() {
|
||||
return this.$store.getters.isFilterTypeEmpty
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#organize >>> .v-input__slot .v-select__slot {
|
||||
margin-left: -4px;
|
||||
}
|
||||
#organize >>> .producttype .v-input__slot .v-select__slot {
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
304
components/Learning/ProductOverview/Texts.vue
Normal file
304
components/Learning/ProductOverview/Texts.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.texts')">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.short_description')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="short_description"
|
||||
id="short_description"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'short_description' }"
|
||||
@focus="onEditorFocus($event, 'short_description')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'short_description')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<!-- @change="onEditorChange($event)" -->
|
||||
|
||||
<span v-html="short_description" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.learning_goals')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="learning_goals"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'learning_goals' }"
|
||||
@focus="onEditorFocus($event, 'learning_goals')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'learning_goals')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="learning_goals" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.review')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="review"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'review' }"
|
||||
@focus="onEditorFocus($event, 'review')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'review')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="review" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.certification')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="certification"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'certification' }"
|
||||
@focus="onEditorFocus($event, 'certification')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'certification')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="certification" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.extra_information')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="extra_information"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'extra_information' }"
|
||||
@focus="onEditorFocus($event, 'extra_information')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'extra_information')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="extra_information" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.product_overview.target_audience')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="target_audience"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'target_audience' }"
|
||||
@focus="onEditorFocus($event, 'target_audience')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'target_audience')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="target_audience" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Kwaliteitsstandaarden
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="pl-6">
|
||||
<quill-editor
|
||||
v-model="quality_standards"
|
||||
:options="editorOption"
|
||||
class="quill"
|
||||
:class="{ focused: selectedEditor === 'quality_standards' }"
|
||||
@focus="onEditorFocus($event, 'quality_standards')"
|
||||
@blur="onEditorBlur($event)"
|
||||
@change="onEditorChange($event, 'quality_standards')"
|
||||
v-if="editMode"
|
||||
/>
|
||||
<span v-html="quality_standards" v-else></span>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
quillEditor,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedEditor: '',
|
||||
editorOption: {
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ size: ['small', false, 'large'] }],
|
||||
['bold', 'italic'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
['link'],
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.learning.local
|
||||
},
|
||||
|
||||
short_description: {
|
||||
get() {
|
||||
return this.local.short_description
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'short_description',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
learning_goals: {
|
||||
get() {
|
||||
return this.local.learning_goals
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'learning_goals',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
review: {
|
||||
get() {
|
||||
return this.local.review
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'review',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
certification: {
|
||||
get() {
|
||||
return this.local.certification
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'certification',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
extra_information: {
|
||||
get() {
|
||||
return this.local.extra_information
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'extra_information',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
target_audience: {
|
||||
get() {
|
||||
return this.local.target_audience
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'target_audience',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
quality_standards: {
|
||||
get() {
|
||||
return this.local.quality_standards
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/UPDATE_FIELD', {
|
||||
field: 'quality_standards',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onEditorBlur(editor) {
|
||||
this.selectedEditor = ''
|
||||
// console.log('editor blur!', editor)
|
||||
},
|
||||
onEditorFocus(editor, nameEditor) {
|
||||
this.selectedEditor = nameEditor
|
||||
},
|
||||
onEditorReady(editor) {
|
||||
// console.log('editor ready!', editor)
|
||||
},
|
||||
onEditorChange(editor, nameEditor) {
|
||||
if (this.selectedEditor !== nameEditor) this.selectedEditor = nameEditor
|
||||
// console.log('editor change!', editor)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-subheader {
|
||||
display: unset;
|
||||
}
|
||||
</style>
|
||||
955
components/Learning/ProductOverview/Versions.vue
Normal file
955
components/Learning/ProductOverview/Versions.vue
Normal file
@@ -0,0 +1,955 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.version')">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="versions"
|
||||
:options="options"
|
||||
hide-default-footer
|
||||
item-key="version"
|
||||
v-if="hasVersions"
|
||||
flat
|
||||
>
|
||||
<template v-slot:item.made_by="{ item }">
|
||||
{{ getFilterItem('made_by', item).title }}
|
||||
</template>
|
||||
<template v-slot:item.dev_environment="{ item }">
|
||||
{{ getFilterItem('dev_environment', item).title }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.status="{ item }">
|
||||
<v-icon
|
||||
x-small
|
||||
class="mr-2"
|
||||
v-if="getFilterItem('status', item).color"
|
||||
:color="getFilterItem('status', item).color"
|
||||
>mdi-circle</v-icon
|
||||
>
|
||||
{{ getFilterItem('status', item).title }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.release_start="{ item }">
|
||||
{{ formatDate(item.release_start) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.release_end="{ item }">
|
||||
{{ formatDate(item.release_end) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
class="mx-4 white--text view"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
small
|
||||
@click="viewItem(item)"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="
|
||||
editMode && ($store.getters.isAdmin || $store.getters.isOperator)
|
||||
"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialogDelete">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{
|
||||
$t('learning.product_overview.delete_confirmation', {
|
||||
productName: item.version_number,
|
||||
})
|
||||
}}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogVersion"
|
||||
max-width="75%"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editMode"
|
||||
class="cta-secondary my-10"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
@click="resetVersionsFilters"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
|
||||
{{ $t('learning.add_new_version') }}</v-btn
|
||||
>
|
||||
</template>
|
||||
<v-form ref="form" v-model="valid" lazy-validation>
|
||||
<v-card ref="card">
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
<!-- <input ref="input" /> -->
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.versions.version_number')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9">
|
||||
<v-text-field
|
||||
v-model="editedItem.version_number"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
:rules="rules.version_number"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row
|
||||
v-for="(filterTitle, i) in filterInputs"
|
||||
:key="`row-filter-${i}`"
|
||||
>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t(`learning.filters.${filterTitle}`)
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9">
|
||||
<universalFilterSelector
|
||||
:filterTitle="filterTitle"
|
||||
:editMode="editModeComputed"
|
||||
target="versions"
|
||||
:key="`universal-filter-version-${i}`"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
{{ $t('learning.versions.release_date.from') }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9" class="d-flex">
|
||||
<v-menu
|
||||
ref="menuStart"
|
||||
v-model="menuStart"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<!-- <input type="text" v-model="startData" /> -->
|
||||
|
||||
<v-text-field
|
||||
:name="`release-start-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedStart"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
:rules="rules.release_start"
|
||||
required
|
||||
error
|
||||
readonly
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="editedItem.release_start"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
locale="nl-NL"
|
||||
>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text @click="menuStart = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
@click="$refs.menuStart.save(editedItem.release_start)"
|
||||
>OK</v-btn
|
||||
>
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
<span class="mx-5 my-3 font-weight-bold">
|
||||
{{ $t('learning.versions.release_date.to') }}
|
||||
</span>
|
||||
<v-menu
|
||||
ref="menuEnd"
|
||||
v-model="menuEnd"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`release-end-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedEnd"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
clearable
|
||||
readonly
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="editedItem.release_end"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
locale="nl-NL"
|
||||
>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text @click="menuEnd = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
@click="$refs.menuEnd.save(editedItem.release_end)"
|
||||
>OK</v-btn
|
||||
>
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.versions.release_planning')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9">
|
||||
<quill-editor
|
||||
class="quill primary"
|
||||
:options="editorOption"
|
||||
v-model="editedItem.release_planning_description"
|
||||
v-if="editModeComputed"
|
||||
/>
|
||||
<span
|
||||
v-html="editedItem.release_planning_description"
|
||||
v-else
|
||||
></span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="mb-10">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
$t('learning.versions.technical_information')
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9">
|
||||
<quill-editor
|
||||
class="quill primary"
|
||||
v-model="editedItem.technical_information"
|
||||
:options="editorOption"
|
||||
v-if="editModeComputed"
|
||||
/>
|
||||
<div v-html="editedItem.technical_information" v-else></div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- Checklist Summary -->
|
||||
<v-row class="mb-10">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">
|
||||
Checklist
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="9">
|
||||
<v-text-field
|
||||
v-model="checklist_summary"
|
||||
solo
|
||||
disabled
|
||||
flat
|
||||
max-height="100px"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- Checklist -->
|
||||
<v-row v-for="checklist in checklists" :key="checklist.id">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{
|
||||
checklist.title
|
||||
}}</v-subheader>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="12"
|
||||
md="9"
|
||||
class="d-flex flex-column justify-center"
|
||||
>
|
||||
<!-- -->
|
||||
<v-list
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
input-value="true"
|
||||
>
|
||||
<v-list-item-group v-model="checklistsSelected" multiple>
|
||||
<template>
|
||||
<v-list-item
|
||||
v-for="(item, i) in checklist.items"
|
||||
:key="`item-${i}`"
|
||||
:value="item.id"
|
||||
active-class="secondary"
|
||||
two-line
|
||||
>
|
||||
<template v-slot:default="{ active, toggle }">
|
||||
<v-list-item-action>
|
||||
<v-checkbox
|
||||
:input-value="active"
|
||||
:true-value="item.id"
|
||||
:click="toggle"
|
||||
on-icon="icon-selectionbox-checked"
|
||||
off-icon="icon-selectionbox"
|
||||
></v-checkbox>
|
||||
</v-list-item-action>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title
|
||||
v-text="item.title"
|
||||
></v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
v-if="item.subtitle"
|
||||
v-text="item.subtitle"
|
||||
></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action>
|
||||
{{ showChecklistInfo(item.id) }}
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
<!-- -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editModeComputed">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="validate"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw product kiest u eerst voor 'Opslaan' om
|
||||
deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Util from '@/util'
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import universalFilterSelector from '@/components/UniversalFilterSelector/UniversalFilterSelector'
|
||||
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
quillEditor,
|
||||
universalFilterSelector,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
content: 'Write here your content...',
|
||||
editorOption: {
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ size: ['small', false, 'large'] }],
|
||||
['bold', 'italic'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
['link'],
|
||||
],
|
||||
},
|
||||
},
|
||||
headers: [
|
||||
{ text: 'versienummer', value: 'version_number' },
|
||||
{ text: 'gemaakt door', value: 'made_by' },
|
||||
{ text: 'ontwikkelomgeving', value: 'dev_environment' },
|
||||
{ text: 'status', value: 'status' },
|
||||
{ text: 'beschikbaar van', value: 'release_start' },
|
||||
{ text: 'beschikbaar tot', value: 'release_end' },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
rules: {
|
||||
version_number: [(v) => !!v || 'Het versienummer is verplicht.'],
|
||||
release_start: [
|
||||
(v) => !!v || 'De startdatum van de release is verplicht.',
|
||||
],
|
||||
},
|
||||
valid: true,
|
||||
loading: false,
|
||||
date: null,
|
||||
menuPlanning: false,
|
||||
menuStart: false,
|
||||
menuEnd: false,
|
||||
modal: false,
|
||||
menu2: false,
|
||||
filterInputs: ['status', 'made_by', 'dev_environment', 'format_version'],
|
||||
version: {},
|
||||
versionEditMode: false,
|
||||
dialogVersion: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {
|
||||
version_number: '',
|
||||
release_start: '',
|
||||
release_end: '',
|
||||
release_planning_description: '',
|
||||
technical_information: '',
|
||||
},
|
||||
defaultItem: {
|
||||
version_number: '',
|
||||
release_start: '',
|
||||
release_end: '',
|
||||
release_planning_description: '',
|
||||
technical_information: '',
|
||||
},
|
||||
// startData: null,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
remote() {
|
||||
return this.$store.state.learning.remote
|
||||
},
|
||||
local() {
|
||||
return this.$store.state.learning.local
|
||||
},
|
||||
versions() {
|
||||
if (!this.local || !Array.isArray(this.local.versions)) return []
|
||||
return this.local.versions
|
||||
},
|
||||
versionsFiltersSelected() {
|
||||
return this.$store.state.learning.versionsFiltersSelected
|
||||
},
|
||||
hasVersions() {
|
||||
if (!this.versions) return false
|
||||
return this.versions.length > 0
|
||||
},
|
||||
|
||||
hasTmpVersion() {
|
||||
return Util.isNotEmptyObj(this.version)
|
||||
},
|
||||
checklists() {
|
||||
return this.$store.state.learning.checklists || null
|
||||
},
|
||||
checklistsSelected: {
|
||||
get() {
|
||||
return this.$store.state.learning.checklistsSelected
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/SELECT_CHECKLIST', value)
|
||||
},
|
||||
},
|
||||
canEdit() {
|
||||
return (
|
||||
this.$route.query.edit === null &&
|
||||
(this.$store.getters.isAdmin || this.$store.getters.isOperator)
|
||||
)
|
||||
},
|
||||
|
||||
formTitle() {
|
||||
return this.editedIndex === -1 ? 'Nieuwe versie' : 'Bewerken versie'
|
||||
},
|
||||
editModeComputed() {
|
||||
return this.versionEditMode && this.editMode
|
||||
},
|
||||
checklist_summary() {
|
||||
let totalChecklists = 0
|
||||
|
||||
this.checklists.forEach((category) => {
|
||||
totalChecklists += category.items.length
|
||||
})
|
||||
|
||||
return `${this.checklistsSelected.length} van ${totalChecklists} voltooid`
|
||||
},
|
||||
|
||||
// computedDateFormattedStart() {
|
||||
// return this.formatDate(this.editedItem.release_start)
|
||||
// },
|
||||
// computedDateFormattedEnd() {
|
||||
// return this.formatDate(this.editedItem.release_end)
|
||||
// },
|
||||
|
||||
computedDateFormattedStart: {
|
||||
get() {
|
||||
return this.formatDate(this.editedItem.release_start)
|
||||
},
|
||||
set(value) {
|
||||
this.editedItem.release_start = value
|
||||
// if (this.isValidDate(value)) {
|
||||
// this.editedItem.release_start = value
|
||||
// }
|
||||
},
|
||||
},
|
||||
|
||||
computedDateFormattedEnd: {
|
||||
get() {
|
||||
return this.formatDate(this.editedItem.release_end)
|
||||
},
|
||||
|
||||
set(value) {
|
||||
this.editedItem.release_end = value
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogVersion(val) {
|
||||
val || this.close()
|
||||
},
|
||||
// startData(val) {
|
||||
// console.log(': val', val)
|
||||
// if (this.isValidDate(val)) {
|
||||
// this.editedItem.release_start = this.parseDate(val)
|
||||
// }
|
||||
// },
|
||||
},
|
||||
|
||||
methods: {
|
||||
validate() {
|
||||
if (!this.$refs.form.validate()) return
|
||||
this.save()
|
||||
},
|
||||
resetVersionsFilters() {
|
||||
this.versionEditMode = true
|
||||
this.$store.commit('learning/RESET_CHECKLIST_SELECTED')
|
||||
this.$store.commit('learning/RESET_VERSIONS_FILTERS')
|
||||
},
|
||||
|
||||
formatDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [year, month, day, time] = date.replace(' ', '-').split('-')
|
||||
return `${day}/${month}/${year}`
|
||||
},
|
||||
|
||||
parseDate(date) {
|
||||
if (!date || !this.isValidDate(date)) return null
|
||||
const [day, month, year] = date.split('/')
|
||||
if (day && day.length < 2) return null
|
||||
if (month && month.length < 2) return null
|
||||
if (year && year.length < 4) return null
|
||||
return `${year}-${month}-${day}`
|
||||
},
|
||||
|
||||
isValidDate(date) {
|
||||
return new Date(date) !== 'Invalid Date' && !isNaN(new Date(date))
|
||||
},
|
||||
|
||||
showChecklistInfo(checklistId) {
|
||||
if (
|
||||
!this.editedItem ||
|
||||
!this.editedItem.checklists ||
|
||||
!this.editedItem.checklists.length > 0
|
||||
)
|
||||
return null
|
||||
|
||||
const checklistFound = this.editedItem.checklists.find(
|
||||
(checklist) => checklist.checklist_id === checklistId
|
||||
)
|
||||
if (!checklistFound) return null
|
||||
return `${checklistFound.created_at}, ${checklistFound.user.fullName}`
|
||||
},
|
||||
|
||||
setVersionFiltersAndChecklist(item) {
|
||||
// Iterate item.filters and set in store versionsFiltersSelected filter_name: filter_item_id
|
||||
item.filters.forEach(async (f) => {
|
||||
const filterItem = this.$store.getters.getFilterItemById(
|
||||
f.filter_item_id
|
||||
)
|
||||
|
||||
await this.$store.commit('learning/UPDATE_FILTERS', {
|
||||
filterId: filterItem.filter_id,
|
||||
target: 'versions',
|
||||
value: f.filter_item_id,
|
||||
})
|
||||
})
|
||||
|
||||
const arrayChecklistIdsSelected = []
|
||||
|
||||
item.checklists.forEach(async (checklist) => {
|
||||
arrayChecklistIdsSelected.push(checklist.checklist_id)
|
||||
this.$store.commit(
|
||||
'learning/SET_CHECKED_CHECKLISTS',
|
||||
arrayChecklistIdsSelected
|
||||
)
|
||||
})
|
||||
|
||||
this.editedIndex = this.versions.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
getFilterItem(filterTitle, version) {
|
||||
const filter = this.$store.getters.getFilterByTitle(filterTitle)
|
||||
|
||||
const arrayTmp = []
|
||||
if (!version.filters) return {}
|
||||
version.filters.forEach((f) => {
|
||||
const filterItemTmp = this.$store.getters.getFilterItemById(
|
||||
f.filter_item_id
|
||||
)
|
||||
arrayTmp.push(filterItemTmp)
|
||||
})
|
||||
|
||||
const filterItem = arrayTmp.find((e) => e.filter_id === filter.id)
|
||||
return filterItem || {}
|
||||
},
|
||||
|
||||
viewItem(item) {
|
||||
this.versionEditMode = false
|
||||
this.setVersionFiltersAndChecklist(item)
|
||||
this.dialogVersion = true
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.versionEditMode = true
|
||||
this.setVersionFiltersAndChecklist(item)
|
||||
this.dialogVersion = true
|
||||
// this.$refs.input.focus()
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No version to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$axios.delete(`/versions/${item.id}`)
|
||||
|
||||
this.$store.commit('learning/DELETE_VERSION_LOCAL', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogVersion = false
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Version deleted`,
|
||||
color: 'success',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
} catch (error) {
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to delete the selected version`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
close() {
|
||||
this.dialogVersion = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
},
|
||||
|
||||
setFiltersSelectedInEditedItem() {
|
||||
let versionFiltersItemsIds = []
|
||||
|
||||
for (const [key, value] of Object.entries(this.versionsFiltersSelected)) {
|
||||
versionFiltersItemsIds.push(value)
|
||||
}
|
||||
|
||||
this.editedItem['filter_items'] = versionFiltersItemsIds
|
||||
},
|
||||
|
||||
setChecklistsSelectedInEditedItem() {
|
||||
this.editedItem['checklists_selected'] = [
|
||||
...this.$store.state.learning.checklistsSelected,
|
||||
]
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
// Edit mode
|
||||
if (this.editedIndex > -1) {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
this.setFiltersSelectedInEditedItem()
|
||||
this.setChecklistsSelectedInEditedItem()
|
||||
|
||||
const response = await this.$axios.post('/versions', this.editedItem)
|
||||
|
||||
this.$store.commit('learning/EDIT_VERSION_LOCAL', {
|
||||
index: this.editedIndex,
|
||||
version: response.data,
|
||||
})
|
||||
|
||||
this.dialogVersion = false
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Version stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogVersion = false
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the version`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
// Create new mode
|
||||
} else {
|
||||
try {
|
||||
this.editedItem.learning_product_id = this.local.id
|
||||
|
||||
this.setFiltersSelectedInEditedItem()
|
||||
this.setChecklistsSelectedInEditedItem()
|
||||
|
||||
const response = await this.$axios.post('/versions', this.editedItem)
|
||||
|
||||
this.dialog = false
|
||||
|
||||
this.$store.commit('learning/ADD_VERSION_LOCAL', response.data)
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Version stored`,
|
||||
color: 'success',
|
||||
icon: 'icon-checkmark',
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
|
||||
this.dialogVersion = false
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
|
||||
this.$notifier.showMessage({
|
||||
content: `Error trying to store the version`,
|
||||
color: 'error',
|
||||
icon: 'mdi-delete',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
this.close()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.v-card >>> p {
|
||||
margin: 0;
|
||||
color: var(--v-txt-base);
|
||||
}
|
||||
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
table tr button.view {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover button.view {
|
||||
opacity: 1;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
max-height: 68%;
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
|
||||
.v-list-item >>> .v-input__slot {
|
||||
background: unset;
|
||||
border: none;
|
||||
}
|
||||
.v-list-item--active.secondary {
|
||||
background-color: var(--v-primary-base) !important;
|
||||
}
|
||||
.v-list-item--active::before {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.v-list {
|
||||
padding: 0;
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 242px !important;
|
||||
}
|
||||
</style>
|
||||
18
components/Learning/Settings.vue
Normal file
18
components/Learning/Settings.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<v-icon
|
||||
class="mx-4"
|
||||
@click.stop="
|
||||
$store.commit('navigation/SWITCH_RIGHT_DRAWER', {
|
||||
component: 'Settings',
|
||||
subMenu: 'columns',
|
||||
})
|
||||
"
|
||||
>icon-settings</v-icon
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
65
components/Learning/SynonymsSelector.vue
Normal file
65
components/Learning/SynonymsSelector.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<v-select
|
||||
v-model="synonymsSelected"
|
||||
:items="allSynonyms"
|
||||
attach
|
||||
chips
|
||||
multiple
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
append-icon="icon-dropdown"
|
||||
>
|
||||
<template v-slot:selection="{ attrs, item, select, selected }">
|
||||
<v-chip
|
||||
v-bind="attrs"
|
||||
:input-value="selected"
|
||||
color="secondary"
|
||||
@click="select"
|
||||
>
|
||||
<!-- close -->
|
||||
<!-- @click:close="remove(item)" -->
|
||||
<v-icon class="mx-2"> mdi-tag</v-icon>
|
||||
|
||||
<strong>{{ item.title }}</strong
|
||||
>
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
synonymsSelected: {
|
||||
get() {
|
||||
return this.$store.state.learning.synonymsSelected
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/SELECT_SYNONYM', value)
|
||||
},
|
||||
},
|
||||
|
||||
allSynonyms() {
|
||||
return this.$store.getters.synonyms
|
||||
},
|
||||
},
|
||||
|
||||
// methods: {
|
||||
// remove(synonym) {
|
||||
// if (!synonym || !synonym.id) return
|
||||
// this.$store.dispatch('learning/removeSynonym', synonym.id)
|
||||
// },
|
||||
// },
|
||||
}
|
||||
</script>
|
||||
34
components/Listener/Listener.vue
Normal file
34
components/Listener/Listener.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<span></span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
// #warning Laravel Echo has been manually disabled until broadcasting issue is fixed.
|
||||
// async mounted() {
|
||||
// this.$echo
|
||||
// .channel('updates')
|
||||
// .listen(`.updated-user-${this.$auth.user.id}`, async (e) => {
|
||||
// await this.$auth.fetchUser()
|
||||
|
||||
// this.$notifier.showMessage({
|
||||
// content: 'Notification received',
|
||||
// color: 'success',
|
||||
// icon: 'icon-message',
|
||||
// })
|
||||
// })
|
||||
|
||||
// this.$echo
|
||||
// .channel('updates')
|
||||
// .listen(`.products-catalog-updated`, async (e) => {
|
||||
// await this.$store.dispatch('learning/pullProducts')
|
||||
|
||||
// this.$notifier.showMessage({
|
||||
// content: 'Products Catalog updated',
|
||||
// color: 'success',
|
||||
// icon: 'icon-message',
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
}
|
||||
</script>
|
||||
43
components/LocaleSwitch/LocaleSwitch.vue
Normal file
43
components/LocaleSwitch/LocaleSwitch.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-avatar size="24" v-on="on" tile class="mx-2">
|
||||
<img
|
||||
:src="require(`@/assets/img/flags/svg/${currentLocale.flag}`)"
|
||||
:alt="currentLocale.name"
|
||||
/>
|
||||
</v-avatar>
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="locale in availableLocales"
|
||||
:key="locale.code"
|
||||
nuxt
|
||||
:to="switchLocalePath(locale.code)"
|
||||
exact
|
||||
>
|
||||
<v-list-item-avatar tile>
|
||||
<img :src="require(`@/assets/img/flags/svg/${locale.flag}`)" />
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="locale.name"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
currentLocale() {
|
||||
return this.$i18n.locales.filter((i) => i.code === this.$i18n.locale)[0]
|
||||
},
|
||||
availableLocales() {
|
||||
return this.$i18n.locales.filter((i) => i.code !== this.$i18n.locale)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
25
components/Logo.vue
Normal file
25
components/Logo.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
|
||||
<component :is="logo" />
|
||||
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
theme: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
computedTheme() {
|
||||
if (this.theme) return this.theme
|
||||
if (this.$vuetify.theme.dark) return 'dark'
|
||||
return 'light'
|
||||
},
|
||||
logo() {
|
||||
const customerLowercase = process.env.CUSTOMER.toLowerCase()
|
||||
return require(`@/assets/img/${customerLowercase}/logo-${this.computedTheme}.svg?inline`)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
714
components/Members/AddressMembers.vue
Normal file
714
components/Members/AddressMembers.vue
Normal file
@@ -0,0 +1,714 @@
|
||||
<template>
|
||||
<accordion-card title="Adressen">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="addresses"
|
||||
:options="options"
|
||||
hide-default-footer
|
||||
item-key="address"
|
||||
flat
|
||||
v-if="hasAddresses"
|
||||
>
|
||||
<template v-slot:item.type="{ item }">
|
||||
{{ $t(`members.types.${item.type}`).toLowerCase() }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.contact="{ item }">
|
||||
{{
|
||||
`${item.first_name_contact_person} ${item.last_name_contact_person}`
|
||||
}}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.address="{ item }">{{
|
||||
`${item.address ? item.address : ''} ${
|
||||
item.postal ? ', ' + item.postal : ''
|
||||
} ${item.city ? item.city : ''}`
|
||||
}}</template>
|
||||
|
||||
<template v-slot:item.profiel="{ item }">
|
||||
<v-icon :color="!item.approved_at ? 'accent' : 'success'">
|
||||
{{
|
||||
!item.approved_at ? 'mdi-alert-circle-outline' : 'icon-checkmark'
|
||||
}}
|
||||
</v-icon>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
class="mx-4 white--text view"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
small
|
||||
@click="viewItem(item)"
|
||||
v-if="$store.getters.hasCharges"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu offset-y v-if="editMode && $store.getters.isSuperAdminOrAdmin">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.edit') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog
|
||||
max-width="740"
|
||||
:persistent="editModeComputed"
|
||||
v-model="dialogDelete"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.delete') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">{{
|
||||
$t('learning.delete_addressmembers_confirmation')
|
||||
}}</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogAddresses"
|
||||
max-width="75%"
|
||||
v-if="$store.getters.isSuperAdminOrAdmin"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editMode"
|
||||
class="my-10 cta-secondary"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
@click="addressEditMode = true"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>Nieuw adres toevoegen
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-form ref="form" v-model="valid" lazy-validation>
|
||||
<v-card ref="card">
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Type</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
v-model="editedItem.type"
|
||||
:items="types"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-if="isCreatedModeAddress"
|
||||
:rules="rules.type"
|
||||
required
|
||||
error
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
disabled
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.type"
|
||||
v-else
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Onder vermelding van</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.indicating"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Aanhef</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.title_contact_person"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Voorletters</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.initials_contact_person"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>T.a.v. voornaam</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.first_name_contact_person"
|
||||
:rules="rules.first_name"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Tussenvoegsel</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.middle_name_contact_person"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>T.a.v. achternaam</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.last_name_contact_person"
|
||||
:rules="rules.last_name"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Mailadres</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.email"
|
||||
type="email"
|
||||
:rules="rules.email"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Functie</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.job_title_contact_person"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Telefoonnummer</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.phone"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Straatnaam</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.address"
|
||||
:rules="rules.address"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Huisnummer</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.house_number"
|
||||
:rules="rules.house_number"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Postcode</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.postal"
|
||||
:rules="rules.postal"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Plaats</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.city"
|
||||
:rules="rules.city"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Land</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.country"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editModeComputed">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="validate() && save()"
|
||||
v-if="
|
||||
$store.getters.isSuperAdmin ||
|
||||
$store.getters.isAdmin ||
|
||||
isUserDelegated
|
||||
"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw lid kiest u eerst voor 'Tussentijds
|
||||
Opslaan' om deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'type', value: 'type' },
|
||||
{ text: 't.a.v.', value: 'contact' },
|
||||
{ text: 'adres', value: 'address' },
|
||||
{ text: 'mailadres', value: 'email' },
|
||||
{ text: 'telefoonnummer', value: 'phone' },
|
||||
{ text: 'profiel', value: 'profiel', sortable: false },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
typeKeys: ['main', 'visiting', 'invoice', 'other'],
|
||||
addressEditMode: false,
|
||||
dialogAddresses: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {},
|
||||
defaultItem: {},
|
||||
loading: false,
|
||||
rules: {
|
||||
type: [(v) => !!v || 'Het type is verplicht.'],
|
||||
address: [(v) => !!v || 'Straatnaam is verplicht.'],
|
||||
house_number: [(v) => !!v || 'Huisnummer is verplicht.'],
|
||||
postal: [
|
||||
(v) => !!v || 'Postcode is verplicht.',
|
||||
(v) =>
|
||||
/^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i.test(v) ||
|
||||
'Ongeldige postcode',
|
||||
],
|
||||
|
||||
city: [(v) => !!v || 'Plaats is verplicht.'],
|
||||
first_name: [(v) => !!v || 'De voornaam is verplicht.'],
|
||||
last_name: [(v) => !!v || 'De achternaam is verplicht.'],
|
||||
email: [(v) => !!v || 'Het e-mailadres is verplicht.'],
|
||||
},
|
||||
valid: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
addresses() {
|
||||
if (!this.local || !Array.isArray(this.local.addresses)) return []
|
||||
return this.local.addresses
|
||||
},
|
||||
hasAddresses() {
|
||||
if (!this.addresses) return false
|
||||
return this.addresses.length > 0
|
||||
},
|
||||
formTitle() {
|
||||
return this.editedIndex === -1 ? 'new' : 'edit'
|
||||
},
|
||||
isCreatedModeAddress() {
|
||||
return this.editedIndex === -1
|
||||
},
|
||||
editModeComputed() {
|
||||
return this.addressEditMode && this.editMode
|
||||
},
|
||||
isUserDelegated() {
|
||||
return this.local.user_id === this.$store.getters.loggedInUser.id
|
||||
},
|
||||
types() {
|
||||
return this.typeKeys.map((key) => ({
|
||||
text: this.$t(`members.types.${key}`).toLowerCase(),
|
||||
value: key,
|
||||
}))
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogAddresses(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialogAddresses = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
},
|
||||
|
||||
viewItem(item) {
|
||||
this.addressEditMode = false
|
||||
this.editedIndex = this.addresses.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
this.dialogAddresses = true
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.addressEditMode = true
|
||||
this.setItemToEdit(item)
|
||||
this.dialogAddresses = true
|
||||
},
|
||||
|
||||
setItemToEdit(item) {
|
||||
this.editedIndex = this.addresses.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
validate() {
|
||||
return this.$refs.form.validate()
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.dialogAddresses = false
|
||||
|
||||
if (this.isCreatedModeAddress) {
|
||||
try {
|
||||
await this.$store.dispatch('members/storeAddress', this.editedItem)
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
} else {
|
||||
// Edit mode
|
||||
try {
|
||||
await this.$store.dispatch('members/storeAddress', this.editedItem)
|
||||
this.loading = false
|
||||
this.dialogAddresses = false
|
||||
} catch (error) {
|
||||
this.loading = false
|
||||
console.log('save -> error', error)
|
||||
}
|
||||
}
|
||||
|
||||
this.close()
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No address to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('members/deleteAddress', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogAddresses = false
|
||||
this.$nuxt.$loading.finish()
|
||||
} catch (error) {
|
||||
console.log('deleteItem -> error', error)
|
||||
this.$nuxt.$loading.finish()
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
max-height: 68% !important;
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 285px !important;
|
||||
}
|
||||
table tr button.view {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover button.view {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
835
components/Members/BasicMembers.vue
Normal file
835
components/Members/BasicMembers.vue
Normal file
@@ -0,0 +1,835 @@
|
||||
<template>
|
||||
<accordion-card :title="$t('learning.product_overview.basic')">
|
||||
<v-row v-if="!isCreateMode">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Lid nummer</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field :value="local.id" hide-details solo disabled flat />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"></v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-if="false">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Gebruiker</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="d-flex users">
|
||||
<v-select
|
||||
v-model="user_id"
|
||||
:items="users"
|
||||
color="blue-grey lighten-2"
|
||||
item-text="fullName"
|
||||
item-value="id"
|
||||
hide-selected
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="12" md="3"></v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">{{ $t('members.fields.type') }}</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
v-model="type"
|
||||
:items="validTypes"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:append-icon="$store.getters.isMember ? '' : 'mdi-menu-down'"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="justify-center d-flex flex-column align-start">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(type, $store.getters['members/revision'].type)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black" append-icon>Hoofdbranche</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
v-model="branch_id"
|
||||
:items="branches"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:append-icon="$store.getters.isMember ? '' : 'mdi-menu-down'"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
branch_id,
|
||||
$store.getters['members/revision'].branch_id
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Subbranche</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
:items="branches"
|
||||
v-model="sub_branches"
|
||||
attach
|
||||
chips
|
||||
multiple
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
:append-icon="$store.getters.isMember ? '' : 'icon-dropdown'"
|
||||
>
|
||||
<template v-slot:selection="{ attrs, item, select, selected }">
|
||||
<v-chip v-bind="attrs" :input-value="selected" @click="select">
|
||||
<v-icon class="mx-2">mdi-source-branch</v-icon>
|
||||
|
||||
<strong>{{ item.title }}</strong>
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-select>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="d-flex flex-column justify-space-between align-start">
|
||||
<span>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
sub_branches,
|
||||
$store.getters['members/revision'].sub_branches
|
||||
)
|
||||
"
|
||||
/>
|
||||
</span>
|
||||
<span>Meerdere keuzes mogelijk</span>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- {{ sub_branches }}
|
||||
{{ $store.getters['members/revision'].sub_branches }}-->
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Naam</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="informal_name"
|
||||
:rules="rules.informal_name"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
informal_name,
|
||||
$store.getters['members/revision'].informal_name
|
||||
)
|
||||
"
|
||||
>
|
||||
<span
|
||||
class="caption accent--text"
|
||||
>{{ $store.getters['members/revision'].informal_name }}</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
informal_name,
|
||||
$store.getters['members/revision'].informal_name
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Juridische tenaamstelling</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="formal_name"
|
||||
:rules="rules.formal_name"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
formal_name,
|
||||
$store.getters['members/revision'].formal_name
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">{{ $store.getters['members/revision'].formal_name }}</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader v-if="editMode">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
formal_name,
|
||||
$store.getters['members/revision'].formal_name
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Aanvang lidmaatschap</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-menu
|
||||
ref="menuStart"
|
||||
v-model="menuStart"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
margin-top="20px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`accreditation-start-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedStart"
|
||||
append-icon="icon-events"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
readonly
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="start_membership"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
locale="nl-NL"
|
||||
/>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
start_membership,
|
||||
$store.getters['members/revision'].start_membership
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Einde lidmaatschap</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-menu
|
||||
ref="menuStart"
|
||||
v-model="menuEnd"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
margin-top="20px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
:name="`accreditation-end-date-${Math.random()}`"
|
||||
v-model="computedDateFormattedEnd"
|
||||
append-icon="icon-events"
|
||||
max-height="100px"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
readonly
|
||||
clearable
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-icon v-on="on">icon-events</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="end_membership"
|
||||
no-title
|
||||
scrollable
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
locale="nl-NL"
|
||||
/>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
end_membership,
|
||||
$store.getters['members/revision'].end_membership
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- <v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Contributie</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="contribution"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
contribution,
|
||||
$store.getters['members/revision'].contribution
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].contribution }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
contribution,
|
||||
$store.getters['members/revision'].contribution
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>-->
|
||||
|
||||
<!-- <v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Factuurnummer</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="invoice_number"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
invoice_number,
|
||||
$store.getters['members/revision'].invoice_number
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].invoice_number }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
invoice_number,
|
||||
$store.getters['members/revision'].invoice_number
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>-->
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">KVK-nummer</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="kvk_number"
|
||||
:rules="rules.kvk_number"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
type="number"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
kvk_number,
|
||||
$store.getters['members/revision'].kvk_number
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">{{ $store.getters['members/revision'].kvk_number }}</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
kvk_number,
|
||||
$store.getters['members/revision'].kvk_number
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- <v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Website</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:rules="rules.website"
|
||||
v-model="website"
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
website,
|
||||
$store.getters['members/revision'].website
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].website }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
website,
|
||||
$store.getters['members/revision'].website
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>-->
|
||||
|
||||
<v-row class="mb-14" v-if="$store.getters.isAdmin || $store.getters.isOperator">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black">Logo</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<vue-dropzone
|
||||
ref="imgDropZoneLogo"
|
||||
class="my-4 cta-secondary"
|
||||
id="customdropzone"
|
||||
:options="dropzoneOptions"
|
||||
@vdropzone-complete="afterCompleteLogo"
|
||||
v-if="editMode"
|
||||
/>
|
||||
|
||||
<v-img :src="logoComputed || noImage" :lazy-src="noImage" contain v-cloak />
|
||||
<!-- <button @click="removeLogo()">
|
||||
<h1>Delete logo</h1>
|
||||
</button> -->
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader>
|
||||
Het logo mag maximaal 160x90px zijn. Zorg dat er minimaal 10px
|
||||
witruimte om het logo zit. Upload in svg, png of jpg.
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import fieldHasChanges from '@/components/Members/FieldHasChanges'
|
||||
import vueDropzone from 'vue2-dropzone'
|
||||
import 'vue2-dropzone/dist/vue2Dropzone.min.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
vueDropzone,
|
||||
fieldHasChanges,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
users: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rules: {
|
||||
informal_name: [(v) => !!v || 'informal name is required'],
|
||||
formal_name: [(v) => !!v || 'formal name is required'],
|
||||
kvk_number: [(v) => !!v || 'kvk number is required'],
|
||||
// website: [(v) => !!v || 'website is required'],
|
||||
},
|
||||
loading: false,
|
||||
showDropzone: false,
|
||||
dropzoneOptions: {
|
||||
url: 'https://httpbin.org/post',
|
||||
maxFilesize: 1.2, // MB
|
||||
maxFiles: 1,
|
||||
thumbnailWidth: 320,
|
||||
thumbnailHeight: 180,
|
||||
addRemoveLinks: true,
|
||||
|
||||
acceptedFiles: '.jpg, .jpeg, .png',
|
||||
dictDefaultMessage: `<p><i class='mr-2 icon icon-image'></i> Upload afbeelding</p>`,
|
||||
},
|
||||
images: [],
|
||||
img: {
|
||||
name: '',
|
||||
url: '',
|
||||
file: null,
|
||||
},
|
||||
menuStart: false,
|
||||
menuEnd: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
branches() {
|
||||
return this.$store.state.members.branches
|
||||
},
|
||||
logo() {
|
||||
return this.local.logo
|
||||
},
|
||||
curLogo() {
|
||||
return this.$store.state.members.logo
|
||||
},
|
||||
logoComputed() {
|
||||
if (this.$store.state.members.logo.url)
|
||||
return this.$store.state.members.logo.url
|
||||
if (this.local.logo) return this.local.logo.full
|
||||
return null
|
||||
},
|
||||
noImage() {
|
||||
return require(`@/assets/img/no_image.png`)
|
||||
},
|
||||
branch_id: {
|
||||
get() {
|
||||
return this.local.branch_id
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'branch_id',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
user_id: {
|
||||
get() {
|
||||
return this.local.user_id
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'user_id',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
sub_branches: {
|
||||
get() {
|
||||
return this.local.sub_branches
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'sub_branches',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
type: {
|
||||
get() {
|
||||
return this.local.type
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'type',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
informal_name: {
|
||||
get() {
|
||||
return this.local.informal_name
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'informal_name',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
formal_name: {
|
||||
get() {
|
||||
return this.local.formal_name
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'formal_name',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
kvk_number: {
|
||||
get() {
|
||||
return this.local.kvk_number
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'kvk_number',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
// website: {
|
||||
// get() {
|
||||
// return this.local.website
|
||||
// },
|
||||
// set(value) {
|
||||
// this.$store.commit('members/UPDATE_FIELD', {
|
||||
// field: 'website',
|
||||
// value,
|
||||
// })
|
||||
// },
|
||||
// },
|
||||
|
||||
start_membership: {
|
||||
get() {
|
||||
return this.local.start_membership
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'start_membership',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
end_membership: {
|
||||
get() {
|
||||
return this.local.end_membership
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'end_membership',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
validTypes() {
|
||||
return this.$store.state.members.types;
|
||||
},
|
||||
|
||||
computedDateFormattedStart() {
|
||||
return this.formatDate(this.start_membership)
|
||||
},
|
||||
computedDateFormattedEnd: {
|
||||
get() {
|
||||
return this.formatDate(this.end_membership);
|
||||
},
|
||||
|
||||
set(value) {
|
||||
this.end_membership = value;
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
areEqualInputs(input1, input2) {
|
||||
return this.$store.getters['utils/areEquals'](input1, input2)
|
||||
},
|
||||
|
||||
// async removeLogo(){
|
||||
// // this.$store.commit('members/RESET_LOGO')
|
||||
// this.$store.commit('members/UPDATE_LOGO', {
|
||||
// name: '',
|
||||
// url: '',
|
||||
// file: null,
|
||||
// })
|
||||
|
||||
// console.log("file deleted");
|
||||
// },
|
||||
|
||||
formatDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [year, month, day, time] = date.replace(' ', '-').split('-')
|
||||
return `${day}/${month}/${year}`
|
||||
},
|
||||
|
||||
async afterCompleteLogo(file) {
|
||||
if (file === undefined) return
|
||||
if (file.name.lastIndexOf('.') <= 0) return
|
||||
|
||||
if (file.size > 2000000) {
|
||||
this.$notifier.showMessage({
|
||||
content: `Exceeded Max filesize`,
|
||||
color: 'error',
|
||||
icon: 'mdi-alert-circle',
|
||||
})
|
||||
this.$store.commit('members/RESET_LOGO')
|
||||
return
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
try {
|
||||
const fr = new FileReader()
|
||||
fr.readAsDataURL(file)
|
||||
fr.addEventListener('load', () => {
|
||||
this.$store.commit('members/UPDATE_LOGO', {
|
||||
name: file.name,
|
||||
url: fr.result,
|
||||
file: file,
|
||||
})
|
||||
})
|
||||
this.isLoading = false
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
this.$refs.imgDropZoneLogo.removeFile(file)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
</style>
|
||||
685
components/Members/ContactsMembers.vue
Normal file
685
components/Members/ContactsMembers.vue
Normal file
@@ -0,0 +1,685 @@
|
||||
<template>
|
||||
<accordion-card title="Contactpersonen">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="contacts"
|
||||
:options="options"
|
||||
hide-default-footer
|
||||
item-key="contact"
|
||||
flat
|
||||
v-if="hasContacts"
|
||||
>
|
||||
<template v-slot:item.contact_person="{ item }">
|
||||
{{ determineNameFullByContactPersonItem(item) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.ledencontrole="{ item }">
|
||||
<v-icon
|
||||
:color="!item.approved_at ? 'accent' : 'success'"
|
||||
>
|
||||
{{
|
||||
!item.approved_at
|
||||
? 'mdi-alert-circle-outline'
|
||||
: 'icon-checkmark'
|
||||
}}
|
||||
</v-icon>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
class="mx-4 white--text view"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
small
|
||||
@click="viewItem(item)"
|
||||
v-if="$store.getters.hasCharges"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="
|
||||
editMode && $store.getters['members/isSuperAdminAdminOrDelegated']
|
||||
"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.edit') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialogDelete">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('general.delete') | capitalize }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">{{
|
||||
$t('learning.delete_contactsmembers_confirmation')
|
||||
}}</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogContacts"
|
||||
:persistent="editModeComputed"
|
||||
max-width="75%"
|
||||
v-if="$store.getters['members/isSuperAdminAdminOrDelegated']"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editMode"
|
||||
class="my-10 cta-secondary"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
@click="contactEditMode = true"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>Nieuw contactperson
|
||||
toevoegen
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card ref="card">
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Rol</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
:items="roles"
|
||||
v-model="editedItem.function"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Locatie</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<!-- :items="formatAddresses(addresses)" -->
|
||||
<v-select
|
||||
:items="addresses"
|
||||
item-text="indicating"
|
||||
item-value="id"
|
||||
v-model="editedItem.address_id"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
>
|
||||
<template v-slot:item="{ item, attrs, on }">
|
||||
{{
|
||||
`
|
||||
${item.indicating || ''}
|
||||
${item.house_number + ',' || ''}
|
||||
${item.postal + ',' || ''}
|
||||
${item.city + ',' || ''}
|
||||
${item.country || ''}
|
||||
`
|
||||
}}
|
||||
</template>
|
||||
</v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Aanhef</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
:items="salutations"
|
||||
v-model="editedItem.salutation"
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Voorletters</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.initials"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Voornaam</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.firstname"
|
||||
:rules="rules.firstname"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Tussenvoegsel</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.middlename"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Achternaam</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.lastname"
|
||||
:rules="rules.lastname"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Functie</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.job_title"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Mailadres</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.email"
|
||||
type="email"
|
||||
required
|
||||
error
|
||||
:rules="[rules.email.required]"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Mailadres 2</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.email2"
|
||||
type="email"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Mailadres 3</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.email3"
|
||||
type="email"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Telefoonnummer</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.phone"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Mobiel</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:outlined="editModeComputed"
|
||||
:solo="!editModeComputed"
|
||||
:disabled="!editModeComputed"
|
||||
:flat="!editModeComputed"
|
||||
v-model="editedItem.mobile"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editModeComputed">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="save"
|
||||
v-if="
|
||||
$store.getters.isAdmin ||
|
||||
$store.getters.isOperator ||
|
||||
isUserDelegated
|
||||
"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw lid kiest u eerst voor 'Tussentijds
|
||||
Opslaan' om deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import Name from '@/util/Name'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'rol', value: 'function' },
|
||||
{ text: 'contactpersoon', value: 'contact_person' },
|
||||
{ text: 'ledencontrole', value: 'ledencontrole', sortable: false },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
roles: [
|
||||
'Bestuurder',
|
||||
'Klankbordgroeplid cc',
|
||||
'Klankbordgroeplid cp',
|
||||
'Algemene vergadering cp',
|
||||
'Algemene vergadering cc',
|
||||
'Vertegenwoordiger',
|
||||
],
|
||||
salutations: ['Mevrouw', 'De heer'],
|
||||
contactEditMode: false,
|
||||
dialogContacts: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {},
|
||||
defaultItem: {},
|
||||
loading: false,
|
||||
rules: {
|
||||
firstname: [(v) => !!v || 'De voornaam is verplicht.'],
|
||||
lastname: [(v) => !!v || 'De achternaam is verplicht.'],
|
||||
email: {
|
||||
required: (value) => !!value || 'Het mailadres is verplicht.',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
addresses() {
|
||||
if (!this.local || !Array.isArray(this.local.addresses)) return []
|
||||
return this.local.addresses
|
||||
},
|
||||
hasAddresses() {
|
||||
if (!this.addresses) return false
|
||||
return this.addresses.length > 0
|
||||
},
|
||||
contacts() {
|
||||
if (!this.local || !Array.isArray(this.local.contacts)) return []
|
||||
return this.local.contacts
|
||||
},
|
||||
hasContacts() {
|
||||
if (!this.contacts) return false
|
||||
return this.contacts.length > 0
|
||||
},
|
||||
formTitle() {
|
||||
return this.editedIndex === -1 ? 'new' : 'edit'
|
||||
},
|
||||
isCreatedModeContact() {
|
||||
return this.editedIndex === -1
|
||||
},
|
||||
editModeComputed() {
|
||||
return this.contactEditMode && this.editMode
|
||||
},
|
||||
isUserDelegated() {
|
||||
return this.local.user_id === this.$store.getters.loggedInUser.id
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogContacts(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialogContacts = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
},
|
||||
|
||||
viewItem(item) {
|
||||
this.contactEditMode = false
|
||||
this.editedIndex = this.contacts.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
this.dialogContacts = true
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.setItemToEdit(item)
|
||||
this.dialogContacts = true
|
||||
},
|
||||
|
||||
setItemToEdit(item) {
|
||||
this.contactEditMode = true
|
||||
this.editedIndex = this.contacts.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.card.$el.scrollIntoView(true)
|
||||
})
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.dialogContacts = false
|
||||
if (this.isCreatedModeContact) {
|
||||
try {
|
||||
await this.$store.dispatch('members/storeContact', this.editedItem)
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
} else {
|
||||
// Edit mode
|
||||
try {
|
||||
await this.$store.dispatch('members/storeContact', this.editedItem)
|
||||
this.loading = false
|
||||
this.dialogContacts = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
this.close()
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No contact to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('members/deleteContact', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogContacts = false
|
||||
this.$nuxt.$loading.finish()
|
||||
} catch (error) {
|
||||
console.log('deleteItem -> error', error)
|
||||
this.$nuxt.$loading.finish()
|
||||
}
|
||||
},
|
||||
|
||||
determineNameFullByContactPersonItem(item) {
|
||||
return Name.fromContactPersonItem(item).nameFull
|
||||
},
|
||||
|
||||
formatAddresses(addresses) {
|
||||
return addresses.map((x) => this.formatAddress(x)).filter((x) => x)
|
||||
},
|
||||
|
||||
formatAddress(address) {
|
||||
const addressParts = [
|
||||
address.indicating || '',
|
||||
address.house_number || '',
|
||||
address.postal || '',
|
||||
address.city || '',
|
||||
address.country || '',
|
||||
]
|
||||
|
||||
return addressParts
|
||||
.filter((x) => x)
|
||||
.map((x) => x.trim())
|
||||
.join(', ')
|
||||
.trimRight()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
max-height: 68% !important;
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 285px !important;
|
||||
}
|
||||
table tr button.view {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover button.view {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
438
components/Members/ContributionMembers.vue
Normal file
438
components/Members/ContributionMembers.vue
Normal file
@@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<accordion-card title="Contributie">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="contributions"
|
||||
:options="options"
|
||||
sort-by="year"
|
||||
sort-desc
|
||||
hide-default-footer
|
||||
item-key="accreditation"
|
||||
flat
|
||||
v-if="hasContributions"
|
||||
>
|
||||
<template v-slot:item.contribution="{ item }">€ {{new Intl.NumberFormat().format(item.contribution)}},00</template>
|
||||
<template v-slot:item.profiel="{ item }">
|
||||
<v-icon
|
||||
:color="!item.approved_at ? 'accent' : 'success'"
|
||||
>{{
|
||||
!item.approved_at
|
||||
? 'mdi-alert-circle-outline'
|
||||
: 'icon-checkmark'
|
||||
}}</v-icon
|
||||
>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="editMode && $store.getters.isSuperAdminOrAdmin"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog
|
||||
max-width="740"
|
||||
:persistent="editMode"
|
||||
v-model="dialogDelete"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{ $t('learning.delete_contributionmembers_confirmation') }}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogContribution"
|
||||
max-width="75%"
|
||||
v-if="editMode && $store.getters.isSuperAdminOrAdmin"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editMode && ($store.getters.isSuperAdmin || $store.getters.isAdmin)"
|
||||
class="my-10 cta-secondary"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
|
||||
Voeg jaartal toe</v-btn
|
||||
>
|
||||
</template>
|
||||
<v-card ref="card">
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Jaar</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
:items="yearsComputed"
|
||||
v-model="editedItem.year"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode || !$store.getters.isSuperAdminOrAdmin"
|
||||
:flat="!editMode"
|
||||
v-if="isCreatedModeContribution"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="editedItem.year"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
disabled
|
||||
:flat="!editMode"
|
||||
v-else
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Contributie
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="editedItem.contribution"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
type="number"
|
||||
prepend-inner-icon="mdi-currency-eur"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-if="isCreatedModeContribution && editMode && $store.getters.isSuperAdminOrAdmin">
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Pas toe op alle leden
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col class="checkbox" cols="12" sm="12" md="1">
|
||||
<v-checkbox
|
||||
v-model="editedItem.toAll"
|
||||
:disabled="!editMode"
|
||||
></v-checkbox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editMode">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
@click="save"
|
||||
>{{ $t('general.save') }}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw lid kiest u eerst voor 'Tussentijds
|
||||
Opslaan' om deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'jaar', value: 'year' },
|
||||
{ text: 'contributie' , value: 'contribution' },
|
||||
{ text: 'profiel', value: 'profiel', sortable: false },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
dialogContribution: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {},
|
||||
defaultItem: {},
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
|
||||
isCreatedModeContribution() {
|
||||
return this.editedIndex === -1
|
||||
},
|
||||
|
||||
formTitle() {
|
||||
return this.isCreatedModeContribution ? 'Nieuw' : 'Bewerk'
|
||||
},
|
||||
|
||||
contributions() {
|
||||
if (!this.local || !Array.isArray(this.local.contributions)) return []
|
||||
return this.local.contributions
|
||||
},
|
||||
hasContributions() {
|
||||
if (!this.contributions) return false
|
||||
return this.contributions.length > 0
|
||||
},
|
||||
|
||||
years() {
|
||||
const year = new Date().getFullYear()
|
||||
return Array.from({ length: 51 }, (value, index) => 2010 + index)
|
||||
},
|
||||
|
||||
yearsTaken() {
|
||||
if (!this.hasContributions) return []
|
||||
return this.contributions.map(({ year }) => year)
|
||||
},
|
||||
|
||||
yearsComputed() {
|
||||
return this.years.filter((y) => !this.yearsTaken.includes(y))
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogContribution(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialogContribution = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
this.$refs.card.$el.scrollIntoView(true);
|
||||
})
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editMode) return
|
||||
this.setSummaryToEdit(item)
|
||||
this.dialogContribution = true
|
||||
},
|
||||
|
||||
setSummaryToEdit(item) {
|
||||
this.editedIndex = this.contributions.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
close() {
|
||||
this.dialogContribution = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
})
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No summary to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('members/deleteContribution', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogContribution = false
|
||||
this.$nuxt.$loading.finish()
|
||||
} catch (error) {
|
||||
console.log('deleteItem -> error', error)
|
||||
this.$nuxt.$loading.finish()
|
||||
}
|
||||
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.card.$el.scrollIntoView(true);
|
||||
})
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.dialogContribution = false
|
||||
|
||||
if (this.isCreatedModeContribution) {
|
||||
try {
|
||||
await this.$store.dispatch(
|
||||
'members/storeContribution',
|
||||
this.editedItem
|
||||
)
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
} else {
|
||||
// Edit mode
|
||||
try {
|
||||
await this.$store.dispatch(
|
||||
'members/storeContribution',
|
||||
this.editedItem
|
||||
)
|
||||
this.dialogContribution = false
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
this.close()
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 285px !important;
|
||||
}
|
||||
</style>
|
||||
543
components/Members/EmployeesMembers.vue
Normal file
543
components/Members/EmployeesMembers.vue
Normal file
@@ -0,0 +1,543 @@
|
||||
<template>
|
||||
<accordion-card title="Werknemers">
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="summaries"
|
||||
:options="options"
|
||||
sort-by="year"
|
||||
sort-desc
|
||||
hide-default-footer
|
||||
item-key="accreditation"
|
||||
flat
|
||||
v-if="hasSummaries"
|
||||
>
|
||||
<template v-slot:item.profiel="{ item }">
|
||||
<v-icon :color="!item.approved_at ? 'accent' : 'success'">{{
|
||||
!item.approved_at ? 'mdi-alert-circle-outline' : 'icon-checkmark'
|
||||
}}</v-icon>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="
|
||||
(editing && $store.getters.isSuperAdminOrAdmin) ||
|
||||
(editing && $store.getters.isOnlyMemberEditor && !item.approved_at)
|
||||
"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item @click="editItem(item)">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog
|
||||
max-width="740"
|
||||
:persistent="editing"
|
||||
v-model="dialogDelete"
|
||||
v-if="!$store.getters.isOnlyMemberEditor"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{ $t('learning.delete_employeesmembers_confirmation') }}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteItem(item)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="dialogDelete = false"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-dialog
|
||||
v-model="dialogEmployees"
|
||||
max-width="75%"
|
||||
v-if="editing && $store.getters['members/isSuperAdminAdminOrDelegated']"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-if="editing && $store.getters.isSuperAdminOrAdmin"
|
||||
class="my-10 cta-secondary"
|
||||
block
|
||||
depressed
|
||||
min-height="60px"
|
||||
:disabled="isCreateMode"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
|
||||
Voeg jaartal toe</v-btn
|
||||
>
|
||||
</template>
|
||||
<v-form ref="form" v-model="valid" lazy-validation>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="headline">{{ formTitle }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Jaar</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-select
|
||||
:items="yearsComputed"
|
||||
v-model.number="editedItem.year"
|
||||
:outlined="editing"
|
||||
:solo="!editing"
|
||||
:disabled="!editing || !$store.getters.isSuperAdminOrAdmin"
|
||||
:flat="!editing"
|
||||
v-if="isCreatedModeSummary"
|
||||
:rules="rules.year"
|
||||
required
|
||||
error
|
||||
/>
|
||||
<v-text-field
|
||||
v-model.number="editedItem.year"
|
||||
:outlined="editing"
|
||||
:solo="!editing"
|
||||
disabled
|
||||
:flat="!editing"
|
||||
v-else
|
||||
:rules="rules.year"
|
||||
required
|
||||
error
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Werkelijk aantal medewerkers per 31-12-{{
|
||||
editedItem.year - 1 || '__'
|
||||
}}</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model.number="editedItem.real_number_last_year"
|
||||
:outlined="editing"
|
||||
:solo="!editing"
|
||||
:disabled="!editing"
|
||||
:flat="!editing"
|
||||
type="number"
|
||||
:rules="rules.real_number_last_year"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Schatting aantal medewerkers per 31-12-{{
|
||||
editedItem.year || '__'
|
||||
}}</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
v-model="editedItem.estimated_number_next_year"
|
||||
:outlined="editing"
|
||||
:solo="!editing"
|
||||
:disabled="!editing"
|
||||
:flat="!editing"
|
||||
type="number"
|
||||
:rules="rules.estimated_number_next_year"
|
||||
required
|
||||
error
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row
|
||||
v-if="
|
||||
isCreatedModeSummary &&
|
||||
editing &&
|
||||
$store.getters.isSuperAdminOrAdmin
|
||||
"
|
||||
>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-subheader class="txt--text font-weight-black"
|
||||
>Pas toe op alle leden
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col class="checkbox" cols="12" sm="12" md="1">
|
||||
<v-checkbox
|
||||
v-model="editedItem.toAll"
|
||||
:disabled="!editing"
|
||||
></v-checkbox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<small> * Personeel in loondienst </small>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<small
|
||||
>Stuur de onderbouwing van het werknemersaantal van vorig
|
||||
jaar (bijvoorbeeld een pagina uit een jaarverslag) naar
|
||||
<a href="mailto:info@ggzecademy.nl"
|
||||
>info@ggzecademy.nl</a
|
||||
></small
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
<v-card-actions v-if="editing">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
:disabled="loading"
|
||||
v-if="isFormFilled"
|
||||
@click="validate() && save()"
|
||||
>{{
|
||||
!isCreatedModeSummary && $store.getters.isSuperAdminOrAdmin
|
||||
? 'Goedkeuren'
|
||||
: $t('general.save')
|
||||
}}</v-btn
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="txt"
|
||||
depressed
|
||||
text
|
||||
:disabled="loading"
|
||||
@click="close"
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
|
||||
<p v-if="isCreateMode" class="text-center">
|
||||
Bij het aanmaken van een nieuw lid kiest u eerst voor 'Tussentijds
|
||||
Opslaan' om deze functie te activeren.
|
||||
</p>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCreateMode: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rules: {
|
||||
year: [(v) => !!v || 'Het jaar is vereist.'],
|
||||
real_number_last_year: [
|
||||
(v) => +v >= 0 || 'Het werkelijk aantal werknemers is vereist.',
|
||||
],
|
||||
estimated_number_next_year: [
|
||||
(v) => +v >= 0 || 'De schatting aantal werknemers is vereist.',
|
||||
],
|
||||
},
|
||||
options: {
|
||||
itemsPerPage: -1,
|
||||
},
|
||||
headers: [
|
||||
{ text: 'jaar', value: 'year' },
|
||||
{ text: 'opgave medewerkers', value: 'real_number_last_year' },
|
||||
{
|
||||
text: 'schatting medewerkers komende jaar',
|
||||
value: 'estimated_number_next_year',
|
||||
},
|
||||
{ text: 'ledencontrole', value: 'profiel', sortable: false },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
employersEditMode: false,
|
||||
dialogEmployees: false,
|
||||
dialogDelete: false,
|
||||
editedIndex: -1,
|
||||
editedItem: {},
|
||||
loading: false,
|
||||
valid: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editing() {
|
||||
return (
|
||||
this.$store.getters.isOnlyMemberEditor ||
|
||||
(this.editMode && this.$store.getters.isSuperAdminOrAdmin)
|
||||
)
|
||||
},
|
||||
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
|
||||
isCreatedModeSummary() {
|
||||
return this.editedIndex === -1
|
||||
},
|
||||
|
||||
formTitle() {
|
||||
return this.isCreatedModeSummary ? 'Nieuw' : 'Bewerken'
|
||||
},
|
||||
|
||||
summaries() {
|
||||
if (!this.local || !Array.isArray(this.local.summaries)) return []
|
||||
|
||||
// Years older than the current are made hidden for Users delegated to edit members
|
||||
if (this.$store.getters.isOnlyMemberEditor) {
|
||||
const yearValid = new Date().getFullYear()
|
||||
const summary = this.local.summaries.find(
|
||||
(summary) => summary.year === yearValid
|
||||
)
|
||||
return summary ? [summary] : []
|
||||
}
|
||||
|
||||
return this.local.summaries
|
||||
},
|
||||
hasSummaries() {
|
||||
if (!this.summaries) return false
|
||||
return this.summaries.length > 0
|
||||
},
|
||||
|
||||
years() {
|
||||
const year = new Date().getFullYear()
|
||||
return Array.from({ length: 51 }, (value, index) => 2010 + index)
|
||||
},
|
||||
|
||||
yearsTaken() {
|
||||
if (!this.hasSummaries) return []
|
||||
return this.summaries.map(({ year }) => year)
|
||||
},
|
||||
|
||||
yearsComputed() {
|
||||
return this.years.filter((y) => !this.yearsTaken.includes(y))
|
||||
},
|
||||
|
||||
isFormFilled() {
|
||||
if (this.editedItem['year'] === null) return false
|
||||
if (this.editedItem['year'] === undefined) return false
|
||||
if (this.editedItem['year'] === '') return false
|
||||
|
||||
if (this.editedItem['real_number_last_year'] === null) return false
|
||||
if (this.editedItem['real_number_last_year'] === undefined) return false
|
||||
if (this.editedItem['real_number_last_year'] === '') return false
|
||||
|
||||
if (this.editedItem['estimated_number_next_year'] === null) return false
|
||||
if (this.editedItem['estimated_number_next_year'] === undefined)
|
||||
return false
|
||||
if (this.editedItem['estimated_number_next_year'] === '') return false
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
defaultItem() {
|
||||
return {
|
||||
year: this.yearsTaken.includes(new Date().getFullYear())
|
||||
? this.yearsComputed[0]
|
||||
: new Date().getFullYear(),
|
||||
real_number_last_year: 0,
|
||||
estimated_number_next_year: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialogEmployees(val) {
|
||||
val || this.close()
|
||||
if (Object.entries(this.editedItem).length === 0) {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialogEmployees = false
|
||||
this.$nextTick(() => {
|
||||
this.editedItem = Object.assign({}, this.defaultItem)
|
||||
this.editedIndex = -1
|
||||
})
|
||||
},
|
||||
|
||||
editItem(item) {
|
||||
if (!this.editing) return
|
||||
this.setSummaryToEdit(item)
|
||||
},
|
||||
|
||||
setSummaryToEdit(item) {
|
||||
this.editedIndex = this.summaries.indexOf(item)
|
||||
this.editedItem = Object.assign({}, item)
|
||||
this.$forceUpdate()
|
||||
this.dialogEmployees = true
|
||||
},
|
||||
|
||||
async deleteItem(item) {
|
||||
if (!item.id) {
|
||||
this.$notifier.showMessage({
|
||||
content: `No summary to delete selected`,
|
||||
color: 'error',
|
||||
icon: 'icon-message',
|
||||
})
|
||||
}
|
||||
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('members/deleteSummary', item)
|
||||
|
||||
this.dialogDelete = false
|
||||
this.dialogEmployees = false
|
||||
this.$nuxt.$loading.finish()
|
||||
} catch (error) {
|
||||
console.log('deleteItem -> error', error)
|
||||
this.$nuxt.$loading.finish()
|
||||
}
|
||||
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
validate() {
|
||||
return this.$refs.form.validate()
|
||||
},
|
||||
|
||||
async save() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.dialogEmployees = false
|
||||
|
||||
if (this.isCreatedModeSummary) {
|
||||
try {
|
||||
await this.$store.dispatch('members/storeSummary', this.editedItem)
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
} else {
|
||||
// Edit mode
|
||||
try {
|
||||
await this.$store.dispatch('members/storeSummary', this.editedItem)
|
||||
this.dialogEmployees = false
|
||||
this.loading = false
|
||||
} catch (error) {
|
||||
console.log('save -> error', error)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
this.close()
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> table,
|
||||
.v-card >>> .v-data-table-header tr,
|
||||
.v-card >>> .v-data-footer {
|
||||
background-color: var(--v-primary-base);
|
||||
}
|
||||
.v-card >>> .v-data-table-header th span {
|
||||
color: var(--v-tertiary-base);
|
||||
}
|
||||
.v-card >>> .text-start,
|
||||
.v-card >>> .v-icon,
|
||||
.v-dialog__content >>> .v-subheader,
|
||||
.v-dialog__content >>> i {
|
||||
color: var(--v-txt-base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.v-dialog__content >>> .v-dialog {
|
||||
border: 4px solid var(--v-secAccent-base);
|
||||
/* box-shadow: inset 0px 0px 2px 2px var(--v-secAccent-base),
|
||||
inset 6px 6px 14px -14px var(--v-secAccent-base) !important; */
|
||||
}
|
||||
.v-dialog .v-card {
|
||||
background: var(--v-secondary-base);
|
||||
}
|
||||
|
||||
.v-dialog__content >>> .v-input__slot {
|
||||
background: var(--v-primary-base);
|
||||
border: 1px solid var(--v-lines-base);
|
||||
}
|
||||
.v-menu__content >>> .v-date-picker-table {
|
||||
height: 285px !important;
|
||||
}
|
||||
</style>
|
||||
5
components/Members/FieldHasChanges.vue
Normal file
5
components/Members/FieldHasChanges.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<v-avatar color="info" class="mx-2" size="26">
|
||||
<v-icon dark> mdi-check </v-icon>
|
||||
</v-avatar>
|
||||
</template>
|
||||
114
components/Members/MembersChanges.vue
Normal file
114
components/Members/MembersChanges.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items-per-page="10"
|
||||
:items="items"
|
||||
sort-by="updated_at"
|
||||
:sort-desc="true"
|
||||
class="pa-4 secondary"
|
||||
>
|
||||
<template v-slot:item.informal_name="{ item }">
|
||||
<v-img
|
||||
:alt="item.informal_name"
|
||||
lazy-src="/images/product-placeholder.jpg"
|
||||
:src="computeImage(item)"
|
||||
contain
|
||||
height="60px"
|
||||
width="110px"
|
||||
/>
|
||||
|
||||
{{ item.informal_name }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.updated_at="{ item }">
|
||||
{{ formatDate(item.updated_at) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.delegated="{ item }">
|
||||
{{ findUserById(item.user_id) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<div class="view-container">
|
||||
<v-btn
|
||||
class="mx-4 white--text"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
nuxt
|
||||
small
|
||||
:to="localePath(`/manager/members/${item.slug}`)"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: [],
|
||||
},
|
||||
users: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
text: 'lid',
|
||||
value: 'informal_name',
|
||||
},
|
||||
{
|
||||
text: 'bijgewerkt op',
|
||||
value: 'updated_at',
|
||||
},
|
||||
{
|
||||
text: 'door',
|
||||
value: 'delegated',
|
||||
},
|
||||
{
|
||||
text: 'aangepast',
|
||||
value: 'changes',
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
value: 'actions',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
return dayjs(date).format('D MMM YYYY, HH:mm').toLowerCase()
|
||||
},
|
||||
|
||||
computeImage(item) {
|
||||
if (item.logo.thumb) return item.logo.thumb
|
||||
return '/images/product-placeholder.jpg'
|
||||
},
|
||||
|
||||
findUserById(id) {
|
||||
const unassigned = 'unassigned'
|
||||
if (!id) return unassigned
|
||||
const user = this.users.find((u) => u.id === id)
|
||||
if (user) return user.fullName
|
||||
return unassigned
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
310
components/Members/MembersTable.vue
Normal file
310
components/Members/MembersTable.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items-per-page="10"
|
||||
:items="members"
|
||||
class="pa-4 secondary"
|
||||
>
|
||||
<template v-slot:item.informal_name="{ item }">
|
||||
<v-img
|
||||
:alt="item.informal_name"
|
||||
lazy-src="/images/mijnggz-placeholder-members.png"
|
||||
:src="computeImage(item)"
|
||||
contain
|
||||
height="60px"
|
||||
width="110px"
|
||||
/>
|
||||
|
||||
{{ item.informal_name }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.main_branch="{ item }">
|
||||
{{ getBranchTitleById(item.branch_id) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.start_membership="{ item }">
|
||||
{{ formatDate(item.start_membership || item.created_at) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.updated_at="{ item }">
|
||||
{{ formatDate(item.updated_at) }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.changes="{ item }">
|
||||
<v-icon
|
||||
v-if="item.revision"
|
||||
:color="item.revision.hasChanges ? 'accent' : 'success'"
|
||||
>{{
|
||||
item.revision.hasChanges
|
||||
? 'mdi-alert-circle-outline'
|
||||
: 'icon-checkmark'
|
||||
}}</v-icon
|
||||
>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<div class="view-container">
|
||||
<v-btn
|
||||
class="mx-4 white--text"
|
||||
style="height: 100%"
|
||||
:color="$vuetify.theme.dark ? 'info' : 'txt'"
|
||||
rounded
|
||||
depressed
|
||||
nuxt
|
||||
small
|
||||
:to="localePath(`/manager/members/${item.slug}`)"
|
||||
>{{ $t('general.view') }}</v-btn
|
||||
>
|
||||
|
||||
<v-menu
|
||||
offset-y
|
||||
v-if="canEditMember"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-hover v-slot:default="{ hover }">
|
||||
<v-btn
|
||||
:color="hover ? 'info' : ''"
|
||||
:outlined="hover"
|
||||
depressed
|
||||
fab
|
||||
small
|
||||
v-on="on"
|
||||
class="menu-btn"
|
||||
>
|
||||
<v-icon>icon-options</v-icon>
|
||||
</v-btn>
|
||||
</v-hover>
|
||||
</template>
|
||||
<v-list width="200">
|
||||
<v-list-item
|
||||
:to="localePath(`/manager/members/${item.slug}?edit`)"
|
||||
nuxt
|
||||
>
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-edit</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.edit') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-dialog max-width="740" persistent v-model="dialog">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-list-item v-on="on">
|
||||
<v-list-item-icon class="mr-1">
|
||||
<v-icon small>icon-remove</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>{{
|
||||
$t('general.delete') | capitalize
|
||||
}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{
|
||||
$t('learning.product_overview.delete_confirmation', {
|
||||
productName: item.informal_name,
|
||||
})
|
||||
}}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
@click="deleteMember(item.id)"
|
||||
class="mx-2"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
@click="close"
|
||||
class="mx-2"
|
||||
color="info"
|
||||
depressed
|
||||
rounded
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
members: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
page: 1,
|
||||
headers: [
|
||||
{
|
||||
text: '#',
|
||||
value: 'id',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.member'),
|
||||
value: 'informal_name',
|
||||
// sortable: false,
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.type'),
|
||||
value: 'type',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.industry'),
|
||||
value: 'main_branch',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.location'),
|
||||
value: 'info_city',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.since'),
|
||||
value: 'start_membership',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.updated'),
|
||||
value: 'updated_at',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.check'),
|
||||
value: 'changes',
|
||||
},
|
||||
{
|
||||
text: this.$t('members.table.headers.action'),
|
||||
value: 'actions',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
dialog(val) {
|
||||
val || this.close()
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
canEditMember() {
|
||||
return this.$store.getters['members/isSuperAdminAdminOrDelegated']
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.dialog = false
|
||||
},
|
||||
|
||||
async deleteMember(memberId) {
|
||||
if (!memberId) return
|
||||
this.dialog = false
|
||||
await this.$store.dispatch('members/deleteMember', memberId)
|
||||
this.$router.push(this.localePath('/manager/members'))
|
||||
},
|
||||
|
||||
formatDate(date) {
|
||||
return dayjs(date).format('D MMM YYYY').toLowerCase()
|
||||
},
|
||||
|
||||
computeImage(item) {
|
||||
if (item.logo.thumb) return item.logo.thumb
|
||||
return '/images/mijnggz-placeholder-members.png'
|
||||
},
|
||||
|
||||
getBranchTitleById(id) {
|
||||
const branch = this.$store.getters['members/getBranchById'](id);
|
||||
|
||||
return branch ? branch.title : '';
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.view-container{
|
||||
display:flex;
|
||||
}
|
||||
table tr a.v-btn {
|
||||
opacity: 0;
|
||||
}
|
||||
table tr:hover a.v-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
.v-list-item:hover >>> .v-list-item__icon i,
|
||||
.v-list-item:hover >>> .v-list-item__content .v-list-item__subtitle {
|
||||
color: var(--v-info-base) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header th:last-child,
|
||||
.v-data-table >>> .v-data-table-header th:nth-child(3) {
|
||||
position: relative;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header th:last-child::before,
|
||||
.v-data-table >>> .v-data-table-header th:nth-child(3)::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
height: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table-header tr th {
|
||||
border-bottom: none !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.v-data-table td .menu-btn {
|
||||
background-color: unset !important;
|
||||
}
|
||||
.v-data-table >>> td {
|
||||
color: var(--v-txt-base);
|
||||
}
|
||||
.v-data-table >>> th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.v-data-table >>> td:first-child {
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
.v-data-table >>> td:first-child .v-image {
|
||||
margin-right: -18px;
|
||||
}
|
||||
.v-data-table >>> td:last-child,
|
||||
.v-data-table >>> td:nth-child(3) {
|
||||
position: relative;
|
||||
}
|
||||
.v-data-table >>> td:last-child::before,
|
||||
.v-data-table >>> td:nth-child(3)::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
height: 60px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.v-data-table >>> .v-data-table__divider {
|
||||
border-right: none !important;
|
||||
}
|
||||
</style>
|
||||
49
components/Members/MoreMembers.vue
Normal file
49
components/Members/MoreMembers.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<accordion-card title="Overige">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black ml-10">
|
||||
Leeromgeving
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field outlined> </v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-btn
|
||||
class="cta-secondary"
|
||||
block
|
||||
depressed
|
||||
@click=""
|
||||
min-height="60px"
|
||||
>
|
||||
<v-icon x-small class="mx-4">icon-add</v-icon>
|
||||
|
||||
{{ $t('general.add') | capitalize }}</v-btn
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3"> </v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
}
|
||||
</script>
|
||||
896
components/Members/PageMembers.vue
Normal file
896
components/Members/PageMembers.vue
Normal file
@@ -0,0 +1,896 @@
|
||||
<template>
|
||||
<accordion-card title="Ledenpagina">
|
||||
<v-row v-if="$store.getters.isAdmin || $store.getters.isOperator">
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Gegevens tonen</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" class="d-flex">
|
||||
<v-switch
|
||||
:disabled="!editMode"
|
||||
inset
|
||||
class="my-3 toggle"
|
||||
v-model="show_on_website"
|
||||
/>
|
||||
<small class="my-4"
|
||||
><strong>
|
||||
{{
|
||||
show_on_website
|
||||
? 'Aan (Met het aanzetten van deze optie worden onderstaande gegevens op de website van GGZ Ecademy gepubliceerd. Ik verklaar daarvoor toestemming te hebben van degene wiens gegevens het betreft.)'
|
||||
: 'Uit'
|
||||
}}
|
||||
</strong>
|
||||
</small>
|
||||
</v-col>
|
||||
<v-col class="my-4" cols="12" sm="12" md="3">
|
||||
Bij 'Uit' wordt alleen het logo en de website link getoond
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Helpdesk voor cursisten</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Afdeling </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="helpdesk_department"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_department,
|
||||
$store.getters['members/revision'].helpdesk_department
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].helpdesk_department }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_department,
|
||||
$store.getters['members/revision'].helpdesk_department
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Contactpersoon </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="helpdesk_contact_person"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_contact_person,
|
||||
$store.getters['members/revision'].helpdesk_contact_person
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].helpdesk_contact_person }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_contact_person,
|
||||
$store.getters['members/revision'].helpdesk_contact_person
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Emailadres </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="helpdesk_email"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_email,
|
||||
$store.getters['members/revision'].helpdesk_email
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].helpdesk_email }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_email,
|
||||
$store.getters['members/revision'].helpdesk_email
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Telefoonnummer </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="helpdesk_phone"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_phone,
|
||||
$store.getters['members/revision'].helpdesk_phone
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].helpdesk_phone }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
helpdesk_phone,
|
||||
$store.getters['members/revision'].helpdesk_phone
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Informatie over scholing</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Afdeling </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_department"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_department,
|
||||
$store.getters['members/revision'].info_department
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_department }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_department,
|
||||
$store.getters['members/revision'].info_department
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Contactpersoon </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_contacteperson"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_contacteperson,
|
||||
$store.getters['members/revision'].info_contacteperson
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_contacteperson }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_contacteperson,
|
||||
$store.getters['members/revision'].info_contacteperson
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Emailadres </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_email"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_email,
|
||||
$store.getters['members/revision'].info_email
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_email }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_email,
|
||||
$store.getters['members/revision'].info_email
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Telefoonnummer </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_phone"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_phone,
|
||||
$store.getters['members/revision'].info_phone
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_phone }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_phone,
|
||||
$store.getters['members/revision'].info_phone
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Straat </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_address"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_address,
|
||||
$store.getters['members/revision'].info_address
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_address }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_address,
|
||||
$store.getters['members/revision'].info_address
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Huisnummer </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_housenumber"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_housenumber,
|
||||
$store.getters['members/revision'].info_housenumber
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_housenumber }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_housenumber,
|
||||
$store.getters['members/revision'].info_housenumber
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Postcode </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_postal"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_postal,
|
||||
$store.getters['members/revision'].info_postal
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_postal }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_postal,
|
||||
$store.getters['members/revision'].info_postal
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Plaats </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_city"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_city,
|
||||
$store.getters['members/revision'].info_city
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_city }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_city,
|
||||
$store.getters['members/revision'].info_city
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Land </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_country"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_country,
|
||||
$store.getters['members/revision'].info_country
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_country }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_country,
|
||||
$store.getters['members/revision'].info_country
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Link </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="info_link"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_link,
|
||||
$store.getters['members/revision'].info_link
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].info_link }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
info_link,
|
||||
$store.getters['members/revision'].info_link
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<v-subheader class="txt--text font-weight-black in_the_picture"
|
||||
>Meer informatie</v-subheader
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-subheader class="txt--text"> Website url </v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field
|
||||
:hide-details="!editMode"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
v-model="more_info_link"
|
||||
>
|
||||
<template
|
||||
slot="append"
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
more_info_link,
|
||||
$store.getters['members/revision'].more_info_link
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="caption accent--text">
|
||||
{{ $store.getters['members/revision'].more_info_link }}
|
||||
</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<field-has-changes
|
||||
v-if="
|
||||
$store.getters['members/revision'] &&
|
||||
!areEqualInputs(
|
||||
more_info_link,
|
||||
$store.getters['members/revision'].more_info_link
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</accordion-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import accordionCard from '@/components/UI/AccordionCard/AccordionCard'
|
||||
import fieldHasChanges from '@/components/Members/FieldHasChanges'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
accordionCard,
|
||||
fieldHasChanges,
|
||||
},
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
show_on_website: {
|
||||
get() {
|
||||
return this.local.show_on_website
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'show_on_website',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
helpdesk_department: {
|
||||
get() {
|
||||
return this.local.helpdesk_department
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'helpdesk_department',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
helpdesk_contact_person: {
|
||||
get() {
|
||||
return this.local.helpdesk_contact_person
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'helpdesk_contact_person',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
helpdesk_email: {
|
||||
get() {
|
||||
return this.local.helpdesk_email
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'helpdesk_email',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
helpdesk_phone: {
|
||||
get() {
|
||||
return this.local.helpdesk_phone
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'helpdesk_phone',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_department: {
|
||||
get() {
|
||||
return this.local.info_department
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_department',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_contacteperson: {
|
||||
get() {
|
||||
return this.local.info_contacteperson
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_contacteperson',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_email: {
|
||||
get() {
|
||||
return this.local.info_email
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_email',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_phone: {
|
||||
get() {
|
||||
return this.local.info_phone
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_phone',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_address: {
|
||||
get() {
|
||||
return this.local.info_address
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_address',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_housenumber: {
|
||||
get() {
|
||||
return this.local.info_housenumber
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_housenumber',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_postal: {
|
||||
get() {
|
||||
return this.local.info_postal
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_postal',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_city: {
|
||||
get() {
|
||||
return this.local.info_city
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_city',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_country: {
|
||||
get() {
|
||||
return this.local.info_country
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_country',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
info_link: {
|
||||
get() {
|
||||
return this.local.info_link
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'info_link',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
more_info_link: {
|
||||
get() {
|
||||
return this.local.more_info_link
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('members/UPDATE_FIELD', {
|
||||
field: 'more_info_link',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
areEqualInputs(input1, input2) {
|
||||
return this.$store.getters['utils/areEquals'](input1, input2)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> .v-subheader {
|
||||
padding: 0px !important;
|
||||
}
|
||||
</style>
|
||||
45
components/Newsletter/Newsletter.vue
Normal file
45
components/Newsletter/Newsletter.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<section id="newsletter" class="my-0">
|
||||
<img :src="require(`@/assets/img/newsletter.jpg`)" />
|
||||
<img :src="require(`@/assets/img/triangle_pattern.png`)" class="pattern"/>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6"></div>
|
||||
<div class="col-12 col-md-4 mx-auto text">
|
||||
<h2>Nieuwsbrief</h2>Je ontvangt een kortingscode van €10,- bij besteding vanaf €75,-. Deze is meteen in te wisselen.
|
||||
<v-text-field outlined label="Inschrijven" append-icon="mdi-arrow-right" class="my-4"></v-text-field>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#newsletter {
|
||||
clear: both;
|
||||
position: relative;
|
||||
background-color: #f5f5f5;
|
||||
margin-bottom: 20px;
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
object-fit: cover;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
left: 0px;
|
||||
// z-index: 1;
|
||||
}
|
||||
.pattern {
|
||||
right: 0px;
|
||||
left: unset;
|
||||
width: 100%;
|
||||
}
|
||||
.text {
|
||||
padding-top: 100px;
|
||||
padding-bottom: 100px;
|
||||
// z-index: 2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
24
components/PageComponent/PageComponent.vue
Normal file
24
components/PageComponent/PageComponent.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<component :is="componentRendered" :data="componentProp.content" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
componentProp: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
componentRendered() {
|
||||
return this.componentProp.component_type.name
|
||||
? () =>
|
||||
import(
|
||||
`@/components/DynamicComponents/${this.componentProp.component_type.name}`
|
||||
)
|
||||
: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
54
components/Post/Post.vue
Normal file
54
components/Post/Post.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<v-card max-width="300" class="mx-auto">
|
||||
<v-list-item>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="subtitle-2">{{title}}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{author}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-img src="https://cdn.vuetifyjs.com/images/cards/mountain.jpg" height="180"></v-img>
|
||||
|
||||
<v-card-text v-html="body" v-if="!noText"/>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn nuxt :to="{ name: 'blog-slug', params: { slug, id } }">Read more</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon>
|
||||
<v-icon>icon-share</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
author: {
|
||||
type: String,
|
||||
},
|
||||
body: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
image: {
|
||||
required: false
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
noText: {
|
||||
type: Boolean,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
14
components/Product/Product.vue
Normal file
14
components/Product/Product.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="d-flex flex-column">
|
||||
<v-sheet class="mx-4 pa-4" max-height="600" max-width="500">
|
||||
|
||||
</v-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
48
components/RightMenu/FiltersMenu.vue
Normal file
48
components/RightMenu/FiltersMenu.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<v-expansion-panels flat accordion tile v-model="panel">
|
||||
<v-expansion-panel v-for="filter in filtersSearchable" :key="filter.title">
|
||||
<v-expansion-panel-header>{{
|
||||
$t(`learning.filters.${filter.title}`) | capitalize
|
||||
}}</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<universalFilterSelector
|
||||
:filterTitle="filter.title"
|
||||
:editMode="true"
|
||||
filterType="menu"
|
||||
/>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import universalFilterSelector from '@/components/UniversalFilterSelector/UniversalFilterSelector'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
universalFilterSelector,
|
||||
},
|
||||
computed: {
|
||||
filtersSearchable() {
|
||||
return this.$store.getters.filtersSearchable
|
||||
},
|
||||
subMenu() {
|
||||
return this.$store.getters.rightDrawer.subMenu
|
||||
},
|
||||
panel: {
|
||||
get() {
|
||||
return this.filtersSearchable.findIndex(
|
||||
(filter) => filter.title === this.subMenu
|
||||
)
|
||||
},
|
||||
set(v) {},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-item-group >>> .v-list-item--active.secondary {
|
||||
background-color: var(--v-primary-base) !important;
|
||||
}
|
||||
</style>
|
||||
165
components/RightMenu/Notifications.vue
Normal file
165
components/RightMenu/Notifications.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mx-10 my-4">
|
||||
<div class="d-flex">
|
||||
<chip-user-logged v-if="$auth.loggedIn" displayName />
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
fab
|
||||
text
|
||||
@click="$store.commit('navigation/SWITCH_RIGHT_DRAWER', false)"
|
||||
>
|
||||
<v-icon x-small>icon-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-divider class="lines" />
|
||||
|
||||
<h3 v-if="hasNotifications" class="my-6">
|
||||
{{ $t('rightMenu.notes') }}
|
||||
<span class="font-weight-light">({{ notifications.length }})</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<v-list two-line v-if="hasNotifications">
|
||||
<v-list-item-group v-model="selected" multiple active-class="secondary">
|
||||
<template v-for="(notification, index) in notifications">
|
||||
<v-divider
|
||||
v-if="!index && hasNotifications"
|
||||
:key="index + notification.title"
|
||||
class="lines"
|
||||
/>
|
||||
<v-list-item
|
||||
:key="`user-notification-${notification.id}`"
|
||||
@click="markAsRead(notification.id)"
|
||||
>
|
||||
<template v-slot:default="{ active, toggle }">
|
||||
<v-list-item-avatar>
|
||||
<!-- <v-icon x-small v-if="active" color="accent">mdi-circle</v-icon>
|
||||
<v-icon x-small v-else>mdi-circle-outline</v-icon> -->
|
||||
<v-icon x-small v-if="!notification.read_at" color="accent"
|
||||
>mdi-circle</v-icon
|
||||
>
|
||||
<v-icon x-small v-else>mdi-circle-outline</v-icon>
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content class="font-weight-bold">
|
||||
<v-list-item-subtitle
|
||||
v-text="notification.data.subject"
|
||||
></v-list-item-subtitle>
|
||||
<v-list-item-subtitle
|
||||
class="terziary--text"
|
||||
v-text="notification.data.message"
|
||||
></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action>
|
||||
<v-list-item-action-text>{{
|
||||
formatDate(notification.created_at)
|
||||
}}</v-list-item-action-text>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider
|
||||
v-if="index + 1 < notifications.length"
|
||||
:key="index"
|
||||
class="lines"
|
||||
/>
|
||||
</template>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
<v-card v-else flat>
|
||||
<v-card-text> No notifications </v-card-text>
|
||||
</v-card>
|
||||
|
||||
<!-- <v-container class="text-center d-flex flex-column">
|
||||
<v-btn
|
||||
color="success"
|
||||
@click="testNotification"
|
||||
class="my-2"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>Test Notification</v-btn
|
||||
>
|
||||
<v-btn
|
||||
color="red"
|
||||
@click="testMailNotifications"
|
||||
class="my-2"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>Test Email Notifications
|
||||
</v-btn>
|
||||
</v-container> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
import PageHeader from '~/components/UI/PageHeader/PageHeader'
|
||||
import chipUserLogged from '~/components/UI/ChipUserLogged/ChipUserLogged'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
chipUserLogged,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: [2],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
notifications() {
|
||||
return this.$store.getters.notifications
|
||||
},
|
||||
hasNotifications() {
|
||||
return this.$store.getters.hasNotifications
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
return dayjs(date).format('D MMM').toLowerCase()
|
||||
},
|
||||
async markAsRead(notificationId) {
|
||||
if (!this.$store.getters.isReadNotification(notificationId)) return
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('notifications/mark-as-read', {
|
||||
id: notificationId,
|
||||
})
|
||||
await this.$auth.setUser(response.data)
|
||||
} catch (error) {
|
||||
console.log('markAsRead -> error', error)
|
||||
}
|
||||
},
|
||||
async delete(notificationId) {
|
||||
if (!this.$store.getters.isReadNotification(notificationId)) return
|
||||
|
||||
try {
|
||||
const response = await this.$axios.post('notifications/delete', {
|
||||
id: notificationId,
|
||||
})
|
||||
await this.$auth.setUser(response.data)
|
||||
} catch (error) {
|
||||
console.log('markAsRead -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
async testNotification() {
|
||||
if (!this.$auth.loggedIn) return
|
||||
try {
|
||||
await this.$axios.post('notifications/test')
|
||||
} catch (error) {
|
||||
console.log('testNotification -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
async testMailNotifications() {
|
||||
if (!this.$auth.loggedIn) return
|
||||
try {
|
||||
await this.$axios.get('notifications/test-mail-notifications')
|
||||
} catch (error) {
|
||||
console.log('testNotification -> error', error)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
156
components/RightMenu/Settings.vue
Normal file
156
components/RightMenu/Settings.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<v-expansion-panels flat accordion tile v-model="panel" multiple>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header>Table</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<draggable v-model="columnsSorted">
|
||||
<transition-group>
|
||||
<div v-for="(column, i) in columnsSorted" :key="column.value">
|
||||
<v-card class="mx-auto" outlined tile flat v-if="!column.fixed">
|
||||
<v-card-text
|
||||
class="d-flex justify-space-between font-weight-black"
|
||||
>
|
||||
<small class="mr-4">{{ i - 1 + ':' }}</small>
|
||||
<small>{{ $t(column.text) }}</small>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
icon
|
||||
x-small
|
||||
class="mr-4"
|
||||
@click="toggleVisibility(column.value)"
|
||||
>
|
||||
<v-icon x-small>{{
|
||||
column.display
|
||||
? 'icon-visible-true'
|
||||
: 'icon-visible-false'
|
||||
}}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon x-small class="mr-2">
|
||||
<v-icon>icon-dragdrop</v-icon>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header>Filters </v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<draggable v-model="filters">
|
||||
<transition-group>
|
||||
<div v-for="(filter, i) in filters" :key="filter.title">
|
||||
<v-card class="mx-auto" outlined tile flat v-if="!filter.fixed">
|
||||
<v-card-text
|
||||
class="d-flex justify-space-between font-weight-black"
|
||||
>
|
||||
<small class="mr-4">{{ i + 1 + ':' }}</small>
|
||||
<small>
|
||||
{{ $t(`learning.filters.${filter.title}`) }}
|
||||
</small>
|
||||
<v-spacer></v-spacer>
|
||||
<!-- <v-btn icon x-small class="mr-4">
|
||||
<v-icon>icon-visible-true</v-icon>
|
||||
</v-btn> -->
|
||||
<v-btn icon x-small class="mr-2">
|
||||
<v-icon>icon-dragdrop</v-icon>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<template v-if="i === 4">
|
||||
<div class="my-4">Meer filters:</div>
|
||||
</template>
|
||||
</div>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
return this.$store.state.learning.columns
|
||||
},
|
||||
subMenu() {
|
||||
return this.$store.getters.rightDrawer.subMenu
|
||||
},
|
||||
panel: {
|
||||
get() {
|
||||
const submenus = ['columns', 'filters']
|
||||
const index = submenus.indexOf(this.subMenu)
|
||||
return [index]
|
||||
},
|
||||
set(v) {},
|
||||
},
|
||||
columnsSorted: {
|
||||
get() {
|
||||
return this.$store.state.learning.columnsSorted
|
||||
},
|
||||
async set(v) {
|
||||
await this.$store.commit('learning/SORT_COLUMNS', v)
|
||||
await this.storeLocallyColumnsSorted()
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
get() {
|
||||
return this.$store.state.learning.filters
|
||||
},
|
||||
async set(v) {
|
||||
await this.$store.commit('learning/SORT_FILTERS', v)
|
||||
await this.storeLocallyFiltersSorted()
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async storeLocallyColumnsSorted() {
|
||||
await localStorage.setItem(
|
||||
'learning_products_cols',
|
||||
JSON.stringify(this.columnsSorted)
|
||||
)
|
||||
},
|
||||
|
||||
async storeLocallyFiltersSorted() {
|
||||
const filtersIdsSorted = this.filters.map(({ id }) => id)
|
||||
|
||||
await localStorage.setItem(
|
||||
'learning_products_filters',
|
||||
JSON.stringify(filtersIdsSorted)
|
||||
)
|
||||
},
|
||||
|
||||
async toggleVisibility(value) {
|
||||
// if no columns sorted, make a copy from columns
|
||||
if (this.columnsSorted.length <= 0) {
|
||||
await this.$store.dispatch('learning/setColumns')
|
||||
}
|
||||
|
||||
// Find column index
|
||||
const columnIndex = this.columnsSorted.findIndex(
|
||||
(element) => element.value === value
|
||||
)
|
||||
|
||||
// find the column to change and edit
|
||||
let colsSortedCopy = [...this.columnsSorted]
|
||||
colsSortedCopy[columnIndex] = {
|
||||
...colsSortedCopy[columnIndex],
|
||||
display: !colsSortedCopy[columnIndex].display,
|
||||
}
|
||||
|
||||
// store in colSsorted
|
||||
await this.$store.commit('learning/SORT_COLUMNS', colsSortedCopy)
|
||||
|
||||
// copy in localStorage
|
||||
this.storeLocallyColumnsSorted()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
78
components/RightMenu/UserMenu.vue
Normal file
78
components/RightMenu/UserMenu.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<v-expansion-panels flat tile v-model="panel" multiple>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header
|
||||
class="font-weight-bold"
|
||||
expand-icon="icon-dropdown-up"
|
||||
>{{ $t('rightMenu.my_account') }}
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<v-list-item
|
||||
nuxt
|
||||
exact
|
||||
:to="localePath(`/manager/accounts/${$auth.user.id}`)"
|
||||
@click="$store.commit('navigation/SWITCH_RIGHT_DRAWER', false)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle> Profiel bewerken </v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<!--<v-list-item
|
||||
nuxt
|
||||
:to="localePath('/manager/accounts')"
|
||||
exact
|
||||
@click="$store.commit('navigation/SWITCH_RIGHT_DRAWER', false)"
|
||||
v-if="$store.getters.isSuperAdmin"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('rightMenu.users_manager') }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-list-item-content>
|
||||
<v-list-item-subtitle>
|
||||
{{ $t('rightMenu.notification_manager') }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item> -->
|
||||
|
||||
<v-divider class="my-2 lines" />
|
||||
|
||||
<v-list-item @click="logout">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ $t('rightMenu.logout') }}
|
||||
<!-- <localeSwitch /> -->
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-avatar>
|
||||
<v-btn text>
|
||||
<v-icon small>icon-logout</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-avatar>
|
||||
</v-list-item>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import localeSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
panel: [0],
|
||||
}),
|
||||
// components: {
|
||||
// localeSwitch,
|
||||
// },
|
||||
methods: {
|
||||
async logout() {
|
||||
await this.$auth.logout()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
75
components/SearchResizable/SearchResizable.vue
Normal file
75
components/SearchResizable/SearchResizable.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="searchbar">
|
||||
<input
|
||||
v-model="search"
|
||||
@keyup.enter="query"
|
||||
class="search_input"
|
||||
type="text"
|
||||
autofocus
|
||||
name
|
||||
placeholder="Search Image"
|
||||
/>
|
||||
<a href="#" @click="query" class="search_icon">
|
||||
<v-icon>icon-search</v-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
middleware: 'auth',
|
||||
layout: `${process.env.CUSTOMER}Admin`,
|
||||
data() {
|
||||
return {
|
||||
search: 'value'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
query() {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import 'https://getbootstrap.com/docs/4.0/examples/cover/cover.css';
|
||||
.searchbar {
|
||||
/* margin-bottom: auto;
|
||||
margin-top: auto;
|
||||
height: 60px; */
|
||||
background-color: #353b48;
|
||||
border-radius: 30px;
|
||||
padding: 10px;
|
||||
}
|
||||
.search_input {
|
||||
color: white;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: none;
|
||||
width: 0;
|
||||
caret-color: transparent;
|
||||
line-height: 40px;
|
||||
transition: width 0.3s linear;
|
||||
}
|
||||
.searchbar:hover > .search_input {
|
||||
padding: 0 10px;
|
||||
width: 250px;
|
||||
caret-color: red;
|
||||
transition: width 0.3s linear;
|
||||
}
|
||||
.searchbar:hover > .search_icon {
|
||||
background: white;
|
||||
color: #e74c3c;
|
||||
}
|
||||
.search_icon {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
float: right;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
54
components/Trending/Trending.vue
Normal file
54
components/Trending/Trending.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<section class="mx-auto trending">
|
||||
<v-container fluid class="pa-4">
|
||||
<h1 class="pa-4">TRENDING</h1>
|
||||
<v-slide-group v-model="model" class="pa-4" show-arrows>
|
||||
<v-slide-item v-for="n in 7" :key="n" v-slot:default="{ active, toggle }">
|
||||
<div class="d-flex flex-column ma-4 pa-4">
|
||||
<v-sheet height="320" width="290" class="pa-4" color="white" tile>
|
||||
<v-img
|
||||
src="https://gusta-online.nl/media/catalog/product/cache/4/image/544000d3f0f3eb3fd09c51e2c6034a96/0/4/04125370.jpg"
|
||||
contain
|
||||
/>
|
||||
</v-sheet>
|
||||
|
||||
<span class="title mt-6">Linteloo</span>
|
||||
<span class="subtitle">Isola salontafel van Roderick Vos, large</span>
|
||||
<span class="mt-6 font-weight-black">4125,-</span>
|
||||
</div>
|
||||
|
||||
<!-- <v-card color="white" class="ma-4 pa-4" height="320" width="290" tile flat>
|
||||
<v-card-text>
|
||||
|
||||
</v-card-text>
|
||||
</v-card>-->
|
||||
</v-slide-item>
|
||||
</v-slide-group>
|
||||
|
||||
<v-expand-transition>
|
||||
<v-sheet v-if="model != null" color="grey lighten-4" height="200" tile>
|
||||
<v-row class="fill-height" align="center" justify="center">
|
||||
<h3 class="title">Selected {{ model }}</h3>
|
||||
</v-row>
|
||||
</v-sheet>
|
||||
</v-expand-transition>
|
||||
</v-container>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Product from '@/components/Product/Product'
|
||||
|
||||
export default {
|
||||
components: { Product },
|
||||
data: () => ({
|
||||
model: null
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.trending {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
50
components/UI/AccordionCard/AccordionCard.vue
Normal file
50
components/UI/AccordionCard/AccordionCard.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<v-card flat class="my-4" color="primary">
|
||||
<v-card-title primary-title v-if="disableAccordion"/>
|
||||
<v-card-title primary-title v-else @click="expanded = !expanded">
|
||||
<v-icon x-small class="mx-4">{{
|
||||
expanded ? 'icon-dropdown' : 'icon-dropdown-up'
|
||||
}}</v-icon>
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text v-if="expanded" class="accordion-body">
|
||||
<div class="addresses-info" v-if="title == 'Adressen'">Wil je een adres wijzigen of toevoegen? Mail dan naar <a href="mailto:info@ggzecademy.nl">info@ggzecademy.nl</a></div>
|
||||
|
||||
<v-divider v-if="!disableAccordion" class="mb-10"/>
|
||||
<slot></slot>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Title',
|
||||
},
|
||||
companyMail: {
|
||||
type: String,
|
||||
default: 'info@ggzecademy.nl',
|
||||
},
|
||||
disableAccordion: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.addresses-info{
|
||||
padding-left: 45px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
</style>
|
||||
45
components/UI/ChipUserLogged/ChipUserLogged.vue
Normal file
45
components/UI/ChipUserLogged/ChipUserLogged.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-badge
|
||||
color="accent"
|
||||
dot
|
||||
overlap
|
||||
class="mx-4"
|
||||
:value="$store.getters.hasUnreadNotifications"
|
||||
>
|
||||
<v-avatar size="50" class="secondary has-outline">
|
||||
<img
|
||||
:src="$auth.user.image.thumb || noImage"
|
||||
:alt="$auth.user.fullName"
|
||||
/>
|
||||
</v-avatar>
|
||||
</v-badge>
|
||||
<small v-if="displayName" class="font-weight-bold txt--text">{{
|
||||
$auth.user.fullName
|
||||
}}</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
props: {
|
||||
displayName: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
noImage() {
|
||||
return require(`@/assets/img/no_image.png`)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.has-outline {
|
||||
box-shadow: 0 0 0 3px #eef7f9;
|
||||
}
|
||||
</style>
|
||||
58
components/UI/DarkModeSwitch/DarkModeSwitch.vue
Normal file
58
components/UI/DarkModeSwitch/DarkModeSwitch.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<v-btn fab text @click="switchDarkMode">
|
||||
<v-tooltip bottom>
|
||||
{{ $t('general.theme')}}
|
||||
<template
|
||||
v-slot:activator="{ on, attrs }"
|
||||
color="#FFCCCC"
|
||||
max-width="10"
|
||||
>
|
||||
<v-icon :color="`${$vuetify.theme.dark && 'yellow'}`" v-bind="attrs" v-on="on">icon-sun</v-icon>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
if (localStorage.getItem('dark') == 'true') {
|
||||
setTimeout(() => (this.$vuetify.theme.dark = true), 0)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
switchDarkMode() {
|
||||
this.$vuetify.theme.dark = !this.$vuetify.theme.dark
|
||||
localStorage.setItem('dark', this.$vuetify.theme.dark.toString())
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-tooltip__content.v-tooltip__content--fixed {
|
||||
max-width: 272px;
|
||||
padding: 15px 20px;
|
||||
line-height: 18px;
|
||||
top: 75px !important;
|
||||
left: 1020px !important;
|
||||
|
||||
position: absolute !important;
|
||||
|
||||
// box-shadow: 2px 10px 2px 1px rgba(0, 0, 0, .15);
|
||||
filter: drop-shadow(5px 10px 0.35rem rgba(0, 0, 0, 0.15));
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
border-top: 13px solid transparent;
|
||||
border-bottom: 13px solid transparent;
|
||||
border-right: 13px solid #30b7cd;
|
||||
left: 130px;
|
||||
top: -17px;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
20
components/UI/ErrorsList/ErrorsList.vue
Normal file
20
components/UI/ErrorsList/ErrorsList.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul v-for="(v, k) in errors" :key="k">
|
||||
<li v-for="error in v" :key="error" class="text-sm">
|
||||
{{ error }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
errors: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
21
components/UI/FullScreen/FullScreen.vue
Normal file
21
components/UI/FullScreen/FullScreen.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<v-btn icon @click="handleFullScreen()">
|
||||
<v-icon small>icon-fullscreen</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Util from '@/util';
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
handleFullScreen () {
|
||||
Util.toggleFullScreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
38
components/UI/GlobalModal/GlobalModal.vue
Normal file
38
components/UI/GlobalModal/GlobalModal.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="text-center">
|
||||
<!-- <v-btn color="error" @click="dialog = !dialog">Show Dialog</v-btn> -->
|
||||
|
||||
<v-overlay :value="dialog">
|
||||
<v-card>
|
||||
<v-card-title class="headline">{{headline}}</v-card-title>
|
||||
<v-card-text>{{text}}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="info" @click="dialog=false" tile depressed>back</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn color="error" @click="proceed()" tile depressed>confirm</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-overlay>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
headline: {
|
||||
type: String
|
||||
},
|
||||
text: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
confirm() {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
60
components/UI/GlobalSnackbar/GlobalSnackbar.vue
Normal file
60
components/UI/GlobalSnackbar/GlobalSnackbar.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<v-snackbar
|
||||
v-model="display"
|
||||
:timeout="3000"
|
||||
:color="color"
|
||||
:multi-line="hasErrors"
|
||||
right
|
||||
top
|
||||
>
|
||||
<v-icon class="mr-2">{{ icon }}</v-icon>
|
||||
{{ content }}
|
||||
|
||||
|
||||
<ul v-if="hasErrors">
|
||||
<li v-for="(allErrors, field) in errors" :key="field">
|
||||
{{ field }}
|
||||
<ul>
|
||||
<li v-for="(error, i) in allErrors" :key="i">
|
||||
{{ error }}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- <v-btn text @click="display = false">Close</v-btn> -->
|
||||
</v-snackbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// https://dev.to/stephannv/how-to-create-a-global-snackbar-using-nuxt-vuetify-and-vuex-1bda
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
display: false,
|
||||
color: 'success',
|
||||
content: '',
|
||||
icon: '',
|
||||
errors: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.subscribe((mutation, state) => {
|
||||
if (mutation.type === 'snackbar/showMessage') {
|
||||
this.content = state.snackbar.content
|
||||
this.color = state.snackbar.color
|
||||
this.icon = state.snackbar.icon
|
||||
this.errors = state.snackbar.errors
|
||||
this.display = true
|
||||
}
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
hasErrors() {
|
||||
return Object.keys(this.errors).length > 0
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
75
components/UI/Loading/Loading.vue
Normal file
75
components/UI/Loading/Loading.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<v-overlay :value="loading" color="#013447">
|
||||
<div class="loading">
|
||||
<div class="spinner">
|
||||
<img class="logo one" :src="mySVG" />
|
||||
</div>
|
||||
<div class="spinner">
|
||||
<img class="logo two" :src="mySVG" />
|
||||
</div>
|
||||
<span>{{ $t('general.loading') }}</span>
|
||||
</div>
|
||||
</v-overlay>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return{
|
||||
loading: false,
|
||||
mySVG: require('assets/img/ggz/loading-logo.svg')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
start() {
|
||||
this.loading = true
|
||||
},
|
||||
finish() {
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.loading {
|
||||
width: 140px;
|
||||
height: 180px;
|
||||
margin: auto;
|
||||
margin-bottom: 25px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.spinner {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
.one {
|
||||
transform: rotate(25deg);
|
||||
}
|
||||
-webkit-animation: spin 5s linear infinite;
|
||||
animation: spin 5s linear infinite;
|
||||
}
|
||||
|
||||
span{
|
||||
display:flex;
|
||||
align-items: flex-end;
|
||||
font-family:"Source Sans Pro", sans-serif;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
5
components/UI/PageHeader/PageHeader.vue
Normal file
5
components/UI/PageHeader/PageHeader.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<h2 class="pa-4 txt--text">
|
||||
<slot></slot>
|
||||
</h2>
|
||||
</template>
|
||||
207
components/UI/SearchBar/SearchBar.vue
Normal file
207
components/UI/SearchBar/SearchBar.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<v-autocomplete
|
||||
v-if="isNotMember()"
|
||||
:items="isMemberPage ? members : learningProducts"
|
||||
:item-text="isMemberPage ? 'informal_name' : 'title'"
|
||||
filled
|
||||
dense
|
||||
id="searchbar"
|
||||
rounded
|
||||
:search-input.sync="search"
|
||||
v-model="selected"
|
||||
append-icon="icon-search"
|
||||
hide-details
|
||||
:placeholder="$t('general.search')"
|
||||
single-line
|
||||
full-width
|
||||
flat
|
||||
return-object
|
||||
class="mx-4"
|
||||
:filter="customFilter"
|
||||
@focus="toDoOnFocus"
|
||||
@blur="switchOverlay(false)"
|
||||
@keydown="switchOverlay(true)"
|
||||
@click="switchOverlay(true)"
|
||||
>
|
||||
<template v-slot:prepend-item v-if="prependText">
|
||||
<v-list-item>
|
||||
<v-list-item-title class="header-search-title pb-4">
|
||||
<span class="pt-4">
|
||||
{{ prependText }}
|
||||
</span>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-autocomplete>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Util from '@/util'
|
||||
var Diacritics = require('diacritic')
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
loading: false,
|
||||
selected: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
learningProducts() {
|
||||
return this.$store.getters.learningProducts.filter((p) => {
|
||||
if (p.parent_id) return false
|
||||
if (p.deleted_at) return false
|
||||
if (!p.published) return false
|
||||
return true
|
||||
})
|
||||
},
|
||||
isMemberPage() {
|
||||
return this.$route.name.includes('manager-members')
|
||||
},
|
||||
members() {
|
||||
return this.$store.getters['members/membersFiltered']
|
||||
},
|
||||
hasMembers() {
|
||||
return this.members?.length > 0
|
||||
},
|
||||
prependText() {
|
||||
if (this.loading) return this.$t('general.loading')
|
||||
|
||||
if (this.isMemberPage) {
|
||||
if (!this.hasMembers) return `No results found`
|
||||
if (this.search) return `Zoeksuggesties voor '${this.search}'`
|
||||
}
|
||||
|
||||
if (!this.$store.getters.hasLearningProducts) {
|
||||
return `No results found`
|
||||
}
|
||||
if (this.$store.getters.hasLearningProducts && this.search) {
|
||||
return `Zoeksuggesties voor '${this.search}'`
|
||||
}
|
||||
return null
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
async selected(item) {
|
||||
if (!item || !item.slug) return
|
||||
|
||||
const route = this.isMemberPage
|
||||
? `/manager/members/${item.slug}`
|
||||
: `/manager/learning/${item.slug}`
|
||||
|
||||
await this.$router.push(this.localePath(route))
|
||||
this.$store.commit('navigation/TOGGLE_SEARCH_OVERLAY', false)
|
||||
this.search = null
|
||||
this.selected = null
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
customFilter(item, queryText, itemText) {
|
||||
const textOne = Diacritics.clean(
|
||||
item[!this.isMemberPage ? 'title' : 'informal_name'].toLowerCase()
|
||||
)
|
||||
let textTwo = ''
|
||||
|
||||
if (!this.isMemberPage) {
|
||||
if (item.synonyms.length > 0) {
|
||||
item.synonyms.forEach((s) => (textTwo += `${s.title.toLowerCase()} `))
|
||||
}
|
||||
}
|
||||
|
||||
const searchText = queryText.toLowerCase()
|
||||
|
||||
return (
|
||||
textOne.indexOf(Diacritics.clean(searchText)) > -1 ||
|
||||
textTwo.indexOf(Diacritics.clean(searchText)) > -1
|
||||
)
|
||||
},
|
||||
async toDoOnFocus() {
|
||||
if (this.isMemberPage && !this.hasMembers) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.loading = true
|
||||
await this.$store.dispatch('members/pullData')
|
||||
await this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
if (!this.isMemberPage && !this.$store.getters.hasLearningProducts) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
this.loading = true
|
||||
await this.$store.dispatch('learning/pullProducts')
|
||||
await this.$nuxt.$loading.finish()
|
||||
this.loading = false
|
||||
}
|
||||
this.$store.commit('navigation/TOGGLE_SEARCH_OVERLAY', true)
|
||||
},
|
||||
switchOverlay(value) {
|
||||
if (value == this.$store.getters.searchOverlay) return
|
||||
this.$store.commit('navigation/TOGGLE_SEARCH_OVERLAY', value)
|
||||
},
|
||||
isNotMember() {
|
||||
const roles = this.$auth.user.roles.map(({ name }) => name)
|
||||
return !Util.findCommonValuesInArray(roles, ['member'])
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#searchbar {
|
||||
width: 400px !important;
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
|
||||
.v-input >>> textarea {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
#searchbar >>> .icon-search {
|
||||
color: var(--v-txt-base) !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
#searchbar >>> .v-text-field--outlined fieldset {
|
||||
color: rgba(255, 255, 255, 0);
|
||||
}
|
||||
#searchbar
|
||||
>>> .v-select.v-select--is-menu-active
|
||||
.v-input__icon--append
|
||||
.v-icon {
|
||||
transform: unset !important;
|
||||
}
|
||||
.v-list {
|
||||
padding: 30px 90px 30px 100px !important;
|
||||
border-radius: 0px;
|
||||
}
|
||||
@media only screen and (min-width: 1536px) {
|
||||
.v-list {
|
||||
padding: 30px 80px 30px 53px !important;
|
||||
}
|
||||
}
|
||||
.v-list:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.v-list >>> .v-list-item {
|
||||
color: var(--v-tertiary-base) !important;
|
||||
background: var(--v-primary-base) !important;
|
||||
}
|
||||
.v-list >>> .v-list-item__title {
|
||||
font-size: 16px;
|
||||
color: var(--v-tab-base);
|
||||
}
|
||||
|
||||
.header-search-title {
|
||||
pointer-events: none;
|
||||
cursor: initial;
|
||||
font-size: 24px !important;
|
||||
height: 22px !important;
|
||||
color: var(--v-txt-base) !important;
|
||||
font-weight: 700;
|
||||
|
||||
border-bottom: 2px solid var(--v-search-base);
|
||||
padding-bottom: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
303
components/UniversalFilterSelector/UniversalFilterSelector.vue
Normal file
303
components/UniversalFilterSelector/UniversalFilterSelector.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select
|
||||
v-model="vModelSelected"
|
||||
:items="filterItems"
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
append-icon="icon-dropdown"
|
||||
v-if="isSelect"
|
||||
>
|
||||
<template slot="item" slot-scope="data">
|
||||
<v-icon
|
||||
x-small
|
||||
class="mr-2"
|
||||
v-if="data.item.color"
|
||||
:color="data.item.color"
|
||||
>mdi-circle</v-icon
|
||||
>
|
||||
<span>
|
||||
{{ data.item.title }}
|
||||
</span>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<v-list
|
||||
v-if="isCheckbox"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
>
|
||||
<v-list-item-group v-model="vModelSelected" multiple>
|
||||
<template v-for="(item, i) in filterItems">
|
||||
<v-list-item
|
||||
:key="`item-${i}`"
|
||||
:value="item.id"
|
||||
active-class="secondary"
|
||||
two-line
|
||||
>
|
||||
<template v-slot:default="{ active, toggle }">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.title"></v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
v-if="item.subtitle"
|
||||
v-text="item.subtitle"
|
||||
></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action>
|
||||
<v-checkbox :input-value="active" :true-value="item.id" />
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
|
||||
<v-select
|
||||
chips
|
||||
multiple
|
||||
v-model="vModelSelected"
|
||||
:items="filterItems"
|
||||
item-text="title"
|
||||
item-value="id"
|
||||
:outlined="editMode"
|
||||
:solo="!editMode"
|
||||
:disabled="!editMode"
|
||||
:flat="!editMode"
|
||||
append-icon="icon-dropdown"
|
||||
v-if="isMixed"
|
||||
/>
|
||||
|
||||
<v-list v-if="isMenu">
|
||||
<v-list-item-group v-model="filtersSelected" multiple id="searchbar">
|
||||
<v-text-field
|
||||
filled
|
||||
dense
|
||||
rounded
|
||||
v-model="search"
|
||||
append-icon="icon-search"
|
||||
hide-details
|
||||
:placeholder="$t('general.search')"
|
||||
single-line
|
||||
full-width
|
||||
flat
|
||||
outlined
|
||||
v-if="hasManyItems"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<template v-for="(item, i) in filterItemsFiltered">
|
||||
<v-divider v-if="!item" :key="`divider-${i}`"></v-divider>
|
||||
|
||||
<v-list-item v-else :key="`item-${i}`" :value="item.id">
|
||||
<template v-slot:default="{ active, toggle }">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.title"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action>
|
||||
<v-checkbox :input-value="active" :true-value="item.id" />
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import searchBar from '~/components/UI/SearchBar/SearchBar'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
searchBar,
|
||||
},
|
||||
props: {
|
||||
filterTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
filterType: {
|
||||
type: String,
|
||||
default: 'select',
|
||||
},
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: 'filters',
|
||||
validator: function (value) {
|
||||
// The value must match one of these strings
|
||||
return ['filters', 'versions', 'accreditations'].indexOf(value) !== -1
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelect() {
|
||||
return this.filterType === 'select'
|
||||
},
|
||||
isCheckbox() {
|
||||
return this.filterType === 'checkbox'
|
||||
},
|
||||
isMixed() {
|
||||
return this.filterType === 'mixed'
|
||||
},
|
||||
isMenu() {
|
||||
return this.filterType === 'menu'
|
||||
},
|
||||
hasItems() {
|
||||
return this.filterItems.length > 0
|
||||
},
|
||||
hasManyItems() {
|
||||
return this.filterItems.length >= 5
|
||||
},
|
||||
// Both Checkbox and Mixed have multiple filters
|
||||
multiple() {
|
||||
return this.isCheckbox || this.isMixed
|
||||
},
|
||||
filterId() {
|
||||
return this.$store.getters.getFilterByTitle(this.filterTitle).id
|
||||
},
|
||||
filterItems() {
|
||||
if (this.filterTitle) {
|
||||
return this.$store.getters.getFilterByTitle(this.filterTitle).items
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
filterItemsFiltered() {
|
||||
if (this.search) {
|
||||
return this.$store.getters
|
||||
.getFilterByTitle(this.filterTitle)
|
||||
.items.filter((filter) => {
|
||||
return filter.title
|
||||
.toLowerCase()
|
||||
.includes(this.search.toLowerCase())
|
||||
})
|
||||
}
|
||||
return this.filterItems
|
||||
},
|
||||
|
||||
filtersSelected: {
|
||||
get() {
|
||||
return this.$store.state.learning.filtersSelected
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('learning/SELECT_FILTERS', value)
|
||||
},
|
||||
},
|
||||
|
||||
vModelSelected: {
|
||||
// Gets Object / Array of Objects from filters
|
||||
get() {
|
||||
if (!this.$store.getters.localProduct.filtersGrouped) {
|
||||
return []
|
||||
}
|
||||
if (
|
||||
this.target === 'filters' &&
|
||||
typeof this.$store.getters.localProduct.filtersGrouped[
|
||||
this.filterId
|
||||
] === 'undefined'
|
||||
) {
|
||||
return []
|
||||
}
|
||||
|
||||
let filterItemsIdsSelectedRaw
|
||||
|
||||
if (this.target === 'filters') {
|
||||
// Gets ids from the local learning product array associated to the filterId
|
||||
filterItemsIdsSelectedRaw =
|
||||
this.$store.getters.localProduct.filtersGrouped[this.filterId] || []
|
||||
}
|
||||
|
||||
if (this.target === 'versions') {
|
||||
filterItemsIdsSelectedRaw =
|
||||
this.$store.state.learning.versionsFiltersSelected[this.filterId] ||
|
||||
[]
|
||||
}
|
||||
|
||||
if (this.target === 'accreditations') {
|
||||
filterItemsIdsSelectedRaw =
|
||||
this.$store.state.learning.accreditationsFiltersSelected[
|
||||
this.filterId
|
||||
] || []
|
||||
}
|
||||
|
||||
// if multiple filter, checkbox type, return array of filter items ids only
|
||||
if (this.multiple) {
|
||||
this.selected = filterItemsIdsSelectedRaw
|
||||
return filterItemsIdsSelectedRaw
|
||||
}
|
||||
|
||||
// Single Select Input
|
||||
return this.filterItems.find(
|
||||
(filterItem) => filterItem.id == filterItemsIdsSelectedRaw[0]
|
||||
)
|
||||
},
|
||||
|
||||
set(value) {
|
||||
this.setFilterItems(value)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setFilterItems(value) {
|
||||
this.$store.commit('learning/UPDATE_FILTERS', {
|
||||
filterId: this.filterId,
|
||||
target: this.target || 'filters',
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-input >>> .v-icon {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
.v-input >>> .mdi-checkbox-blank-outline::before {
|
||||
font-family: 'mijnggz';
|
||||
content: '\e921' !important;
|
||||
}
|
||||
.v-input >>> .mdi-checkbox-marked::before {
|
||||
font-family: 'mijnggz';
|
||||
content: '\e923' !important;
|
||||
}
|
||||
#searchbar.mx-4 {
|
||||
margin: 30px -24px !important;
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
.v-input >>> .v-expansion-panel-header {
|
||||
color: var(--v-txt-base) !important;
|
||||
}
|
||||
/* .v-input >>> .v-input__slot label {
|
||||
font-weight: 600;
|
||||
color: var(--v-txt-base) !important;
|
||||
} */
|
||||
|
||||
/* .v-input >>> .v-messages__message {
|
||||
padding-left: 33px;
|
||||
font-size: 16px;
|
||||
color: var(--v-tertiary-base) !important;
|
||||
}
|
||||
.v-input >>> .v-input__control:hover label,
|
||||
.v-input >>> .v-input__control:hover .v-messages__message {
|
||||
color: var(--v-secAccent-base) !important;
|
||||
} */
|
||||
</style>
|
||||
68
components/Usp/Usp.vue
Normal file
68
components/Usp/Usp.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<section id="usp">
|
||||
<v-container fluid class="px-4 mx-4">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-4 item">
|
||||
<div class="d-flex">
|
||||
<v-icon size="60" color="#5885C0">mdi-script-outline</v-icon>
|
||||
|
||||
<div class="d-flex flex-column pa-4 mx-4">
|
||||
<span class="title">Behangrol advies</span>
|
||||
<span>Hulp nodig bij het uitrekenen van het aantal rollen behang?</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 item">
|
||||
<div class="d-flex">
|
||||
<v-icon size="60" color="#5885C0">mdi-script-outline</v-icon>
|
||||
|
||||
<div class="d-flex flex-column pa-4 mx-4">
|
||||
<span class="title">Interieuradvies</span>
|
||||
<span>Hulp nodig bij het uitrekenen van het aantal rollen behang?</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 item">
|
||||
<div class="d-flex">
|
||||
<v-icon size="60" color="#5885C0">mdi-script-outline</v-icon>
|
||||
|
||||
<div class="d-flex flex-column pa-4 mx-4">
|
||||
<span class="title">Bezoek ons</span>
|
||||
<span>Wij ontvangen je graag op afspraak voor een persoonlijk gesprek!</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-container>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
items: [
|
||||
{icon: 'mdi-script-outline', title: '', text: ''},
|
||||
{icon: '', title: '', text: ''},
|
||||
{icon: '', title: '', text: ''},
|
||||
]
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#usp {
|
||||
margin: 80px 0;
|
||||
.item {
|
||||
#icon {
|
||||
font-size: 60px;
|
||||
color: yellow;
|
||||
width: 90px;
|
||||
float: left;
|
||||
}
|
||||
.title {
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
176
components/layout/Footer.vue
Normal file
176
components/layout/Footer.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<v-footer light padless>
|
||||
<v-card class="flex my-0">
|
||||
<v-card-title>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-list dense>
|
||||
<v-subheader>Productcatalogus</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-list dense>
|
||||
<v-subheader>Diensten</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-list dense>
|
||||
<v-subheader>CATEGORY</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="3">
|
||||
<v-list dense>
|
||||
<v-subheader>CATEGORY</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-row no-gutters>
|
||||
<v-col cols="12" sm="3">
|
||||
<v-list dense>
|
||||
<v-subheader>CATEGORY</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="3">
|
||||
<v-list dense>
|
||||
<v-subheader>CATEGORY</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="3">
|
||||
<v-list dense>
|
||||
<v-subheader>CATEGORY</v-subheader>
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item v-for="(item, i) in items" :key="i">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.text"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="3" class="d-flex flex-column">
|
||||
<v-list dense>
|
||||
<v-subheader>Betalingsmethode</v-subheader>
|
||||
|
||||
<v-row>
|
||||
<v-col
|
||||
v-for="payment in payments"
|
||||
:key="payment.name"
|
||||
class="d-flex child-flex"
|
||||
cols="2"
|
||||
>
|
||||
<v-img
|
||||
:src="require(`@/assets/img/${payment.filename}`)"
|
||||
:lazy-src="require(`@/assets/img/${payment.filename}`)"
|
||||
contain
|
||||
>
|
||||
<template v-slot:placeholder>
|
||||
<v-row class="fill-height ma-0" align="center" justify="center">
|
||||
<v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
|
||||
</v-row>
|
||||
</template>
|
||||
</v-img>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-list>
|
||||
|
||||
<v-list dense>
|
||||
<v-subheader>Volg ons</v-subheader>
|
||||
<v-btn v-for="icon in icons" :key="icon" class="mx-2" light icon>
|
||||
<v-icon small>{{ 'mdi-' + icon }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="py-2 grey lighten-4">
|
||||
<span>© Buningh {{ new Date().getFullYear() }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<span>Alle vermelde prijzen zijn in euro's en inclusief BTW</span>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Newsletter from '~/components/Newsletter/Newsletter'
|
||||
import Disclaimer from '~/components/Info/Disclaimer'
|
||||
import Privacy from '~/components/Info/Privacy'
|
||||
import Cookies from '~/components/Info/Cookies'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Newsletter,
|
||||
Disclaimer,
|
||||
Privacy,
|
||||
Cookies
|
||||
},
|
||||
data: () => ({
|
||||
item: 99,
|
||||
payments: [
|
||||
{ name: 'Bancontact', filename: 'BC_logo_ORGNL_RGB.png' },
|
||||
{ name: 'PayPal', filename: 'PayPal.png' },
|
||||
{ name: 'Maestro', filename: 'MAES.png' },
|
||||
{ name: 'IDeal', filename: 'iDeal.png' },
|
||||
{ name: 'MasterCard', filename: 'MC.png' },
|
||||
{ name: 'Visa', filename: 'Visa.png' }
|
||||
],
|
||||
items: [
|
||||
{ text: 'Real-Time' },
|
||||
{ text: 'Audience' },
|
||||
{ text: 'Conversions' },
|
||||
{ text: 'Whatever' }
|
||||
],
|
||||
icons: ['twitter', 'facebook', 'linkedin', 'instagram'],
|
||||
disclaimer: false,
|
||||
privacy: false,
|
||||
cookies: false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
80
components/layout/Header/Header.vue
Normal file
80
components/layout/Header/Header.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div>
|
||||
<topbar />
|
||||
|
||||
<v-row align="center" justify="space-between">
|
||||
<div class="d-flex mx-4">
|
||||
<v-card class="ma-3 pa-6" outlined tile>LOGO Buningh</v-card>
|
||||
<v-row align="center" class="mx-4">
|
||||
<v-col>
|
||||
<v-btn
|
||||
text
|
||||
small
|
||||
:to="item.to"
|
||||
v-for="(item,i) in menu"
|
||||
:key="i"
|
||||
class="mx-4"
|
||||
>{{item.title}}</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
append-icon="icon-search"
|
||||
label="Zoeken naar merk of product.."
|
||||
single-line
|
||||
hide-details
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-row align="center" class="mx-4">
|
||||
<v-col>
|
||||
<v-btn icon to="/login">
|
||||
<v-icon>icon-password</v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn icon>
|
||||
<v-icon>mdi-heart</v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn icon>
|
||||
<v-icon>mdi-shopping-outline</v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Topbar from '~/components/layout/Header/Topbar'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Topbar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
menu: [
|
||||
{ title: 'Verlichting', to: '/' },
|
||||
{ title: 'Meubels', to: '/' },
|
||||
{ title: 'Behang', to: '/' },
|
||||
{ title: 'Stoffen', to: '/' },
|
||||
{ title: 'Accessoires', to: '/' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return `${process.env.NAME}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
53
components/layout/Header/Topbar.vue
Normal file
53
components/layout/Header/Topbar.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<v-toolbar dense flat>
|
||||
<span v-for="(item,i) in menuItems.left" :key="`x${i}`" class="mx-4 caption">
|
||||
<v-avatar color="#ffcc00" size="6" class="mx-2"></v-avatar>
|
||||
<span>{{item.label}}</span>
|
||||
</span>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<span v-for="(item,i) in menuItems.right" :key="i" class="mx-4 caption">
|
||||
{{item.label}}
|
||||
</span>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
menuItems: {
|
||||
left: [
|
||||
{ label: 'Gratis verzending in NL & BE' },
|
||||
{ label: 'Meer dan 500 merken' },
|
||||
{ label: '135 jaar de nieuwste trends' }
|
||||
],
|
||||
right: [
|
||||
{ label: 'Interieuradvies', to: '/interieuradvies' },
|
||||
{ label: 'Over Buningh', to: '/algemeen' },
|
||||
{ label: 'Klantenservice', to: '/klantenservice' },
|
||||
{ label: '+31 10 41 40 560' }
|
||||
]
|
||||
},
|
||||
|
||||
menu: [
|
||||
{ title: 'Verlichting', route: '/' },
|
||||
{ title: 'Meubels', route: '/' },
|
||||
{ title: 'Behang', route: '/' },
|
||||
{ title: 'Stoffen', route: '/' },
|
||||
{ title: 'Accessoires', route: '/' },
|
||||
{ title: 'Sale', route: '/' },
|
||||
{ title: 'Inspiratie', route: '/' },
|
||||
{ title: 'Merken', route: '/' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return `${process.env.NAME}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
31
components/layout/LeftMenu.vue
Normal file
31
components/layout/LeftMenu.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
<template>
|
||||
<v-navigation-drawer v-model="drawer" app>
|
||||
<v-list dense>
|
||||
<v-list-item link>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-home</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Home</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item link>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-contact-mail</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Contact</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
drawer: false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
10
components/layout/SystemBar.vue
Normal file
10
components/layout/SystemBar.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<v-system-bar window light>
|
||||
<v-icon>mdi-message</v-icon>
|
||||
<span>10 unread messages</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
<v-icon>icon-checkmarkbox-blank-outline</v-icon>
|
||||
<v-icon x-small>icon-close</v-icon>
|
||||
</v-system-bar>
|
||||
</template>
|
||||
Reference in New Issue
Block a user