diff --git a/assets/javascripts/initializers/discourse-post-event-decorator.js.es6 b/assets/javascripts/initializers/discourse-post-event-decorator.js.es6 index c6548175..c3fbcbe9 100644 --- a/assets/javascripts/initializers/discourse-post-event-decorator.js.es6 +++ b/assets/javascripts/initializers/discourse-post-event-decorator.js.es6 @@ -9,53 +9,66 @@ function _decorateEvent(api, cooked, post) { _attachWidget(api, cooked, post); } -function _decorateEventPreview(api, cooked) { - const eventContainer = cooked.querySelector(".discourse-post-event"); +function _validEventPreview(eventContainer) { + eventContainer.innerHTML = ""; + eventContainer.classList.add("discourse-post-event-preview"); - if (eventContainer) { - if (!eventContainer.dataset.start) { - return; - } - - const eventPreviewContainer = document.createElement("div"); - eventPreviewContainer.classList.add("discourse-post-event-preview"); - - const statusLocaleKey = `discourse_post_event.models.event.status.${eventContainer - .dataset.status || "public"}.title`; - if (I18n.lookup(statusLocaleKey, { locale: "en" })) { - const statusContainer = document.createElement("div"); - statusContainer.classList.add("event-preview-status"); - statusContainer.innerText = I18n.t(statusLocaleKey); - eventPreviewContainer.appendChild(statusContainer); - } - - const datesContainer = document.createElement("div"); - datesContainer.classList.add("event-preview-dates"); - - const startsAt = moment - .utc(eventContainer.dataset.start) - .tz(moment.tz.guess()); - - const endsAtValue = eventContainer.dataset.end; - const format = guessDateFormat( - startsAt, - endsAtValue && moment.utc(endsAtValue).tz(moment.tz.guess()) - ); - - let datesString = `${startsAt.format(format)}`; - if (endsAtValue) { - datesString += ` → ${moment - .utc(endsAtValue) - .tz(moment.tz.guess()) - .format(format)}`; - } - datesContainer.innerHTML = datesString; - - eventPreviewContainer.appendChild(datesContainer); - - eventContainer.innerHTML = ""; - eventContainer.appendChild(eventPreviewContainer); + const statusLocaleKey = `discourse_post_event.models.event.status.${eventContainer + .dataset.status || "public"}.title`; + if (I18n.lookup(statusLocaleKey, { locale: "en" })) { + const statusContainer = document.createElement("div"); + statusContainer.classList.add("event-preview-status"); + statusContainer.innerText = I18n.t(statusLocaleKey); + eventContainer.appendChild(statusContainer); } + + const datesContainer = document.createElement("div"); + datesContainer.classList.add("event-preview-dates"); + + const startsAt = moment + .utc(eventContainer.dataset.start) + .tz(moment.tz.guess()); + + const endsAtValue = eventContainer.dataset.end; + const format = guessDateFormat( + startsAt, + endsAtValue && moment.utc(endsAtValue).tz(moment.tz.guess()) + ); + + let datesString = `${startsAt.format(format)}`; + if (endsAtValue) { + datesString += ` → ${moment + .utc(endsAtValue) + .tz(moment.tz.guess()) + .format(format)}`; + } + datesContainer.innerHTML = datesString; + + eventContainer.appendChild(datesContainer); +} + +function _invalidEventPreview(eventContainer) { + eventContainer.classList.add( + "discourse-post-event-preview", + "alert", + "alert-error" + ); + eventContainer.classList.remove("discourse-post-event"); + eventContainer.innerText = I18n.t( + "discourse_post_event.preview.more_than_one_event" + ); +} + +function _decorateEventPreview(api, cooked) { + const eventContainers = cooked.querySelectorAll(".discourse-post-event"); + + eventContainers.forEach((eventContainer, index) => { + if (index > 0) { + _invalidEventPreview(eventContainer); + } else { + _validEventPreview(eventContainer); + } + }); } let _glued = []; diff --git a/assets/stylesheets/common/discourse-post-event-preview.scss b/assets/stylesheets/common/discourse-post-event-preview.scss index 8b73c019..2df21b7f 100644 --- a/assets/stylesheets/common/discourse-post-event-preview.scss +++ b/assets/stylesheets/common/discourse-post-event-preview.scss @@ -1,11 +1,11 @@ .discourse-post-event-preview { background: $secondary; - display: flex; - flex: 1 0 auto; align-items: center; flex-direction: column; padding: 0.5em; border: 1px solid $primary-low; + display: flex; + flex: 1 0 auto; .event-preview-status { margin: 0 0 0.5em 0; @@ -14,4 +14,12 @@ .event-preview-dates { font-weight: 700; } + + &.alert-error { + border-color: lighten($danger, 25); + } +} + +.discourse-post-event-preview + .discourse-post-event-preview { + margin-top: 1em; } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0af8c815..52d6d389 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -19,6 +19,8 @@ en: search: "Search..." group_availability: "%{group} availability" discourse_post_event: + preview: + more_than_one_event: You can’t have more than one event. edit_reason: Event updated models: invitee: diff --git a/test/javascripts/acceptance/discourse-post-event/composer-preview-test.js.es6 b/test/javascripts/acceptance/discourse-post-event/composer-preview-test.js.es6 new file mode 100644 index 00000000..c241f757 --- /dev/null +++ b/test/javascripts/acceptance/discourse-post-event/composer-preview-test.js.es6 @@ -0,0 +1,85 @@ +import discoursePostEventAcceptance, { + utcToLocal +} from "./discourse-post-event-helper"; + +discoursePostEventAcceptance("composer-preview"); + +test("an event with a start date", async assert => { + await visit("/"); + await click("#create-topic"); + await fillIn(".d-editor-input", '[event start="2020-02-03"]\n[/event]'); + + const preview = find(".d-editor-preview .discourse-post-event"); + assert.ok(exists(preview), "it creates the preview"); + assert.equal( + preview.find(".event-preview-status").text(), + I18n.t("discourse_post_event.models.event.status.public.title"), + "it displays the status" + ); + assert.equal( + preview.find(".event-preview-dates .start").text(), + utcToLocal("2020-02-03"), + "it displays the start date" + ); +}); + +test("an event with a start date and end date", async assert => { + await visit("/"); + await click("#create-topic"); + await fillIn( + ".d-editor-input", + '[event start="2020-02-03" end="2002-03-04"]\n[/event]' + ); + + const preview = find(".d-editor-preview .discourse-post-event"); + assert.equal( + preview.find(".event-preview-dates .start").text(), + utcToLocal("2020-02-03"), + "it displays the start date" + ); + assert.equal( + preview.find(".event-preview-dates .end").text(), + utcToLocal("2002-03-04"), + "it displays the start date" + ); +}); + +test("an event with a status", async assert => { + await visit("/"); + await click("#create-topic"); + await fillIn( + ".d-editor-input", + '[event status="private" start="2020-02-03"]\n[/event]' + ); + + const preview = find(".d-editor-preview .discourse-post-event"); + assert.equal( + preview.find(".event-preview-status").text(), + I18n.t("discourse_post_event.models.event.status.private.title"), + "it displays the status" + ); +}); + +test("more than one event", async assert => { + await visit("/"); + await click("#create-topic"); + await fillIn( + ".d-editor-input", + '[event start="2020-02-03"]\n[/event]\n\n[event start="2021-04-03"]\n[/event]' + ); + + const preview = find( + ".d-editor-preview .discourse-post-event-preview[data-start=2020-02-03]" + ); + assert.ok(exists(preview), "it displays the first event"); + + const errorPreview = find( + ".d-editor-preview .discourse-post-event-preview.alert-error" + ); + assert.ok(exists(errorPreview), "it displays the error"); + assert.equal( + errorPreview.text(), + I18n.t("discourse_post_event.preview.more_than_one_event"), + "it displays the error" + ); +}); diff --git a/test/javascripts/acceptance/discourse-post-event/discourse-post-event-helper.js.es6 b/test/javascripts/acceptance/discourse-post-event/discourse-post-event-helper.js.es6 new file mode 100644 index 00000000..ece8122c --- /dev/null +++ b/test/javascripts/acceptance/discourse-post-event/discourse-post-event-helper.js.es6 @@ -0,0 +1,26 @@ +import { acceptance } from "helpers/qunit-helpers"; + +export function utcToLocal(date, format = "LLL") { + return moment + .utc(date) + .local() + .format(format); +} + +export default function discoursePostEventAcceptance(moduleName, options = {}) { + acceptance( + `discourse-post-event/${moduleName}`, + Object.assign( + {}, + { + settings: { + calendar_enabled: true, + discourse_post_event_enabled: true + }, + + loggedIn: true + }, + options + ) + ); +}