FEATURE: display upcoming events in a calendar (#33)

FEATURE: display upcoming events in a calendar (#33)

diff --git a/assets/javascripts/discourse/components/events-calendar.js.es6 b/assets/javascripts/discourse/components/events-calendar.js.es6
new file mode 100644
index 0000000..43dab75
--- /dev/null
+++ b/assets/javascripts/discourse/components/events-calendar.js.es6
@@ -0,0 +1,56 @@
+import { isNotFullDayEvent } from "discourse/plugins/discourse-calendar/lib/guess-best-date-format";
+import { formatEventName } from "discourse/plugins/discourse-calendar/helpers/format-event-name";
+import loadScript from "discourse/lib/load-script";
+import Component from "@ember/component";
+import { schedule } from "@ember/runloop";
+
+export default Component.extend({
+  tagName: "",
+  events: null,
+
+  init() {
+    this._super(...arguments);
+
+    this._calendar = null;
+  },
+
+  willDestroyElement() {
+    this._super(...arguments);
+
+    this._calendar && this._calendar.destroy();
+    this._calendar = null;
+  },
+
+  didInsertElement() {
+    this._super(...arguments);
+
+    loadScript(
+      "/plugins/discourse-calendar/javascripts/fullcalendar-with-moment-timezone.min.js"
+    ).then(() => {
+      schedule("afterRender", () => {
+        const calendarNode = document.getElementById("events-calendar");
+        this._calendar = new window.FullCalendar.Calendar(calendarNode, {});
+      });
+    });
+  },
+
+  didUpdateAttrs() {
+    this._super(...arguments);
+
+    (this.events || []).forEach(event => {
+      this._calendar.addEvent({
+        title: formatEventName(event),
+        start: event.starts_at,
+        end: event.ends_at || event.starts_at,
+        allDay: !isNotFullDayEvent(
+          moment(event.starts_at),
+          moment(event.ends_at)
+        ),
+        url: Discourse.getURL(
+          `/t/-/${event.post.topic.id}/${event.post.post_number}`
+        )
+      });
+    });
+    this._calendar.render();
+  }
+});
diff --git a/assets/javascripts/discourse/templates/components/events-calendar.hbs b/assets/javascripts/discourse/templates/components/events-calendar.hbs
new file mode 100644
index 0000000..207feef
--- /dev/null
+++ b/assets/javascripts/discourse/templates/components/events-calendar.hbs
@@ -0,0 +1 @@
+<div id="events-calendar"></div>
diff --git a/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-index.hbs b/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-index.hbs
index f447b19..24c80cc 100644
--- a/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-index.hbs
+++ b/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-index.hbs
@@ -1,35 +1,3 @@
 <div class="discourse-post-event-upcoming-events">
-  <h1>{{i18n "discourse_post_event.upcoming_events.title"}}</h1>
-
-  <table class="table upcoming-events-table">
-    <thead>
-      <tr>
-        <th></th>
-        <th>{{i18n "discourse_post_event.upcoming_events.creator"}}</th>
-        <th>{{i18n "discourse_post_event.upcoming_events.status"}}</th>
-        <th>{{i18n "discourse_post_event.upcoming_events.starts_at"}}</th>
-      </tr>
-    </thead>
-    <tbody>
-      {{#each events as |event|}}
-        <tr>
-          <td>
-            <a href={{event.post.url}}>
-              {{format-event-name event}}
-            </a>
-          </td>
-          <td>
-            {{avatar event.creator imageSize="tiny"}}
-            {{format-username event.creator.username}}
-          </td>
-          <td>
-            {{event.status}}
-          </td>
-          <td>
-            {{format-future-date event.starts_at}}
-          </td>
-        </tr>
-      {{/each}}
-    </tbody>
-  </table>
+  {{events-calendar events=events}}
 </div>
diff --git a/assets/javascripts/helpers/format-event-name.js.es6 b/assets/javascripts/helpers/format-event-name.js.es6
index 111571a..77618d0 100644
--- a/assets/javascripts/helpers/format-event-name.js.es6
+++ b/assets/javascripts/helpers/format-event-name.js.es6
@@ -1,5 +1,7 @@
 import { htmlHelper } from "discourse-common/lib/helpers";
 
-export default htmlHelper(event => {
+export function formatEventName(event) {
   return event.name || event.post.topic.title;
-});
+}
+
+export default htmlHelper(event => formatEventName(event));
diff --git a/assets/javascripts/lib/guess-best-date-format.js.es6 b/assets/javascripts/lib/guess-best-date-format.js.es6
index fc01d78..e085a66 100644
--- a/assets/javascripts/lib/guess-best-date-format.js.es6
+++ b/assets/javascripts/lib/guess-best-date-format.js.es6
@@ -1,13 +1,17 @@
-export default function guessDateFormat(startsAt, endsAt) {
-  let format;
-  if (
+export function isNotFullDayEvent(startsAt, endsAt) {
+  return (
     startsAt.hours() > 0 ||
     startsAt.minutes() > 0 ||
     (endsAt && (moment(endsAt).hours() > 0 || moment(endsAt).minutes() > 0))
-  ) {
-    format = "LLL";
-  } else {
+  );
+}
+
+export default function guessDateFormat(startsAt, endsAt) {
+  let format;
+  if (isNotFullDayEvent(startsAt, endsAt)) {
     format = "LL";
+  } else {
+    format = "LLL";
   }
 
   return format;
diff --git a/assets/stylesheets/common/events-calendar.scss b/assets/stylesheets/common/events-calendar.scss
new file mode 100644
index 0000000..0f22533
--- /dev/null
+++ b/assets/stylesheets/common/events-calendar.scss
@@ -0,0 +1,132 @@
+#events-calendar {
+  &.fc-unthemed {
+    tbody,
+    thead,
+    tr {
+      border: none;
+    }
+
+    .fc-basic-view .fc-day-top .fc-day-number {
+      float: left;
+    }
+
+    .fc-bg td.fc-today {
+      background-color: $highlight-medium;
+      border-style: solid;
+    }
+
+    .fc-month-view .fc-widget-content,
+    .fc-basicWeek-view .fc-widget-content,
+    .fc-head-container {
+      padding: 0;
+    }
+
+    .fc-bg tbody {
+      border-width: 0;
+    }
+
+    .fc-header-toolbar {
+      margin: 1em 0 0.5em 0;
+    }
+
+    .fc-title {
+      // TODO: use @include ellipsis after stable is 2.4+
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+
+      display: block;
+    }
+
+    .fc-widget-header span {
+      padding: 3px 3px 3px 0.5em;
+    }
+
+    .fc-center {
+      display: none;
+    }
+
+    .fc-button {
+      border-radius: 0;
+      box-shadow: none;
+      background: $primary-low;
+      text-transform: capitalize;
+      color: $primary;
+      text-shadow: none;
+      border: none;
+
+      padding: 6px 12px;
+
+      &:hover {
+        background: $primary-medium;
+        color: $secondary;
+      }
+
+      &.fc-state-active {
+        background: $tertiary;
+        color: $secondary;
+      }
+      margin: 0.3em 0 0.3em 0.5em;
+    }
+
+    .fc-button-group {
+      margin: 0.3em 0 0.3em 0.5em;
+      // margin-right: 0;
+      .fc-button {
+        margin: 0;
+      }
+    }
+
+    .fc-divider,
+    .fc-list-empty,
+    .fc-list-heading td,
+    .fc-popover .fc-header {
+      background: $primary-low;
+    }
+
+    .fc-content,
+    .fc-divider,
+    .fc-list-heading td,
+    .fc-list-view,
+    .fc-popover,
+    .fc-row,
+    tbody,
+    td,
+    th,
+    thead {
+      border-color: $primary-low;
+    }
+  }
+
+  .fc-event,
+  .fc-event-dot {
+    color: $secondary;
+    background-color: $tertiary;
+    border: 1px solid transparent;
+
+    .fc-time {
+      display: none;
+    }
+
+    &.grouped-event {
+      background-color: none;
+      background: $secondary;
+      border: 1px solid $primary-low-mid;
+      color: $primary;
+
+      .emoji {
+        margin-right: 0.25em;
+      }
+    }
+  }
+
+  .fc-left {
+    .fc-button-group:first-child {
+      margin-left: 0;
+    }
+  }
+  .fc-list-item-add-to-calendar {
+    color: $tertiary;
+    font-size: $font-down-1;
+  }
+}
diff --git a/plugin.rb b/plugin.rb
index 86503c9..4c73450 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -14,6 +14,7 @@ enabled_site_setting :calendar_enabled
 
 register_asset "stylesheets/vendor/fullcalendar.min.css"
 register_asset "stylesheets/common/discourse-calendar.scss"

[... diff too long, it was truncated ...]

GitHub sha: 3a9b218b

This commit appears in #33 which was merged by jjaffeux.

Is there a chance this is torn down before this runs and the element no longer exists?

Fixed in FIX: strengthen calendar rendering · discourse/discourse-calendar@e568468 · GitHub