- 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:
236
pages/manager/members/index.vue
Normal file
236
pages/manager/members/index.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="pa-6">
|
||||
<page-header class="d-flex justify-space-between">
|
||||
<div class="subtitle-1">
|
||||
<span
|
||||
:class="{ 'display-1': selector === 'allMembers' }"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
@click="selector = 'allMembers'"
|
||||
class="mr-4"
|
||||
>
|
||||
Leden
|
||||
<small class="font-weight-light">({{ allMembers.length }})</small>
|
||||
</span>
|
||||
|
||||
<span
|
||||
:class="{ 'display-1': selector === 'active' }"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
@click="selector = 'active'"
|
||||
class="mx-4"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
Actieve leden
|
||||
<small class="font-weight-light">({{ active.length }})</small>
|
||||
</span>
|
||||
|
||||
<span
|
||||
:class="{ 'display-1': selector === 'inactive' }"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
@click="selector = 'inactive'"
|
||||
class="mx-4"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
Inactieve leden
|
||||
<small class="font-weight-light">({{ inactive.length }})</small>
|
||||
</span>
|
||||
|
||||
<span
|
||||
:class="{ 'display-1': selector === 'deleted' }"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
@click="selector = 'deleted'"
|
||||
class="mx-4"
|
||||
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
||||
>
|
||||
Verwijderd
|
||||
<small class="font-weight-light">({{ deleted.length }})</small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- here checks -->
|
||||
</div>
|
||||
</page-header>
|
||||
</div>
|
||||
|
||||
<members-table :members="membersComputed" />
|
||||
|
||||
<v-footer
|
||||
fixed
|
||||
style="z-index: 4"
|
||||
height="90"
|
||||
color="primary"
|
||||
v-if="$store.getters.isSuperAdminOrAdmin"
|
||||
>
|
||||
<v-btn text nuxt :to="localePath('/manager')">
|
||||
<v-icon>icon-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<div class="mx-10">
|
||||
<v-btn
|
||||
color="accent"
|
||||
depressed
|
||||
rounded
|
||||
to="/manager/members/new"
|
||||
class="ml-10"
|
||||
>
|
||||
<v-icon left size="8">icon-add</v-icon>
|
||||
<small>Lid toevoegen</small>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-spacer />
|
||||
<v-btn class="ma-2" tile text small @click="exportCsv">
|
||||
<v-icon class="mx-2" x-small>icon-export</v-icon>
|
||||
{{ $t('general.export_csv') | capitalize }}
|
||||
</v-btn>
|
||||
</v-footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import csv from 'csv'
|
||||
import {DateTime} from 'luxon'
|
||||
import dayjs from 'dayjs'
|
||||
import download from 'downloadjs'
|
||||
import MembersTable from '~/components/Members/MembersTable'
|
||||
import PageHeader from '~/components/UI/PageHeader/PageHeader'
|
||||
|
||||
const I18N_CSV_WRAPPER_KEY = 'csv.members'
|
||||
const I18N_CSV_HEADER_KEYS = [
|
||||
'id',
|
||||
'type',
|
||||
'informal_name',
|
||||
'formal_name',
|
||||
'start_membership',
|
||||
'main_branch',
|
||||
'sub_branches',
|
||||
]
|
||||
const CSV_VALUE_NONE = '-'
|
||||
|
||||
export default {
|
||||
layout: `${process.env.CUSTOMER}Admin`,
|
||||
// middleware: 'adminsOrOperatorsOrMemberEditors',
|
||||
|
||||
components: {
|
||||
PageHeader,
|
||||
MembersTable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selector: 'allMembers',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
exportCsv() {
|
||||
let inputData = [
|
||||
I18N_CSV_HEADER_KEYS.map((key) => {
|
||||
return this.$t(`${I18N_CSV_WRAPPER_KEY}.${key}`)
|
||||
}),
|
||||
]
|
||||
|
||||
this.allMembers.forEach((member) => {
|
||||
let subBranchTitles = member.sub_branches.map(branch => branch.title)
|
||||
subBranchTitles.sort()
|
||||
|
||||
inputData.push([
|
||||
member.id,
|
||||
member.type ?? CSV_VALUE_NONE,
|
||||
member.informal_name ?? CSV_VALUE_NONE,
|
||||
member.formal_name ?? CSV_VALUE_NONE,
|
||||
this.formatCsvDate(
|
||||
member.start_membership,
|
||||
'yyyy-LL-dd HH:mm:ss',
|
||||
) ?? CSV_VALUE_NONE,
|
||||
member.main_branch ?? CSV_VALUE_NONE,
|
||||
subBranchTitles.length
|
||||
? subBranchTitles.join(', ')
|
||||
: CSV_VALUE_NONE,
|
||||
])
|
||||
})
|
||||
|
||||
inputData.sort((rowLeft, rowRight) => rowRight.id - rowLeft.id);
|
||||
|
||||
csv.stringify(inputData, { quoted: true }, (err, output) => {
|
||||
if (err) {
|
||||
// TODO: handle
|
||||
} else {
|
||||
download(
|
||||
output,
|
||||
this.$t(`${I18N_CSV_WRAPPER_KEY}.filename`),
|
||||
'text/csv'
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
formatCsvDate: (input, inputFormat) => {
|
||||
if (input) {
|
||||
return DateTime.fromFormat(input, inputFormat).toFormat('yyyy-LL-dd')
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
allMembers() {
|
||||
return this.$store.getters['members/membersFiltered']
|
||||
},
|
||||
published() {
|
||||
return this.allMembers.filter((member) => !member.deleted_at)
|
||||
},
|
||||
active() {
|
||||
return this.published.filter(
|
||||
(member) =>
|
||||
!member.end_membership || dayjs().isBefore(member.end_membership)
|
||||
)
|
||||
},
|
||||
inactive() {
|
||||
return this.published.filter(
|
||||
(member) =>
|
||||
member.end_membership && !dayjs().isBefore(member.end_membership)
|
||||
)
|
||||
},
|
||||
deleted() {
|
||||
return this.allMembers.filter((member) => member.deleted_at)
|
||||
},
|
||||
membersComputed() {
|
||||
if (
|
||||
!['allMembers', 'active', 'inactive', 'deleted'].includes(this.selector)
|
||||
) {
|
||||
return []
|
||||
}
|
||||
return this[this.selector]
|
||||
},
|
||||
},
|
||||
|
||||
async asyncData({ $axios, store }) {
|
||||
try {
|
||||
await store.dispatch('members/pullBranches')
|
||||
|
||||
if (!store.getters['members/hasMembers']) {
|
||||
await store.dispatch('members/pullData')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Data -> error', error)
|
||||
}
|
||||
},
|
||||
|
||||
// #warning Laravel Echo has been manually disabled until broadcasting issue is fixed.
|
||||
// async mounted() {
|
||||
// this.$echo.channel('updates').listen(`.members-updated`, async (e) => {
|
||||
// await this.$store.dispatch('members/pullData')
|
||||
//
|
||||
// this.$notifier.showMessage({
|
||||
// content: 'Members updated',
|
||||
// color: 'success',
|
||||
// icon: 'icon-message',
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
async beforeRouteLeave(to, from, next) {
|
||||
await this.$store.commit('members/RESET_MEMBERS')
|
||||
next()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user