refactor to use store for storing events

This commit is contained in:
Julien Fastré 2022-05-17 16:57:31 +02:00
parent 9ceb66e2da
commit f68c69d443
11 changed files with 373 additions and 147 deletions

View File

@ -1,16 +1,5 @@
<template> <template>
<concerned-groups></concerned-groups> <concerned-groups></concerned-groups>
<location></location>
<teleport to="#calendarControls">
<calendar-user-selector
v-bind:users="users"
v-bind:calendarEvents="calendarEvents"
v-bind:updateEventsSource="updateEventsSource"
v-bind:showMyCalendar="showMyCalendar"
v-bind:toggleMyCalendar="toggleMyCalendar"
v-bind:toggleWeekends="toggleWeekends" >
</calendar-user-selector>
</teleport>
<teleport to="#fullCalendar"> <teleport to="#fullCalendar">
<FullCalendar ref="fullCalendar" :options="calendarOptions"> <FullCalendar ref="fullCalendar" :options="calendarOptions">
<template v-slot:eventContent='arg'> <template v-slot:eventContent='arg'>
@ -19,9 +8,11 @@
</template> </template>
</FullCalendar> </FullCalendar>
</teleport> </teleport>
<location></location>
</template> </template>
<script> <script>
//import {mapGetters} from 'vuex';
import ConcernedGroups from 'ChillActivityAssets/vuejs/Activity/components/ConcernedGroups.vue'; import ConcernedGroups from 'ChillActivityAssets/vuejs/Activity/components/ConcernedGroups.vue';
import Location from 'ChillActivityAssets/vuejs/Activity/components/Location.vue'; import Location from 'ChillActivityAssets/vuejs/Activity/components/Location.vue';
import CalendarUserSelector from '../_components/CalendarUserSelector/CalendarUserSelector.vue'; import CalendarUserSelector from '../_components/CalendarUserSelector/CalendarUserSelector.vue';
@ -44,6 +35,7 @@ export default {
data() { data() {
return { return {
errorMsg: [], errorMsg: [],
/*
users: { users: {
loaded: [], loaded: [],
selected: [], selected: [],
@ -62,23 +54,31 @@ export default {
id: window.mainUser, id: window.mainUser,
color: '#bbbbbb' color: '#bbbbbb'
} }
}, },*/
selectedEvent: null, selectedEvent: null,
previousSelectedEvent: null, previousSelectedEvent: null,
previousSelectedEventColor: null, previousSelectedEventColor: null,
showMyCalendar: false, showMyCalendar: false,
calendarOptions: { }
},
computed: {
events() {
return this.$store.getters.getEventSources;
},
calendarOptions() {
return {
locale: frLocale, locale: frLocale,
plugins: [ dayGridPlugin, interactionPlugin, timeGridPlugin ], plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
initialView: 'timeGridWeek', initialView: 'timeGridWeek',
initialDate: window.startDate !== undefined ? window.startDate : new Date(), initialDate: this.$store.getters.initialDate,
eventSource: [], eventSources: this.events,
selectable: true, selectable: true,
datesSet: this.onDatesSet,
select: this.onDateSelect, select: this.onDateSelect,
eventChange: this.onEventChange, eventChange: this.onEventChange,
eventClick: this.onEventClick, eventClick: this.onEventClick,
// eventMouseEnter: this.onEventMouseEnter, // eventMouseEnter: this.onEventMouseEnter,
// eventMouseLeave: this.onEventMouseLeave, // eventMouseLeave: this.onEventMouseLeave,
selectMirror: true, selectMirror: true,
editable: true, editable: true,
weekends: false, weekends: false,
@ -86,37 +86,46 @@ export default {
left: 'prev,next today', left: 'prev,next today',
center: 'title', center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth,listWeek,listDay' right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth,listWeek,listDay'
}, }
} };
} },
}, },
methods: { methods: {
init() { init() {
this.updateEventsSource(); //this.updateEventsSource();
}, },
toggleMyCalendar(value) { toggleMyCalendar(value) {
this.showMyCalendar = value; this.showMyCalendar = value;
}, },
toggleWeekends: function() { toggleWeekends: function () {
this.calendarOptions.weekends = !this.calendarOptions.weekends; this.calendarOptions.weekends = !this.calendarOptions.weekends;
}, },
updateEventsSource() { updateEventsSource() {
this.calendarOptions.eventSources = []; /*
this.calendarOptions.eventSources.push(...this.calendarEvents.selected); this.calendarOptions.eventSources = [];
if (window.startDate !== undefined) { this.calendarOptions.eventSources.push(...this.calendarEvents.selected);
this.calendarOptions.eventSources.push(this.calendarEvents.current); if (window.startDate !== undefined) {
} this.calendarOptions.eventSources.push(this.calendarEvents.current);
if (this.showMyCalendar) { }
this.calendarOptions.eventSources.push(this.calendarEvents.user); if (this.showMyCalendar) {
} this.calendarOptions.eventSources.push(this.calendarEvents.user);
}
console.log('eventSources', this.calendarOptions.eventSoruces);
*/
},
onDatesSet(event) {
console.log('onDatesSet', event);
this.$store.dispatch('setCurrentDatesView', {start: event.start, end: event.end});
}, },
unSelectPreviousEvent(event) { unSelectPreviousEvent(event) {
if (event) { if (event) {
if (typeof event.setProp === 'function') { if (typeof event.setProp === 'function') {
event.setProp('backgroundColor', this.previousSelectedEventColor); event.setProp('backgroundColor', this.previousSelectedEventColor);
event.setProp('borderColor', this.previousSelectedEventColor); event.setProp('borderColor', this.previousSelectedEventColor);
event.setProp('textColor','#444444'); event.setProp('textColor', '#444444');
event.setProp('title',''); event.setProp('title', '');
} }
} }
}, },
@ -136,20 +145,20 @@ export default {
this.previousSelectedEventColor = payload.event.extendedProps.sourceColor; this.previousSelectedEventColor = payload.event.extendedProps.sourceColor;
this.selectedEvent = payload.event; this.selectedEvent = payload.event;
this.unSelectPreviousEvent(this.previousSelectedEvent); this.unSelectPreviousEvent(this.previousSelectedEvent);
payload.event.setProp('backgroundColor','#3788d8'); payload.event.setProp('backgroundColor', '#3788d8');
payload.event.setProp('borderColor','#3788d8'); payload.event.setProp('borderColor', '#3788d8');
payload.event.setProp('title', 'Choisir cette plage'); payload.event.setProp('title', 'Choisir cette plage');
payload.event.setProp('textColor','#ffffff'); payload.event.setProp('textColor', '#ffffff');
}, },
onEventMouseEnter(payload) { onEventMouseEnter(payload) {
payload.event.setProp('borderColor','#444444'); payload.event.setProp('borderColor', '#444444');
}, },
onEventMouseLeave(payload) { onEventMouseLeave(payload) {
payload.event.setProp('borderColor','#ffffff'); payload.event.setProp('borderColor', '#ffffff');
} }
}, },
mounted() { mounted() {
this.init(); //this.init();
} }
} }
</script> </script>

