import { createStore } from 'vuex' import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api' import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle, getRelationshipDirection, splitId } from './vis-network' const debug = process.env.NODE_ENV !== 'production' const store = createStore({ strict: debug, state: { persons: [], households: [], courses: [], relationships: [], links: [], personLoadedIds: [], householdLoadingIds: [], courseLoadedIds: [], relationshipLoadedIds: [], excludedNodesIds: [] }, getters: { nodes(state) { let nodes = [] state.persons.forEach(p => { nodes.push(p) }) state.households.forEach(h => { nodes.push(h) }) state.courses.forEach(c => { nodes.push(c) }) // except excluded nodes (unchecked layers) state.excludedNodesIds.forEach(excluded => { nodes = nodes.filter(n => n.id !== excluded) }) return nodes }, edges(state) { let edges = [] state.links.forEach(l => { edges.push(l) }) return edges }, isHouseholdLoading: (state) => (household_id) => { return state.householdLoadingIds.includes(household_id) }, isCourseLoaded: (state) => (course_id) => { return state.courseLoadedIds.includes(course_id) }, isRelationshipLoaded: (state) => (relationship_id) => { return state.relationshipLoadedIds.includes(relationship_id) }, isPersonLoaded: (state) => (person_id) => { return state.personLoadedIds.includes(person_id) } }, mutations: { addPerson(state, person) { console.log('+ addPerson', person.id) state.persons.push(person) }, addHousehold(state, household) { console.log('+ addHousehold', household.id) state.households.push(household) }, addCourse(state, course) { console.log('+ addCourse', course.id) state.courses.push(course) }, addRelationship(state, relationship) { console.log('+ addRelationship', relationship.id) state.relationships.push(relationship) }, addLink(state, link) { console.log('+ addLink from', link.from, 'to', link.to) state.links.push(link) }, //// id markers markPersonLoaded(state, id) { state.personLoadedIds.push(id) }, unmarkPersonLoaded(state, id) { state.personLoadedIds = state.personLoadedIds.filter(i => i !== id) }, markHouseholdLoading(state, id) { console.log('..loading household', id) state.householdLoadingIds.push(id) }, unmarkHouseholdLoading(state, id) { state.householdLoadingIds = state.householdLoadingIds.filter(i => i !== id) }, markCourseLoaded(state, id) { state.courseLoadedIds.push(id) }, unmarkCourseLoaded(state, id) { state.courseLoadedIds = state.courseLoadedIds.filter(i => i !== id) }, markRelationshipLoaded(state, id) { state.relationshipLoadedIds.push(id) }, unmarkRelationshipLoaded(state, id) { state.relationshipLoadedIds = state.relationshipLoadedIds.filter(i => i !== id) }, //// excluded addExcludedNode(state, id) { state.excludedNodesIds.push(id) }, removeExcludedNode(state, id) { state.excludedNodesIds = state.excludedNodesIds.filter(e => e !== id) } }, actions: { /** * 1) Add a person in state * @param object * @param person */ addPerson({ commit, dispatch }, person) { commit('markPersonLoaded', person.id) commit('addPerson', adapt2vis(person, { folded: false })) dispatch('fetchInfoForPerson', person) }, /** * 2) Fetch infos for this person (hub) * @param object * @param person */ fetchInfoForPerson({ dispatch }, person) { if (null !== person.current_household_id) { dispatch('fetchHouseholdForPerson', person) } dispatch('fetchCoursesByPerson', person) dispatch('fetchRelationshipByPerson', person) }, /** * 3) Fetch person current household (if it is not already loading) * check first isHouseholdLoading to fetch household once * @param object * @param person */ fetchHouseholdForPerson({ commit, getters, dispatch }, person) { console.log(' isHouseholdLoading ?', getters.isHouseholdLoading(person.current_household_id)) if (! getters.isHouseholdLoading(person.current_household_id)) { commit('markHouseholdLoading', person.current_household_id) getHouseholdByPerson(person) .then(household => new Promise(resolve => { //console.log('getHouseholdByPerson', household) commit('addHousehold', adapt2vis(household)) //commit('addExcludedNode', household.id) dispatch('addLinkFromPersonsToHousehold', household) resolve() }) ).catch( () => { commit('unmarkHouseholdLoading', person.current_household_id) }) } }, /** * 4) Add an edge for each household member (household -> person) * @param object * @param household */ addLinkFromPersonsToHousehold({ commit, getters, dispatch }, household) { const currentMembers = household.members.filter(v => household.current_members_id.includes(v.id)) currentMembers.forEach(m => { //console.log('-> addLink from person', m.person.id, 'to household', m.person.current_household_id) commit('addLink', { from: `${m.person.type}_${m.person.id}`, to: `household_${m.person.current_household_id}`, id: `p${m.person.id}-h${m.person.current_household_id}`, arrows: 'from', color: 'pink', font: { color: '#D04A60' }, label: getHouseholdLabel(m), width: getHouseholdWidth(m), }) if (!getters.isPersonLoaded(m.person.id)) { console.log(' person is not loaded', m.person.id) dispatch('addMissingPerson', m.person) } }) }, /** * 5) Fetch AccompanyingCourses for the person * @param object * @param person */ fetchCoursesByPerson({ commit, dispatch }, person) { //console.log('fetchCoursesByPerson', person) getCoursesByPerson(person) .then(courses => new Promise(resolve => { console.log('fetch courses', courses.length) dispatch('addCourses', courses) resolve() })) }, /** * 6) Add each distinct course * @param object * @param courses */ addCourses({ commit, getters, dispatch }, courses) { //console.log('addCourse', courses) let currentCourses = courses.filter(c => c.closingDate === null) currentCourses.forEach(course => { console.log(' isCourseLoaded ?', getters.isCourseLoaded(course.id)) if (! getters.isCourseLoaded(course.id)) { //console.log('course', course.id) commit('markCourseLoaded', course.id) commit('addCourse', adapt2vis(course)) commit('addExcludedNode', course.id) dispatch('addLinkFromPersonsToCourse', course) } }) }, /** * 7) Add an edge for each course participation (course <- person) * @param object * @param course */ addLinkFromPersonsToCourse({ commit, getters, dispatch }, course) { let currentParticipations = course.participations.filter(p => p.endDate === null) console.log(' participations', currentParticipations.length) currentParticipations.forEach(p => { commit('addLink', { from: `${p.person.type}_${p.person.id}`, to: `${course.id}`, id: `p${p.person.id}-c`+ splitId(course.id,'id'), arrows: 'from', color: 'orange', font: { color: 'darkorange' }, }) if (!getters.isPersonLoaded(p.person.id)) { console.log(' person is not loaded', p.person.id) dispatch('addMissingPerson', p.person) } }) }, /** * 8) Fetch Relationship * @param object * @param person */ fetchRelationshipByPerson({ dispatch }, person) { //console.log('fetchRelationshipByPerson', person) getRelationshipsByPerson(person) .then(relationships => new Promise(resolve => { console.log('fetch relationships', relationships.length) dispatch('addRelationships', relationships) resolve() })) }, /** * 9) Add each distinct relationship * @param object * @param relationships */ addRelationships({ commit, getters, dispatch }, relationships) { relationships.forEach(relationship => { console.log(' isRelationshipLoaded ?', getters.isRelationshipLoaded(relationship.id)) if (! getters.isRelationshipLoaded(relationship.id)) { //console.log('relationship', relationship.id) commit('markRelationshipLoaded', relationship.id) commit('addRelationship', adapt2vis(relationship)) dispatch('addLinkFromRelationship', relationship) } }) }, /** * 10) Add an edge for each relationship (person -> person) * @param object * @param r (relationship) */ addLinkFromRelationship({ commit, getters, dispatch }, r) { //console.log('-> addLink from person', r.fromPerson.id, 'to person', r.toPerson.id) commit('addLink', { from: `person_${r.fromPerson.id}`, to: `person_${r.toPerson.id}`, id: 'r' + splitId(r.id,'id') + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, arrows: getRelationshipDirection(r), color: 'lightblue', font: { color: '#33839d' }, dashes: true, //physics: false, label: getRelationshipLabel(r), title: getRelationshipTitle(r), }) for (let person of [r.fromPerson, r.toPerson]) { if (!getters.isPersonLoaded(person.id)) { console.log(' person is not loaded', person.id) dispatch('addMissingPerson', person) } } }, /** * Fetch missing person * @param object * @param person */ addMissingPerson({ commit, getters, dispatch }, person) { commit('markPersonLoaded', person.id) commit('addPerson', adapt2vis(person, { folded: true })) console.log(' fetch infos for missing', person.id) //dispatch('fetchInfoForPerson', person) }, } }) export { store }