Some checks failed
continuous-integration/drone/push Build is failing
- 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
329 lines
9.0 KiB
Vue
329 lines
9.0 KiB
Vue
<template>
|
|
<div>
|
|
<div class="pa-lg-6">
|
|
<page-header class="d-flex justify-space-between">
|
|
<div class="subtitle-1">
|
|
<span
|
|
:class="{ 'display-1': selector === 'published' }"
|
|
:style="{ cursor: 'pointer' }"
|
|
@click="selector = 'published'"
|
|
class="mr-lg-4"
|
|
>
|
|
{{ $t('learning.products') }}
|
|
<small class="font-weight-light">({{ published.length }})</small>
|
|
</span>
|
|
|
|
<span
|
|
:class="{ 'display-1': selector === 'drafts' }"
|
|
:style="{ cursor: 'pointer' }"
|
|
@click="selector = 'drafts'"
|
|
class="mx-lg-4"
|
|
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
|
>
|
|
{{ $t('learning.drafts') }}
|
|
<small class="font-weight-light">({{ drafts.length }})</small>
|
|
</span>
|
|
<span
|
|
:class="{ 'display-1': selector === 'deleted' }"
|
|
:style="{ cursor: 'pointer' }"
|
|
@click="selector = 'deleted'"
|
|
class="mx-lg-4"
|
|
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
|
>
|
|
{{ $t('general.deleted') }}
|
|
<small class="font-weight-light">({{ deleted.length }})</small>
|
|
</span>
|
|
</div>
|
|
|
|
<div>
|
|
<settings />
|
|
|
|
<v-btn
|
|
color="accent"
|
|
depressed
|
|
rounded
|
|
to="/manager/learning/new"
|
|
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
|
>
|
|
<v-icon left x-small>icon-add</v-icon>
|
|
<small>{{ $t('general.add') }}</small>
|
|
</v-btn>
|
|
</div>
|
|
</page-header>
|
|
|
|
<div class="d-flex justify-space-between">
|
|
<filters />
|
|
<filters-selected />
|
|
</div>
|
|
</div>
|
|
|
|
<courses-table
|
|
:deleted="deleted"
|
|
:drafts="drafts"
|
|
:published="published"
|
|
:selector="selector"
|
|
@reload-learning-products="getProducts()"
|
|
/>
|
|
|
|
<v-footer
|
|
fixed
|
|
style="z-index: 4"
|
|
height="90"
|
|
color="primary"
|
|
v-if="$store.getters.isAdmin || $store.getters.isOperator"
|
|
>
|
|
<v-btn text nuxt :to="localePath('/manager/learning')">
|
|
<v-icon>icon-arrow-left</v-icon>
|
|
</v-btn>
|
|
<div class="mx-10">
|
|
<v-btn
|
|
color="accent"
|
|
depressed
|
|
rounded
|
|
to="/manager/learning/new"
|
|
class="ml-10"
|
|
>
|
|
<v-icon left size="8">icon-add</v-icon>
|
|
<small>{{ $t('general.add') }}</small>
|
|
</v-btn>
|
|
</div>
|
|
|
|
<v-spacer />
|
|
|
|
<!-- <v-btn
|
|
class="ma-2"
|
|
tile
|
|
text
|
|
small
|
|
color="success"
|
|
nuxt
|
|
target="_blank"
|
|
:to="`${this.localePath(
|
|
'/manager/learning'
|
|
)}?filters=${sharedUrlSuffix}`"
|
|
id="url_to_share"
|
|
v-show="showCopiedButton"
|
|
>
|
|
<v-icon class="mx-2" small>icon-selectionbox-checked</v-icon>
|
|
URL gekopieerd
|
|
</v-btn>
|
|
|
|
<v-tooltip top v-if="!showCopiedButton">
|
|
<template v-slot:activator="{ on, attrs }">
|
|
<v-btn
|
|
class="ma-2"
|
|
tile
|
|
text
|
|
small
|
|
@click="copyUrl"
|
|
v-bind="attrs"
|
|
v-on="on"
|
|
>
|
|
<v-icon class="mx-2" small>icon-share</v-icon>
|
|
Delen Lijst
|
|
</v-btn>
|
|
</template>
|
|
<span> {{ $t('general.tooltip_share') }}</span>
|
|
</v-tooltip> -->
|
|
|
|
<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>
|
|
<settings class="ml-10" />
|
|
</v-footer>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Util from '@/util'
|
|
import PageHeader from '~/components/UI/PageHeader/PageHeader'
|
|
import Settings from '~/components/Learning/Settings'
|
|
import Filters from '~/components/Learning/Filters'
|
|
import FiltersSelected from '~/components/Learning/FiltersSelected'
|
|
import CoursesTable from '~/components/Learning/CoursesTable'
|
|
|
|
export default {
|
|
layout: `${process.env.CUSTOMER}Admin`,
|
|
middleware: ['denyToOnlyMembers'],
|
|
components: {
|
|
PageHeader,
|
|
Settings,
|
|
Filters,
|
|
CoursesTable,
|
|
FiltersSelected,
|
|
},
|
|
data() {
|
|
return {
|
|
selector: 'published',
|
|
showCopiedButton: false,
|
|
}
|
|
},
|
|
computed: {
|
|
learningProducts() {
|
|
return this.$store.getters.learningProducts
|
|
},
|
|
hasProducts() {
|
|
return this.$store.getters.hasLearningProducts
|
|
},
|
|
|
|
published() {
|
|
return this.learningProductsFiltered.filter(
|
|
(product) => product.published && !product.deleted_at
|
|
)
|
|
},
|
|
drafts() {
|
|
return this.learningProductsFiltered.filter(
|
|
(product) => !product.deleted_at && !product.published
|
|
)
|
|
},
|
|
deleted() {
|
|
return this.learningProductsFiltered.filter(
|
|
(product) => product.deleted_at
|
|
)
|
|
},
|
|
filtersSelected() {
|
|
return this.$store.getters.filtersSelected
|
|
},
|
|
learningProductsFiltered() {
|
|
if (!this.filtersSelected.length > 0) return this.learningProducts
|
|
|
|
return this.learningProducts.filter((product) => {
|
|
return Util.findItemsWithExactValuesInArray(
|
|
this.filtersSelected,
|
|
product.filterItemsSelected
|
|
)
|
|
})
|
|
},
|
|
|
|
// sharedUrlSuffix() {
|
|
// let filtersSelectedIdsStringyfied = ''
|
|
// this.filtersSelected.map(
|
|
// (id) => (filtersSelectedIdsStringyfied += `${id},`)
|
|
// )
|
|
// return filtersSelectedIdsStringyfied
|
|
// },
|
|
// sharedUrlParsed() {
|
|
// // if is a shared Url
|
|
// if (!this.$route.query.filters) return null
|
|
|
|
// // parse content, convert every element to number
|
|
// let filterItemIds = this.$route.query.filters.split(',').map(Number)
|
|
|
|
// // validate it and return
|
|
// return filterItemIds.filter(
|
|
// (el) => !isNaN(el) && this.$store.getters.filtersItemsMap.has(el)
|
|
// )
|
|
// },
|
|
},
|
|
|
|
async asyncData({ $axios, store }) {
|
|
try {
|
|
if (!store.getters.hasLearningProducts) {
|
|
await store.dispatch('learning/pullProducts')
|
|
}
|
|
|
|
const response = await $axios.get('/filters')
|
|
const filters = response.data
|
|
await store.commit('learning/SORT_FILTERS', filters)
|
|
} catch (error) {
|
|
console.log('Data -> error', error)
|
|
}
|
|
},
|
|
|
|
async mounted() {
|
|
if (this.sharedUrlParsed) {
|
|
this.$store.commit('learning/SELECT_FILTERS', this.sharedUrlParsed)
|
|
}
|
|
|
|
// If filters sorting preferences saved in localstorage
|
|
if (localStorage.getItem('learning_products_filters')) {
|
|
// Get them
|
|
const filtersOrder = JSON.parse(
|
|
localStorage.getItem('learning_products_filters')
|
|
)
|
|
|
|
// Get filters from store
|
|
const filters = [...this.$store.state.learning.filters]
|
|
|
|
// Sort by preferences
|
|
const filtersSorted = filters.sort(
|
|
(a, b) => filtersOrder.indexOf(a.id) - filtersOrder.indexOf(b.id)
|
|
)
|
|
|
|
// send to store, sorted
|
|
await this.$store.commit('learning/SORT_FILTERS', filtersSorted)
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
async getProducts() {
|
|
try {
|
|
const response = await this.$axios.get('/learning-products')
|
|
await this.$store.commit('learning/STORE_PRODUCTS', response.data)
|
|
} catch (error) {
|
|
console.log('getProducts -> error', error)
|
|
}
|
|
},
|
|
async copyUrl() {
|
|
if (this.showCopiedButton) return
|
|
|
|
// Create <a> link with v-show false and Copy from there to have the full path?
|
|
const url = document.getElementById('url_to_share').href
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(url)
|
|
|
|
this.showCopiedButton = true
|
|
setTimeout(() => (this.showCopiedButton = false), 5000)
|
|
} catch (error) {
|
|
console.log('copyUrl -> error', error)
|
|
}
|
|
},
|
|
|
|
exportCsv() {
|
|
const data = [...this.learningProductsFiltered]
|
|
|
|
const headersNeeded = [
|
|
'title',
|
|
'code',
|
|
'partner',
|
|
'owner',
|
|
'status',
|
|
'lead_time',
|
|
'product_type',
|
|
'theme',
|
|
'course',
|
|
]
|
|
|
|
const dataFiltered = this.$store.getters[
|
|
'utils/filterArrayObjsByArrayOfProperties'
|
|
](data, headersNeeded)
|
|
|
|
let dataCsv =
|
|
this.$store.getters['utils/arrayOfObjectToCsv'](dataFiltered)
|
|
|
|
// Translate every entry in 'headersNeeded'
|
|
let headersTranslated =
|
|
headersNeeded.map((h) => this.$t(`csv.learning.${h}`)).join(',') + '\n'
|
|
|
|
// Remove 1st row (string)
|
|
dataCsv = dataCsv.split('\n').slice(1).join('\n')
|
|
|
|
// Add as 1st row the one translated
|
|
dataCsv = headersTranslated + dataCsv
|
|
|
|
// Simulate click to download file
|
|
const universalBOM = '\uFEFF'
|
|
const blob = new Blob([universalBOM + dataCsv], { type: 'text/csv' })
|
|
const link = document.createElement('a')
|
|
link.href = URL.createObjectURL(blob)
|
|
link.setAttribute('hidden', '')
|
|
link.setAttribute('download', 'producten.csv')
|
|
link.click()
|
|
URL.revokeObjectURL(link.href)
|
|
},
|
|
},
|
|
}
|
|
</script>
|