import { LightningElement, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import SCHEDULER from '@salesforce/resourceUrl/bryntum_scheduler';
import getListResource from '@salesforce/apex/Scheduler.getListResource';
import getListEvent from '@salesforce/apex/Scheduler.getListEvent';
import getListEventUnplanned from '@salesforce/apex/Scheduler.getListEventUnplanned';
import deleteEvent from '@salesforce/apex/Scheduler.deleteEvent';
import insertEvent from '@salesforce/apex/Scheduler.insertEvent';
import updateEvent from '@salesforce/apex/Scheduler.updateEvent';
export default class Scheduler_component extends LightningElement {
ListResource;
ListEvent;
ListEventNotPlanned;
currentDate = new Date();
scheduler;
UnplannedGrid;
splitter;
Drag;
DomHelper;
DateHelper;
errorUpdate;
eventStore;
me = this;
DH;
today;
start;
center;
animate;
@wire(getListEventUnplanned)
wiredgetListofEventNotPlanned({ error, data })
{
if (data)
{
this.ListEventNotPlanned = JSON.parse(data);
} else if (error) {
console.log(error);
}
}
@wire(getListEvent)
wiredgetListofEvent({ error, data })
{
if (data)
{
this.ListEvent = JSON.parse(data);
} else if (error) {
console.log(error);
}
}
@wire(getListResource)
wiredgetListofResource({ error, data })
{
if (data)
{
this.ListResource = JSON.parse(data);
} else if (error) {
console.log(error);
}
}
renderedCallback() {
if (this.bryntumInitialized) {
return;
}
this.bryntumInitialized = true;
Promise.all([
loadScript(this, SCHEDULER + '/scheduler.lwc.module.js'),
loadStyle(this, SCHEDULER + '/scheduler.stockholm.css'),
])
.then(() => {
this.DH = bryntum.scheduler.DateHelper;
this.today = this.DH.clearTime(new Date());
this.start = this.DH.startOf(this.today, 'week');
this.center = true;
this.animate = 2000;
console.log('this.today:'+this.today);
//Fri Dec 02 2022 00:00:00 GMT+0100 (heure normale d’Europe centrale)
console.log('this.start:'+this.start);
//Sun Nov 27 2022 00:00:00 GMT+0100 (heure normale d’Europe centrale)
this.createScheduler();
this.createSplitter();
this.createGrid(this.ListEventNotPlanned);
console.log('this.scheduler.timeAxis.last.startDate:'+this.scheduler.timeAxis.last.startDate);
//Sat Dec 17 2022 00:00:00 GMT+0100 (heure normale d’Europe centrale)
console.log('this.DH.add(this.today, value, :'+this.DH.add(this.today, 2, 'days'));
//Sun Dec 04 2022 00:00:00 GMT+0100 (heure normale d’Europe centrale)
//this.createDrag();
})
.catch(error => {
console.log('createScheduler:'+error);
this.dispatchEvent(
new ShowToastEvent({
title: "Error loading Bryntum Scheduler",
message: error,
variant: "error"
})
);
});
}
/* createDrag()
{
this.Drag = new bryntum.scheduler.DragHelper (
{
cloneTarget : true,
mode : 'translateXY',
dropTargetSelector : '.b-timeline-subgrid',
targetSelector : '.b-grid-row:not(.b-group-row)',
grid : this.UnplannedGrid,
schedule : this.scheduler,
constrain : false,
outerElement : this.UnplannedGrid.element,
construct(config){
const me = this;
super.construct(config);
console.log('construct config');
me.on({
dragstart : me.onDragStart,
drag : me.onDrag,
drop : me.onDrop,
thisObj : me
});
},
createProxy(element) {
const
proxy = document.createElement('div'),
{ schedule } = this,
task = this.grid.getRecordFromElement(element),
durationInPx = schedule.timeAxisViewModel.getDistanceForDuration(task.duration);
console.log('task.duration:'+task.duration);
console.log('durationInPx:'+durationInPx);
console.log('schedule.isHorizontal:'+schedule.isHorizontal);
// Fake an event bar
proxy.classList.add('b-sch-event-wrap', 'b-sch-event', 'b-unassigned-class', 'b-sch-${schedule.mode}');
proxy.innerHTML = `<div class="b-sch-event b-has-content b-sch-event-withicon">
<div class="b-sch-event-content">
<i class="${task.iconCls}"></i> ${task.name}
</div>
</div>`;
if (schedule.isHorizontal) {
proxy.style.height = `${schedule.rowHeight - (2 * schedule.resourceMargin)}px`;
proxy.style.width = `${durationInPx}px`;
}
else {
proxy.style.height = `${durationInPx}px`;
proxy.style.width = `${schedule.resourceColumnWidth}px`;
}
console.log('proxy.style.width:'+proxy.style.width);
return proxy;
},
onDragStart({ context }) {
const
me = this,
{ schedule } = me,
{ eventTooltip, eventDrag } = schedule.features;
// save a reference to the task so we can access it later
context.task = me.grid.getRecordFromElement(context.grabbed);
// Prevent tooltips from showing while dragging
eventTooltip.disabled = true;
schedule.enableScrollingCloseToEdges(schedule.timeAxisSubGrid);
if (eventDrag.showTooltip && !me.tip) {
me.tip = new Tooltip({
align : 'b-t',
clippedBy : [schedule.timeAxisSubGridElement, schedule.bodyContainer],
forElement : context.element,
cls : 'b-popup b-sch-event-tooltip'
});
}
},
onDrag({ event, context }) {
const
me = this,
{ schedule } = me,
{ task } = context,
coordinate = bryntum.scheduler.DomHelper[`getTranslate${schedule.isHorizontal ? 'X' : 'Y'}`](context.element),
startDate = schedule.getDateFromCoordinate(coordinate, 'round', false),
endDate = startDate && DateHelper.add(startDate, task.duration, task.durationUnit),
// Coordinates required when used in vertical mode, since it does not use actual columns
resource = context.target && schedule.resolveResourceRecord(context.target, [event.offsetX, event.offsetY]);
// Don't allow drops anywhere, only allow drops if the drop is on the timeaxis and on top of a Resource
context.valid = Boolean(startDate && resource) &&
(schedule.allowOverlap || schedule.isDateRangeAvailable(startDate, endDate, null, resource));
// Save reference to resource so we can use it in onTaskDrop
context.resource = resource;
console.log('ondrag');
if (me.tip && context.valid) {
const
dateFormat = schedule.displayDateFormat,
formattedStartDate = DateHelper.format(startDate, dateFormat),
formattedEndDate = DateHelper.format(endDate, dateFormat);
me.tip.html = `
<div class="b-sch-event-title">${task.name}</div>
<div class="b-sch-tooltip-startdate">Starts: ${formattedStartDate}</div>
<div class="b-sch-tooltip-enddate">Ends: ${formattedEndDate}</div>
`;
me.tip.showBy(context.element);
}
else {
me.tip?.hide();
}
},
// Drop callback after a mouse up, take action and transfer the unplanned task to the real EventStore (if it's valid)
onDrop({ context, event }) {
const
me = this,
{ schedule } = me,
{ task, target, resource, valid, element } = context;
me.tip?.hide();
console.log('ondrop');
schedule.disableScrollingCloseToEdges(me.schedule.timeAxisSubGrid);
// If drop was done in a valid location, set the startDate and transfer the task to the Scheduler event store
if (valid && target) {
const
coordinate = bryntum.scheduler.DomHelper[`getTranslate${schedule.isHorizontal ? 'X' : 'Y'}`](element),
date = schedule.getDateFromCoordinate(coordinate, 'round', false),
// Try resolving event record from target element, to determine if drop was on another event
targetEventRecord = schedule.resolveEventRecord(target);
if (date) {
// Remove from grid first so that the data change
// below does not fire events into the grid.
me.grid.store.remove(task);
task.startDate = date;
task.assign(resource);
schedule.eventStore.add(task);
}
// Dropped on a scheduled event, display toast
if (targetEventRecord) {
WidgetHelper.toast(`Dropped on ${targetEventRecord.name}`);
}
}
if (resource) {
resource.cls = '';
}
schedule.features.eventTooltip.disabled = false;
},
onDragAbort() {
this.tip?.hide();
}
},
);
}
*/
createSplitter() {
this.splitter = new bryntum.scheduler.Splitter({
appendTo : this.template.querySelector('.main')
});
}
createScheduler() {
this.scheduler = window.scheduler = new bryntum.scheduler.Scheduler({
features: {
eventDrag : {
triggerEvent : 'eventClick',
validatorFn({ draggedRecords, event }) {
console.log('freddy');
return true;
},
},
resourceTimeRanges: true,
nonWorkingTime : true,
dependencies: false,
timeRanges: {
showHeaderElements: true,
showCurrentTimeLine: true
},
eventEdit: {
editorConfig : {
bbar : {
items : {
deleteButton : null
}
}
},
triggerEvent : 'eventClick',
extraWidgets: [
{
type: 'text',
name: 'WOnumber',
label: 'Number Work Order',
typeAhead: true,
forceSelection: true,
editor: false,
selectOnFocus: true,
readOnly: true,
}
]
},
stripe : true,
timeRanges : true,
eventMenu : {
items : {
unassign : {
text : 'Unassign',
icon : 'b-fa b-fa-user-times',
weight : 200,
onItem : ({ eventRecord, resourceRecord }) => eventRecord.unassign(resourceRecord)
},
deleteEvent : false,
copyEvent : false,
cutEvent : false
}
},
scheduleMenu : {
items : {
// Remove "Add event" default item
addEvent : false
}
},
},
insertFirst: this.template.querySelector('.main'),
rowHeight: 50,
barMargin: 8,
columns: [
{
text: 'Salariés',
width: 150,
field: 'name',
}
],
startDate : this.DH.add(this.start, -2, 'weeks'),
endDate : this.DH.add(this.start, 3, 'weeks'),
viewPreset : 'dayAndWeek',
eventRenderer({ eventRecord, resourceRecord, renderData }) {
renderData.eventColor = 'indigo';
return bryntum.scheduler.StringHelper.encodeHtml(eventRecord.name);
},
resourceStore: new bryntum.scheduler.ResourceStore({
data: this.ListResource
}),
eventStore: new bryntum.scheduler.EventStore({
data: this.ListEvent,
listeners: {
beforeUpdate: (event) => {
},
update: (event) => {
this.onEventUpdate(event);
},
}
}),
tbar : [
//'',
//'->',
//{ type : 'viewpresetcombo' },
{
type : 'dropdown',
ref : 'scrollToTime',
placeholder : 'Scroll to time',
editable : false,
items : [
[0, 'Today'],
[2, '2 days from now'],
[10, '10 days from now'],
[-1, `Last day in view`]
],
onAction : ({ value }) => {
this.scheduler.scrollToDate(
value === -1 ? this.scheduler.timeAxis.last.startDate : this.DH.add(this.today, value, 'days'),
{
highlight,
animate : {
easing : 'easeFromTo',
duration : this.animate
},
block : this.center ? 'center' : 'nearest'
}
);
}
},
],
listeners: {
beforeEventAdd: (event) => {
return false;
},
afterEventDrop: (event) => {
console.log('afterEventDrop');
},
}
});
}
deleteEventJS(IdVisite, payload)
{
//delete event
deleteEvent({
IdVisite: IdVisite,
payload: payload
})
.then(result =>
{
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: "Erreur",
message: error.body.message,
variant: "error"
})
);
})
}
insertEventJS(IdVisite, payload)
{
//insert event
insertEvent({
IdVisite: IdVisite,
payload: payload
})
.then(result =>
{
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: "Erreur",
message: error.body.message,
variant: "error"
})
);
})
}
onEventUpdate(event)
{
let record = event.record;
//{"id":"a105r000001GRQPAA4","startDate":"2022-11-22T06:15:00+01:00","endDate":"2022-11-22T17:15:00+01:00","duration":0.4583333333333333,"durationUnit":"day","cls":"","name":"VI-000002","exceptionDates":[],"resourceId":"a0X5r000006HmeoEAC","allDay":false}
let changes = event.changes;
//{"recurrenceCombo":{"value":"none"},"startDate":{"value":"2022-11-22T05:15:00.000Z","oldValue":"2022-11-22T05:30:00.000Z"},"endDate":{"value":"2022-11-22T16:15:00.000Z","oldValue":"2022-11-22T16:30:00.000Z"}}
//event's employee is update => delete event and create new
if(JSON.stringify(changes).includes('resourceId'))
{
//delete event
this.deleteEventJS(record.id, JSON.stringify(changes));
//insert event
if(changes.resourceId.value != null)
{
this.insertEventJS(record.id, JSON.stringify(changes));
}
else
{
const totalMinutes = record.duration*24*60;
const minutes = totalMinutes % 60;
const hours = Math.floor(totalMinutes / 60);
const clocktime = hours+':'+minutes;
let task = new bryntum.scheduler.Model(
{
name : record.name,
id : record.id,
duration : clocktime,
start : record.startDate,
finish : record.endDate
}
);
this.UnplannedGrid.store.add(task);
}
}
else //data update except employee
{
this.updateEventJS(record.id, JSON.stringify(changes), record, changes);
}
}
updateEventJS(IdVisite, jsonChanges, record, changes)
{
//update event
updateEvent({
IdVisite: IdVisite,
payload: jsonChanges
})
.then(result =>
{
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: "Erreur",
message: error.body.message,
variant: "error"
})
);
var oldStartDate;
if(JSON.stringify(changes).includes('startDate'))
{
oldStartDate = changes.startDate.oldValue;
}
var oldEndDate;
if(JSON.stringify(changes).includes('endDate'))
{
oldEndDate = changes.endDate.oldValue;
}
if(oldStartDate != undefined)
{
record.startDate = oldStartDate;
}
if(oldEndDate != undefined)
{
record.endDate = oldEndDate;
}
})
}
createGrid(ListEventNotPlanned) {
this.UnplannedGrid = new bryntum.scheduler.Grid({
features: {
rowReorder: true,
search: true
},
title : 'Visites non planifiées',
appendTo : this.template.querySelector('.main'),
collapsible : true,
store : {
fields : [
{ name : 'start', type : 'date' }
],
data : ListEventNotPlanned,
},
columns:[
{ type: 'rownumber' },
{
text: 'Visite',
field: 'name',
flex: 1,
type: 'template',
template: (data) => `${data.record.data.name}`,
},
{
text: 'Date',
field: 'start',
flex: 1,
type: 'date',
format: 'DD/MM/YYYY',
},
{ text: 'Durée', field: 'duration', flex: 1, type: 'time', format: 'HH:mm' },
]
});
}
}