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

176
store/index.js Normal file
View File

@@ -0,0 +1,176 @@
import Util from '@/util'
export const getters = {
loggedInUser: (state) => state.auth.user,
learningProducts: (state) => state.learning.products,
learningProductsActive: (state, getters) => {
getters.learningProducts.filter((p) => !p.deleted_at)
},
hasLearningProducts: (state, getters) => getters.learningProducts.length > 0,
searchOverlay: (state) => state.navigation.searchOverlay,
snackbar: (state) => state.snackbar,
rightDrawer: (state) => state.navigation.rightDrawer,
isSuperAdmin: (state) =>
state.auth.user.roles.some((r) => r.name === 'super_admin'),
isAdmin: (state) => state.auth.user.roles.some((r) => r.name === 'admin'),
isSuperAdminOrAdmin: (state, getters) =>
getters.isSuperAdmin || getters.isAdmin,
isOperator: (state) =>
state.auth.user.roles.some((r) => r.name === 'operator'),
isUser: (state) => state.auth.user.roles.some((r) => r.name === 'user'),
isMember: (state) => state.auth.user.isMemberEditor || false,
hasCharges: (state, getters) =>
getters.isSuperAdmin || getters.isAdmin || getters.isOperator,
isOnlyMemberEditor: (state, getters) =>
!getters.hasCharges && getters.isMember,
notifications: (state) => state.auth.user.notifications,
unreadNotifications: (state) =>
state.auth.user.notifications.filter((n) => !n.read_at),
readNotifications: (state) =>
state.auth.user.notifications.filter((n) => n.read_at),
hasNotifications: (state) => state.auth.user.notifications.length > 0,
hasUnreadNotifications: (state, getters) =>
getters.unreadNotifications.length > 0,
isReadNotification: (state, getters) => (notificationId) => {
if (!notificationId) return false
return getters.notifications.find((n) => n.id === notificationId)
},
columnsSortedSubset: (state, rootGetters) => {
const actionsColumn = [
{
text: '',
value: 'actions',
sortable: false,
fixed: true,
},
]
const columns = [
...state.learning.columnsSorted.filter((el) => el.fixed),
...rootGetters['columnBrowser/subset'],
...actionsColumn,
]
return columns
},
filters: (state) => state.learning.filters,
filtersSelected: (state) => state.learning.filtersSelected,
filtersSearchable: (state) => {
return state.learning.filters.filter(
(f) => !state.learning.filtersDisabledForSearch.includes(f.title)
)
},
// Map with filterId as key and full Filter object as value
filtersMap: (state, getters) => {
const map = new Map()
getters.filters.forEach((filter) => map.set(filter.id, filter))
return map
},
filtersItemsMap: (state, getters) => {
const map = new Map()
// Cycle all filters
getters.filters.forEach((filter) => {
// Cycle all filter items
filter.items.forEach((item) => {
map.set(item.id, item)
})
})
return map
},
getFilterByTitle: (state, getters) => (title) => {
if (!getters.filters.length > 0) return []
return getters.filters.find((filter) => filter.title === title)
},
getFilterById: (state, getters) => (filterId) => {
const emptyFilter = {
id: '*',
title: '*',
items: [],
}
if (!filterId) {
return emptyFilter
}
if (!getters.filtersMap.has(filterId)) {
return emptyFilter
}
return getters.filtersMap.get(filterId)
},
getFilterItemById: (state, getters) => (filterItemId) => {
const emptyFilterItem = {
id: '*',
filter_id: '*',
title: '*',
}
if (!filterItemId) {
return emptyFilterItem
}
if (!getters.filtersItemsMap.has(filterItemId)) {
return emptyFilterItem
}
return getters.filtersItemsMap.get(filterItemId)
},
filterItemsResolved:
(state, getters) =>
({ filterTitle = '', filters = [] }) => {
const filter = getters.getFilterByTitle(filterTitle)
return filters.filter((f) => f.filter_item.filter_id === filter.id)
},
synonyms: (state) => state.learning.synonyms || [],
attachedSynonymsIds: (state, getters) => {
return getters.remoteProduct.synonyms
? getters.remoteProduct.synonyms.map(({ id }) => id)
: []
},
synonymsHaveChanges: (state, getters) =>
!Util.arraysMatch(
getters.attachedSynonymsIds,
state.learning.synonymsSelected
),
remoteProduct: (state) => state.learning.remote,
localProduct: (state) => state.learning.local,
productHasChanges: (state, getters) => {
if (!Util.areEqualInputs(getters.remoteProduct, getters.localProduct))
return true
if (getters.synonymsHaveChanges) return true
if (state.learning.cover.url) return true
if (state.learning.tile.url) return true
return false
},
isFilterTypeEmpty: (state, getters) => {
const idType = getters.getFilterByTitle('type').id
if (!getters.localProduct.filtersGrouped) return true
if (!getters.localProduct.filtersGrouped[idType]) return true
if (getters.localProduct.filtersGrouped[idType].length > 0) return false
return true
},
isLearningProductValidated: (state, getters) => {
return (
!!getters.localProduct.title &&
!!getters.localProduct.code &&
!!getters.localProduct.seo_title
)
},
}