Initial Nuxt frontend import
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
This commit is contained in:
Joris Slagter
2025-12-02 17:48:48 +01:00
parent 0f691e83e3
commit 791aebc346
290 changed files with 113801 additions and 0 deletions

View 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>