adding location to ranges and more control on MyCalendarRanges

This commit is contained in:
2022-06-29 15:28:37 +02:00
parent 809a0a38ab
commit 849e7158e4
13 changed files with 357 additions and 78 deletions

View File

@@ -3,22 +3,8 @@ import {datetimeToISO} from '../../../../../ChillMainBundle/Resources/public/chi
import {User} from '../../../../../ChillMainBundle/Resources/public/types';
import {CalendarRange, CalendarRemote} from '../../types';
export const whoami = (): Promise<User> => {
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
};
});
};
// re-export whoami
export {whoami} from "../../../../../ChillMainBundle/Resources/public/lib/api/user";
/**
*

View File

@@ -73,6 +73,8 @@ export const calendarRangeToFullCalendarEvent = (entity: CalendarRange): EventIn
allDay: false,
userId: entity.user.id,
calendarRangeId: entity.id,
locationId: entity.location.id,
locationName: entity.location.name,
is: 'range',
};
}

View File

@@ -1,5 +1,10 @@
<template>
<p>Il y a {{ 'eventSources[0].length' }} plages</p>
<div class="row">
<div class="col-sm">
<label>Localisation</label>
<vue-multiselect v-model="pickedLocation" :options="locations" :label="'name'" :track-by="'id'"></vue-multiselect>
</div>
</div>
<div class="display-options row justify-content-between">
<div class="col-sm col-xs-12">
<div class="input-group mb-3">
@@ -10,15 +15,45 @@
<option value="00:15:00">15 minutes</option>
<option value="00:30:00">30 minutes</option>
</select>
<label class="input-group-text" for="slotMinTime">De</label>
<select v-model="slotMinTime" id="slotMinTime" class="form-select">
<option value="00:00:00">0h</option>
<option value="01:00:00">1h</option>
<option value="02:00:00">2h</option>
<option value="03:00:00">3h</option>
<option value="04:00:00">4h</option>
<option value="05:00:00">5h</option>
<option value="06:00:00">6h</option>
<option value="07:00:00">7h</option>
<option value="08:00:00">8h</option>
<option value="09:00:00">9h</option>
<option value="10:00:00">10h</option>
<option value="11:00:00">11h</option>
<option value="12:00:00">12h</option>
</select>
<label class="input-group-text" for="slotMaxTime">À</label>
<select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
<option value="12:00:00">12h</option>
<option value="13:00:00">13h</option>
<option value="14:00:00">14h</option>
<option value="15:00:00">15h</option>
<option value="16:00:00">16h</option>
<option value="17:00:00">17h</option>
<option value="18:00:00">18h</option>
<option value="19:00:00">19h</option>
<option value="20:00:00">20h</option>
<option value="21:00:00">21h</option>
<option value="22:00:00">22h</option>
<option value="23:00:00">23h</option>
<option value="23:59:59">24h</option>
</select>
</div>
</div>
<div class="col-sm col-xs-12">
<div class="float-end">
<div class="input-group mb-3">
<div class="input-group-text">
<input id="showHideWE" class="form-check-input mt-0" type="checkbox" v-model="showWeekends">
<label for="showHideWE" class="form-check-label"> Masquer les week-ends</label>
</div>
<div class="form-check form-switch">
<input id="showHideWE" class="form-check-input mt-0" type="checkbox" v-model="showWeekends">
<label for="showHideWE" class="form-check-label">Week-ends</label>
</div>
</div>
</div>
@@ -27,7 +62,7 @@
<template v-slot:eventContent='arg'>
<span :class="eventClasses(arg.event)">
<b v-if="arg.event.extendedProps.is === 'remote'">{{ arg.event.title}}</b>
<b v-else-if="arg.event.extendedProps.is === 'range'">{{ arg.timeText }}</b>
<b v-else-if="arg.event.extendedProps.is === 'range'">{{ arg.timeText }} - {{ arg.event.extendedProps.locationName }}</b>
<b v-else >no 'is'</b>
<a v-if="arg.event.extendedProps.is === 'range'" class="fa fa-fw fa-times"
@click.prevent="onClickDelete(arg.event)">
@@ -71,11 +106,15 @@ import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/inte
import timeGridPlugin from "@fullcalendar/timegrid";
import {EventApi, DateSelectArg, EventDropArg} from "@fullcalendar/core";
import {ISOToDate, ISOToDatetime} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
import VueMultiselect from "vue-multiselect";
import {Location} from "../../../../../ChillMainBundle/Resources/public/types";
const store = useStore(key);
const showWeekends = ref(true);
const showWeekends = ref(false);
const slotDuration = ref('00:15:00');
const slotMinTime = ref('08:00:00');
const slotMaxTime = ref('19:00:00');
const copyFrom = ref<string | null>(null);
const copyTo = ref<string | null>(null);
@@ -96,8 +135,6 @@ const baseOptions = ref<CalendarOptions>({
eventDrop: onEventDropOrResize,
selectMirror: false,
editable: true,
slotMinTime: "08:00:00",
slotMaxTime: "19:00:00",
headerToolbar: {
left: 'prev,next today',
center: 'title',
@@ -109,6 +146,19 @@ const ranges = computed<EventInput[]>(() => {
return store.state.calendarRanges.ranges;
});
const locations = computed<Location[]>(() => {
return store.state.locations.locations;
});
const pickedLocation = computed<Location | null>({
get(): Location | null {
return store.state.locations.locationPicked || store.state.locations.currentLocation;
},
set(newLocation: Location | null): void {
store.commit('locations/setLocationPicked', newLocation, { root: true});
}
})
/**
* return the show classes for the event
* @param arg
@@ -143,6 +193,8 @@ const calendarOptions = computed((): CalendarOptions => {
weekends: showWeekends.value,
slotDuration: slotDuration.value,
events: ranges.value,
slotMinTime: slotMinTime.value,
slotMaxTime: slotMaxTime.value,
};
});
@@ -154,7 +206,13 @@ function onDatesSet(event: DatesSetArg): void {
}
function onDateSelect(event: DateSelectArg): void {
store.dispatch('calendarRanges/createRange', {start: event.start, end: event.end});
if (null === pickedLocation.value) {
window.alert("Indiquez une localisation avant de créer une période de disponibilité.");
return;
}
store.dispatch('calendarRanges/createRange', {start: event.start, end: event.end, location: pickedLocation.value});
}
/**

View File

@@ -1,30 +1,22 @@
import 'es6-promise/auto';
import {Store, createStore} from 'vuex';
import {InjectionKey} from "vue";
//import actions from './actions';
//import getters from './getters';
//import mutations from './mutations';
import me, {MeState} from './modules/me';
import fullCalendar, {FullCalendarState} from './modules/fullcalendar';
import calendarRanges, {CalendarRangesState} from './modules/calendarRanges';
import calendarRemotes, {CalendarRemotesState} from './modules/calendarRemotes';
import {whoami} from '../../Calendar/api';
import {whoami} from "../../../../../../ChillMainBundle/Resources/public/lib/api/user";
import {User} from '../../../../../../ChillMainBundle/Resources/public/types';
import locations, {LocationState} from "./modules/location";
const debug = process.env.NODE_ENV !== 'production';
export interface State {
/*
appointments: Calendar[],
appointmentsShown: boolean,
startDate: Date|null,
endDate: Date|null,
*/
//key: number,
calendarRanges: CalendarRangesState,
calendarRemotes: CalendarRemotesState,
fullCalendar: FullCalendarState,
me: MeState,
locations: LocationState
}
export const key: InjectionKey<Store<State>> = Symbol();
@@ -33,38 +25,20 @@ const futureStore = function(): Promise<Store<State>> {
return whoami().then((user: User) => {
const store = createStore<State>({
strict: debug,
/*
state: (): State => ({
//key: 0,
}),
*/
modules: {
me,
fullCalendar,
calendarRanges,
calendarRemotes,
locations,
},
mutations: {
increaseKey(state: State) {
//state.key = state.key + 1;
}
}
/*
state: {
appointments: [],
appointmentsShown: true,
startDate: null,
endDate: null,
},
*/
//getters,
//mutations,
//actions,
mutations: {}
});
store.commit('me/setWhoAmi', user, {root: true})
//store.dispatch('calendarRanges/fetchRanges', null, {root: true});
store.commit('me/setWhoAmi', user, {root: true});
store.dispatch('locations/getLocations', null, {root: true}).then(_ => {
return store.dispatch('locations/getCurrentLocation', null, {root: true});
});
return Promise.resolve(store);
});

View File

@@ -1,6 +1,7 @@
import {State} from './../index';
import {ActionContext, Module} from 'vuex';
import {CalendarRange, CalendarRangeCreate, CalendarRangeEdit, isEventInputCalendarRange} from "../../../../types";
import {Location} from "../../../../../../../ChillMainBundle/Resources/public/types";
import {fetchCalendarRangeForUser} from '../../../Calendar/api';
import {calendarRangeToFullCalendarEvent} from '../../../Calendar/store/utils';
import {EventInput} from '@fullcalendar/vue3';
@@ -89,7 +90,7 @@ export default <Module<CalendarRangesState, State>>{
},*/
addRange(state: CalendarRangesState, payload: CalendarRange) {
const asEvent = calendarRangeToFullCalendarEvent(payload);
state.ranges.push(asEvent);
state.ranges.push({...asEvent, backgroundColor: 'white', borderColor: '#3788d8', textColor: 'black'});
state.rangesIndex.add(asEvent.id);
state.key = state.key + 1;
},
@@ -122,17 +123,14 @@ export default <Module<CalendarRangesState, State>>{
},
actions: {
fetchRanges(ctx: Context, payload: { start: Date, end: Date }): Promise<null> {
console.log('fetchRanges', payload);
const start = payload.start;
const end = payload.end;
if (ctx.rootGetters['me/getMe'] === null) {
console.log('me is not there');
return Promise.resolve(ctx.getters.getRangeSource);
}
if (ctx.getters.isRangeLoaded({start, end})) {
console.log('range already loaded');
return Promise.resolve(ctx.getters.getRangeSource);
}
@@ -151,7 +149,7 @@ export default <Module<CalendarRangesState, State>>{
return Promise.resolve(null);
});
},
createRange(ctx, {start, end}: { start: Date, end: Date }): Promise<null> {
createRange(ctx, {start, end, location}: { start: Date, end: Date, location: Location }): Promise<null> {
const url = `/api/1.0/calendar/calendar-range.json?`;
if (ctx.rootState.me.me === null) {
@@ -169,6 +167,10 @@ export default <Module<CalendarRangesState, State>>{
endDate: {
datetime: datetimeToISO(end)
},
location: {
id: location.id,
type: "location"
}
} as CalendarRangeCreate;
return makeFetch<CalendarRangeCreate, CalendarRange>('POST', url, body)
@@ -179,7 +181,7 @@ export default <Module<CalendarRangesState, State>>{
return Promise.resolve(null);
})
.catch((error) => {
console.log(error);
console.error(error);
throw error;
})
@@ -208,7 +210,7 @@ export default <Module<CalendarRangesState, State>>{
ctx.commit('updateRange', range);
})
.catch((error) => {
console.log(error);
console.error(error);
})
},
copyFromDayToAnotherDay(ctx, {from, to}: {from: Date, to: Date}): Promise<null> {

View File

@@ -0,0 +1,57 @@
import {Location} from "../../../../../../../ChillMainBundle/Resources/public/types";
import {State} from '../index';
import {Module} from 'vuex';
import {getLocations} from "../../../../../../../ChillMainBundle/Resources/public/lib/api/locations";
import {whereami} from "../../../../../../../ChillMainBundle/Resources/public/lib/api/user";
export interface LocationState {
locations: Location[];
locationPicked: Location | null;
currentLocation: Location | null;
}
export default <Module<LocationState, State>>{
namespaced: true,
state: (): LocationState => {
return {
locations: [],
locationPicked: null,
currentLocation: null,
}
},
mutations: {
setLocations(state, locations): void {
state.locations = locations;
},
setLocationPicked(state, location: Location | null): void {
if (null === location) {
state.locationPicked = null;
return;
}
state.locationPicked = state.locations.find(l => l.id === location.id) || null;
},
setCurrentLocation(state, location: Location | null): void {
if (null === location) {
state.currentLocation = null;
return;
}
state.currentLocation = state.locations.find(l => l.id === location.id) || null;
}
},
actions: {
getLocations(ctx): Promise<void> {
return getLocations().then(locations => {
ctx.commit('setLocations', locations);
return Promise.resolve();
});
},
getCurrentLocation(ctx): Promise<void> {
return whereami().then(location => {
ctx.commit('setCurrentLocation', location);
})
}
}
}