Our pure JavaScript Scheduler component


Post by jqueija »

Hi, I'm building a scheduler using scheduler pro and I'd like to work out the avatars that exists automatically generated by the scheduler at the moment. I couldn't find a way to work with the avatar content (please see attached picture of my current scheduler and situation). I'm using React/Redux.

My idea would be to be able to do a couple of things when it comes to the avatars, being these:

1 - Change the avatar background color depending on the second column (resource types "tipo de recurso)), so as marked up for example if it is a "Persona" the avatar background would be yellow and if it is "equipos" it would be red.

2 - Id like to be able (if possible), to modify the avatar content by being able to use initials (that I could for example get by extracting the first letter from the name only), or maybe use a photo, etc etc. I'm seeing examples with photos but taken from the server and don't know how to do it locally here plus I need to be able to connect each photo with its staff id.

Would you please be so kind to shed some light on this matter? (a code example would be ideal and exactly what I need). I'm attaching a capture for you to see where I am at.

I look forward to hearing from you,

Attachments
Capture01.PNG
Capture01.PNG (53.73 KiB) Viewed 1817 times

Post by alex.l »

Please check https://bryntum.com/docs/scheduler-pro/#Scheduler/column/ResourceInfoColumn

Displays basic resource information. Defaults to showing an image + name + event count (all configurable).

If a resource has no image, you can either provide an icon using iconCls in the data (you then need to specify image === false in your data) or the resource initials will be shown.

Be sure to specify resourceImagePath to instruct the column where to look for the images.

If a image fails to load or if a resource lacks an image, the resource name initials will be rendered. If the resource has an eventColor specified, it will be used as the background color of the initials.

https://bryntum.com/docs/scheduler-pro/#Scheduler/view/mixin/SchedulerEventRendering#config-resourceImagePath

All the best,
Alex


Post by jqueija »

Hi Alex, thank you for your response but this answer none of my questions. I'd appreciate if you could elaborate a bit more than what I've already read on your website documentation and following my original enquiry. A code example would be necessary I guess... is this possible to obtain? I am paying for a full scheduler pro license.

I look forward to hearing from you,

Regards


Post by alex.l »

1 - Change the avatar background color depending on the second column (resource types "tipo de recurso)), so as marked up for example if it is a "Persona" the avatar background would be yellow and if it is "equipos" it would be red.

A background color for initials will be taken from resourceRecord.eventColor field. Initials itself will be taken from resourceRecord.initials. It is not configurable now, so please provide the bg color in that field to make it work. You could also try to play with https://bryntum.com/docs/gantt/#Grid/column/Column#config-cellCls , apply custom CSS and override backgroundColor for an avatar initials element.

2 - Id like to be able (if possible), to modify the avatar content by being able to use initials (that I could for example get by extracting the first letter from the name only), or maybe use a photo, etc etc.

if resourceImagePath specified, first of all it will try to find an image file there. If no image, it'll check if resourceRecord.iconCls is provided to use it. If no luck, it'll generate initials icon, using resourceRecord.eventColor and resourceRecord.initials configs.

I'm seeing examples with photos but taken from the server and don't know how to do it locally here plus I need to be able to connect each photo with its staff id.

Just determine https://bryntum.com/docs/scheduler-pro/#Scheduler/view/mixin/SchedulerEventRendering#config-resourceImagePath
Path to load resource images from. Used by the resource header in vertical mode and the ResourceInfoColumn in horizontal mode. Set this to display miniature images for each resource using their image or imageUrl fields.

image represents image name inside the specified resourceImagePath,
imageUrl represents fully qualified image URL.
If set and a resource has no imageUrl or image specified it will try show miniature using the resource's name with resourceImageExtension appended.

NOTE: The path should end with a /:

new Scheduler({
  resourceImagePath : 'images/resources/'
});

Examples:
Basic here: https://www.bryntum.com/examples/scheduler-pro/constraints/
React here: https://www.bryntum.com/examples/scheduler-pro/frameworks/react/javascript/resource-histogram/build/index.html

All the best,
Alex


Post by jqueija »

Hi Alex, thanks very much for your info, can I please ask you where to get more information on the resourceRecord configurations and how to access them? I've tried to trace it throughout the docs but couldn't find anything. I'd need to alterate the original initials settings to be able to pick up all names and surnames and also I'm getting some names without the correct initial (inspecting with google console I'm getting that is not picking up the name for some reason).

Thanks once again for your assistance,


Post by mats »

Here are the docs: https://bryntum.com/docs/scheduler/#Scheduler/model/ResourceModel

Check the Fields section for the available fields.


Post by jqueija »

Hi mats, thanks for your reply,

I'm sorry but I'm still not able to locate and/or get a hold of what alex told me, and I qoute what he said:

"if resourceImagePath specified, first of all it will try to find an image file there. If no image, it'll check if resourceRecord.iconCls is provided to use it. If no luck, it'll generate initials icon, using resourceRecord.eventColor and resourceRecord.initials configs."

I'm not seeing any "initials" prop that I can tweak or adapt to my current names. Also I'm attaching a capture for you to see what is happening. Also I see on the other rows it only takes the first letter of the first and last name and I need it to show avery first letter of every word since our customers have mutliple names/surnames. This last thing I can do it with Javascript but I need to know where to access to modifiy this manually if possible.

I feel like I really need a code example of this. I already went through the docs but this seems to be not really well explained when it comes to avatars and how to handle/customize them. There's just to little information in my opinion. Is there any demo example in React that you could provide me that it is not on your examples (the ones in the web, I already went through those also but there is none in which initials are customized inside an avatar).

Thanks in advance for whatever help you can provide.

Attachments
Capture02.PNG
Capture02.PNG (42.87 KiB) Viewed 1799 times

Post by mats »

Can you please provide the data you load into the resource store? We'll make the 'initials' getter public in the next release, you can already subclass our ResourceModel and override it to implement it as you please.

class MyResource extends ResourceModel {
    get initials() { return 'foo'; }
}

Post by jqueija »

Hi mats, I'm leaving you here how my appConfiguration, (I called it schedulerConfiguration), the way is being written so far. The resource prop is loading data that is obtained from an endpoint from one of our API's. This results are being stored in a local state called "schedulerResourcesResults" to which I am applying a map method. (the reason from the local state it is because of some treatement that I need to give to this values so they show properly. I am also attaching a sample of how this data looks in a new capture and a line indicating where is being inserted to). The events are still mocked up from the original example but taking the ids so they work with the resources I am applying to them.

const schedulerConfig = !!schedulerResources && {
        eventStyle: 'colored',
        eventColor: null,
        resourceImagePath: null,
        columns: [
            {
                type: 'resourceInfo',
                text: onTranslation(language.id, fieldsPage, "resourceList_filter_orderBy_name", scenario.id),
                width: '11.5rem',
                editor: false
            },
            {
                text: onTranslation(language.id, fieldsPage, "resourceList_filter_orderBy_resourceType", scenario.id),
                field: 'resourceTypeId',
                align: 'center',
                width: '8rem',
                editor: false
            },
            {
                width: '1rem',
                type: 'widget',
                widgets: [{
                    cls: 'b-transparent',
                    type: 'button',
                    icon: 'b-fa b-fa-fw b-fa-ellipsis-v',
                    onAction: ({ source: btn }) => {
                        const menu = btn.menu || (btn.menu = new Menu({
                            cls: 'b-transparent',
                            forElement: btn.element,
                            items: [
                                {
                                    cls: 'b-transparent',
                                    text: 'Show team members',
                                    onItem({ item }) {
                                        console.log('showing team members', item);
                                    }
                                }
                            ],
                            focusOnHover: false,
                        }));
                        menu.show();
                    }
                }]
            },
        ],
        filterBarFeature: true,
        stripeFeature: true,
        timeRangesFeature: true,
        eventEditFeature: {
            items: {
                locationField: {
                    type: 'text',
                    name: 'location',
                    label: 'Location',
                    dataset: { eventType: 'Meeting' },
                    weight: 200
                }
            }
        },

    barMargin: 5,
    rowHeight: 40,
    startDate: new Date(2017, 1, 7, 8), // year, monthIndex (starts with 0), day, hours
    endDate: new Date(2017, 1, 7, 19),
    viewPreset: 'hourAndDay',
    resources: schedulerResourcesResults.map(sr => (sr)),
    events: [
        {
            resourceId: 3132,
            name: "Make marketing plan",
            startDate: "2017-02-07 11:00",
            endDate: "2017-02-07 14:00"
        },
        {
            resourceId: 3131,
            name: "Read spec.",
            startDate: "2017-02-07 12:00",
            endDate: "2017-02-07 15:00"
        },
        {
            resourceId: 3126,
            name: "Sign documents",
            startDate: "2017-02-07 13:00",
            endDate: "2017-02-07 16:00"
        },
        {
            resourceId: 2705,
            name: "Board meeting",
            startDate: "2017-02-07 09:00",
            endDate: "2017-02-07 11:00"
        },
        {
            resourceId: 3147,
            name: "Sales call",
            startDate: "2017-02-07 10:00",
            endDate: "2017-02-07 12:00"
        },
        {
            resourceId: 3155,
            name: "Customer visit",
            startDate: "2017-02-07 11:00",
            endDate: "2017-02-07 13:00",
            location: "Customer office"
        },
        {
            resourceId: 3118,
            name: "Prepare happy hour",
            startDate: "2017-02-07 14:00",
            endDate: "2017-02-07 17:00"
        },
        {
            resourceId: 3116,
            name: "Sales call",
            startDate: "2017-02-07 14:00",
            endDate: "2017-02-07 17:00"
        }
    ],
    tbar: [
        {
            type: 'button',
            cls: 'b-transparent',
            icon: 'b-fa-search',
            align: 'left',
            onClick: (e) => handleOnOpenResourcesSchedulerSearchPopup()
        },
        {
            type: 'button',
            cls: 'b-transparent',
            icon: 'b-fa-trash',
            align: 'left',
            onClick: (e) => handleClearClick()
        },
    ],

    // Specialized body template with header and footer
    eventBodyTemplate: data => `
    <div class="b-sch-event-header">${data.headerText}</div>
    <div class="b-sch-event-footer">${data.footerText}</div>
    `,

    eventRenderer({ eventRecord, resourceRecord, renderData }) {
        renderData.style = 'background-color:' + resourceRecord.color;
        return {
            headerText: DateHelper.format(eventRecord.startDate, this.displayDateFormat),
            footerText: eventRecord.name || ''
        };
    },
};

Another thing worth to be mentioned is that we do not work with classes in React, but with hooks so an example in hooks would be what I need please if you don't mind (this is regarding your piece of code example).

Thanks once again and I look forward to hearing from you,

Attachments
Capture04.PNG
Capture04.PNG (146.5 KiB) Viewed 1793 times

Post by sergey.maltsev »

Hi!

Subclassing of resource model is not actually related to React things/hooks so it should be made in the unit where you configure schedulerConfig. So this is just a config for underlaying Bryntum JS Scheduler.

Basics of sublassing can be found here https://www.bryntum.com/docs/scheduler/#Scheduler/guides/data/displayingdata.md#defining-additional-fields check Custom Model

This is simple example to override initials() method for ResourceModel. This should return first two letters of the resource name for initials, but you may use any other return value:

class MyResource extends ResourceModel {
    get initials() {
        return this.name.substring(0, 2);
    }
}

Then we will use this new MyResource class as https://www.bryntum.com/docs/scheduler/#Core/data/Store#config-modelClass for
https://www.bryntum.com/docs/scheduler/#Scheduler/view/Scheduler#config-resourceStore config.

const
    schedulerConfig = {
        columns : [
            {
                text  : 'Name',
                field : 'name',
                width : 100
            },
            {
                type   : 'resourceInfo',
                width  : '11.5rem',
                editor : false
            }
        ],
        resourceStore : {
            data       : getResources(),   // <--------- your method for loading resources
            modelClass : MyResource   // <--------- class override 
        },
       ...
    },

Hope this would help you to replace initials for resources.


Post Reply