Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom event/filter background colors #187

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 96 additions & 2 deletions src/components/organisms/Calendar/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,44 @@ class Calendar extends HTMLElement {
// eslint-disable-next-line no-console
console.error(`Failed to parse list of events:\n${eventsJSON}`);
}
events = this.applyEventPropertyRules(events);
const eventSource = {
id: 'eventsArray',
events: events,
};
return eventSource;
}

/**
* Apply additional event properties as defined by event
* property rules supplied in the `event-property-rules` attribute.
*
* @param {Object[]} events - An array of pre-parsed
* event objects. See https://fullcalendar.io/docs/event-parsing.
* @returns {Object[]} An array of pre-parsed event objects.
*/
applyEventPropertyRules(events) {
const eventPropertyRules = this.getEventPropertyRules();
for (const property in eventPropertyRules) {
events = events.map((event) => {
const eventPropertyValue = event[property];
if (
!Object.prototype.hasOwnProperty.call(
eventPropertyRules[property],
eventPropertyValue,
)
) {
return event;
}
return {
...event,
...eventPropertyRules[property][eventPropertyValue],
};
});
}
return events;
}

/**
* Replaces the 'eventsArray' event source with a new event source.
*
Expand Down Expand Up @@ -132,7 +163,6 @@ class Calendar extends HTMLElement {
* @param {string} [newFiltersJSON=null] - A JSON serialized array of event filter definitions.
* If null, filters will be fetched from the 'event-filters' attribute on the
* component instead.
* @returns void
*/
buildEventFilters(newFiltersJSON = null) {
const calendarFilterElt = this.shadowRoot.getElementById('calendarFilters');
Expand Down Expand Up @@ -164,7 +194,6 @@ class Calendar extends HTMLElement {
* @param {HTMLElement} calendarFilterElt - An HTML element to be used
* as the container for the event filter created.
* @param {Object} filter - A single event filter object.
* @returns void
*/
buildEventFilter(calendarFilterElt, filter) {
switch (filter.type) {
Expand Down Expand Up @@ -198,6 +227,8 @@ class Calendar extends HTMLElement {
const radioButtonLabel = document.createElement('label');
radioButtonLabel.setAttribute('for', value);
radioButtonLabel.classList.add('btn', 'btn-primary');
const eventRule = this.getEventPropertyRule(filter.key, value);
this.applyFilterPropertyRule(radioButtonLabel, eventRule);
radioButtonLabel.innerText = value;
radioButtonContainer.appendChild(radioButtonLabel);
radioFiltersContainer.appendChild(radioButtonContainer);
Expand All @@ -214,6 +245,31 @@ class Calendar extends HTMLElement {
}
}

/**
* Applies necessary styles based on the event property rule supplied.
*
* @param {HTMLElement} filterElement - The HTML element where the filter
* property rule will be applied.
* @param {Object} eventPropertyRule - An event property rule to be used as
* the filter property.
*/
applyFilterPropertyRule(filterElement, eventPropertyRule) {
for (const property in eventPropertyRule) {
switch (property) {
case 'backgroundColor': {
filterElement.style.backgroundColor = eventPropertyRule[property];
break;
}
default: {
// TODO: Introduce proper error logging.
// eslint-disable-next-line no-console
console.warn(`Ignoring unsupported filter property: ${property}`);
return;
}
}
}
}

/**
* Handles filter element events by filter down events to the
* user-selected criteria.
Expand All @@ -237,6 +293,44 @@ class Calendar extends HTMLElement {
this.updateEventArraySource(JSON.stringify(events));
}

/**
* Get an event/filter property and value for a given event/filter key and
* value.
* @param {string} eventKey - The event key used to filter down filters
* and events for rules.
* @param {string} eventKeyValue - The value at the sepcified event key
* used to filter down filters and events for rules.
* @returns Object - An event property rule consisting of
* property keys and values to be applied to events and filters.
*/
getEventPropertyRule(eventKey, eventKeyValue) {
const rules = this.getEventPropertyRules();
return rules[eventKey][eventKeyValue] ?? {};
}

/**
* Get all the event property rules from the `event-property-rules`
* attribute.
* @returns Object - All event property rules.
*/
getEventPropertyRules() {
const eventPropertyRulesJSON = this.getAttribute('event-property-rules');
if (!eventPropertyRulesJSON) {
return {};
}
let eventPropertyRules = {};
try {
eventPropertyRules = JSON.parse(eventPropertyRulesJSON ?? '{}');
} catch (error) {
// TODO: Introduce proper error logging.
// eslint-disable-next-line no-console
console.error(
`Failed to parse event property rules:\n${eventPropertyRulesJSON}`,
);
}
return eventPropertyRules;
}

attributeChangedCallback(name, oldValue, newValue) {
if (name in Calendar.observedAttributeCbs) {
this.handleObservedAttribute(
Expand Down
33 changes: 33 additions & 0 deletions src/stories/calendar.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ export default {
}
}`,
},
eventPropertyRules: {
control: { type: 'text' },
description: `A JSON object of event properties to be applied to events matching
a specific criteria. The keys and value of the object correspond to keys and
values of the event and filters where the properties are applied. The object
associated with each key is a list of event properties and their values
as defined in https://fullcalendar.io/docs/event-object.
The rules should take the following form:
{
event_field_key: {
event_field_key_value: {
backgroundColor: '#000',
}
}
}
`,
},
},
args: {
events: JSON.stringify([
Expand Down Expand Up @@ -60,6 +77,19 @@ export default {
],
},
}),
eventPropertyRules: JSON.stringify({
location: {
'Say Detroit Play Center': {
backgroundColor: '#ff6c37',
},
'Senior Facility': {
backgroundColor: '#1f71bf',
},
'Detroit Housing Commission': {
backgroundColor: '#1ed760',
},
},
}),
},
};

Expand All @@ -70,6 +100,9 @@ const Template = (args) => {
if (args.eventFilters) {
calendarElt.setAttribute('event-filters', args.eventFilters);
}
if (args.eventPropertyRules) {
calendarElt.setAttribute('event-property-rules', args.eventPropertyRules);
}
return calendarElt;
};

Expand Down