/* globals bryntum : true */
import { LightningElement, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import SCHEDULER from '@salesforce/resourceUrl/bryntum_scheduler';
import {dependencies, events, resources} from './data';
import getListResource from '@salesforce/apex/Scheduler.getListResource';
import getListEvent from '@salesforce/apex/Scheduler.getListEvent';
import getListEventUnplanned from '@salesforce/apex/Scheduler.getListEventUnplanned';
//import { columns, data } from './data';
export default class Scheduler_component extends LightningElement {
ListResource;
ListEvent;
ListEventNotPlanned;
currentDate = new Date();
scheduler;
UnplannedGrid;
splitter;
Drag;
DomHelper;
DateHelper;
me = this;
@wire(getListEventUnplanned)
wiredgetListofEventNotPlanned({ error, data })
{
if (data)
{
this.ListEventNotPlanned = JSON.parse(data);
//console.log('this.ListEventNotPlanned JSON:'+JSON.stringify(this.ListEventNotPlanned));
} else if (error) {
console.log(error);
}
}
@wire(getListEvent)
wiredgetListofEvent({ error, data })
{
if (data)
{
this.ListEvent = JSON.parse(data);
//console.log('this.ListEvent JSON:'+JSON.stringify(this.ListEvent));
} else if (error) {
console.log(error);
}
}
@wire(getListResource)
wiredgetListofResource({ error, data })
{
if (data)
{
this.ListResource = JSON.parse(data);
//console.log('this.ListResource JSON:'+JSON.stringify(this.ListResource));
} 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(() => {
bryntum.scheduler.DomHelper.supportsTemplate = false;
var DH = bryntum.scheduler.DateHelper,
date = DH.clearTime(new Date());
console.log('date :'+date);
this.createScheduler();
this.createSplitter();
this.createGrid(this.ListEventNotPlanned);
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')
});
//console.log('this.splitter :'+this.splitter);
}
createScheduler() {
this.scheduler = window.scheduler = new bryntum.scheduler.Scheduler({
features: {
resourceTimeRanges: true,
nonWorkingTime : true,
timeRanges: {
showHeaderElements: true,
showCurrentTimeLine: true
},
eventEdit: {
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)
}
}
}
},
insertFirst: this.template.querySelector('.main'),
rowHeight: 50,
barMargin: 8,
columns: [
{
text: 'Salariés',
width: 150,
field: 'name',
}
],
startDate: new Date(this.currentDate.getFullYear(),this.currentDate.getMonth(),this.currentDate.getDate()-1),
endDate: new Date(this.currentDate.getFullYear(),this.currentDate.getMonth(),this.currentDate.getDate()+1),
viewPreset : {
base: 'hourAndDay',
tickWidth: 25,
columnLinesFor: 0,
headers: [
{
unit: 'd',
align: 'center',
dateFormat: 'ddd DD MMM'
},
{
unit: 'h',
align: 'center',
dateFormat: 'HH'
}
]
},
eventRenderer({ eventRecord, resourceRecord, renderData }) {
const bgColor = resourceRecord.bg || '';
renderData.style = `background:${bgColor};border-color:${bgColor};color:${resourceRecord.textColor}`;
renderData.iconCls.add('b-fa', `b-fa-${resourceRecord.icon}`);
return eventRecord.name;
},
resourceStore: new bryntum.scheduler.ResourceStore({
data: this.ListResource
}),
eventStore: new bryntum.scheduler.EventStore({
data: this.ListEvent
}),
dependencyStore: new bryntum.scheduler.DependencyStore({
data: dependencies
}),
tbar : [
//'Schedule view',
'',
'->',
{ type : 'viewpresetcombo' },
/*{
type : 'button',
toggleable : true,
icon : 'b-fa-calendar',
pressedIcon : 'b-fa-calendar-check',
text : 'Automatic rescheduling',
tooltip : 'Toggles whether to automatically reschedule overlapping tasks',
cls : 'reschedule-button',
onToggle({ pressed }) {
schedule.autoRescheduleTasks = pressed;
}
},*/
/*{
type : 'buttonGroup',
toggleGroup : true,
items : [
{
icon : 'b-fa-fw b-fa-arrows-alt-v',
pressed : 'up.isVertical',
tooltip : 'Vertical mode',
schedulerConfig : {
mode : 'vertical',
subGridConfigs : {
locked : {
minWidth : 100,
flex : null
}
}
}
},
{
icon : 'b-fa-fw b-fa-arrows-alt-h',
pressed : 'up.isHorizontal',
tooltip : 'Horizontal mode',
schedulerConfig : {
mode : 'horizontal'
}
}
],
onAction({ source : button }) {
const newConfig = { ...schedule.initialConfig, ...button.schedulerConfig };
// Recreate the scheduler to switch orientation
schedule.destroy();
schedule = new Schedule(newConfig);
// Provide drag helper a reference to the new instance
drag.schedule = schedule;
}
}*/
]
});
//console.log('this.scheduler :'+this.scheduler);
}
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' },
]
});
}
}