/volto-fullcalendar-block

FullCalendar Block for Volto

Primary LanguageJavaScriptMIT LicenseMIT

volto-fullcalendar-block

Block for Volto to display events from an iCal/ics file in a FullCalendar.

Features

Listing block variation for Event-ish content-types

as_event_listing.mp4
  • Display content-types with behavior plone.eventbasic within a listing block as calendar (for customization see below)
  • In order to display recurrent events, you need to add a catalog index and metadata column:
<?xml version="1.0"?>
<object name="portal_catalog">
    <index name="recurrence" meta_type="FieldIndex">
        <indexed_attr value="recurrence"/>
    </index>
    <column value="recurrence"/>
</object>

More details checkout the following link: https://5.docs.plone.org/external/plone.app.dexterity/docs/advanced/catalog-indexing-strategies.html#adding-new-indexes-and-metadata-columns

Calendar block for remote events

remote_events.mp4
  • Specifiy an URL to an .ics/.iCal file -> Contained events are displayed in the calendar using FullCalendars iCalendar plugin

Configure FullCalendar toolbar via block settings

customize_title.mp4

Customize FullCalendar options

If you want to add props to the FullCalendar component (see: https://fullcalendar.io/docs/react#props), you can specify them in this config entry:

config.settings.fullcalendar = {
  additionalOptions: {
    ...
  }
}

Example: Custom event renderer to display descriptions as popups

(see: https://fullcalendar.io/docs/react#content-injection)

import { Popup } from 'semantic-ui-react';
import '@plone/volto/config';

export default function applyConfig(config) {
  config.settings.fullcalendar = {
    additionalOptions: {
      eventContent: (eventInfo) => {
        const MAX_LEN = 500;
        const description =
          (eventInfo.event.extendedProps?.description || '').length > MAX_LEN
            ? eventInfo.event.extendedProps.description.slice(0, MAX_LEN) +
              ' ...'
            : eventInfo.event.extendedProps.description;
        return (
          <>
            <div className="fc-event-time">{eventInfo.timeText}</div>
            {description ? (
              <Popup
                content={description}
                trigger={
                  <div className="fc-event-title">{eventInfo.event.title}</div>
                }
                wide="very"
              />
            ) : (
              <div className="fc-event-title">{eventInfo.event.title}</div>
            )}
          </>
        );
      },
    },
  };
  return config;
}

Customize listing block variation

Only items which have an attribute start will translate into calendar entries. (You can enable the behavior plone.eventbasic if you want this for your custom content-type.)

If you need to perform some data transformation before passing the listing items into the FullCalendar, you can build a wrapper around the listing component of this addon, like that:

  1. Adapt tsconfig.js:
{
  "compilerOptions": {
    "paths": {
      "@mbarde/volto-fullcalendar-block-original": [
        "../node_modules/@mbarde/volto-fullcalendar-block/src"
      ]
    }
}
  1. Create src/customizations/@mbarde/volto-fullcalendar-block/components/manage/Blocks/Listing/FullCalendar.jsx (see https://training.plone.org/mastering-plone/volto_overrides.html#component-shadowing)
/* EXAMPLE Wrapper around the original component to transform offers into events.
   (One offer can have multiple dates.)   
*/
// eslint-disable-next-line import/no-unresolved
import FullCalendarListingOrig from '@mbarde/volto-fullcalendar-block-original/components/manage/Blocks/Listing/FullCalendar';

const FullCalendarListing = ({ items, ...props }) => {
  const allEvents = items.flatMap((item) => {
    if (item['@type'] !== 'Offer') return item;
    let itemEvents = item.offer_dates.items
      .filter((od) => od.start && od.end)
      .map((od) => {
        return {
          '@id': item['@id'],
          title: item.title,
          description: item.description,
          start: od.start,
          end: od.end,
        };
      });
    return itemEvents;
  });
  return <FullCalendarListingOrig items={allEvents} {...props} />;
};

export default FullCalendarListing;

(Wrapper imports the original component and passes the transformed items array as property to it.)

Setup

Add volto-fullcalendar-block to your Volto project

  1. Make sure you have a Plone backend up-and-running at http://localhost:8080/Plone

    For example Docker container via command:

    docker run --name plone -p 8080:8080 -e SITE=Plone -e PROFILES="profile-plone.restapi:blocks" plone
    
  2. Start Volto frontend

  • If you already have a volto project, just update package.json:

    "addons": [
        "@mbarde/volto-fullcalendar-block"
    ],
    
    "dependencies": {
        "@mbarde/volto-fullcalendar-block": "*"
    }
  • If not, create one:

    npm install -g yo @plone/generator-volto
    yo @plone/volto my-volto-project --addon @mbarde/volto-fullcalendar-block
    cd my-volto-project
    
  1. Install new add-ons and restart Volto:

    yarn
    yarn start
    
  2. Go to http://localhost:3000

Tests

Expects Volto to run on http://localhost:3000 by default (see cypress.json).

Run tests: yarn cypres:run