FIX: recurring events not displayed on /upcoming-events (#676)
When we introduced the DiscoursePostEventEvent model and the API service, the recurrent events stopped working as their logic still relied on the old naming convention, upcoming_dates. This PR changes the addRecurrentEvents logic to work with and to create DiscoursePostEventEvents for each of the upcomingDates, and changes the logic on the Category calendar to also work with the DiscoursePostEventEvent instance instead of the plain object, as well as re-using the API service to fetch the events. The function passed to onPageChange was also changed to async/await with some minor changes for clarity.
This commit is contained in:
parent
764fd67b5e
commit
3c833c99e3
|
|
@ -47,7 +47,7 @@ function initializeDiscourseCalendar(api) {
|
|||
selector = `.topic-list:not(.shared-drafts) .${outletName}-outlet`;
|
||||
}
|
||||
|
||||
api.onPageChange((url) => {
|
||||
api.onPageChange(async (url) => {
|
||||
const categoryCalendarNode = document.querySelector(
|
||||
`${selector}.category-calendar`
|
||||
);
|
||||
|
|
@ -98,28 +98,27 @@ function initializeDiscourseCalendar(api) {
|
|||
categoryCalendarNode.innerHTML =
|
||||
'<div class="calendar"><div class="spinner medium"></div></div>';
|
||||
|
||||
loadFullCalendar().then(() => {
|
||||
const options = [`postId=${postId}`];
|
||||
await loadFullCalendar();
|
||||
|
||||
const optionals = ["weekends", "tzPicker", "defaultView"];
|
||||
optionals.forEach((optional) => {
|
||||
if (isPresent(categorySetting[optional])) {
|
||||
options.push(
|
||||
`${optional}=${escapeExpression(categorySetting[optional])}`
|
||||
);
|
||||
}
|
||||
});
|
||||
const options = [`postId=${postId}`];
|
||||
|
||||
const rawCalendar = `[calendar ${options.join(" ")}]\n[/calendar]`;
|
||||
const cookRaw = cook(rawCalendar);
|
||||
const loadPost = ajax(`/posts/${postId}.json`);
|
||||
Promise.all([cookRaw, loadPost]).then((results) => {
|
||||
const cooked = results[0];
|
||||
const post = results[1];
|
||||
categoryCalendarNode.innerHTML = cooked.toString();
|
||||
render($(".calendar"), post);
|
||||
});
|
||||
const optionals = ["weekends", "tzPicker", "defaultView"];
|
||||
optionals.forEach((optional) => {
|
||||
if (isPresent(categorySetting[optional])) {
|
||||
options.push(
|
||||
`${optional}=${escapeExpression(categorySetting[optional])}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const rawCalendar = `[calendar ${options.join(" ")}]\n[/calendar]`;
|
||||
const cookRaw = cook(rawCalendar);
|
||||
const loadPost = ajax(`/posts/${postId}.json`);
|
||||
|
||||
const [cooked, post] = await Promise.all([cookRaw, loadPost]);
|
||||
|
||||
categoryCalendarNode.innerHTML = cooked.toString();
|
||||
render($(".calendar"), post);
|
||||
} else {
|
||||
if (!categoryEventNode) {
|
||||
return;
|
||||
|
|
@ -131,97 +130,91 @@ function initializeDiscourseCalendar(api) {
|
|||
);
|
||||
|
||||
if (foundCategory) {
|
||||
loadFullCalendar().then(() => {
|
||||
let fullCalendar = new window.FullCalendar.Calendar(
|
||||
categoryEventNode,
|
||||
{
|
||||
...fullCalendarDefaultOptions(),
|
||||
eventPositioned: (info) => {
|
||||
if (siteSettings.events_max_rows === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fcContent = info.el.querySelector(".fc-content");
|
||||
let computedStyle = window.getComputedStyle(fcContent);
|
||||
let lineHeight = parseInt(computedStyle.lineHeight, 10);
|
||||
|
||||
if (lineHeight === 0) {
|
||||
lineHeight = 20;
|
||||
}
|
||||
let maxHeight = lineHeight * siteSettings.events_max_rows;
|
||||
|
||||
if (fcContent) {
|
||||
fcContent.style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
|
||||
let fcTitle = info.el.querySelector(".fc-title");
|
||||
if (fcTitle) {
|
||||
fcTitle.style.overflow = "hidden";
|
||||
fcTitle.style.whiteSpace = "pre-wrap";
|
||||
}
|
||||
fullCalendar.updateSize();
|
||||
},
|
||||
await loadFullCalendar();
|
||||
let fullCalendar = new window.FullCalendar.Calendar(categoryEventNode, {
|
||||
...fullCalendarDefaultOptions(),
|
||||
eventPositioned: (info) => {
|
||||
if (siteSettings.events_max_rows === 0) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
const params = {
|
||||
category_id: browsedCategory.id,
|
||||
include_subcategories: true,
|
||||
};
|
||||
if (siteSettings.include_expired_events_on_calendar) {
|
||||
params.include_expired = true;
|
||||
|
||||
let fcContent = info.el.querySelector(".fc-content");
|
||||
let computedStyle = window.getComputedStyle(fcContent);
|
||||
let lineHeight = parseInt(computedStyle.lineHeight, 10);
|
||||
|
||||
if (lineHeight === 0) {
|
||||
lineHeight = 20;
|
||||
}
|
||||
let maxHeight = lineHeight * siteSettings.events_max_rows;
|
||||
|
||||
if (fcContent) {
|
||||
fcContent.style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
|
||||
let fcTitle = info.el.querySelector(".fc-title");
|
||||
if (fcTitle) {
|
||||
fcTitle.style.overflow = "hidden";
|
||||
fcTitle.style.whiteSpace = "pre-wrap";
|
||||
}
|
||||
fullCalendar.updateSize();
|
||||
},
|
||||
});
|
||||
const params = {
|
||||
category_id: browsedCategory.id,
|
||||
include_subcategories: true,
|
||||
};
|
||||
if (siteSettings.include_expired_events_on_calendar) {
|
||||
params.include_expired = true;
|
||||
}
|
||||
|
||||
const tagsColorsMap = JSON.parse(siteSettings.map_events_to_color);
|
||||
|
||||
const discoursePostEventApiService = api.container.lookup(
|
||||
"service:discourse-post-event-api"
|
||||
);
|
||||
|
||||
const events = await discoursePostEventApiService.events(params);
|
||||
addRecurrentEvents(events).forEach((event) => {
|
||||
const { startsAt, endsAt, post, categoryId } = event;
|
||||
|
||||
let backgroundColor;
|
||||
|
||||
if (post.topic.tags) {
|
||||
const tagColorEntry = tagsColorsMap.find(
|
||||
(entry) =>
|
||||
entry.type === "tag" && post.topic.tags.includes(entry.slug)
|
||||
);
|
||||
backgroundColor = tagColorEntry ? tagColorEntry.color : null;
|
||||
}
|
||||
const loadEvents = ajax(`/discourse-post-event/events`, {
|
||||
data: params,
|
||||
});
|
||||
|
||||
const tagsColorsMap = JSON.parse(siteSettings.map_events_to_color);
|
||||
if (!backgroundColor) {
|
||||
const categoryColorFromMap = tagsColorsMap.find(
|
||||
(entry) =>
|
||||
entry.type === "category" &&
|
||||
entry.slug === post.topic.category_slug
|
||||
)?.color;
|
||||
backgroundColor =
|
||||
categoryColorFromMap ||
|
||||
`#${Category.findById(categoryId)?.color}`;
|
||||
}
|
||||
|
||||
Promise.all([loadEvents]).then((results) => {
|
||||
const [{ events }] = results;
|
||||
let classNames;
|
||||
if (moment(endsAt || startsAt).isBefore(moment())) {
|
||||
classNames = "fc-past-event";
|
||||
}
|
||||
|
||||
addRecurrentEvents(events).forEach((event) => {
|
||||
const { starts_at, ends_at, post, category_id } = event;
|
||||
|
||||
let backgroundColor;
|
||||
|
||||
if (post.topic.tags) {
|
||||
const tagColorEntry = tagsColorsMap.find(
|
||||
(entry) =>
|
||||
entry.type === "tag" && post.topic.tags.includes(entry.slug)
|
||||
);
|
||||
backgroundColor = tagColorEntry ? tagColorEntry.color : null;
|
||||
}
|
||||
|
||||
if (!backgroundColor) {
|
||||
const categoryColorFromMap = tagsColorsMap.find(
|
||||
(entry) =>
|
||||
entry.type === "category" &&
|
||||
entry.slug === post.topic.category_slug
|
||||
)?.color;
|
||||
backgroundColor =
|
||||
categoryColorFromMap ||
|
||||
`#${Category.findById(category_id)?.color}`;
|
||||
}
|
||||
|
||||
let classNames;
|
||||
if (moment(ends_at || starts_at).isBefore(moment())) {
|
||||
classNames = "fc-past-event";
|
||||
}
|
||||
|
||||
fullCalendar.addEvent({
|
||||
title: formatEventName(event),
|
||||
start: starts_at,
|
||||
end: ends_at || starts_at,
|
||||
allDay: !isNotFullDayEvent(moment(starts_at), moment(ends_at)),
|
||||
url: getURL(`/t/-/${post.topic.id}/${post.post_number}`),
|
||||
backgroundColor,
|
||||
classNames,
|
||||
});
|
||||
});
|
||||
|
||||
fullCalendar.render();
|
||||
fullCalendar.addEvent({
|
||||
title: formatEventName(event),
|
||||
start: startsAt,
|
||||
end: endsAt || startsAt,
|
||||
allDay: !isNotFullDayEvent(moment(startsAt), moment(endsAt)),
|
||||
url: getURL(`/t/-/${post.topic.id}/${post.post_number}`),
|
||||
backgroundColor,
|
||||
classNames,
|
||||
});
|
||||
});
|
||||
|
||||
fullCalendar.render();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
import DiscoursePostEventEvent from "../models/discourse-post-event-event";
|
||||
|
||||
export default function addRecurrentEvents(events) {
|
||||
return events.flatMap((event) => {
|
||||
const upcomingEvents =
|
||||
event.upcoming_dates?.map((upcomingDate) => ({
|
||||
...event,
|
||||
starts_at: upcomingDate.starts_at,
|
||||
ends_at: upcomingDate.ends_at,
|
||||
upcoming_dates: [],
|
||||
})) || [];
|
||||
event.upcomingDates?.map((upcomingDate) =>
|
||||
DiscoursePostEventEvent.create({
|
||||
name: event.name,
|
||||
post: event.post,
|
||||
category_id: event.categoryId,
|
||||
starts_at: upcomingDate.starts_at,
|
||||
ends_at: upcomingDate.ends_at,
|
||||
})
|
||||
) || [];
|
||||
|
||||
return [event, ...upcomingEvents];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { tomorrow } from "discourse/lib/time-utils";
|
||||
import { tomorrow, twoDays } from "discourse/lib/time-utils";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Discourse Calendar - Upcoming Events Calendar", function (needs) {
|
||||
|
|
@ -38,7 +39,7 @@ acceptance("Discourse Calendar - Upcoming Events Calendar", function (needs) {
|
|||
events: [
|
||||
{
|
||||
id: 67501,
|
||||
starts_at: tomorrow(),
|
||||
starts_at: tomorrow().add(1, "hour"),
|
||||
ends_at: null,
|
||||
timezone: "Asia/Calcutta",
|
||||
post: {
|
||||
|
|
@ -51,6 +52,12 @@ acceptance("Discourse Calendar - Upcoming Events Calendar", function (needs) {
|
|||
},
|
||||
},
|
||||
name: "Awesome Event",
|
||||
upcoming_dates: [
|
||||
{
|
||||
starts_at: twoDays().format("YYYY-MM-DDT15:14:00.000Z"),
|
||||
ends_at: twoDays().format("YYYY-MM-DDT16:14:00.000Z"),
|
||||
},
|
||||
],
|
||||
category_id: 1,
|
||||
},
|
||||
{
|
||||
|
|
@ -101,4 +108,21 @@ acceptance("Discourse Calendar - Upcoming Events Calendar", function (needs) {
|
|||
"Event item uses the proper color from category 2"
|
||||
);
|
||||
});
|
||||
|
||||
test("upcoming events calendar shows recurrent events", async (assert) => {
|
||||
await visit("/upcoming-events");
|
||||
|
||||
const [, first, second] = queryAll(".fc-event .fc-title");
|
||||
assert.equal(first.textContent, "Awesome Event");
|
||||
assert.equal(second.textContent, "Awesome Event");
|
||||
|
||||
const firstCell = first.closest("td");
|
||||
const secondCell = second.closest("td");
|
||||
|
||||
assert.notEqual(
|
||||
firstCell,
|
||||
secondCell,
|
||||
"events should be in different days"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue