From bb22ab84fc10e054dd17abbf548f7fc85d3582a4 Mon Sep 17 00:00:00 2001
From: KDSBrowne <kert.browne85@gmail.com>
Date: Mon, 10 Aug 2020 12:51:06 +0000
Subject: [PATCH] add download link to current presentation toast

---
 .../ui/components/presentation/component.jsx  | 57 +++++++++++++++++--
 .../ui/components/presentation/styles.scss    | 49 ++++++++++++----
 .../components/status-notifier/component.jsx  |  5 +-
 .../ui/components/status-notifier/styles.scss | 22 +------
 .../imports/ui/components/toast/styles.scss   | 23 ++++++--
 .../ui/stylesheets/variables/typography.scss  |  1 +
 bigbluebutton-html5/private/locales/en.json   |  1 +
 7 files changed, 116 insertions(+), 42 deletions(-)

diff --git a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx
index cda84f25cc..e084ee858f 100755
--- a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx
@@ -11,6 +11,7 @@ import AnnotationGroupContainer from '../whiteboard/annotation-group/container';
 import PresentationOverlayContainer from './presentation-overlay/container';
 import Slide from './slide/component';
 import { styles } from './styles.scss';
+import toastStyles from '/imports/ui/components/toast/styles';
 import MediaService, { shouldEnableSwapLayout } from '../media/service';
 import PresentationCloseButton from './presentation-close-button/component';
 import DownloadPresentationButton from './download-presentation-button/component';
@@ -29,6 +30,10 @@ const intlMessages = defineMessages({
     id: 'app.presentation.notificationLabel',
     description: 'label displayed in toast when presentation switches',
   },
+  downloadLabel: {
+    id: 'app.presentation.downloadLabel',
+    description: 'label for downloadable presentations',
+  },
 });
 
 const ALLOW_FULLSCREEN = Meteor.settings.public.app.allowFullscreen;
@@ -131,6 +136,7 @@ class PresentationArea extends PureComponent {
       restoreOnUpdate,
       layoutContextDispatch,
       layoutContextState,
+      userIsPresenter,
     } = this.props;
 
     const { numUsersVideo } = layoutContextState;
@@ -172,16 +178,36 @@ class PresentationArea extends PureComponent {
       }
     }
 
