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);