From 0f50285cf6ef35ef3513656b06d7a57dceba3a83 Mon Sep 17 00:00:00 2001 From: Julien Banken Date: Thu, 8 Apr 2021 06:56:32 +0000 Subject: [PATCH] [IMP] website_event_track[_live]: add visual & usability improvements to event.tracks PURPOSE This commit adds several minor visual improvements to the event.tracks frontend and backend views as well as a few quality of life changes to ease usability. SPECS - Add "hide and show" feature for tracks In the event homepage, all the tracks of the selected event will be displayed. As the tracks are grouped by day, some sections will only contain tracks that have already taken place. If there are a lot of tracks, it might be better to fold these sections to reduce the payload of the page. That way, the user will be able to see the upcoming tracks more easily. With these changes, a new chevron icon will be added above each section. When the user clicks on it, the user can fold and unfold a section. By default, the section containing tracks that have already taken place will be initially folded. - Add partner tag line The user may need to know more about the speaker before attending a talk. The user may wonder: Who will give the talk ? What is his/her field of expertise ? Where the speaker comes from ? To answer these questions, we will display: the name, the job position and the company name of the speaker. - Add replay suggestion when no suggestion can be provided When a video ends and no suggestion can be provided, the player will display an empty cover to hide the Youtube suggestions. With these new changes, the cover will now suggest the user to replay the video when no suggestion can be provided. - Dynamic count down for incoming tracks When the user accesses a track that will start in several hours, an alert will indicate the remaining time before the beginning of the track. Unfortunately, this alert is not dynamic: If the user keeps the page in a tab and come back later, the alert will not be updated and will display an incorrect estimation. The changes address this issue: The timer will now be updated dynamically as the time goes on. When the countdown reaches 0, the alert will automatically be removed from the dom. - Fix links of the agenda view In the agenda, the title of a track can be a link. When the user hover it, the cursor of the user will now turn into a clickable hand only if the track is accessible. - Remove the default date for the new tracks. - Set a default duration of half an hour for the new tracks. LINKS Task-2347597 COM PR odoo/odoo#69102 ENT PR odoo/enterprise#17612 X-original-commit: 6804b8a92c03db09c2694150f968d8056492a1d4 --- .../views/event_templates_widgets.xml | 9 + addons/website_event_track/__manifest__.py | 1 + .../controllers/event_track.py | 7 + .../website_event_track/models/event_track.py | 33 ++- .../static/src/js/event_track_timer.js | 87 ++++++++ .../src/scss/event_track_templates.scss | 17 +- .../views/event_event_views.xml | 3 +- .../views/event_track_templates_agenda.xml | 20 +- .../views/event_track_templates_list.xml | 188 +++++++++--------- .../views/event_track_templates_page.xml | 14 +- .../website_event_track_live/__manifest__.py | 1 + .../static/src/js/website_event_track_live.js | 75 ++++--- .../website_event_track_replay_suggestion.js | 42 ++++ .../website_event_track_live_templates.xml | 16 ++ .../views/event_track_templates_page.xml | 5 +- 15 files changed, 362 insertions(+), 156 deletions(-) create mode 100644 addons/website_event_track/static/src/js/event_track_timer.js create mode 100644 addons/website_event_track_live/static/src/js/website_event_track_replay_suggestion.js diff --git a/addons/website_event/views/event_templates_widgets.xml b/addons/website_event/views/event_templates_widgets.xml index 4b994176bde..f367aa8b370 100644 --- a/addons/website_event/views/event_templates_widgets.xml +++ b/addons/website_event/views/event_templates_widgets.xml @@ -78,4 +78,13 @@ + + diff --git a/addons/website_event_track/__manifest__.py b/addons/website_event_track/__manifest__.py index 507dbba588c..b78d1a40517 100644 --- a/addons/website_event_track/__manifest__.py +++ b/addons/website_event_track/__manifest__.py @@ -51,6 +51,7 @@ 'website_event_track/static/src/js/website_event_track_proposal_form.js', 'website_event_track/static/src/js/website_event_track_proposal_form_tags.js', 'website_event_track/static/src/js/event_track_reminder.js', + 'website_event_track/static/src/js/event_track_timer.js', 'website_event_track/static/src/js/website_event_pwa_widget.js', 'website_event_track/static/lib/idb-keyval/idb-keyval.js', ], diff --git a/addons/website_event_track/controllers/event_track.py b/addons/website_event_track/controllers/event_track.py index e448d373b2c..7ec755dd535 100644 --- a/addons/website_event_track/controllers/event_track.py +++ b/addons/website_event_track/controllers/event_track.py @@ -121,6 +121,13 @@ class EventTrackController(http.Controller): tracks_announced = tracks_announced.sorted('wishlisted_by_default', reverse=True) tracks_by_day.append({'date': False, 'name': _('Coming soon'), 'tracks': tracks_announced}) + for tracks_group in tracks_by_day: + # the tracks group is folded if all tracks are done (and if it's not "today") + tracks_group['default_collapsed'] = (today_tz != tracks_group['date']) and all( + track.is_track_done and not track.is_track_live + for track in tracks_group['tracks'] + ) + # return rendering values return { # event information diff --git a/addons/website_event_track/models/event_track.py b/addons/website_event_track/models/event_track.py index 953ac757ede..7c36e729ca6 100644 --- a/addons/website_event_track/models/event_track.py +++ b/addons/website_event_track/models/event_track.py @@ -74,8 +74,11 @@ class Track(models.Model): partner_company_name = fields.Char( 'Company Name', compute='_compute_partner_company_name', readonly=False, store=True) + partner_tag_line = fields.Char( + 'Tag Line', compute='_compute_partner_tag_line', + help='Description of the partner (name, function and company name)') image = fields.Image( - string="Speaker Photo", compute="_compute_speaker_image", + string="Speaker Photo", compute="_compute_partner_image", readonly=False, store=True, max_width=256, max_height=256) # contact information @@ -91,7 +94,7 @@ class Track(models.Model): # time information date = fields.Datetime('Track Date') date_end = fields.Datetime('Track End Date', compute='_compute_end_date', store=True) - duration = fields.Float('Duration', default=1.5, help="Track duration in hours.") + duration = fields.Float('Duration', default=0.5, help="Track duration in hours.") is_track_live = fields.Boolean( 'Is Track Live', compute='_compute_track_time_data', help="Track has started and is ongoing") @@ -199,8 +202,32 @@ class Track(models.Model): elif not track.partner_company_name: track.partner_company_name = track.partner_id.parent_id.name + @api.depends('partner_name', 'partner_function', 'partner_company_name') + def _compute_partner_tag_line(self): + for track in self: + if not track.partner_name: + track.partner_tag_line = False + continue + + tag_line = track.partner_name + if track.partner_function: + if track.partner_company_name: + tag_line = _('%(name)s, %(function)s at %(company)s', + name=track.partner_name, + function=track.partner_function, + company=track.partner_company_name + ) + else: + tag_line = '%s, %s' % (track.partner_name, track.partner_function) + elif track.partner_company_name: + tag_line = _('%(name)s from %(company)s', + name=tag_line, + company=track.partner_company_name + ) + track.partner_tag_line = tag_line + @api.depends('partner_id') - def _compute_speaker_image(self): + def _compute_partner_image(self): for track in self: if not track.image: track.image = track.partner_id.image_256 diff --git a/addons/website_event_track/static/src/js/event_track_timer.js b/addons/website_event_track/static/src/js/event_track_timer.js new file mode 100644 index 00000000000..1ee02595e2b --- /dev/null +++ b/addons/website_event_track/static/src/js/event_track_timer.js @@ -0,0 +1,87 @@ +odoo.define('website_event_track.website_event_track_timer', function (require) { + +'use strict'; + +const publicWidget = require('web.public.widget'); + +/* + * Simple implementation of a timer widget that uses a "time to live" configuration + * value to countdown seconds on a target element. + * Will be used to visually countdown the time before a talk starts. + * When the timer reaches 0, the element destroys itself. + */ +publicWidget.registry.websiteEventTrackTimer = publicWidget.Widget.extend({ + + selector: '.o_we_track_timer', + events: { + 'click .close': '_onCloseClick', + }, + + /** + * @override + */ + start: function () { + return this._super.apply(this, arguments).then(() => { + let timeToLive = this.$el.data('time-to-live'); + let deadline = moment().add(timeToLive, 'seconds'); + let remainingMs = deadline.diff(moment()); + if (remainingMs > 0) { + this._updateTimerDisplay(remainingMs); + this.$el.removeClass('d-none'); + this.deadline = deadline; + this.timer = setInterval(this._refreshTimer.bind(this), 1000); + } else { + this.destroy(); + } + }); + }, + + /** + * @override + */ + destroy: function() { + this.$el.parent().remove(); + clearInterval(this.timer); + this._super(...arguments); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + _onCloseClick: function () { + this.destroy(); + }, + + /** + * The function will trigger an update if the timer has not yet expired. + * Otherwise, the component will be destroyed. + */ + _refreshTimer: function () { + let remainingMs = this.deadline.diff(moment()); + if (remainingMs > 0) { + this._updateTimerDisplay(remainingMs); + } else { + this.destroy(); + } + }, + + /** + * The function will have the responsibility to update the text indicating + * the time remaining before the counter expires. The function will use + * MomentJS to transform the remaining time in more a human friendly format + * Example: "in 32 minutes", "in 17 hours", etc. + * @param {integer} remainingMs - Time remaining before the counter expires (in ms). + */ + _updateTimerDisplay: function (remainingMs) { + let $timerTextEl = this.$el.find('span'); + let str = moment.duration(remainingMs, 'ms').humanize(true); + if (str !== $timerTextEl.text()) { + $timerTextEl.text(str); + } + }, +}); + +return publicWidget.registry.websiteEventTrackTimer; + +}); diff --git a/addons/website_event_track/static/src/scss/event_track_templates.scss b/addons/website_event_track/static/src/scss/event_track_templates.scss index 442a146ff53..6d5ec0807f5 100644 --- a/addons/website_event_track/static/src/scss/event_track_templates.scss +++ b/addons/website_event_track/static/src/scss/event_track_templates.scss @@ -81,12 +81,12 @@ } div.o_we_agenda_card_content { height: 100%; - span { - cursor: pointer; - } .o_we_agenda_card_title, small { word-break: break-word; } + .badge:hover { + cursor: pointer; + } } .badge { height: fit-content; @@ -180,6 +180,13 @@ /* * EVENT TOOL: DATE */ -.o_wevent_event .o_we_track_day_header > div > span.h1 { - font-size: xx-large; +.o_wevent_event { + .o_we_track_day_header { + & > div > span.h1 { + font-size: xx-large; + } + a.collapsed { + transform: rotate(-90deg); + } + } } diff --git a/addons/website_event_track/views/event_event_views.xml b/addons/website_event_track/views/event_event_views.xml index 2d6ba3c544a..5c95db16d6a 100644 --- a/addons/website_event_track/views/event_event_views.xml +++ b/addons/website_event_track/views/event_event_views.xml @@ -11,8 +11,7 @@ diff --git a/addons/website_event_track/views/event_track_templates_agenda.xml b/addons/website_event_track/views/event_track_templates_agenda.xml index 61c4dc0cf3a..b6a6411756b 100644 --- a/addons/website_event_track/views/event_track_templates_agenda.xml +++ b/addons/website_event_track/views/event_track_templates_agenda.xml @@ -174,14 +174,20 @@
-
- +
+ + + + + + + + + +
-
- - +
+
diff --git a/addons/website_event_track/views/event_track_templates_list.xml b/addons/website_event_track/views/event_track_templates_list.xml index 59a88a1fde8..83892d187bf 100644 --- a/addons/website_event_track/views/event_track_templates_list.xml +++ b/addons/website_event_track/views/event_track_templates_list.xml @@ -170,8 +170,8 @@ -
-
+
+
@@ -181,102 +181,112 @@ t-options="{'widget': 'date', 'format': 'YYYY'}"/>
-
+
+ + +
-
- -
- - - - -
-
- -
- -
- - - - -
- - - - - - - - - Unpublished - - -
- - - -
- • - Live - - - - - Finished -
- - - • - - -
-
+
+
+ +
+ + + +
- -
- -
- Live - - +
+ +
+ +
+ + + + +
+ + + + + + + + + Unpublished + - - Finished +
+ + + +
+ • + Live + + + + + Finished +
+ + + • + + +
+
- -
- - - + +
+ +
+ Live + + + + + Finished +
+ +
+ + + +
diff --git a/addons/website_event_track/views/event_track_templates_page.xml b/addons/website_event_track/views/event_track_templates_page.xml index d2ccdb535c1..53663448248 100644 --- a/addons/website_event_track/views/event_track_templates_page.xml +++ b/addons/website_event_track/views/event_track_templates_page.xml @@ -45,12 +45,10 @@
-
-
- Starting in - -
+
+ + +
@@ -135,9 +133,9 @@