mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
edit location on existing ranges
This commit is contained in:
parent
adad4313a6
commit
9e93e2a3f9
@ -64,7 +64,7 @@
|
|||||||
<b v-if="arg.event.extendedProps.is === 'remote'">{{ arg.event.title}}</b>
|
<b v-if="arg.event.extendedProps.is === 'remote'">{{ arg.event.title}}</b>
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'range'">{{ arg.timeText }} - {{ arg.event.extendedProps.locationName }}</b>
|
<b v-else-if="arg.event.extendedProps.is === 'range'">{{ arg.timeText }} - {{ arg.event.extendedProps.locationName }}</b>
|
||||||
<b v-else >no 'is'</b>
|
<b v-else >no 'is'</b>
|
||||||
<a v-if="arg.event.extendedProps.is === 'range'" class="fa fa-fw fa-times"
|
<a v-if="arg.event.extendedProps.is === 'range'" class="fa fa-fw fa-times delete"
|
||||||
@click.prevent="onClickDelete(arg.event)">
|
@click.prevent="onClickDelete(arg.event)">
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
</FullCalendar>
|
</FullCalendar>
|
||||||
|
|
||||||
<div id="copy-widget">
|
<div id="copy-widget">
|
||||||
<h4 class="chill-red" style="margin-top: 2rem;">{{ 'copy_range_from_to' }}</h4>
|
<h4 class="chill-red" style="margin-top: 2rem;">{{ $t('copy_range_from_to') }}</h4>
|
||||||
<div style="display: flex; margin-top: 1rem;">
|
<div style="display: flex; margin-top: 1rem;">
|
||||||
<div class="col-sm-3" style="margin-right: 1rem">
|
<div class="col-sm-3" style="margin-right: 1rem">
|
||||||
<input class="form-control" type="date" v-model="copyFrom" />
|
<input class="form-control" type="date" v-model="copyFrom" />
|
||||||
@ -82,10 +82,13 @@
|
|||||||
<input class="form-control" type="date" v-model="copyTo" />
|
<input class="form-control" type="date" v-model="copyTo" />
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-action" @click="copyDay">
|
<button class="btn btn-action" @click="copyDay">
|
||||||
{{ 'copy_range' }}
|
{{ $t('copy_range') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- not directly seen, but include in a modal -->
|
||||||
|
<edit-location ref="editLocation"></edit-location>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -104,10 +107,11 @@ import FullCalendar from '@fullcalendar/vue3';
|
|||||||
import frLocale from '@fullcalendar/core/locales/fr';
|
import frLocale from '@fullcalendar/core/locales/fr';
|
||||||
import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/interaction";
|
import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/interaction";
|
||||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||||
import {EventApi, DateSelectArg, EventDropArg} from "@fullcalendar/core";
|
import {EventApi, DateSelectArg, EventDropArg, EventClickArg} from "@fullcalendar/core";
|
||||||
import {ISOToDate, ISOToDatetime} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
import {ISOToDate, ISOToDatetime} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||||
import VueMultiselect from "vue-multiselect";
|
import VueMultiselect from "vue-multiselect";
|
||||||
import {Location} from "../../../../../ChillMainBundle/Resources/public/types";
|
import {Location} from "../../../../../ChillMainBundle/Resources/public/types";
|
||||||
|
import EditLocation from "./Components/EditLocation.vue";
|
||||||
|
|
||||||
const store = useStore(key);
|
const store = useStore(key);
|
||||||
|
|
||||||
@ -117,6 +121,7 @@ const slotMinTime = ref('08:00:00');
|
|||||||
const slotMaxTime = ref('19:00:00');
|
const slotMaxTime = ref('19:00:00');
|
||||||
const copyFrom = ref<string | null>(null);
|
const copyFrom = ref<string | null>(null);
|
||||||
const copyTo = ref<string | null>(null);
|
const copyTo = ref<string | null>(null);
|
||||||
|
const editLocation = ref<InstanceType<typeof EditLocation> | null>(null)
|
||||||
|
|
||||||
const baseOptions = ref<CalendarOptions>({
|
const baseOptions = ref<CalendarOptions>({
|
||||||
locale: frLocale,
|
locale: frLocale,
|
||||||
@ -133,6 +138,8 @@ const baseOptions = ref<CalendarOptions>({
|
|||||||
eventResize: onEventDropOrResize,
|
eventResize: onEventDropOrResize,
|
||||||
// when an event is moved
|
// when an event is moved
|
||||||
eventDrop: onEventDropOrResize,
|
eventDrop: onEventDropOrResize,
|
||||||
|
// when an event si clicked
|
||||||
|
eventClick: onEventClick,
|
||||||
selectMirror: false,
|
selectMirror: false,
|
||||||
editable: true,
|
editable: true,
|
||||||
headerToolbar: {
|
headerToolbar: {
|
||||||
@ -229,8 +236,10 @@ function onClickDelete(event: EventApi): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
||||||
|
if (payload.event.extendedProps.is !== 'range') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const changedEvent = payload.event;
|
const changedEvent = payload.event;
|
||||||
console.log('eventDropOrResize', payload);
|
|
||||||
|
|
||||||
store.dispatch('calendarRanges/patchRangeTime', {
|
store.dispatch('calendarRanges/patchRangeTime', {
|
||||||
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
||||||
@ -239,6 +248,18 @@ function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function onEventClick(payload: EventClickArg): void {
|
||||||
|
// @ts-ignore TS does not recognize the target. But it does exists.
|
||||||
|
if (payload.jsEvent.target.classList.contains('delete')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.event.extendedProps.is !== 'range') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editLocation.value?.startEdit(payload.event);
|
||||||
|
}
|
||||||
|
|
||||||
function copyDay() {
|
function copyDay() {
|
||||||
if (null === copyFrom.value || null === copyTo.value) {
|
if (null === copyFrom.value || null === copyTo.value) {
|
||||||
return;
|
return;
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<teleport to="body">
|
||||||
|
<modal v-if="showModal"
|
||||||
|
@close="showModal = false">
|
||||||
|
|
||||||
|
<template v-slot:header>
|
||||||
|
<div>boum!</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body>
|
||||||
|
<label>Localisation</label>
|
||||||
|
<vue-multiselect v-model="pickedLocation" :options="locations" :label="'name'" :track-by="'id'"></vue-multiselect>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>close</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</modal>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Modal from "../../../../../../ChillMainBundle/Resources/public/vuejs/_components/Modal.vue";
|
||||||
|
import {computed, ref} from "vue";
|
||||||
|
import {EventApi} from "@fullcalendar/vue3";
|
||||||
|
import {useStore} from "vuex";
|
||||||
|
import {key} from "../store";
|
||||||
|
import {Location} from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
|
import VueMultiselect from "vue-multiselect";
|
||||||
|
|
||||||
|
const store = useStore(key);
|
||||||
|
|
||||||
|
const calendarRangeId = ref<number | null>(null);
|
||||||
|
const location = ref<Location | null>(null);
|
||||||
|
const showModal = ref(false);
|
||||||
|
|
||||||
|
const locations = computed<Location[]>(() => {
|
||||||
|
return store.state.locations.locations;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pickedLocation = computed<Location | null>({
|
||||||
|
get(): Location | null {
|
||||||
|
return location.value;
|
||||||
|
},
|
||||||
|
set(newLocation: Location | null): void {
|
||||||
|
console.log('newLocation', newLocation);
|
||||||
|
store.dispatch('calendarRanges/patchRangeLocation', {location: newLocation, calendarRangeId: calendarRangeId.value})
|
||||||
|
.then(_ => {showModal.value = false;})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const startEdit = function(event: EventApi): void {
|
||||||
|
console.log('startEditing', event);
|
||||||
|
calendarRangeId.value = event.extendedProps.calendarRangeId;
|
||||||
|
location.value = store.getters['locations/getLocationById'](event.extendedProps.locationId) || null;
|
||||||
|
|
||||||
|
console.log('new location value', location.value);
|
||||||
|
console.log('calendar range id', calendarRangeId.value);
|
||||||
|
showModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({startEdit});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,18 +1,18 @@
|
|||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
//import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
|
import { _createI18n } from '../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n'
|
||||||
//import { appMessages } from './i18n'
|
import { appMessages } from './i18n'
|
||||||
import futureStore, {key} from './store/index'
|
import futureStore, {key} from './store/index'
|
||||||
|
|
||||||
import App2 from './App2.vue';
|
import App2 from './App2.vue';
|
||||||
|
|
||||||
futureStore().then((store) => {
|
futureStore().then((store) => {
|
||||||
//const i18n = _createI18n(appMessages);
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app></app>`,
|
template: `<app></app>`,
|
||||||
})
|
})
|
||||||
.use(store, key)
|
.use(store, key)
|
||||||
//.use(i18n)
|
.use(i18n)
|
||||||
.component('app', App2)
|
.component('app', App2)
|
||||||
.mount('#myCalendar');
|
.mount('#myCalendar');
|
||||||
});
|
});
|
||||||
|
@ -53,7 +53,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return founds;
|
return founds;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
||||||
@ -83,11 +83,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
},
|
},
|
||||||
addLoaded(state: CalendarRangesState, payload: { start: Date, end: Date }) {
|
addLoaded(state: CalendarRangesState, payload: { start: Date, end: Date }) {
|
||||||
state.rangesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
|
state.rangesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
|
||||||
},/*
|
},
|
||||||
|
|
||||||
setRangesToCopy(state: State, payload: CalendarRange[]) {
|
|
||||||
state.rangesToCopy = payload
|
|
||||||
},*/
|
|
||||||
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
||||||
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
||||||
state.ranges.push({...asEvent, backgroundColor: 'white', borderColor: '#3788d8', textColor: 'black'});
|
state.ranges.push({...asEvent, backgroundColor: 'white', borderColor: '#3788d8', textColor: 'black'});
|
||||||
@ -116,6 +112,8 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
if (found !== undefined) {
|
if (found !== undefined) {
|
||||||
found.start = newEvent.start;
|
found.start = newEvent.start;
|
||||||
found.end = newEvent.end;
|
found.end = newEvent.end;
|
||||||
|
found.locationId = range.location.id;
|
||||||
|
found.locationName = range.location.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.key = state.key + 1;
|
state.key = state.key + 1;
|
||||||
@ -194,7 +192,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
ctx.commit('removeRange', calendarRangeId);
|
ctx.commit('removeRange', calendarRangeId);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
patchRangeTime(ctx, {calendarRangeId, start, end}: {calendarRangeId: number, start: Date, end: Date}): void {
|
patchRangeTime(ctx, {calendarRangeId, start, end}: {calendarRangeId: number, start: Date, end: Date}): Promise<null> {
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
const body = {
|
const body = {
|
||||||
startDate: {
|
startDate: {
|
||||||
@ -205,12 +203,33 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
},
|
},
|
||||||
} as CalendarRangeEdit;
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
makeFetch<CalendarRangeEdit, CalendarRange>('PATCH', url, body)
|
return makeFetch<CalendarRangeEdit, CalendarRange>('PATCH', url, body)
|
||||||
.then((range) => {
|
.then((range) => {
|
||||||
ctx.commit('updateRange', range);
|
ctx.commit('updateRange', range);
|
||||||
|
return Promise.resolve(null);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
patchRangeLocation(ctx, {location, calendarRangeId}: {location: Location, calendarRangeId: number}): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
const body = {
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location"
|
||||||
|
},
|
||||||
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeEdit, CalendarRange>('PATCH', url, body)
|
||||||
|
.then((range) => {
|
||||||
|
ctx.commit('updateRange', range);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.resolve(null);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
copyFromDayToAnotherDay(ctx, {from, to}: {from: Date, to: Date}): Promise<null> {
|
copyFromDayToAnotherDay(ctx, {from, to}: {from: Date, to: Date}): Promise<null> {
|
||||||
|
@ -51,43 +51,18 @@ export default <Module<CalendarRemotesState, State>> {
|
|||||||
},
|
},
|
||||||
addLoaded(state: CalendarRemotesState, payload: {start: Date, end: Date}) {
|
addLoaded(state: CalendarRemotesState, payload: {start: Date, end: Date}) {
|
||||||
state.remotesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
|
state.remotesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
|
||||||
},/*
|
|
||||||
|
|
||||||
setRangesToCopy(state: State, payload: CalendarRange[]) {
|
|
||||||
state.rangesToCopy = payload
|
|
||||||
},*/
|
|
||||||
addRemote(state: CalendarRemotesState, payload: CalendarRemote) {
|
|
||||||
const asEvent = remoteToFullCalendarEvent(payload);
|
|
||||||
state.remotes.push(asEvent);
|
|
||||||
state.remotesIndex.add(asEvent.id);
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
removeRemote(state: CalendarRemotesState, 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: {
|
actions: {
|
||||||
fetchRemotes(ctx: Context, payload: {start: Date, end: Date}): Promise<null> {
|
fetchRemotes(ctx: Context, payload: {start: Date, end: Date}): Promise<null> {
|
||||||
console.log('fetchRanges', payload);
|
|
||||||
const start = payload.start;
|
const start = payload.start;
|
||||||
const end = payload.end;
|
const end = payload.end;
|
||||||
|
|
||||||
if (ctx.rootGetters['me/getMe'] === null) {
|
if (ctx.rootGetters['me/getMe'] === null) {
|
||||||
console.log('me is not there');
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isRemotesLoaded({start, end})) {
|
if (ctx.getters.isRemotesLoaded({start, end})) {
|
||||||
console.log('range already loaded');
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +77,7 @@ export default <Module<CalendarRemotesState, State>> {
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
.then((remotes: CalendarRemote[]) => {
|
.then((remotes: CalendarRemote[]) => {
|
||||||
|
// to be add when reactivity problem will be solve ?
|
||||||
//ctx.commit('addRemotes', remotes);
|
//ctx.commit('addRemotes', remotes);
|
||||||
const inputs = remotes
|
const inputs = remotes
|
||||||
.map(cr => remoteToFullCalendarEvent(cr))
|
.map(cr => remoteToFullCalendarEvent(cr))
|
||||||
|
@ -19,6 +19,11 @@ export default <Module<LocationState, State>>{
|
|||||||
currentLocation: null,
|
currentLocation: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getters: {
|
||||||
|
getLocationById: (state) => (id: number): Location|undefined => {
|
||||||
|
return state.locations.find(l => l.id === id);
|
||||||
|
},
|
||||||
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setLocations(state, locations): void {
|
setLocations(state, locations): void {
|
||||||
state.locations = locations;
|
state.locations = locations;
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import {defineComponent} from "vue";
|
||||||
/*
|
/*
|
||||||
* This Modal component is a mix between Vue3 modal implementation
|
* This Modal component is a mix between Vue3 modal implementation
|
||||||
* [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
* [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
||||||
@ -36,20 +37,22 @@
|
|||||||
* [+] using bootstrap css classes, the modal have a responsive behaviour,
|
* [+] using bootstrap css classes, the modal have a responsive behaviour,
|
||||||
* [+] modal design can be configured using css classes (size, scroll)
|
* [+] modal design can be configured using css classes (size, scroll)
|
||||||
*/
|
*/
|
||||||
export default {
|
export default defineComponent({
|
||||||
name: 'Modal',
|
name: 'Modal',
|
||||||
props: {
|
props: {
|
||||||
modalDialogClass: {
|
modalDialogClass: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: false
|
required: false,
|
||||||
|
default: {},
|
||||||
},
|
},
|
||||||
hideFooter: {
|
hideFooter: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['close']
|
emits: ['close']
|
||||||
}
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user