-    if (prevProps.currentPresentation.name !== currentPresentation.name) {
+    const downloadableOn = !prevProps.currentPresentation.downloadable
+      && currentPresentation.downloadable;
+
+    const shouldCloseToast = !(currentPresentation.downloadable && !userIsPresenter);
+
+    if (
+      prevProps.currentPresentation.name !== currentPresentation.name
+      || (downloadableOn && !userIsPresenter)
+    ) {
       if (this.currentPresentationToastId) {
-        return toast.update(this.currentPresentationToastId, {
+        toast.update(this.currentPresentationToastId, {
+          autoClose: shouldCloseToast,
           render: this.renderCurrentPresentationToast(),
         });
+      } else {
+        this.currentPresentationToastId = toast(this.renderCurrentPresentationToast(), {
+          onClose: () => { this.currentPresentationToastId = null; },
+          autoClose: shouldCloseToast,
+          className: toastStyles.actionToast,
+        });
       }
+    }
+
+    const downloadableOff = prevProps.currentPresentation.downloadable
+      && !currentPresentation.downloadable;
 
-      this.currentPresentationToastId = toast(this.renderCurrentPresentationToast(), {
-        onClose: () => { this.currentPresentationToastId = null; },
+    if (this.currentPresentationToastId && downloadableOff) {
+      toast.update(this.currentPresentationToastId, {
         autoClose: true,
+        render: this.renderCurrentPresentationToast(),
       });
     }
 
@@ -670,7 +696,10 @@ class PresentationArea extends PureComponent {
   }
 
   renderCurrentPresentationToast() {
-    const { intl, currentPresentation } = this.props;
+    const {
+      intl, currentPresentation, userIsPresenter, downloadPresentationUri,
+    } = this.props;
+    const { downloadable } = currentPresentation;
 
     return (
       <div className={styles.innerToastWrapper}>
@@ -679,10 +708,28 @@ class PresentationArea extends PureComponent {
             <Icon iconName="presentation" />
           </div>
         </div>
+
         <div className={styles.toastTextContent} data-test="toastSmallMsg">
           <div>{`${intl.formatMessage(intlMessages.changeNotification)}`}</div>
           <div className={styles.presentationName}>{`${currentPresentation.name}`}</div>
         </div>
+
+        {downloadable && !userIsPresenter
+          ? (
+            <span className={styles.toastDownload}>
+              <div className={toastStyles.separator} />
+              <a
+                className={styles.downloadBtn}
+                aria-label={`${intl.formatMessage(intlMessages.downloadLabel)} ${currentPresentation.name}`}
+                href={downloadPresentationUri}
+                target="_blank"
+                rel="noopener noreferrer"
+              >
+                {intl.formatMessage(intlMessages.downloadLabel)}
+              </a>
+            </span>
+          ) : null
+        }
       </div>
     );
   }
diff --git a/bigbluebutton-html5/imports/ui/components/presentation/styles.scss b/bigbluebutton-html5/imports/ui/components/presentation/styles.scss
index d7efec3bc5..fdf85c3c89 100644
--- a/bigbluebutton-html5/imports/ui/components/presentation/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/presentation/styles.scss
@@ -4,6 +4,7 @@
 :root {
   --innerToastWidth: 17rem;
   --iconWrapperSize: 2rem;
+  --toast-icon-side: 40px;
 }
 
 .enter {
@@ -93,14 +94,17 @@
 }
 
 .innerToastWrapper {
-  display: flex;
-  flex-direction: row;
   width: var(--innerToastWidth);
 }
 
 .toastTextContent {
   position: relative;
   overflow: hidden;
+  margin-top: var(--sm-padding-y);
+
+  > div:first-of-type {
+    font-weight: bold;
+  }
 }
 
 .presentationName {
@@ -108,6 +112,13 @@
   overflow: hidden;
 }
 
+.toastMessage {
+  font-size: var(--font-size-small);
+  margin-top: var(--toast-margin);
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
 .toastIcon {
   margin-right: var(--sm-padding-x);
   [dir="rtl"] & {
@@ -118,21 +129,37 @@
 
 .iconWrapper {
   background-color: var(--color-primary);
-  width: var(--iconWrapperSize);
-  height: var(--iconWrapperSize);
+  width: var(--toast-icon-side);
+  height: var(--toast-icon-side);
   border-radius: 50%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 
   > i {
     position: relative;
-    left: var(--md-padding-y);
-    top: var(--sm-padding-y);
-    font-size: var(--font-size-base);
     color: var(--color-white);
+    font-size: var(--font-size-larger);
+  }
+}
+
+.toastDownload {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
 
-    [dir="rtl"] & {
-      left: 0;
-      right: var(--md-padding-y);
-   }
+  a {
+    color: var(--color-primary);
+    cursor: pointer;
+    text-decoration: none;
+
+    &:focus,
+    &:hover,
+    &:active {
+      color: var(--color-primary);
+      box-shadow: 0;
+    }
   }
 }
 
diff --git a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx
index a337150da8..78f822c1fb 100644
--- a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx
@@ -5,6 +5,7 @@ import { toast } from 'react-toastify';
 import Icon from '/imports/ui/components/icon/component';
 import Button from '/imports/ui/components/button/component';
 import { ENTER } from '/imports/utils/keyCodes';
+import toastStyles from '/imports/ui/components/toast/styles';
 import { styles } from './styles';
 
 const messages = defineMessages({
@@ -71,7 +72,7 @@ class StatusNotifier extends Component {
             autoClose: false,
             closeOnClick: false,
             closeButton: false,
-            className: styles.raisedHandsToast,
+            className: toastStyles.actionToast,
           });
         }
         break;
@@ -161,7 +162,7 @@ class StatusNotifier extends Component {
           <div>{intl.formatMessage(messages.raisedHandsTitle)}</div>
           {formattedRaisedHands}
         </div>
-        <div className={styles.separator} />
+        <div className={toastStyles.separator} />
         <Button
           className={styles.clearBtn}
           label={intl.formatMessage(messages.lowerHandsLabel)}
diff --git a/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss b/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss
index 5f396dfcc9..d5f4978fdc 100644
--- a/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss
@@ -3,7 +3,6 @@
 
 :root {
   --iconWrapperSize: 40px;
-  --icon-offset: .6rem;
   --innerToastWidth: 17rem;
   --toast-margin: .5rem;
   --toast-icon-side: 40px;
@@ -87,23 +86,6 @@
   padding: 5px 0;
 }
 
-.raisedHandsToast {
-  display: flex;
-  position: relative;
-  margin-bottom: var(--sm-padding-x);
-  padding: var(--md-padding-x);
-  border-radius: var(--border-radius);
-  box-shadow: 0 var(--border-size-small) 10px 0 rgba(0, 0, 0, 0.1), 0 var(--border-size) 15px 0 rgba(0, 0, 0, 0.05);
-  justify-content: space-between;
-  color: var(--color-text);
-  background-color: var(--color-white);
-  -webkit-animation-duration: 0.75s;
-  animation-duration: 0.75s;
-  -webkit-animation-fill-mode: both;
-  animation-fill-mode: both;
-  max-width: var(--toast-max-width);
-}
-
 .avatar:hover,
 .avatar:focus {
     border: solid var(--border-size) var(--color-gray-lighter);
@@ -118,8 +100,8 @@
   > i {
     position: relative;
     color: var(--color-white);
-    top: var(--icon-offset);
-    left: var(--icon-offset);
+    top: var(--toast-margin);
+    left: var(--toast-margin);
     font-size: var(--font-size-xl);
   
     [dir="rtl"] & {
diff --git a/bigbluebutton-html5/imports/ui/components/toast/styles.scss b/bigbluebutton-html5/imports/ui/components/toast/styles.scss
index a5ff879223..854bfffeb7 100755
--- a/bigbluebutton-html5/imports/ui/components/toast/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/toast/styles.scss
@@ -144,21 +144,28 @@
   }
 }
 
-.toast {
+.toast ,
+.actionToast {
   position: relative;
   margin-bottom: var(--sm-padding-x);
-  padding: var(--md-padding-x);
+  padding: 12px;
   border-radius: var(--border-radius);
   box-shadow: 0 var(--border-size-small) 10px 0 rgba(0, 0, 0, 0.1), 0 var(--border-size) 15px 0 rgba(0, 0, 0, 0.05);
   display: flex;
   justify-content: space-between;
-  cursor: pointer;
   color: var(--color-text);
-  background-color: var(--background);
+  -webkit-animation-duration: 0.75s;
   animation-duration: 0.75s;
+  -webkit-animation-fill-mode: both;
   animation-fill-mode: both;
   max-width: var(--toast-max-width);
+  min-width: var(--toast-max-width);
   width: var(--toast-max-width);
+}
+
+.toast {
+  cursor: pointer;
+  background-color: var(--background);
 
   &:hover,
   &:focus {
@@ -166,6 +173,14 @@
   }
 }
 
+.actionToast {
+  background-color: var(--color-white);
+
+  i.close {
+    left: none !important;
+  }
+}
+
 .body {
   margin: auto auto;
   flex: 1;
diff --git a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
index bf83f8da39..492a95241e 100644
--- a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
+++ b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
@@ -7,6 +7,7 @@
 
   --font-size-base: 1rem;
   --font-size-xl: 1.75rem;
+  --font-size-larger: 1.5rem;
   --font-size-large: 1.25rem;
   --font-size-md: 0.95rem; 
   --font-size-small: 0.875rem;
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json
index cc6ff15f39..6457c594cf 100755
--- a/bigbluebutton-html5/private/locales/en.json
+++ b/bigbluebutton-html5/private/locales/en.json
@@ -135,6 +135,7 @@
     "app.meeting.alertBreakoutEndsUnderMinutesSingular": "Breakout is closing in one minute.",
     "app.presentation.hide": "Hide presentation",
     "app.presentation.notificationLabel": "Current presentation",
+    "app.presentation.downloadLabel": "Download",
     "app.presentation.slideContent": "Slide Content",
     "app.presentation.startSlideContent": "Slide content start",
     "app.presentation.endSlideContent": "Slide content end",
-- 
GitLab