View File

@ -0,0 +1,39 @@
import {fetchResults} from 'ChillMainAssets/lib/api/apiMethods';
import {datetimeToISO} from 'ChillMainAssets/chill/js/date';
const whoami = () => {
const url = `/api/1.0/main/whoami.json`;
return fetch(url)
.then(response => {
if (response.ok) {
return response.json();
}
throw {
msg: 'Error while getting whoami.',
sta: response.status,
txt: response.statusText,
err: new Error(),
body: response.body
};
});
};
/**
*
* @param user
* @param Date start
* @param Date end
* @return Promise
*/
const fetchCalendarRangeForUser = (user, start, end) => {
const uri = `/api/1.0/calendar/calendar-range-available/${user.id}.json`;
const dateFrom = datetimeToISO(start);
const dateTo = datetimeToISO(end);
return fetchResults(uri, {dateFrom, dateTo});
}
export {
whoami,
fetchCalendarRangeForUser,
};

View File

@ -0,0 +1,8 @@
const USER_CALENDAR_SHOW_RANGES = 'ranges';
const USER_CALENDAR_SHOW_EVENTS = 'events';
export {
USER_CALENDAR_SHOW_RANGES,
USER_CALENDAR_SHOW_EVENTS,
};

View File

@ -4,8 +4,38 @@ import {
removeIdFromValue, removeIdFromValue,
mapEntity mapEntity
} from './utils'; } from './utils';
import {fetchCalendarRangeForUser} from './../api';
export default { export default {
setCurrentDatesView({ commit, dispatch }, {start, end}) {
commit('setCurrentDatesView', {start, end});
return dispatch('fetchCalendarEvents');
},
fetchCalendarEvents({ state, getters, dispatch }) {
if (state.currentView.start === null && state.currentView.end === null) {
return Promise.resolve();
}
let promises = [];
if (null !== getters.getMainUser) {
promises.push(
dispatch('fetchCalendarRangeForUser',
{user: getters.getMainUser, start: state.currentView.start, end: state.currentView.end})
);
}
return Promise.all(promises);
},
fetchCalendarRangeForUser({ commit, getters }, { user, start, end }) {
if (!getters.isCalendarRangeLoadedForUser({user, start, end})) {
return fetchCalendarRangeForUser(user, start, end).then((ranges) => {
commit('addCalendarRangesForUser', {user, ranges, start, end});
return Promise.resolve();
});
}
},
addPersonsInvolved({ commit }, payload) { addPersonsInvolved({ commit }, payload) {
console.log('### action addPersonsInvolved', payload.result.type); console.log('### action addPersonsInvolved', payload.result.type);
switch (payload.result.type) { switch (payload.result.type) {

View File

@ -1,56 +1,122 @@
export default { import {USER_CALENDAR_SHOW_RANGES, USER_CALENDAR_SHOW_EVENTS} from './../const';
suggestedEntities(state, getters) { import {calendarRangeToFullCalendarEvent} from './utils';
if (typeof(state.activity.accompanyingPeriod) === 'undefined') {
return [];
}
const allEntities = [
getters.suggestedPersons,
getters.suggestedRequestor,
getters.suggestedUser,
getters.suggestedResources
];
const uniqueIds = [...new Set(allEntities.map(i => `${i.type}-${i.id}`))];
return Array.from(uniqueIds, id => allEntities.filter(r => `${r.type}-${r.id}` === id)[0]);
},
suggestedPersons(state) {
const existingPersonIds = state.activity.persons.map(p => p.id);
return state.activity.accompanyingPeriod.participations
.filter(p => p.endDate === null)
.map(p => p.person)
.filter(p => !existingPersonIds.includes(p.id))
},
suggestedRequestor(state) {
if (state.activity.accompanyingPeriod.requestor === null) {
return [];
}
const existingPersonIds = state.activity.persons.map(p => p.id); export default {
const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id); getMainUser(state) {
return [state.activity.accompanyingPeriod.requestor] return state.activity.mainUser || null;
.filter(r => },
(r.type === 'person' && !existingPersonIds.includes(r.id)) || getEventDate(state) {
(r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id)) if (null === state.activity.start) {
); return new Date();
},
suggestedUser(state) {
if (null === state.activity.users) {
return [];
}
const existingUserIds = state.activity.users.map(p => p.id);
return [state.activity.accompanyingPeriod.user]
.filter(
u => u !== null && !existingUserIds.includes(u.id)
);
},
suggestedResources(state) {
const resources = state.activity.accompanyingPeriod.resources;
const existingPersonIds = state.activity.persons.map(p => p.id);
const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id);
return state.activity.accompanyingPeriod.resources
.map(r => r.resource)
.filter(r =>
(r.type === 'person' && !existingPersonIds.includes(r.id)) ||
(r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id))
);
} }
throw 'transform date to object ?';
},
getEventSources(state) {
console.log('getEventSources');
let sources = [];
for (const [userId, kinds] of state.currentView.users.entries()) {
console.log('loop', userId, kinds);
if (!state.usersData.has(userId)) {
console.log('try to get events on a user which not exists', userId);
continue;
}
console.log('addingUser', userId);
const userData = state.usersData.get(userId);
console.log('userData', userData);
if (kinds.includes(USER_CALENDAR_SHOW_RANGES) && userData.calendarRanges.length > 0) {
console.log('adding ranges for user', userId);
const s = {
//'id': `ranges_${userId}`,
'events': userData.calendarRanges,
};
console.log('range source', s);
sources.push(s);
} else {
console.log('not adding ranges for user', userId);
}
}
console.log('eventSources', sources);
return sources;
},
getUserData: (state) => (user) => {
return state.usersData.get(user.id);
},
hasUserData: (state) => (user) => {
return state.usersData.has(user.id);
},
isCalendarRangeLoadedForUser: (state, getters) => ({user, start, end}) => {
if (!getters.hasUserData(user)) {
return false;
}
for (let interval of getters.getUserData(user).calendarRangesLoaded) {
if (start >= interval.start && end <= interval.end) {
return true;
}
}
return false;
},
suggestedEntities(state, getters) {
if (typeof (state.activity.accompanyingPeriod) === 'undefined') {
return [];
}
const allEntities = [
getters.suggestedPersons,
getters.suggestedRequestor,
getters.suggestedUser,
getters.suggestedResources
];
const uniqueIds = [...new Set(allEntities.map(i => `${i.type}-${i.id}`))];
return Array.from(uniqueIds, id => allEntities.filter(r => `${r.type}-${r.id}` === id)[0]);
},
suggestedPersons(state) {
const existingPersonIds = state.activity.persons.map(p => p.id);
return state.activity.accompanyingPeriod.participations
.filter(p => p.endDate === null)
.map(p => p.person)
.filter(p => !existingPersonIds.includes(p.id))
},
suggestedRequestor(state) {
if (state.activity.accompanyingPeriod.requestor === null) {
return [];
}
const existingPersonIds = state.activity.persons.map(p => p.id);
const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id);
return [state.activity.accompanyingPeriod.requestor]
.filter(r =>
(r.type === 'person' && !existingPersonIds.includes(r.id)) ||
(r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id))
);
},
suggestedUser(state) {
if (null === state.activity.users) {
return [];
}
const existingUserIds = state.activity.users.map(p => p.id);
return [state.activity.accompanyingPeriod.user]
.filter(
u => u !== null && !existingUserIds.includes(u.id)
);
},
suggestedResources(state) {
const resources = state.activity.accompanyingPeriod.resources;
const existingPersonIds = state.activity.persons.map(p => p.id);
const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id);
return state.activity.accompanyingPeriod.resources
.map(r => r.resource)
.filter(r =>
(r.type === 'person' && !existingPersonIds.includes(r.id)) ||
(r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id))
);
}
} }

