wip on app2

This commit is contained in:
2022-06-23 12:26:48 +02:00
parent 6b3b010631
commit d8f80f3d02
44 changed files with 545 additions and 358 deletions

View File

@@ -1,5 +0,0 @@
export function whoami(): import('ChillCalendarAssets/types').User;
export function fetchCalendarRangeForUser(user: import('ChillCalendarAssets/types').User, start: Date, end: Date): import('ChillCalendarAssets/types').CalendarRange[];
export function fetchCalendarRemoteForUser(user: import('ChillCalendarAssets/types').User, start: Date, end: Date): import('ChillCalendarAssets/types').Calendar[];

View File

@@ -1,7 +1,9 @@
import {fetchResults} from 'ChillMainAssets/lib/api/apiMethods';
import {datetimeToISO} from 'ChillMainAssets/chill/js/date';
import {User} from 'ChillMainAssets/types';
import {CalendarRange, CalendarRemote} from 'ChillCalendarAssets/types';
const whoami = () => {
export const whoami = (): Promise<User> => {
const url = `/api/1.0/main/whoami.json`;
return fetch(url)
.then(response => {
@@ -25,24 +27,18 @@ const whoami = () => {
* @param Date end
* @return Promise
*/
const fetchCalendarRangeForUser = (user, start, end) => {
export const fetchCalendarRangeForUser = (user: User, start: Date, end: Date): Promise<CalendarRange[]> => {
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});
return fetchResults<CalendarRange>(uri, {dateFrom, dateTo});
}
const fetchCalendarRemoteForUser = (user, start, end) => {
export const fetchCalendarRemoteForUser = (user: User, start: Date, end: Date): Promise<CalendarRemote[]> => {
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
const dateFrom = datetimeToISO(start);
const dateTo = datetimeToISO(end);
return fetchResults(uri, {dateFrom, dateTo});
return fetchResults<CalendarRemote>(uri, {dateFrom, dateTo});
}
export {
whoami,
fetchCalendarRangeForUser,
fetchCalendarRemoteForUser,
};

View File

@@ -1,2 +0,0 @@
export function calendarRangeToFullCalendarEvent(entity: import('ChillCalendarAssets/types').CalendarRange): import('@fullcalendar/vue3').EventInput;

View File

@@ -1,14 +1,26 @@
import {COLORS} from '../const';
import {ISOToDatetime} from 'ChillMainAssets/chill/js/date';
import {DateTime, User} from 'ChillMainAssets/types';
import {CalendarRange, CalendarRemote} from 'ChillCalendarAssets/types';
import {EventInput} from '@fullcalendar/vue3';
const addIdToValue = (string, id) => {
export interface UserData {
user: User,
calendarRanges: CalendarRange[],
calendarRangesLoaded: {}[],
remotes: CalendarRemote[],
remotesLoaded: {}[],
mainColor: string,
}
export const addIdToValue = (string: string, id: number): string => {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
};
const removeIdFromValue = (string, id) => {
export const removeIdFromValue = (string: string, id: number) => {
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
@@ -18,7 +30,7 @@ const removeIdFromValue = (string, id) => {
/*
* Assign missing keys for the ConcernedGroups component
*/
const mapEntity = (entity) => {
export const mapEntity = (entity: EventInput): EventInput => {
let calendar = { ...entity};
Object.assign(calendar, {thirdParties: entity.professionals});
@@ -37,7 +49,7 @@ const mapEntity = (entity) => {
return calendar;
};
const createUserData = (user, colorIndex) => {
export const createUserData = (user: User, colorIndex: number): UserData => {
const colorId = colorIndex % COLORS.length;
console.log('colorId', colorId);
return {
@@ -51,7 +63,7 @@ const createUserData = (user, colorIndex) => {
}
// TODO move this function to a more global namespace, as it is in use in MyCalendarRange app
const calendarRangeToFullCalendarEvent = (entity) => {
export const calendarRangeToFullCalendarEvent = (entity: CalendarRange): EventInput & {id: string} => {
return {
id: `range_${entity.id}`,
title: "(" + entity.user.text + ")",
@@ -64,7 +76,7 @@ const calendarRangeToFullCalendarEvent = (entity) => {
};
}
const remoteToFullCalendarEvent = (entity) => {
export const remoteToFullCalendarEvent = (entity: CalendarRemote): EventInput & {id: string} => {
console.log(entity);
return {
id: `range_${entity.id}`,
@@ -75,12 +87,3 @@ const remoteToFullCalendarEvent = (entity) => {
is: 'remote',
};
}
export {
addIdToValue,
calendarRangeToFullCalendarEvent,
removeIdFromValue,
remoteToFullCalendarEvent,
mapEntity,
createUserData,
};

View File

@@ -11,7 +11,7 @@
<label class="form-check-label" for="weekends">{{ $t('show_weekends') }}</label>
</div>
<div>Il y a {{ this.eventSource[0].events.length }} events</div>
<div>Il y a {{ this.calendarOptions.eventSources[0].events.length }} events</div>
<FullCalendar ref="fullCalendar" :options="calendarOptions">
<template v-slot:eventContent='arg' >
@@ -96,7 +96,7 @@ import interactionPlugin from '@fullcalendar/interaction';
import timeGridPlugin from '@fullcalendar/timegrid';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import { mapGetters, mapActions, mapState } from 'vuex';
import { vShow } from 'vue';
import { vShow} from 'vue';
export default {
name: "App",
@@ -104,6 +104,12 @@ export default {
FullCalendar,
Modal
},
renderTracked(event) {
console.log('renderTracked' ,event);
},
renderTriggered(e) {
console.log('renderTriggered', e);
},
data() {
return {
errorMsg: [],
@@ -122,14 +128,19 @@ export default {
lastNewDate: null,
disableCopyDayButton: true,
showWeekends: false,
eventSources: [],
start: new Date(),
}
},
computed: {
...mapState({
rangesToCopy: state => state.rangesToCopy
rangesToCopy: state => state.rangesToCopy,
key: state => {
let k = state.fullCalendar.key + state.calendarRanges.key;
console.log('key', k);
return k;
},
}),
//...mapGetters(),
...mapGetters(['getEventSources']),
/*, 'appointmentSource'*/
showMyCalendarWidget: {
set(value) {
@@ -139,32 +150,22 @@ export default {
return this.showMyCalendar;
}
},
/*
events() {
let e = this.$store.getters.getEventSources;
console.log('events', e);
e.push(
{
id: 'fake',
events: [
{
start: '2022-06-17T12:00:00+02:00',
end: '2022-06-17T14:00:00+02:00',
title: Math.random().toString(36).slice(2, 7),
}
]
}
);
return e;
let sources = this.getEventSources;
console.log('events', sources);
return function (calendarInfo, successCallback, failureCallback) {
successCallback(sources);
}
},
*/
calendarOptions() {
return {
locale: frLocale,
plugins: [ dayGridPlugin, interactionPlugin, timeGridPlugin ],
plugins: [interactionPlugin, timeGridPlugin],
initialView: 'timeGridWeek',
initialDate: window.startDate !== undefined ? window.startDate : new Date(),
initialDate: new Date(),
selectable: true,
select: this.onDateSelect,
datesSet: this.onDatesSet,
@@ -172,22 +173,32 @@ export default {
eventDrop: this.onEventDropOrResize,
eventResize: this.onEventDropOrResize,
eventClick: this.onEventClick,
eventSources: this.eventSources,
eventSources: this.getEventSources,
selectMirror: false,
editable: true,
weekends: this.showWeekends,
slotDuration: '00:15:00',
slotMinTime: "08:00:00",
slotMaxTime: "19:00:00",
contentHeight: 500,
//contentHeight: 500,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth timeGridWeek timeGridDay'
right: 'timeGridWeek timeGridDay'
},
};
},
},
watch: {
key() {
console.log('key changed');
this.calendarOptions.initialDate = this.start;
//this.$refs.fullCalendar.getApi().render();
},
calendarOptions() {
console.log('calendar options changed');
}
},
methods: {
...mapActions([
//'fetchRanges',
@@ -198,10 +209,11 @@ export default {
]),
onDatesSet(event) {
console.log('onDatesSet', event);
this.start = event.start;
this.$store.dispatch('fullCalendar/setCurrentDatesView', {start: event.start, end: event.end})
.then(source => {
console.log('onDatesSet finished');
this.eventSources.push(source);
//this.eventSources.push(source);
});
},
openModal() {

View File

@@ -0,0 +1,59 @@
<template>
<p>Il y a {{eventSources[0].events.length}} événements</p>
<FullCalendar :options="calendarOptions"></FullCalendar>
</template>
<script setup lang="ts">
//import {CalendarOptions, DatesSetArg, EventSourceInput} from '@fullcalendar/vue3';
import {reactive, computed, ref} from "vue";
import {mapGetters, useStore} from "vuex";
import {key} from './store';
import '@fullcalendar/core/vdom'; // solves problem with Vite
import frLocale from '@fullcalendar/core/locales/fr';
import FullCalendar from '@fullcalendar/vue3';
import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
const store = useStore(key);
const eventSources = computed<[]>(() => {
console.log('event sources');
return store.getters.getEventSources;
});
const calendarOptions = computed(() => {
return {
locale: frLocale,
plugins: [interactionPlugin, timeGridPlugin],
initialView: 'timeGridWeek',
initialDate: new Date(),
selectable: true,
datesSet: onDatesSet,
eventSources: eventSources.value,
selectMirror: false,
editable: true,
slotDuration: '00:15:00',
slotMinTime: "08:00:00",
slotMaxTime: "19:00:00",
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'timeGridWeek timeGridDay'
},
};
});
function onDatesSet(event: any) {
console.log('onDatesSet', event);
store.dispatch('fullCalendar/setCurrentDatesView', {start: event.start, end: event.end})
.then(source => {
console.log('onDatesSet finished');
//this.eventSources.push(source);
});
}
</script>
<style scoped>
</style>

View File

@@ -1,16 +1,18 @@
import { createApp } from 'vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { appMessages } from './i18n'
import store from './store/index'
import futureStore from './store/index'
import App from './App.vue';
const i18n = _createI18n(appMessages);
futureStore().then((store) => {
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
.use(store)
.use(i18n)
.component('app', App)
.mount('#myCalendar');
const app = createApp({
template: `<app></app>`,
})
.use(store)
.use(i18n)
.component('app', App)
.mount('#myCalendar');
});

View File

@@ -0,0 +1,18 @@
import { createApp } from 'vue';
//import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
//import { appMessages } from './i18n'
import futureStore, {key} from './store/index'
import App2 from './App2.vue';
futureStore().then((store) => {
//const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
.use(store, key)
//.use(i18n)
.component('app', App2)
.mount('#myCalendar');
});

View File

@@ -1,11 +0,0 @@
import 'es6-promise/auto';
import { MeState } from './modules/me';
import { FullCalendarState } from './modules/fullcalendar';
import { CalendarRangesState } from './modules/calendarRanges';
export interface State {
me: MeState;
fullCalendar: FullCalendarState;
calendarRanges: CalendarRangesState;
}
declare const store: import("vuex").Store<State>;
export default store;

View File

@@ -1,13 +1,14 @@
import 'es6-promise/auto';
import Vuex from 'vuex';
import {Store, createStore} from 'vuex';
import {InjectionKey} from "vue";
//import actions from './actions';
//import getters from './getters';
//import mutations from './mutations';
import {User} from 'ChillCalendarAssets/types';
import me, {MeState} from './modules/me';
import fullCalendar, {FullCalendarState} from './modules/fullcalendar';
import calendarRanges, {CalendarRangesState} from './modules/calendarRanges';
import calendarRanges, {CalendarRangesState, RangeSource} from './modules/calendarRanges';
import {whoami} from 'ChillCalendarAssets/vuejs/Calendar/api';
import {User} from 'ChillMainAssets/types';
const debug = process.env.NODE_ENV !== 'production';
@@ -18,46 +19,61 @@ export interface State {
startDate: Date|null,
endDate: Date|null,
*/
me: MeState,
fullCalendar: FullCalendarState,
//key: number,
calendarRanges: CalendarRangesState,
fullCalendar: FullCalendarState
}
const store = new Vuex.Store<State>({
strict: debug,
modules: {
me,
fullCalendar,
calendarRanges,
},
getters: {
getEventSources(state, getters) {
let s = [
getters["calendarRanges/getRangeSource"],
];
export const key: InjectionKey<Store<State>> = Symbol();
console.log('getEventSources', s);
const futureStore = function(): Promise<Store<State>> {
return whoami().then((user: User) => {
const store = createStore<State>({
strict: debug,
/*
state: (): State => ({
//key: 0,
}),
return s;
}
}
/*
state: {
appointments: [],
appointmentsShown: true,
startDate: null,
endDate: null,
},
*/
//getters,
//mutations,
//actions,
});
*/
modules: {
me,
fullCalendar,
calendarRanges,
},
getters: {
getEventSources(state, getters, rootState): RangeSource[] {
let s = [];
s.push(rootState.calendarRanges.rangeSource);
whoami().then((me: User) => {
store.commit('me/setWhoAmi', me, {root: true})
store.dispatch('calendarRanges/fetchRanges', null, {root: true});
});
console.log('getEventSources', s);
export default store;
return s;
},
},
mutations: {
increaseKey(state: State) {
//state.key = state.key + 1;
}
}
/*
state: {
appointments: [],
appointmentsShown: true,
startDate: null,
endDate: null,
},
*/
//getters,
//mutations,
//actions,
});
store.commit('me/setWhoAmi', user, {root: true})
//store.dispatch('calendarRanges/fetchRanges', null, {root: true});
return Promise.resolve(store);
});
}
export default futureStore;

View File

@@ -1,43 +1,66 @@
import {State} from './../index';
import {ActionContext} from 'vuex';
import {ActionContext, Module} from 'vuex';
import {CalendarRange/*, CalendarRangeEvent*/} from 'ChillCalendarAssets/types';
import {fetchCalendarRangeForUser} from 'ChillCalendarAssets/vuejs/Calendar/api';
import {calendarRangeToFullCalendarEvent/*, CalendarRangeEvent*/} from 'ChillCalendarAssets/vuejs/Calendar/store/utils';
import {EventInput} from '@fullcalendar/vue3';
export interface CalendarRangesState {
ranges: EventInput[],
rangesLoaded: {start: Date, end: Date}[],
rangesIndex: Set<string>,
}
import {EventInput, EventSource} from '@fullcalendar/vue3';
export interface RangeSource {
id: string,
events: EventInput[],
borderColor: string,
backgroundColor: string,
textColor: string
//borderColor: string,
//backgroundColor: string,
//textColor: string
}
export interface CalendarRangesState {
rangeSource: RangeSource,
rangesLoaded: {start: number, end: number}[],
rangesIndex: Set<string>,
key: number
}
type Context = ActionContext<CalendarRangesState, State>;
export default {
export default <Module<CalendarRangesState, State>> {
namespaced: true,
state: (): CalendarRangesState => ({
ranges: [],
rangeSource: {
id: 'ranges',
events: [],
//borderColor: "#3788d8",
//backgroundColor: '#ffffff',
//textColor: '#444444',
},
rangesLoaded: [],
rangesIndex: new Set<string>
rangesIndex: new Set<string>(),
key: 0
}),
getters: {
/*
getRangeSource(state: CalendarRangesState): RangeSource {
let o = {
const o = {
id: 'ranges',
events: state.ranges,
borderColor: "#3788d8",
backgroundColor: '#ffffff',
textColor: '#444444',
//borderColor: "#3788d8",
//backgroundColor: '#ffffff',
//textColor: '#444444',
}
console.log('getRangeSource', o);
return o;
},
*/
isRangeLoaded: (state: CalendarRangesState) => ({start, end}: {start: Date, end: Date}): boolean => {
for (let range of state.rangesLoaded) {
if (start.getTime() === range.start && end.getTime() === range.end) {
return true;
}
}
return false;
},
},
mutations: {
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
@@ -46,12 +69,17 @@ export default {
const toAdd = ranges
.map(cr => calendarRangeToFullCalendarEvent(cr))
.filter(r => !state.rangesIndex.has(r.id));
state.ranges.push(...toAdd);
toAdd.forEach((r) => {state.rangesIndex.add(r.id)});
console.log('ranges', state.ranges);
console.log('toAdd', toAdd);
//state.rangeSource.events.push(...toAdd);
toAdd.forEach((r) => {
state.rangesIndex.add(r.id);
state.rangeSource.events.push(r);
});
state.key = state.key + toAdd.length;
console.log('ranges', state.rangeSource.events);
},
addLoaded(state: CalendarRangesState, payload: {start: Date, end: Date}) {
state.rangesLoaded.push({start: payload.start, end: payload.end});
state.rangesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
},/*
setRangesToCopy(state: State, payload: CalendarRange[]) {
@@ -59,49 +87,52 @@ export default {
},*/
addRange(state: CalendarRangesState, payload: CalendarRange) {
const asEvent = calendarRangeToFullCalendarEvent(payload);
state.ranges = [...state.ranges, asEvent];
state.rangeSource.events.push(asEvent);
state.rangesIndex.add(asEvent.id);
state.key = state.key + 1;
},
removeRange(state: CalendarRangesState, payload: EventInput) {
/*
state.ranges = state.ranges.filter(
(r) => r.id !== payload.id
);
if (typeof payload.id === "string") {
state.rangesIndex.delete(payload.id);
}
state.key = state.key + 1;
*/
},
},
actions: {
fetchRanges(ctx: Context): Promise<RangeSource> {
console.log('fetchRanges');
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.rootState.fullCalendar.currentView.start === null || ctx.rootState.fullCalendar.currentView.end === null) {
console.log('current view dates are null');
return Promise.resolve(ctx.getters.getRangeSource);
}
if (ctx.getters.isRangeLoaded) {
/*
if (ctx.getters.isRangeLoaded({start, end})) {
console.log('range already loaded');
return Promise.resolve(ctx.getters.getRangeSource);
}
}*/
ctx.commit('addLoaded', {
start: ctx.rootState.fullCalendar.currentView.start,
end: ctx.rootState.fullCalendar.currentView.end,
start: start,
end: end,
});
return fetchCalendarRangeForUser(
ctx.rootGetters['me/getMe'],
ctx.rootState.fullCalendar.currentView.start,
ctx.rootState.fullCalendar.currentView.end
start,
end
)
.then((ranges: CalendarRange[]) => {
.then((ranges) => {
ctx.commit('addRanges', ranges);
return Promise.resolve(ctx.getters.getRangeSource);
return Promise.resolve(null);
});
}
}

View File

@@ -6,7 +6,8 @@ export interface FullCalendarState {
currentView: {
start: Date|null,
end: Date|null,
}
},
key: number
}
type Context = ActionContext<FullCalendarState, State>;
@@ -17,20 +18,32 @@ export default {
currentView: {
start: null,
end: null,
}
},
key: 0,
}),
mutations: {
setCurrentDatesView: function(state: FullCalendarState, payload: {start: Date, end: Date}): void {
state.currentView.start = payload.start;
state.currentView.end = payload.end;
},
increaseKey: function(state: FullCalendarState): void {
state.key = state.key + 1;
}
},
actions: {
setCurrentDatesView(ctx: Context, p: {start: Date, end: Date}): Promise<RangeSource> {
console.log('dispatch setCurrentDatesView', p);
ctx.commit('setCurrentDatesView', {start: p.start, end: p.end});
setCurrentDatesView(ctx: Context, {start, end}: {start: Date|null, end: Date|null}): Promise<null> {
console.log('dispatch setCurrentDatesView', {start, end});
return ctx.dispatch('calendarRanges/fetchRanges', null, {root: true});
if (ctx.state.currentView.start !== start || ctx.state.currentView.end !== end) {
ctx.commit('setCurrentDatesView', {start, end});
}
if (start !== null && end !== null) {
console.log('start, end', {start, end});
return ctx.dispatch('calendarRanges/fetchRanges', {start, end}, {root: true}).then(_ => Promise.resolve(null));
} else {
return Promise.resolve(null);
}
},
}
}

View File

@@ -1,5 +1,5 @@
import {State} from './../index';
import {User} from 'ChillCalendarAssets/types';
import {User} from 'ChillMainAssets/types';
import {ActionContext} from 'vuex';
export interface MeState {