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-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"
|
||||
<a v-if="arg.event.extendedProps.is === 'range'" class="fa fa-fw fa-times delete"
|
||||
@click.prevent="onClickDelete(arg.event)">
|
||||
</a>
|
||||
</span>
|
||||
@ -72,7 +72,7 @@
|
||||
</FullCalendar>
|
||||
|
||||
<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 class="col-sm-3" style="margin-right: 1rem">
|
||||
<input class="form-control" type="date" v-model="copyFrom" />
|
||||
@ -82,10 +82,13 @@
|
||||
<input class="form-control" type="date" v-model="copyTo" />
|
||||
</div>
|
||||
<button class="btn btn-action" @click="copyDay">
|
||||
{{ 'copy_range' }}
|
||||
{{ $t('copy_range') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- not directly seen, but include in a modal -->
|
||||
<edit-location ref="editLocation"></edit-location>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -104,10 +107,11 @@ import FullCalendar from '@fullcalendar/vue3';
|
||||
import frLocale from '@fullcalendar/core/locales/fr';
|
||||
import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/interaction";
|
||||
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 VueMultiselect from "vue-multiselect";
|
||||
import {Location} from "../../../../../ChillMainBundle/Resources/public/types";
|
||||
import EditLocation from "./Components/EditLocation.vue";
|
||||
|
||||
const store = useStore(key);
|
||||
|
||||
@ -117,6 +121,7 @@ const slotMinTime = ref('08:00:00');
|
||||
const slotMaxTime = ref('19:00:00');
|
||||
const copyFrom = ref<string | null>(null);
|
||||
const copyTo = ref<string | null>(null);
|
||||
const editLocation = ref<InstanceType<typeof EditLocation> | null>(null)
|
||||
|
||||
const baseOptions = ref<CalendarOptions>({
|
||||
locale: frLocale,
|
||||
@ -133,6 +138,8 @@ const baseOptions = ref<CalendarOptions>({
|
||||
eventResize: onEventDropOrResize,
|
||||
// when an event is moved
|
||||
eventDrop: onEventDropOrResize,
|
||||
// when an event si clicked
|
||||
eventClick: onEventClick,
|
||||
selectMirror: false,
|
||||
editable: true,
|
||||
headerToolbar: {
|
||||
@ -155,7 +162,7 @@ const pickedLocation = computed<Location | null>({
|
||||
return store.state.locations.locationPicked || store.state.locations.currentLocation;
|
||||
},
|
||||
set(newLocation: Location | null): void {
|
||||
store.commit('locations/setLocationPicked', newLocation, { root: true});
|
||||
store.commit('locations/setLocationPicked', newLocation, {root: true});
|
||||
}
|
||||
})
|
||||
|
||||
@ -229,8 +236,10 @@ function onClickDelete(event: EventApi): void {
|
||||
}
|
||||
|
||||
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
||||
if (payload.event.extendedProps.is !== 'range') {
|
||||
return;
|
||||
}
|
||||
const changedEvent = payload.event;
|
||||
console.log('eventDropOrResize', payload);
|
||||
|
||||
store.dispatch('calendarRanges/patchRangeTime', {
|
||||
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() {
|
||||
if (null === copyFrom.value || null === copyTo.value) {
|
||||
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 { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
|
||||
//import { appMessages } from './i18n'
|
||||
import { _createI18n } from '../../../../../ChillMainBundle/Resources/public/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 i18n = _createI18n(appMessages);
|
||||
|
||||
const app = createApp({
|
||||
template: `<app></app>`,
|
||||
})
|
||||
.use(store, key)
|
||||
//.use(i18n)
|
||||
.use(i18n)
|
||||
.component('app', App2)
|
||||
.mount('#myCalendar');
|
||||
});
|
||||
|
@ -53,7 +53,7 @@ export default <Module<CalendarRangesState, State>>{
|
||||
}
|
||||
|
||||
return founds;
|
||||
}
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
||||
@ -83,11 +83,7 @@ export default <Module<CalendarRangesState, State>>{
|
||||
},
|
||||
addLoaded(state: CalendarRangesState, payload: { start: Date, end: Date }) {
|
||||
state.rangesLoaded.push({start: payload.start.getTime(), end: payload.end.getTime()});
|
||||
},/*
|
||||
|
||||
setRangesToCopy(state: State, payload: CalendarRange[]) {
|
||||
state.rangesToCopy = payload
|
||||
},*/
|
||||
},
|
||||
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
||||
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
||||
state.ranges.push({...asEvent, backgroundColor: 'white', borderColor: '#3788d8', textColor: 'black'});
|
||||
@ -116,6 +112,8 @@ export default <Module<CalendarRangesState, State>>{
|
||||
if (found !== undefined) {
|
||||
found.start = newEvent.start;
|
||||
found.end = newEvent.end;
|
||||
found.locationId = range.location.id;
|
||||
found.locationName = range.location.name;
|
||||
}
|
||||
|
||||
state.key = state.key + 1;
|
||||
@ -194,7 +192,7 @@ export default <Module<CalendarRangesState, State>>{
|
||||
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 body = {
|
||||
startDate: {
|
||||
@ -205,12 +203,33 @@ export default <Module<CalendarRangesState, State>>{
|
||||
},
|
||||
} as CalendarRangeEdit;
|
||||
|
||||
makeFetch<CalendarRangeEdit, CalendarRange>('PATCH', url, body)
|
||||
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);
|
||||
})
|
||||
},
|
||||
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> {
|
||||
|
@ -51,43 +51,18 @@ export default <Module<CalendarRemotesState, State>> {
|
||||
},
|
||||
addLoaded(state: CalendarRemotesState, payload: {start: Date, end: Date}) {
|
||||
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: {
|
||||
fetchRemotes(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(null);
|
||||
}
|
||||
|
||||
if (ctx.getters.isRemotesLoaded({start, end})) {
|
||||
console.log('range already loaded');
|
||||
return Promise.resolve(ctx.getters.getRangeSource);
|
||||
}
|
||||
|
||||
@ -102,6 +77,7 @@ export default <Module<CalendarRemotesState, State>> {
|
||||
end
|
||||
)
|
||||
.then((remotes: CalendarRemote[]) => {
|
||||
// to be add when reactivity problem will be solve ?
|
||||
//ctx.commit('addRemotes', remotes);
|
||||
const inputs = remotes
|
||||
.map(cr => remoteToFullCalendarEvent(cr))
|
||||
|
@ -19,6 +19,11 @@ export default <Module<LocationState, State>>{
|
||||
currentLocation: null,
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getLocationById: (state) => (id: number): Location|undefined => {
|
||||
return state.locations.find(l => l.id === id);
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setLocations(state, locations): void {
|
||||
state.locations = locations;
|
||||
|
@ -26,7 +26,8 @@
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {defineComponent} from "vue";
|
||||
/*
|
||||
* 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
|
||||
@ -36,20 +37,22 @@
|
||||
* [+] using bootstrap css classes, the modal have a responsive behaviour,
|
||||
* [+] modal design can be configured using css classes (size, scroll)
|
||||
*/
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Modal',
|
||||
props: {
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
required: false
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {},
|
||||
},
|
||||
hideFooter: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['close']
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
Loading…
x
Reference in New Issue
Block a user