View File

@ -6,6 +6,8 @@ import getters from './getters';
import actions from './actions'; import actions from './actions';
import mutations from './mutations'; import mutations from './mutations';
import { mapEntity } from './utils'; import { mapEntity } from './utils';
import { whoami } from '../api';
import { USER_CALENDAR_SHOW_RANGES }from './../const';
import { import {
getLocations, getLocationTypeByDefaultFor, getLocations, getLocationTypeByDefaultFor,
@ -14,18 +16,34 @@ import {
const debug = process.env.NODE_ENV !== 'production'; const debug = process.env.NODE_ENV !== 'production';
const store = createStore({ const store = createStore({
strict: debug, strict: debug,
state: { state: {
activity: mapEntity(window.entity), // activity is the calendar entity actually activity: mapEntity(window.entity), // activity is the calendar entity actually
currentEvent: null, currentEvent: null,
availableLocations: [], availableLocations: [],
mainUser: null me: null,
initialDate: null,
currentView: {
start: null,
end: null,
users: new Map(),
},
usersData: new Map(),
}, },
getters, getters,
mutations, mutations,
actions, actions,
}); });
console.log('calendar event', store.state.activity);
whoami().then(me => {
store.commit('setWhoAmiI', me);
});
if (null !== store.getters.getMainUser) {
store.commit('showUserOnCalendar', {what: [USER_CALENDAR_SHOW_RANGES], user: store.getters.getMainUser});
}
export default store; export default store;

View File

@ -1,41 +1,72 @@
import {createUserData, calendarRangeToFullCalendarEvent} from './utils';
export default { export default {
// ConcernedGroups setWhoAmiI(state, me) {
addPersonsInvolved(state, payload) { state.me = me;
//console.log('### mutation addPersonsInvolved', payload.result.type); },
switch (payload.result.type) { setCurrentDatesView(state, {start, end}) {
case 'person': state.currentView.start = start;
state.activity.persons.push(payload.result); state.currentView.end = end;
break; },
case 'thirdparty': showUserOnCalendar(state, {user, what}) {
state.activity.thirdParties.push(payload.result); console.log('showUserOnCalendar', {user: user.id, what});
break; state.currentView.users.set(user.id, what);
case 'user': },
state.activity.users.push(payload.result);
break; // ConcernedGroups
}; addPersonsInvolved(state, payload) {
}, //console.log('### mutation addPersonsInvolved', payload.result.type);
removePersonInvolved(state, payload) { switch (payload.result.type) {
//console.log('### mutation removePersonInvolved', payload.type); case 'person':
switch (payload.type) { state.activity.persons.push(payload.result);
case 'person': break;
state.activity.persons = state.activity.persons.filter(person => person !== payload); case 'thirdparty':
break; state.activity.thirdParties.push(payload.result);
case 'thirdparty': break;
state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload); case 'user':
break; state.activity.users.push(payload.result);
case 'user': break;
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
};
},
// Calendar
setEvents(state, payload) {
console.log(payload)
state.currentEvent = {start: payload.start, end: payload.end}
},
// Location
updateLocation(state, value) {
console.log('### mutation: updateLocation', value);
state.activity.location = value;
} }
;
},
removePersonInvolved(state, payload) {
//console.log('### mutation removePersonInvolved', payload.type);
switch (payload.type) {
case 'person':
state.activity.persons = state.activity.persons.filter(person => person !== payload);
break;
case 'thirdparty':
state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload);
break;
case 'user':
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
}
;
},
addCalendarRangesForUser(state, {user, ranges, start, end}) {
let userData;
if (state.usersData.has(user.id)) {
userData = state.usersData.get(user.id);
} else {
userData = createUserData(user);
state.usersData.set(user.id, userData);
}
const eventRanges = ranges.map(r => calendarRangeToFullCalendarEvent(r));
userData.calendarRanges = userData.calendarRanges.concat(eventRanges);
userData.calendarRangesLoaded.push({start, end});
},
/*
// Calendar
setEvents(state, payload) {
console.log(payload)
state.currentEvent = {start: payload.start, end: payload.end}
},*/
// Location
updateLocation(state, value) {
console.log('### mutation: updateLocation', value);
state.activity.location = value;
}
}; };

View File

@ -1,27 +1,48 @@
const addIdToValue = (string, id) => { const addIdToValue = (string, id) => {
let array = string ? string.split(',') : []; let array = string ? string.split(',') : [];
array.push(id.toString()); array.push(id.toString());
let str = array.join(); let str = array.join();
return str; return str;
}; };
const removeIdFromValue = (string, id) => { const removeIdFromValue = (string, id) => {
let array = string.split(','); let array = string.split(',');
array = array.filter(el => el !== id.toString()); array = array.filter(el => el !== id.toString());
let str = array.join(); let str = array.join();
return str; return str;
}; };
/* /*
* Assign missing keys for the ConcernedGroups component * Assign missing keys for the ConcernedGroups component
*/ */
const mapEntity = (entity) => { const mapEntity = (entity) => {
Object.assign(entity, {thirdParties: entity.professionals, users: entity.invites}); Object.assign(entity, {thirdParties: entity.professionals, users: entity.invites});
return entity; return entity;
}; };
const createUserData = (user) => {
return {
user: user,
calendarRanges: [],
calendarRangesLoaded: [],
}
}
const calendarRangeToFullCalendarEvent = (entity) => {
return {
//id: `range_${entity.id}`,
title: "Disponible",
start: entity.startDate.datetime8601,
end: entity.endDate.datetime8601,
allDay: false,
//userId: entity.user.id,
};
}
export { export {
addIdToValue, addIdToValue,
removeIdFromValue, calendarRangeToFullCalendarEvent,
mapEntity removeIdFromValue,
mapEntity,
createUserData,
}; };

View File

@ -4,6 +4,7 @@
* @returns {Promise} a promise containing all Calendar ranges objects * @returns {Promise} a promise containing all Calendar ranges objects
*/ */
const fetchCalendarRanges = () => { const fetchCalendarRanges = () => {
return Promise.resolve([]);
const url = `/api/1.0/calendar/calendar-range-available.json`; const url = `/api/1.0/calendar/calendar-range-available.json`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {
@ -13,6 +14,7 @@ const fetchCalendarRanges = () => {
}; };
const fetchCalendarRangesByUser = (userId) => { const fetchCalendarRangesByUser = (userId) => {
return Promise.resolve([]);
const url = `/api/1.0/calendar/calendar-range-available.json?user=${userId}`; const url = `/api/1.0/calendar/calendar-range-available.json?user=${userId}`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {
@ -27,6 +29,7 @@ const fetchCalendarRangesByUser = (userId) => {
* @returns {Promise} a promise containing all Calendar objects * @returns {Promise} a promise containing all Calendar objects
*/ */
const fetchCalendar = (mainUserId) => { const fetchCalendar = (mainUserId) => {
return Promise.resolve([]);
const url = `/api/1.0/calendar/calendar.json?main_user=${mainUserId}&item_per_page=1000`; const url = `/api/1.0/calendar/calendar.json?main_user=${mainUserId}&item_per_page=1000`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {

View File

@ -24,8 +24,6 @@ function loadDynamicPicker(element) {
null : [ JSON.parse(input.value) ] null : [ JSON.parse(input.value) ]
) )
; ;
console.log('picked at startup', picked);
console.log('input', input);
if (!isMultiple) { if (!isMultiple) {
if (input.value === '[]'){ if (input.value === '[]'){

View File

@ -146,6 +146,9 @@ export default {
} }
}, },
titleCreate() { titleCreate() {
if (typeof this.allowedTypes === 'undefined') {
return 'onthefly.create.title.default';
}
return this.allowedTypes.every(t => t === 'person') return this.allowedTypes.every(t => t === 'person')
? 'onthefly.create.title.person' ? 'onthefly.create.title.person'
: this.allowedTypes.every(t => t === 'thirdparty') : this.allowedTypes.every(t => t === 'thirdparty')