- 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:
483
pages/manager/members/_member.vue
Normal file
483
pages/manager/members/_member.vue
Normal file
@@ -0,0 +1,483 @@
|
||||
<template>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<div class="d-flex justify-space-between">
|
||||
<h2 class="ma-4" v-if="isNew">Nieuw</h2>
|
||||
<span v-else>
|
||||
<h2 class="ma-4">{{ local.informal_name || '' }}</h2>
|
||||
<h3 class="ma-4">{{ local.formal_name || '' }}</h3>
|
||||
</span>
|
||||
<span class="justify-center d-flex flex-column" v-if="local.revision">
|
||||
<small>
|
||||
<v-icon color="success" class="mr-2">icon-checkmark</v-icon>
|
||||
bijgewerkt op
|
||||
<strong>{{ formatDate(local.revision.updated_at) }}</strong> door
|
||||
<strong>{{ local.revision.user.fullName }}</strong>
|
||||
</small>
|
||||
|
||||
<small v-if="local.revision.accepted_at">
|
||||
<v-icon color="success">icon-checkmark</v-icon>
|
||||
<v-icon color="success" class="mr-2">icon-checkmark</v-icon>
|
||||
gecontroleerd op
|
||||
<strong>{{ formatDate(local.revision.accepted_at) }}</strong> door
|
||||
<strong>{{ local.revision.revisor.fullName }}</strong>
|
||||
</small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-space-between">
|
||||
<div class="d-flex">
|
||||
<small
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="index"
|
||||
@click="selectedTab = tab"
|
||||
class="ma-4 dot"
|
||||
:class="{ 'accent--text activeTab': selectedTab === tab }"
|
||||
>{{ $t(`members.tabs.${tab}`) }}</small
|
||||
>
|
||||
</div>
|
||||
<!-- here checks -->
|
||||
</div>
|
||||
|
||||
<basic-members
|
||||
v-if="isTabSelected('basic')"
|
||||
:editMode="canEditSuperAdminsAndAdmins"
|
||||
:isCreateMode="isNew"
|
||||
:users="users"
|
||||
/>
|
||||
|
||||
<address-members
|
||||
v-if="isTabSelected('address')"
|
||||
:editMode="canEditSuperAdminsAndAdmins"
|
||||
:isCreateMode="isNew"
|
||||
/>
|
||||
<contacts-members
|
||||
v-if="isTabSelected('contacts')"
|
||||
:editMode="canEditSuperAdminsAdminsAndDelegated"
|
||||
:isCreateMode="isNew"
|
||||
/>
|
||||
|
||||
<contribution-members
|
||||
v-if="isTabSelected('contribution')"
|
||||
:editMode="canEditSuperAdminsAndAdmins"
|
||||
:isCreateMode="isNew"
|
||||
/>
|
||||
|
||||
<employees-members
|
||||
v-if="isTabSelected('employees')"
|
||||
:editMode="canEditSuperAdminsAdminsAndDelegated"
|
||||
:isCreateMode="isNew"
|
||||
/>
|
||||
<page-members
|
||||
v-if="isTabSelected('member_page')"
|
||||
:editMode="canEditSuperAdminsAdminsAndDelegated"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-footer
|
||||
fixed
|
||||
style="z-index: 4"
|
||||
height="90"
|
||||
color="primary"
|
||||
v-if="$store.getters['members/isSuperAdminAdminOrDelegated']"
|
||||
>
|
||||
<v-btn title text small :to="localePath('/manager/members')">
|
||||
<v-icon>icon-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<div class="mx-10">
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
color="accent"
|
||||
depressed
|
||||
v-if="
|
||||
$store.getters['members/isSuperAdminAdminOrDelegated'] &&
|
||||
!$store.getters.isOnlyMemberEditor &&
|
||||
!isNew &&
|
||||
!isEditMode
|
||||
"
|
||||
rounded
|
||||
@click="switchToEdit"
|
||||
>
|
||||
<!-- :to="localePath(`${$nuxt.$route.path}?edit`)"
|
||||
nuxt -->
|
||||
{{ $t('general.edit') }}</v-btn
|
||||
>
|
||||
|
||||
<v-btn
|
||||
class="ma-2 white--text"
|
||||
:color="$vuetify.theme.dark ? 'secondary' : 'txt'"
|
||||
depressed
|
||||
@click="save()"
|
||||
v-if="
|
||||
canSave && ($store.getters.isSuperAdmin || $store.getters.isAdmin)
|
||||
"
|
||||
rounded
|
||||
>Tussentijds opslaan</v-btn
|
||||
>
|
||||
|
||||
<!-- Accept Revision - only super admins or admins -->
|
||||
<template v-if="$store.getters.isSuperAdmin || $store.getters.isAdmin">
|
||||
<v-btn
|
||||
v-cloak
|
||||
class="ma-2 white--text"
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
v-if="
|
||||
!isNew &&
|
||||
$store.getters['members/revision'] &&
|
||||
local.revision.hasChanges &&
|
||||
isEditMode
|
||||
"
|
||||
@click="save(true)"
|
||||
>Opslaan en indienen</v-btn
|
||||
>
|
||||
</template>
|
||||
<!-- Store revision - only delegated users -->
|
||||
<template v-else>
|
||||
<v-btn
|
||||
v-cloak
|
||||
class="ma-2 white--text"
|
||||
color="accent"
|
||||
depressed
|
||||
v-if="canSave && !isNew"
|
||||
rounded
|
||||
@click="storeRevision()"
|
||||
>Opslaan en indienen</v-btn
|
||||
>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<v-btn
|
||||
class="ma-2"
|
||||
tile
|
||||
text
|
||||
v-if="canSave && !isNew"
|
||||
color="accent"
|
||||
depressed
|
||||
>
|
||||
<v-icon class="mx-2" size="26">mdi-alert-circle-outline</v-icon>
|
||||
wijziging
|
||||
</v-btn>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<!-- <v-btn class="ma-2" tile text small>
|
||||
<v-icon class="mx-2" small>icon-sharepoint</v-icon>
|
||||
Documenten
|
||||
</v-btn> -->
|
||||
|
||||
<!-- <v-dialog v-model="dialog" persistent max-width="740">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn
|
||||
class="ma-2"
|
||||
tile
|
||||
text
|
||||
small
|
||||
v-if="!isNew && canEdit"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon class="mx-2">icon-remove</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card class="primary pa-10" flat>
|
||||
<v-card-title class="headline">
|
||||
{{
|
||||
$t('learning.product_overview.delete_confirmation', {
|
||||
productName: local.title,
|
||||
})
|
||||
}}
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<div class="ma-4">
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="mx-2"
|
||||
@click="deleteMember()"
|
||||
rounded
|
||||
depressed
|
||||
>{{ $t('general.delete') }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
class="mx-2"
|
||||
color="info"
|
||||
@click="close"
|
||||
rounded
|
||||
depressed
|
||||
>{{ $t('general.cancel') }}</v-btn
|
||||
>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog> -->
|
||||
</v-footer>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
import PageHeader from '~/components/UI/PageHeader/PageHeader'
|
||||
import basicMembers from '@/components/Members/BasicMembers'
|
||||
import addressMembers from '@/components/Members/AddressMembers'
|
||||
import contactsMembers from '@/components/Members/ContactsMembers'
|
||||
import employeesMembers from '@/components/Members/EmployeesMembers'
|
||||
import pageMembers from '@/components/Members/PageMembers'
|
||||
import moreMembers from '@/components/Members/MoreMembers'
|
||||
import contributionMembers from '~/components/Members/ContributionMembers.vue'
|
||||
|
||||
export default {
|
||||
layout: `${process.env.CUSTOMER}Admin`,
|
||||
components: {
|
||||
PageHeader,
|
||||
basicMembers,
|
||||
addressMembers,
|
||||
contactsMembers,
|
||||
employeesMembers,
|
||||
pageMembers,
|
||||
moreMembers,
|
||||
contributionMembers,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: [
|
||||
'all',
|
||||
'basic',
|
||||
'address',
|
||||
'contacts',
|
||||
'contribution',
|
||||
'employees',
|
||||
'member_page',
|
||||
],
|
||||
selectedTab: 'all',
|
||||
dialog: false,
|
||||
users: [],
|
||||
}
|
||||
},
|
||||
|
||||
async asyncData({ $axios, store }) {
|
||||
try {
|
||||
await store.dispatch('members/pullBranches')
|
||||
await store.dispatch('members/pullTypes')
|
||||
|
||||
if (store.getters.isAdmin || store.getters.isOperator) {
|
||||
const response = await $axios.get('/admin/users/getList')
|
||||
return { users: response.data }
|
||||
}
|
||||
return { users: [] }
|
||||
} catch (error) {
|
||||
console.log('asyncData -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
if (!this.isValidSlug) {
|
||||
this.$nuxt.error({ statusCode: 404, message: 'URL niet geldig' })
|
||||
// this.$router.push('/manager')
|
||||
}
|
||||
if (this.isSlugNumber) {
|
||||
await this.$store.dispatch('members/getAndSetMember', this.slug)
|
||||
}
|
||||
if (this.isNew && !this.$store.getters.isSuperAdminOrAdmin) {
|
||||
this.$nuxt.error({ statusCode: 401, message: 'Je mag dit niet doen' })
|
||||
// this.$router.push('/manager')
|
||||
}
|
||||
|
||||
// #warning Laravel Echo has been manually disabled until broadcasting issue is fixed.
|
||||
// this.$echo.channel('updates').listen(`.members-updated`, async (e) => {
|
||||
// if (this.isSlugNumber) {
|
||||
// await this.$store.dispatch('members/getAndSetMember', this.slug)
|
||||
// }
|
||||
//
|
||||
// this.$notifier.showMessage({
|
||||
// content: 'Member updated',
|
||||
// color: 'success',
|
||||
// icon: 'icon-message',
|
||||
// })
|
||||
// })
|
||||
},
|
||||
|
||||
computed: {
|
||||
canEditSuperAdminsAdminsAndDelegated() {
|
||||
return (
|
||||
(this.isNew || this.isEditMode) &&
|
||||
this.$store.getters['members/isSuperAdminAdminOrDelegated']
|
||||
)
|
||||
},
|
||||
canEditSuperAdminsAndAdmins() {
|
||||
return (
|
||||
(this.isNew || this.isEditMode) &&
|
||||
(this.$store.getters.isSuperAdmin || this.$store.getters.isAdmin)
|
||||
)
|
||||
},
|
||||
canSave() {
|
||||
if (this.isNew && this.isMemberValidated) return true
|
||||
// if (this.isNew) return true
|
||||
return (
|
||||
this.isSlugNumber &&
|
||||
this.isDownloaded &&
|
||||
this.$store.getters['members/hasChanges'] &&
|
||||
this.isMemberValidated
|
||||
)
|
||||
},
|
||||
isMemberValidated() {
|
||||
return this.$store.getters['members/isMemberValidated']
|
||||
},
|
||||
slug() {
|
||||
return this.$route.params.member
|
||||
},
|
||||
isNew() {
|
||||
return this.slug.toLowerCase() === 'new'
|
||||
},
|
||||
isEditMode() {
|
||||
return this.$route.query.edit === null
|
||||
},
|
||||
remote() {
|
||||
return this.$store.state.members.remote
|
||||
},
|
||||
local() {
|
||||
return this.$store.state.members.local
|
||||
},
|
||||
title() {
|
||||
if (this.isNew) return `<h2 class="ma-4">Nieuw</h2>`
|
||||
return `${this.local.informal_name || ''} <h2 class="ma-4">${
|
||||
this.local.formal_name || ''
|
||||
}`
|
||||
},
|
||||
isSlugNumber() {
|
||||
return !isNaN(this.slug.split(['-'], 1))
|
||||
},
|
||||
isValidSlug() {
|
||||
return this.isNew || this.isSlugNumber
|
||||
},
|
||||
isDownloaded() {
|
||||
return Object.keys(this.remote).length > 0
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
return dayjs(date).format('D MMM YYYY hh:mm').toLowerCase()
|
||||
},
|
||||
|
||||
close() {
|
||||
this.dialog = false
|
||||
},
|
||||
isTabSelected(tab) {
|
||||
return this.selectedTab === tab || this.selectedTab === 'all'
|
||||
},
|
||||
|
||||
async save(revision = false) {
|
||||
this.$nextTick(() => this.$nuxt.$loading.start())
|
||||
|
||||
try {
|
||||
const response = await this.$store.dispatch('members/store', revision)
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$router.push(this.localePath('/manager/members'))
|
||||
$nuxt.$notifier.showMessage({
|
||||
content: `Member stored`,
|
||||
color: 'success',
|
||||
icon: 'mdi-check',
|
||||
})
|
||||
} catch (error) {
|
||||
this.$nuxt.$loading.finish()
|
||||
console.log('save -> error', error)
|
||||
this.$notifier.showMessage({
|
||||
content: `${
|
||||
this.slug.toLowerCase() === 'new' ? 'Creating' : 'Editing'
|
||||
} page: ${error.response ? error.response.data.message : error}.`,
|
||||
...(error.response && {
|
||||
errors: error.response.data.errors,
|
||||
}),
|
||||
color: 'error',
|
||||
icon: 'mdi-alert',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
switchToEdit() {
|
||||
this.$router.push(this.localePath(`${$nuxt.$route.path}?edit`))
|
||||
},
|
||||
|
||||
async storeRevision() {
|
||||
try {
|
||||
await this.$store.dispatch('members/storeRevision')
|
||||
this.$nuxt.$loading.finish()
|
||||
this.$router.push(this.localePath('/manager/members'))
|
||||
$nuxt.$notifier.showMessage({
|
||||
content: `Revision stored`,
|
||||
color: 'success',
|
||||
icon: 'mdi-check',
|
||||
})
|
||||
} catch (error) {
|
||||
this.$nuxt.$loading.finish()
|
||||
console.log('storeRevision -> error', error)
|
||||
this.$notifier.showMessage({
|
||||
content: `${error.response ? error.response.data.message : error}.`,
|
||||
...(error.response && {
|
||||
errors: error.response.data.errors,
|
||||
}),
|
||||
color: 'error',
|
||||
icon: 'mdi-alert',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async deleteMember() {
|
||||
this.dialog = false
|
||||
await this.$store.dispatch('members/deleteMember')
|
||||
this.$router.push(this.localePath('/manager/members'))
|
||||
},
|
||||
},
|
||||
|
||||
async beforeRouteLeave(to, from, next) {
|
||||
await this.$store.dispatch('members/resetMember')
|
||||
next()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card >>> .v-btn__content,
|
||||
.v-select .v-select__selection--comma,
|
||||
.v-chip__content,
|
||||
.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled),
|
||||
.v-select.v-select--chips:not(.v-text-field--single-line).v-text-field--enclosed
|
||||
.v-select__selections,
|
||||
.v-list-item .v-list-item__title,
|
||||
.v-list-item .v-list-item__subtitle,
|
||||
.v-list-item span,
|
||||
.v-input--is-disabled input,
|
||||
.v-input--is-disable,
|
||||
.dot,
|
||||
h2,
|
||||
p {
|
||||
/* color: var(--v-txt-base); */
|
||||
}
|
||||
.v-card >>> .v-chip--disabled {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
.v-card >>> .v-chip {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
.dot {
|
||||
cursor: pointer;
|
||||
}
|
||||
.dot::before {
|
||||
content: '\A';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
background: #e54e0f;
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 30px;
|
||||
left: 50%;
|
||||
opacity: 0;
|
||||
}
|
||||
.dot:hover::before {
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
.dot.activeTab::before {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user