diff --git a/assets/javascripts/discourse/components/upcoming-events-list.gjs b/assets/javascripts/discourse/components/upcoming-events-list.gjs
index aadf144f..c6787d04 100644
--- a/assets/javascripts/discourse/components/upcoming-events-list.gjs
+++ b/assets/javascripts/discourse/components/upcoming-events-list.gjs
@@ -41,7 +41,6 @@ export default class UpcomingEventsList extends Component {
count = this.args.params?.count ?? DEFAULT_COUNT;
upcomingDays = this.args.params?.upcomingDays ?? DEFAULT_UPCOMING_DAYS;
- title = I18n.t("discourse_post_event.upcoming_events_list.title");
emptyMessage = I18n.t("discourse_post_event.upcoming_events_list.empty");
allDayLabel = I18n.t("discourse_post_event.upcoming_events_list.all_day");
errorMessage = I18n.t("discourse_post_event.upcoming_events_list.error");
@@ -57,6 +56,29 @@ export default class UpcomingEventsList extends Component {
return this.router.currentRoute.attributes?.category?.id;
}
+ get title() {
+ const categorySlug = this.router.currentRoute.attributes?.category?.slug;
+ const titleSetting = this.siteSettings.map_events_title;
+
+ if (titleSetting === "") {
+ return I18n.t("discourse_post_event.upcoming_events_list.title");
+ }
+
+ const categories = JSON.parse(titleSetting).map(
+ ({ category_slug }) => category_slug
+ );
+
+ if (categories.includes(categorySlug)) {
+ const titleMap = JSON.parse(titleSetting);
+ const customTitleLookup = titleMap.find(
+ (o) => o.category_slug === categorySlug
+ );
+ return customTitleLookup?.custom_title;
+ } else {
+ return I18n.t("discourse_post_event.upcoming_events_list.title");
+ }
+ }
+
get hasEmptyResponse() {
return (
!this.isLoading &&
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 2eb9ef0b..fe5592ad 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -31,6 +31,7 @@ en:
site_settings:
events_max_rows: "Maximum text rows per event in the Calendar."
map_events_to_color: "Assign a color to each tag or category."
+ map_events_title: "Overwrites 'Events' in the 'Upcoming Events' sidebar title per category."
calendar_enabled: "Enable the discourse-calendar plugin. This will add support for a [calendar][/calendar] tag in the first post of a topic."
discourse_post_event_enabled: "Enables the Event features. Note: also needs `calendar enabled` to be enabled."
displayed_invitees_limit: "Limits the numbers of invitees displayed on an event."
diff --git a/config/settings.yml b/config/settings.yml
index f5884a7d..623d2aa7 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -120,6 +120,10 @@ discourse_calendar:
client: true
default: "[]"
json_schema: DiscourseCalendar::SiteSettings::MapEventTagColorsJsonSchema
+ map_events_title:
+ client: true
+ default: ""
+ json_schema: DiscourseCalendar::SiteSettings::MapEventsTitleJsonSchema
include_expired_events_on_calendar:
default: false
client: true
diff --git a/lib/discourse_calendar/site_settings/map_events_title_json_schema.rb b/lib/discourse_calendar/site_settings/map_events_title_json_schema.rb
new file mode 100644
index 00000000..0c439e7d
--- /dev/null
+++ b/lib/discourse_calendar/site_settings/map_events_title_json_schema.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module DiscourseCalendar
+ module SiteSettings
+ class MapEventsTitleJsonSchema
+ def self.schema
+ @schema ||= {
+ type: "array",
+ uniqueItems: true,
+ items: {
+ type: "object",
+ title: "Title Mapping",
+ properties: {
+ category_slug: {
+ type: "string",
+ description: "Slug of the category",
+ },
+ custom_title: {
+ type: "string",
+ default: "Upcoming events",
+ description:
+ "The words you want to replace 'Upcoming Events' with for the sidebar calendar",
+ },
+ },
+ required: %w[category_slug custom_title],
+ },
+ }
+ end
+ end
+ end
+end
diff --git a/test/javascripts/integration/components/upcoming-events-list-test.gjs b/test/javascripts/integration/components/upcoming-events-list-test.gjs
index 06fb6126..f954e1b8 100644
--- a/test/javascripts/integration/components/upcoming-events-list-test.gjs
+++ b/test/javascripts/integration/components/upcoming-events-list-test.gjs
@@ -18,7 +18,7 @@ import UpcomingEventsList, {
} from "../../discourse/components/upcoming-events-list";
class RouterStub extends Service {
- currentRoute = { attributes: { category: { id: 1 } } };
+ currentRoute = { attributes: { category: { id: 1, slug: "announcements" } } };
currentRouteName = "discovery.latest";
on() {}
off() {}
@@ -163,6 +163,43 @@ module("Integration | Component | upcoming-events-list", function (hooks) {
);
});
+ test("Uses custom category name from 'map_events_title'", async function (assert) {
+ pretender.get("/discourse-post-event/events", () => {
+ return response({ events: [] });
+ });
+
+ this.siteSettings.map_events_title =
+ '[{"category_slug": "announcements", "custom_title": "Upcoming Announcements"}]';
+
+ await render();
+ this.appEvents.trigger("page:changed", { url: "/c/announcements" });
+
+ assert
+ .dom(".upcoming-events-list__heading")
+ .hasText(
+ "Upcoming Announcements",
+ "sets 'Upcoming Announcements' as the title in 'c/announcements'"
+ );
+ });
+
+ test("Uses default title for upcoming events list", async function (assert) {
+ pretender.get("/discourse-post-event/events", () => {
+ return response({ events: [] });
+ });
+
+ this.siteSettings.map_events_title = "";
+
+ await render();
+ this.appEvents.trigger("page:changed", { url: "/c/announcements" });
+
+ assert
+ .dom(".upcoming-events-list__heading")
+ .hasText(
+ "Upcoming events",
+ "it sets default value as the title in 'c/announcements'"
+ );
+ });
+
test("with events, view-all navigation", async function (assert) {
pretender.get("/discourse-post-event/events", twoEventsResponseHandler);