Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React big calendar, add bootstrap popover to event?

Looks like you can create custom components for the react calendar component. I was looking at this example:

https://github.com/intljusticemission/react-big-calendar/blob/master/examples/demos/customView.js.

But it isn't clear how to create a custom event component. I'm also looked through the documentation, but there are no explicit examples:

http://intljusticemission.github.io/react-big-calendar/examples/index.html#prop-components

I'm particularly interested in creating a tooltip for each event that shows a more detailed event description.

Can anyone point to an example of where someone has created a custom component for react-big-calendar?

UPDATE: Here is an image of the calendar and some events rendered in the month view. I'm thinking, a custom event should definitely include the 'rbc-event' and 'rbc-event-content'. To add the bootstrap tool tip I'm thinking something like this in the custom event component:

enter image description here

And here is where the event cell component is created in the react-big-calendar source code.

    return _react2.default.createElement(
              'div',
              _extends({}, props, {
                style: _extends({}, props.style, style),
                className: (0, _classnames2.default)('rbc-event', className, xClassName, {
                  'rbc-selected': selected,
                  'rbc-event-allday': isAllDay || _dates2.default.diff(start, _dates2.default.ceil(end, 'day'), 'day') > 1,
                  'rbc-event-continues-prior': continuesPrior,
                  'rbc-event-continues-after': continuesAfter
                }),
                onClick: function onClick() {
                  return onSelect(event);
                }
              }),
              _react2.default.createElement(
                'div',
                { className: 'rbc-event-content', title: title },
                Component ? _react2.default.createElement(Component, { event: event, title: title }) : title
              )
    );
  }
});

exports.default = EventCell;
module.exports = exports['default'];

I decided to try extending the EventCell component, when I passed it in as the event component prop, the event no longer had any content. Not sure how to pass event details into the 'rcb-event' div inside of the EventCell component. See below..

import React, { PropTypes } from 'react';
import MyCalendar from '../components/bigCalendar';
import _ from 'lodash';
import EventCell from 'react-big-calendar/lib/EventCell.js';

class MyEvent extends React.Component {
    constructor(props){
        super(props)
    }
    render(){
        return (
            <div className="testing">
                <EventCell />
            </div>
        );
    }
}

let components = {
    event: MyEvent
}

Here, I am passing the components object I just created down to the MyCalendar presentation component:

export default class Calendar extends React.Component {
    constructor(props) {
        super(props);

        var eventsList = Object.keys(props).map(function(k){
            return props[k];
        });

        eventsList.map(function(event){
            event["start"] = new Date(event["start"])
            event["end"] = new Date(event["end"])
        })

        this.state = {
            events: eventsList
        };
    };

    render() {
        return (
            <div>
                <MyCalendar components={components} events={this.state.events}/>
            </div>
        );
    }
}

And, finally passing the components object to the presentation component via props. Which does successfully render in the view, but as I said earlier - without content.

const MyCalendar = props => (
    <div className="calendar-container">
        <BigCalendar
            selectable
            popup
            components={props.components}
            views={{month: true, week: true, day: true}}
            events={props.events}
            onSelectEvent={event => onSelectEvent(event)}
            eventPropGetter={eventStyleGetter}
            scrollToTime={new Date(1970, 1, 1, 6)}
            defaultView='month'
            defaultDate={new Date(2015, 3, 12)}
            />
    </div>
);

MyCalendar.propTypes = {
    events: PropTypes.array.isRequired,
    components: PropTypes.object.isRequired
};

Seems like I'm supposed to go about this another way...Any suggestions?

like image 797
malexanders Avatar asked Aug 08 '16 06:08

malexanders


2 Answers

This is what I came up with, I'm sure it could be cleaned up - but it works.

Create custom Event component, which includes the popover content.

import React, { PropTypes } from 'react';
import MyCalendar from '../components/bigCalendar';
import _ from 'lodash';

class MyEvent extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount(){
        MyGlobal.popOver();
    }
    render(){
        return (
        <div>
            <div    className="custom_event_content"
                    data-toggle="popover"
                    data-placement="top"
                    data-popover-content={"#custom_event_" + this.props.event.id}
                    tabIndex="0"
                    >
                {this.props.event.title}
            </div>

            <div className="hidden" id={"custom_event_" + this.props.event.id} >
              <div className="popover-heading">
                {this.props.event.driver}
              </div>

              <div className="popover-body">
                {this.props.event.title}<br/>
              </div>
            </div>
        </div>
        );
    }
}

let components = {
    event: MyEvent
}

export default class Calendar extends React.Component {
    constructor(props) {
        super(props);

        var eventsList = Object.keys(props).map(function(k){
            return props[k];
        });

        eventsList.map(function(event){
            event["start"] = new Date(event["start"])
            event["end"] = new Date(event["end"])
        })

        this.state = {
            events: eventsList
        };
    };

    render() {
        return (
            <div>
                <MyCalendar components={components} events={this.state.events}/>
            </div>
        );
    }
}

Add event listeners:

MyGlobal.popOver = function(){
    $('body').on('click', function (e) {
        //did not click a popover toggle or popover
        if ($(e.target).data('toggle') !== 'popover'
            && $(e.target).parents('.popover.in').length === 0) {
            $('[data-toggle="popover"]').popover('hide');
        }
    });

    $("[data-toggle=popover]").popover({
        html : true,
        container: 'body',
        content: function() {
            var content = $(this).attr("data-popover-content");
            return $(content).children(".popover-body").html();
        },
        title: function() {
            var title = $(this).attr("data-popover-content");
            return $(title).children(".popover-heading").html();
        }
    });
}

Pass custom props to MyCalendar presentation component:

const MyCalendar = props => (
    <div className="calendar-container">
        <BigCalendar
            selectable
            popup
            components={props.components}
            views={{month: true, week: true, day: true}}
            events={props.events}
            onSelectEvent={event => onSelectEvent(event)}
            eventPropGetter={eventStyleGetter}
            scrollToTime={new Date(1970, 1, 1, 6)}
            defaultView='month'
            defaultDate={new Date(2015, 3, 12)}
            />
    </div>
);

MyCalendar.propTypes = {
    events: PropTypes.array.isRequired,
    components: PropTypes.object.isRequired
};
like image 163
malexanders Avatar answered Oct 20 '22 01:10

malexanders


Just to update answer to 2020 using moment and reactstrap.

import React, {FC} from "react";
import {Calendar, Event, momentLocalizer, ToolbarProps} from "react-big-calendar";
import {UncontrolledTooltip} from "reactstrap";
import moment from "moment";

const localizer = momentLocalizer(moment);

interface CalendarToolbarProps extends ToolbarProps {

}

const CalendarToolbar: FC<CalendarToolbarProps> = ({date, view: viewMode, onView, ...props}) => {
    return <div>Whatever you want on toolbar</div>
};


const eventPropGetter = (event: any, start: any, end: any, isSelected: boolean) => {
    const style = {
        backgroundColor: "#FF0000",
        paddingLeft: "10px",
        color: 'white',
    };
    return {
        style: style
    };
}

export interface FooEvent extends Event {
}

interface CalendarWithTooltipProps {
    events: Event[]
}

const CalendarWithTooltip: FC<CalendarWithTooltipProps> = ({events, ...props}) => {
    return <Calendar
        events={events}
        localizer={localizer}
        eventPropGetter={eventPropGetter}
        className={"overflow-scroll"}
        components={{
            event: (component: any) => {
                const targetId = "...."
                const {event} = component
                return <div id={targetId}>
                    {event?.title}
                    <UncontrolledTooltip placement={"top"}
                                         autohide={false}
                                         style={{minWidth: 200}}
                                         target={targetId} trigger={"hover"}>
                        Your tooltip content
                    </UncontrolledTooltip>
                </div>
            },
            toolbar: (props) => <CalendarToolbar {...props}/>
        }}
    />
}

export default CalendarWithTooltip
like image 40
Luca Davanzo Avatar answered Oct 20 '22 00:10

Luca Davanzo