Hello mats, sorry I can't attach full files here as it have some credentials and keys stored, I'm sharing both config and scheduler file then:
import moment from 'moment'
import TaskStore from '~/scheduler-2.2.5/lib/TaskStore'
const tickWidth = 25
export default {
columns: [
{
text: 'Driver / Vehicle Type',
field: 'name',
width: 200,
editor: false,
htmlEncode: false,
headerMenuItems: [
{
text: 'My unique header item',
icon: 'fa fa-flask',
onItem : () => function() {
console.log('Edit')
}
}
],
renderer: function({ value, record }) {
if( record.id == 'temporary-row' ) {
return 'Unassigned'
}
return `
<div class="react-resource">
${record.urlPicture ? `<img class="react-resource__picture" src="${record.urlPicture}" alt="${value}" title="${value}" loading="lazy" />` : '' }
<div class="grid-resource-vehicle__text">
${record.vehicleName ? record.vehicleName : '' }
<small>${record.vehicleType ? record.vehicleType : '' }</small>
</div>
</div>`;
},
sortable: function(user1, user2) {
return user1.name < user2.name ? -1 : 1;
},
filterable: {
filterFn : function({ record, value }) {
const vehicleName = record.vehicleName ? record.vehicleName.toLowerCase() : ''
const vehicleType = record.vehicleType ? record.vehicleType.toLowerCase() : ''
const searchValue = value.toLowerCase()
if( record.id == 'temporary-row' ) {
return true
}
console.log('Search', searchValue, record.name.toLowerCase(), vehicleName, vehicleType)
return (record.name.toLowerCase().indexOf(searchValue) !== -1) || (vehicleName.indexOf(searchValue) !== -1) || (vehicleType.indexOf(searchValue) !== -1)
},
filterField : {
emptyText : 'Filter by driver or vehicle'
}
}
}
],
viewPreset: {
name: 'hourAndDay',
tickWidth: tickWidth,
columnLinesFor: 'top',
timeResolution: { // Dates will be snapped to this resolution
unit: 'minute', // Valid values are 'millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'.
increment: 5
},
headerConfig: {
top: {
unit: 'd',
align: 'center',
dateFormat: 'ddd DD MMM'
},
middle: {
unit: 'h',
align: 'center',
dateFormat: 'HH'
},
bottom: {
unit: 'm',
align: 'left',
dateFormat: 'mm',
increment: 15
}
}
},
features: {
filterBar : true,
stripe: true,
resourceTimeRanges: true,
eventContextMenu: {
processItems({eventRecord, items}) {
items.editEvent.text = 'Edit ride'
//console.log(items)
// Do not show menu for secret events
if (eventRecord.editable === false) {
return false;
}
},
items: {
deleteEvent : false,
// custom item with inline handler
unassign: {
text: 'Unassign',
icon: 'b-fa b-fa-user-times',
weight: 200,
onItem: ({ source, eventRecord, resourceRecord }) => {
//console.log('Unassign source', source)
eventRecord.unassign(resourceRecord)
}
},
resetTime: {
text: 'Reset time & duration',
icon: 'b-fa b-fa-clock',
weight: 200,
onItem: ({ eventRecord }) => {
//console.log('Unassign source', source)
eventRecord.startDate = eventRecord.originalStartDate
eventRecord.duration = eventRecord.originalDuration
}
},
booking: {
text: 'Booking editor',
icon: 'b-fa b-fa-book',
weight: 200,
onItem: (data) => {
//alert('Booking')
//console.log(data)
//this.$emit('openBookingEditor')
}
}
}
},
eventEdit: {
showDeleteButton: false,
showNameField: false,
/*startDateConfig: {
min: '2019-10-15',
max: '2019-10-18'
},
endDateConfig: {
min: '2019-10-15',
max: '2019-10-18'
},*/
/*extraItems: [
{
type : 'combo',
ref : 'roomCombo',
items : [],
name : 'vehicleId',
label : 'Vehicle',
placeholder : 'Select vehicle...',
index : 2,
//editable : false,
clearable : false,
//listItemTpl: item => `<div>${item.name} - ${item.vehicleType}</div>`
}
]*/
},
eventDrop: {
validatorFn: function (context) {
console.log('drop!')
}
},
eventDrag: {
validatorFn: function (context) {
const task = context.draggedRecords[0]
// const newResource = context.newResource
const startLimit = moment(task.originalStartDate).subtract(15, 'minutes')
const endLimit = moment(task.originalStartDate).add(60, 'minutes')
// Ride can only be dragged 15min earlier or 60min later
const currentTime = moment(context.startDate)
if (currentTime.isBefore(startLimit)) {
return {
valid: false,
message: "Start time can't be moved more than 15min before"
}
}
if (currentTime.isAfter(endLimit)) {
return {
valid: false,
message: "Start time can't be moved more than 60min after"
}
}
return {
valid: true
}
}
},
eventResize: {
validatorFn: function (context) {
const task = context.eventRecord
const startDate = moment(context.startDate)
const endDate = moment(context.endDate)
//const originalDuration = task.endDate - task.originalStartDate
const startLimit = moment(task.originalStartDate).subtract(0, 'minutes')
const currentTime = moment(context.startDate)
if (currentTime.isBefore(startLimit)) {
return {
valid: false,
message: "Can't resize from start"
}
}
// Duration can't be larger than the double of the time
if ((task.originalDuration * 2) < endDate.diff(startDate, 'seconds')) {
return {
valid: false,
message: "The duration of a ride can't be more than the double of original duration"
}
}
return {
valid: true
}
}
}
},
crudManager: {
resourceStore: {
// Add some custom fields
fields: ['driverId', 'vehicleId','vehicleName', 'vehicleType', 'urlPicture', 'latitude', 'longitude']
},
eventStore: {
storeClass: TaskStore
},
// autoLoad: true,
transport: {
load: {
requestConfig: {
// url: null,
url: '####',
method: 'GET',
disableCaching: false,
autoLoad : false,
headers: {
Authorization: null
},
fetchOptions: {
credentials: 'omit'
}
}
}
},
listeners: {
// Will be called after data is fetched but before it is loaded into stores
beforeLoadApply({ response }) {
// console.log('Response!', response)
//response.events.rows = FakeData.events.rows
response.resources.rows.unshift({
id: 'temporary-row',
name: 'Temporary',
cls: 'b-grid-row--temporary'
});
response.resources.rows.forEach(function (driver) {
driver.driverId = driver.id
driver.id = `${driver.id}--${driver.vehicleId}`
})
// Set necessary fields
response.events.rows.forEach(function (ride) {
//console.log('Ride start before', ride.start, ride)
ride.startDate = moment(ride.start).format('YYYY-MM-DD HH:mm')
//console.log('Ride start after', ride.startDate)
//ride.endDate = moment(ride.endDate).format('YYYY-MM-DD hh:mm')
ride.resourceId = `${ride.driverAssigned}--${ride.vehicleAssigned}`
ride.originalStartDate = ride.startDate
ride.originalDuration = ride.duration
ride.durationUnit = 's'
//ride.transportTime = 1800
if(!ride.editable) {
ride.draggable = false;
ride.resizable = false;
}
if(ride.staged) {
ride.resourceId = 'temporary-row'
}
})
// console.log('Response after', response.events.rows)
// this.columns[1].editor.items = response.vehicles.rows
// Turn "nested event" dates into actual dates, to not have to process them each time during render
// response.events.rows.forEach(event => refreshAgendaOffsets(event))
//console.log(response.timeRanges.rows[0])
/*response.timeRanges.rows.forEach(function (item) {
item.startDate = moment(item.startDate).format('YYYY-MM-DD hh:mm')
item.endDate = moment(item.endDate).format('YYYY-MM-DD hh:mm')
})*/
//console.log('TimeRanges', response)
},
}
},
listeners: {
finishCellEdit({ editorContext }) {
// Update resource record after selecting another vehicle
if (editorContext.column.field == 'vehicleId') {
var vehicles = editorContext.editor._inputField._store._data
const newVehicle = vehicles.find(function (item) {
return item.data.id === editorContext.value
})
editorContext.record.set('vehicleName', newVehicle.name)
editorContext.record.set('vehicleType', newVehicle.vehicleType)
}
}
},
onCellClick(context) {
//alert('hola')
},
// eventBodyTemplate is used to render markup inside an event. It is populated using data from eventRenderer()
eventBodyTemplate: function (event) {
/*var startTime = moment(event.startDate)
var originalStartTime = moment(event.originalStartDate)
var startTimeOffset = startTime.diff(originalStartTime, 'minutes');*/
return `
<div class="event-icon event-icon--transport" style="width:${event.transportWidth}px; left:-${event.transportWidth}px"></div>
<div class="event-text">
${event.ride.name}
<small>${event.pax}pax</small>
</div>
<div class="event-icon event-icon--security" style="width:${event.securityWidth}px"></div>`
},
// eventRenderer is here used to translate the dates of nested events into pixels, passed on to the eventBodyTemplate
eventRenderer({ eventRecord, tplData }) {
// getCoordinateFromDate gives us a px value in time axis, subtract events left from it to be within the event
// const dateToPx = date => this.getCoordinateFromDate(date) - tplData.left
return {
ride: eventRecord,
transportWidth: Math.round(eventRecord.approachDuration*0.02777),
securityWidth: Math.round(eventRecord.coolDownTime*0.02777),
pax: 4
}
/*
// Calculate coordinates for all nested events and put in an array passed on to eventBodyTemplate
return (eventRecord.agenda || [eventRecord]).map(nestedEvent => ({
left: dateToPx(DateHelper.add(eventRecord.startDate, nestedEvent.startOffset)),
width: dateToPx(DateHelper.add(eventRecord.startDate, nestedEvent.endOffset)),
name: nestedEvent.name,
cls: nestedEvent.cls,
type: nestedEvent.type
})) */
},
// taken from the original example
onEquipmentStoreLoad({ source: store }) {
// Save vehicles from store to dropdown editor
this.columns.get('vehicleId').editor.items = store.getRange()
this.eventEdit.extraItems[0].items = store.getRange()
// console.log('Hello from store!', this.columns.get('vehicleId').editor.items)
// Setup the data for the equipment combo inside the event editor
// const equipmentCombo = this.features.eventEdit.getEditor().query(item => item.name === 'equipment')
// equipmentCombo.items = store.getRange()
// this._equipmentStore = store
// Since the event bars contain icons for equipment, we need to refresh rows once equipment store is available
// this.refreshRows()
}
}