mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
adding location to ranges and more control on MyCalendarRanges
This commit is contained in:
parent
809a0a38ab
commit
849e7158e4
@ -15,10 +15,12 @@ use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
|||||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||||
|
use Chill\MainBundle\Entity\Location;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Table(
|
* @ORM\Table(
|
||||||
@ -42,7 +44,8 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||||
* @groups({"read", "write", "calendar:read"})
|
* @Groups({"read", "write", "calendar:read"})
|
||||||
|
* @Assert\NotNull()
|
||||||
*/
|
*/
|
||||||
private ?DateTimeImmutable $endDate = null;
|
private ?DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
@ -50,29 +53,54 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
* @groups({"read"})
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Location::class)
|
||||||
|
* @ORM\JoinColumn(nullable=false)
|
||||||
|
* @Groups({"read", "write", "calendar:read"})
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
private ?Location $location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||||
* @groups({"read", "write", "calendar:read"})
|
* @groups({"read", "write", "calendar:read"})
|
||||||
|
* @Assert\NotNull()
|
||||||
*/
|
*/
|
||||||
private ?DateTimeImmutable $startDate = null;
|
private ?DateTimeImmutable $startDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||||
* @groups({"read", "write", "calendar:read"})
|
* @Groups({"read", "write", "calendar:read"})
|
||||||
|
* @Assert\NotNull()
|
||||||
*/
|
*/
|
||||||
private ?User $user = null;
|
private ?User $user = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Location|null
|
||||||
|
*/
|
||||||
|
public function getLocation(): ?Location
|
||||||
|
{
|
||||||
|
return $this->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Location|null $location
|
||||||
|
*/
|
||||||
|
public function setLocation(?Location $location): void
|
||||||
|
{
|
||||||
|
$this->location = $location;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getCalendar(): ?Calendar
|
public function getCalendar(): ?Calendar
|
||||||
{
|
{
|
||||||
return $this->calendar;
|
return $this->calendar;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Lieu
|
|
||||||
|
|
||||||
public function getEndDate(): ?DateTimeImmutable
|
public function getEndDate(): ?DateTimeImmutable
|
||||||
{
|
{
|
||||||
return $this->endDate;
|
return $this->endDate;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import {EventInput} from '@fullcalendar/vue3';
|
import {EventInput} from '@fullcalendar/vue3';
|
||||||
import {DateTime, User, UserAssociatedInterface} from '../../../ChillMainBundle/Resources/public/types' ;
|
import {DateTime, Location, User, UserAssociatedInterface} from '../../../ChillMainBundle/Resources/public/types' ;
|
||||||
|
|
||||||
export interface CalendarRange {
|
export interface CalendarRange {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
user: User;
|
user: User;
|
||||||
|
location: Location;
|
||||||
createdAt: DateTime;
|
createdAt: DateTime;
|
||||||
createdBy: User;
|
createdBy: User;
|
||||||
updatedAt: DateTime;
|
updatedAt: DateTime;
|
||||||
@ -13,14 +14,16 @@ export interface CalendarRange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeCreate {
|
export interface CalendarRangeCreate {
|
||||||
user: UserAssociatedInterface,
|
user: UserAssociatedInterface;
|
||||||
startDate: DateTime,
|
startDate: DateTime;
|
||||||
endDate: DateTime
|
endDate: DateTime;
|
||||||
|
location: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeEdit {
|
export interface CalendarRangeEdit {
|
||||||
startDate?: DateTime,
|
startDate?: DateTime,
|
||||||
endDate?: DateTime
|
endDate?: DateTime
|
||||||
|
location?: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Calendar {
|
export interface Calendar {
|
||||||
@ -38,6 +41,8 @@ export type EventInputCalendarRange = EventInput & {
|
|||||||
id: string,
|
id: string,
|
||||||
userId: number,
|
userId: number,
|
||||||
calendarRangeId: number,
|
calendarRangeId: number,
|
||||||
|
locationId: number,
|
||||||
|
locationName: string,
|
||||||
start: string,
|
start: string,
|
||||||
end: string,
|
end: string,
|
||||||
is: "range"
|
is: "range"
|
||||||
|
@ -3,22 +3,8 @@ import {datetimeToISO} from '../../../../../ChillMainBundle/Resources/public/chi
|
|||||||
import {User} from '../../../../../ChillMainBundle/Resources/public/types';
|
import {User} from '../../../../../ChillMainBundle/Resources/public/types';
|
||||||
import {CalendarRange, CalendarRemote} from '../../types';
|
import {CalendarRange, CalendarRemote} from '../../types';
|
||||||
|
|
||||||
export const whoami = (): Promise<User> => {
|
// re-export whoami
|
||||||
const url = `/api/1.0/main/whoami.json`;
|
export {whoami} from "../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
||||||
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
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -73,6 +73,8 @@ export const calendarRangeToFullCalendarEvent = (entity: CalendarRange): EventIn
|
|||||||
allDay: false,
|
allDay: false,
|
||||||
userId: entity.user.id,
|
userId: entity.user.id,
|
||||||
calendarRangeId: entity.id,
|
calendarRangeId: entity.id,
|
||||||
|
locationId: entity.location.id,
|
||||||
|
locationName: entity.location.name,
|
||||||
is: 'range',
|
is: 'range',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<template>
|
<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="display-options row justify-content-between">
|
||||||
<div class="col-sm col-xs-12">
|
<div class="col-sm col-xs-12">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
@ -10,15 +15,45 @@
|
|||||||
<option value="00:15:00">15 minutes</option>
|
<option value="00:15:00">15 minutes</option>
|
||||||
<option value="00:30:00">30 minutes</option>
|
<option value="00:30:00">30 minutes</option>
|
||||||
</select>
|
</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>
|
</div>
|
||||||
<div class="col-sm col-xs-12">
|
<div class="col-sm col-xs-12">
|
||||||
<div class="float-end">
|
<div class="float-end">
|
||||||
<div class="input-group mb-3">
|
<div class="form-check form-switch">
|
||||||
<div class="input-group-text">
|
<input id="showHideWE" class="form-check-input mt-0" type="checkbox" v-model="showWeekends">
|
||||||
<input id="showHideWE" class="form-check-input mt-0" type="checkbox" v-model="showWeekends">
|
<label for="showHideWE" class="form-check-label">Week-ends</label>
|
||||||
<label for="showHideWE" class="form-check-label"> Masquer les week-ends</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,7 +62,7 @@
|
|||||||
<template v-slot:eventContent='arg'>
|
<template v-slot:eventContent='arg'>
|
||||||
<span :class="eventClasses(arg.event)">
|
<span :class="eventClasses(arg.event)">
|
||||||
<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 }}</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"
|
||||||
@click.prevent="onClickDelete(arg.event)">
|
@click.prevent="onClickDelete(arg.event)">
|
||||||
@ -71,11 +106,15 @@ import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/inte
|
|||||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||||
import {EventApi, DateSelectArg, EventDropArg} from "@fullcalendar/core";
|
import {EventApi, DateSelectArg, EventDropArg} 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 {Location} from "../../../../../ChillMainBundle/Resources/public/types";
|
||||||
|
|
||||||
const store = useStore(key);
|
const store = useStore(key);
|
||||||
|
|
||||||
const showWeekends = ref(true);
|
const showWeekends = ref(false);
|
||||||
const slotDuration = ref('00:15:00');
|
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 copyFrom = ref<string | null>(null);
|
||||||
const copyTo = ref<string | null>(null);
|
const copyTo = ref<string | null>(null);
|
||||||
|
|
||||||
@ -96,8 +135,6 @@ const baseOptions = ref<CalendarOptions>({
|
|||||||
eventDrop: onEventDropOrResize,
|
eventDrop: onEventDropOrResize,
|
||||||
selectMirror: false,
|
selectMirror: false,
|
||||||
editable: true,
|
editable: true,
|
||||||
slotMinTime: "08:00:00",
|
|
||||||
slotMaxTime: "19:00:00",
|
|
||||||
headerToolbar: {
|
headerToolbar: {
|
||||||
left: 'prev,next today',
|
left: 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
@ -109,6 +146,19 @@ const ranges = computed<EventInput[]>(() => {
|
|||||||
return store.state.calendarRanges.ranges;
|
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
|
* return the show classes for the event
|
||||||
* @param arg
|
* @param arg
|
||||||
@ -143,6 +193,8 @@ const calendarOptions = computed((): CalendarOptions => {
|
|||||||
weekends: showWeekends.value,
|
weekends: showWeekends.value,
|
||||||
slotDuration: slotDuration.value,
|
slotDuration: slotDuration.value,
|
||||||
events: ranges.value,
|
events: ranges.value,
|
||||||
|
slotMinTime: slotMinTime.value,
|
||||||
|
slotMaxTime: slotMaxTime.value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -154,7 +206,13 @@ function onDatesSet(event: DatesSetArg): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onDateSelect(event: DateSelectArg): 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});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,30 +1,22 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import {Store, createStore} from 'vuex';
|
import {Store, createStore} from 'vuex';
|
||||||
import {InjectionKey} from "vue";
|
import {InjectionKey} from "vue";
|
||||||
//import actions from './actions';
|
|
||||||
//import getters from './getters';
|
|
||||||
//import mutations from './mutations';
|
|
||||||
import me, {MeState} from './modules/me';
|
import me, {MeState} from './modules/me';
|
||||||
import fullCalendar, {FullCalendarState} from './modules/fullcalendar';
|
import fullCalendar, {FullCalendarState} from './modules/fullcalendar';
|
||||||
import calendarRanges, {CalendarRangesState} from './modules/calendarRanges';
|
import calendarRanges, {CalendarRangesState} from './modules/calendarRanges';
|
||||||
import calendarRemotes, {CalendarRemotesState} from './modules/calendarRemotes';
|
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 {User} from '../../../../../../ChillMainBundle/Resources/public/types';
|
||||||
|
import locations, {LocationState} from "./modules/location";
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
/*
|
|
||||||
appointments: Calendar[],
|
|
||||||
appointmentsShown: boolean,
|
|
||||||
startDate: Date|null,
|
|
||||||
endDate: Date|null,
|
|
||||||
*/
|
|
||||||
//key: number,
|
|
||||||
calendarRanges: CalendarRangesState,
|
calendarRanges: CalendarRangesState,
|
||||||
calendarRemotes: CalendarRemotesState,
|
calendarRemotes: CalendarRemotesState,
|
||||||
fullCalendar: FullCalendarState,
|
fullCalendar: FullCalendarState,
|
||||||
me: MeState,
|
me: MeState,
|
||||||
|
locations: LocationState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const key: InjectionKey<Store<State>> = Symbol();
|
export const key: InjectionKey<Store<State>> = Symbol();
|
||||||
@ -33,38 +25,20 @@ const futureStore = function(): Promise<Store<State>> {
|
|||||||
return whoami().then((user: User) => {
|
return whoami().then((user: User) => {
|
||||||
const store = createStore<State>({
|
const store = createStore<State>({
|
||||||
strict: debug,
|
strict: debug,
|
||||||
/*
|
|
||||||
state: (): State => ({
|
|
||||||
//key: 0,
|
|
||||||
}),
|
|
||||||
|
|
||||||
*/
|
|
||||||
modules: {
|
modules: {
|
||||||
me,
|
me,
|
||||||
fullCalendar,
|
fullCalendar,
|
||||||
calendarRanges,
|
calendarRanges,
|
||||||
calendarRemotes,
|
calendarRemotes,
|
||||||
|
locations,
|
||||||
},
|
},
|
||||||
mutations: {
|
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.commit('me/setWhoAmi', user, {root: true});
|
||||||
//store.dispatch('calendarRanges/fetchRanges', null, {root: true});
|
store.dispatch('locations/getLocations', null, {root: true}).then(_ => {
|
||||||
|
return store.dispatch('locations/getCurrentLocation', null, {root: true});
|
||||||
|
});
|
||||||
|
|
||||||
return Promise.resolve(store);
|
return Promise.resolve(store);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {State} from './../index';
|
import {State} from './../index';
|
||||||
import {ActionContext, Module} from 'vuex';
|
import {ActionContext, Module} from 'vuex';
|
||||||
import {CalendarRange, CalendarRangeCreate, CalendarRangeEdit, isEventInputCalendarRange} from "../../../../types";
|
import {CalendarRange, CalendarRangeCreate, CalendarRangeEdit, isEventInputCalendarRange} from "../../../../types";
|
||||||
|
import {Location} from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
import {fetchCalendarRangeForUser} from '../../../Calendar/api';
|
import {fetchCalendarRangeForUser} from '../../../Calendar/api';
|
||||||
import {calendarRangeToFullCalendarEvent} from '../../../Calendar/store/utils';
|
import {calendarRangeToFullCalendarEvent} from '../../../Calendar/store/utils';
|
||||||
import {EventInput} from '@fullcalendar/vue3';
|
import {EventInput} from '@fullcalendar/vue3';
|
||||||
@ -89,7 +90,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
},*/
|
},*/
|
||||||
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
||||||
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
||||||
state.ranges.push(asEvent);
|
state.ranges.push({...asEvent, backgroundColor: 'white', borderColor: '#3788d8', textColor: 'black'});
|
||||||
state.rangesIndex.add(asEvent.id);
|
state.rangesIndex.add(asEvent.id);
|
||||||
state.key = state.key + 1;
|
state.key = state.key + 1;
|
||||||
},
|
},
|
||||||
@ -122,17 +123,14 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
fetchRanges(ctx: Context, payload: { start: Date, end: Date }): Promise<null> {
|
fetchRanges(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(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isRangeLoaded({start, end})) {
|
if (ctx.getters.isRangeLoaded({start, end})) {
|
||||||
console.log('range already loaded');
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +149,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
return Promise.resolve(null);
|
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?`;
|
const url = `/api/1.0/calendar/calendar-range.json?`;
|
||||||
|
|
||||||
if (ctx.rootState.me.me === null) {
|
if (ctx.rootState.me.me === null) {
|
||||||
@ -169,6 +167,10 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
endDate: {
|
endDate: {
|
||||||
datetime: datetimeToISO(end)
|
datetime: datetimeToISO(end)
|
||||||
},
|
},
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location"
|
||||||
|
}
|
||||||
} as CalendarRangeCreate;
|
} as CalendarRangeCreate;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeCreate, CalendarRange>('POST', url, body)
|
return makeFetch<CalendarRangeCreate, CalendarRange>('POST', url, body)
|
||||||
@ -179,7 +181,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.error(error);
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
@ -208,7 +210,7 @@ export default <Module<CalendarRangesState, State>>{
|
|||||||
ctx.commit('updateRange', range);
|
ctx.commit('updateRange', range);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.error(error);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
copyFromDayToAnotherDay(ctx, {from, to}: {from: Date, to: Date}): Promise<null> {
|
copyFromDayToAnotherDay(ctx, {from, to}: {from: Date, to: Date}): Promise<null> {
|
||||||
|
@ -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);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Calendar;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20220629095515 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add location on calendar range';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.calendar_range ADD location_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('UPDATE chill_calendar.calendar_range SET location_id = n.min FROM (SELECT min(id) FROM public.chill_main_location) AS n');
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER COLUMN location_id SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.calendar_range ADD CONSTRAINT FK_38D57D0564D218E FOREIGN KEY (location_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('CREATE INDEX IDX_38D57D0564D218E ON chill_calendar.calendar_range (location_id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('alter table chill_calendar.calendar_range DROP COLUMN location_id');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import {fetchResults} from "./apiMethods";
|
||||||
|
import {Location, LocationType} from "../../types";
|
||||||
|
|
||||||
|
export const getLocations = (): Promise<Location[]> => fetchResults('/api/1.0/main/location.json');
|
||||||
|
|
||||||
|
export const getLocationTypes = (): Promise<LocationType[]> => fetchResults('/api/1.0/main/location-type.json');
|
25
src/Bundle/ChillMainBundle/Resources/public/lib/api/user.ts
Normal file
25
src/Bundle/ChillMainBundle/Resources/public/lib/api/user.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {User} from "../../types";
|
||||||
|
import {makeFetch} from "./apiMethods";
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const whereami = (): Promise<Location | null> => {
|
||||||
|
const url = `/api/1.0/main/user-current-location.json`;
|
||||||
|
|
||||||
|
return makeFetch<null, Location|null>("GET", url);
|
||||||
|
}
|
@ -39,3 +39,95 @@ export interface UserAssociatedInterface {
|
|||||||
type: "user";
|
type: "user";
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TranslatableString = {
|
||||||
|
fr?: string;
|
||||||
|
nl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Postcode {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
center: Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Point = {
|
||||||
|
type: "Point";
|
||||||
|
coordinates: [lat: number, lon: number];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Country {
|
||||||
|
id: number;
|
||||||
|
name: TranslatableString;
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Address {
|
||||||
|
type: "address";
|
||||||
|
address_id: number;
|
||||||
|
text: string;
|
||||||
|
street: string;
|
||||||
|
streetNumber: string;
|
||||||
|
postcode: Postcode;
|
||||||
|
country: Country;
|
||||||
|
floor: string | null;
|
||||||
|
corridor: string | null;
|
||||||
|
steps: string | null;
|
||||||
|
flat: string | null;
|
||||||
|
buildingName: string | null;
|
||||||
|
distribution: string | null;
|
||||||
|
extra: string | null;
|
||||||
|
confidential: boolean;
|
||||||
|
lines: string[];
|
||||||
|
addressReference: AddressReference | null;
|
||||||
|
validFrom: DateTime;
|
||||||
|
validTo: DateTime | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressReference {
|
||||||
|
id: number;
|
||||||
|
createdAt: DateTime | null;
|
||||||
|
deletedAt: DateTime | null;
|
||||||
|
municipalityCode: string;
|
||||||
|
point: Point;
|
||||||
|
postcode: Postcode;
|
||||||
|
refId: string;
|
||||||
|
source: string;
|
||||||
|
street: string;
|
||||||
|
streetNumber: string;
|
||||||
|
updatedAt: DateTime | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Location {
|
||||||
|
type: "location";
|
||||||
|
id: number;
|
||||||
|
active: boolean;
|
||||||
|
address: Address | null;
|
||||||
|
availableForUsers: boolean;
|
||||||
|
createdAt: DateTime | null;
|
||||||
|
createdBy: User | null;
|
||||||
|
updatedAt: DateTime | null;
|
||||||
|
updatedBy: User | null;
|
||||||
|
email: string | null
|
||||||
|
name: string;
|
||||||
|
phonenumber1: string | null;
|
||||||
|
phonenumber2: string | null;
|
||||||
|
locationType: LocationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LocationAssociated {
|
||||||
|
type: "location";
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LocationType {
|
||||||
|
type: "location-type";
|
||||||
|
id: number;
|
||||||
|
active: boolean;
|
||||||
|
addressRequired: "optional" | "required";
|
||||||
|
availableForUsers: boolean;
|
||||||
|
editableByUsers: boolean;
|
||||||
|
contactData: "optional" | "required";
|
||||||
|
title: TranslatableString;
|
||||||
|
}
|
||||||
|
14
src/vue-multiselect.d.ts
vendored
Normal file
14
src/vue-multiselect.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
declare module "vue-multiselect" {
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export interface VueMultiselectProps<T> {
|
||||||
|
options: T;
|
||||||
|
searchable: boolean;
|
||||||
|
trackBy: keyof T;
|
||||||
|
label: keyof T;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Component: ReturnType<typeof defineComponent<VueMultiselectProps<T>>>;
|
||||||
|
|
||||||
|
export default Component
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user