diff --git a/app/assets/stylesheets/shared/notifier.scss b/app/assets/stylesheets/shared/notifier.scss
index 8c59976327..7e3f89d648 100644
--- a/app/assets/stylesheets/shared/notifier.scss
+++ b/app/assets/stylesheets/shared/notifier.scss
@@ -8,17 +8,19 @@
}
#notifications {
- bottom: 2em;
+ bottom: 0;
display: flex;
flex-direction: column;
font-weight: 900;
+ max-height: 100vh;
+ overflow-y: auto;
position: fixed;
right: 2em;
z-index: 100;
div {
border-radius: .25em;
- margin: .25em;
+ margin-bottom: .5em;
margin-left: auto;
margin-right: 0;
padding: .5em;
@@ -28,17 +30,22 @@
}
}
- .failure-indicator {
+ .danger-notification {
background-color: #b71c1c;
color: white
}
- .success-indicator {
+ .messages {
+ margin-bottom: 0;
+ padding: 0;
+ }
+
+ .success-notification {
background-color: #28a745;
color: white
}
- .warn-indicator {
+ .warning-notification {
background-color: #ffc107;
}
@@ -58,4 +65,16 @@
width: 1em
}
}
+
+ #toggle-minimize-notifications {
+ background-color: #333;
+ border: 0;
+ border-radius: 10px 10px 0 0;
+ color: white;
+ padding: 0.25em 1em;
+
+ span {
+ display: inline;
+ }
+ }
}
diff --git a/app/javascript/__tests__/notifier.test.js b/app/javascript/__tests__/notifier.test.js
index acdce50ae1..4a564f0bd1 100644
--- a/app/javascript/__tests__/notifier.test.js
+++ b/app/javascript/__tests__/notifier.test.js
@@ -9,13 +9,22 @@ let notifier
beforeEach(() => {
document.body.innerHTML = `
+ `
${escapedMessage}
${dismissButtonAsHTML}
`
)
- this.notificationsElement.append(newNotificationAsJQuery)
+ this.elements.messagesContainer.append(newNotificationAsJQuery)
- if (isDismissable) {
- newNotificationAsJQuery.children('button').on('click', function () {
- $(this).parent().remove()
- })
- }
+ const newNotification = new Notification(newNotificationAsJQuery, this)
- const newNotification = new Notification(newNotificationAsJQuery)
+ this.notificationsCount[level]++
return newNotification
}
- // Shows a loading indicator until all operations resolve
- waitForAsyncOperation () {
- this.loadingToast.show()
- this.waitingAsyncOperationCount++
- }
-
// Shows the saved toast for 2 seconds and hides the loading indicator if no more async operations are pending
// @param {string=} error The error to be displayed(optional)
// @throws {Error} for trying to resolve more async operations than the amount currently awaiting
@@ -178,18 +216,18 @@ class Notifier {
this.waitingAsyncOperationCount--
if (this.waitingAsyncOperationCount === 0) {
- this.loadingToast.hide()
+ this.elements.loadingToast.hide()
}
if (!errorMsg) {
- this.savedToast.show()
+ this.elements.savedToast.show()
this.savedToastTimeouts.forEach((timeoutID) => {
clearTimeout(timeoutID)
})
this.savedToastTimeouts.push(setTimeout(() => {
- this.savedToast.hide()
+ this.elements.savedToast.hide()
this.savedToastTimeouts.shift()
}, 2000))
} else {
@@ -200,6 +238,51 @@ class Notifier {
this.notify(errorMsg, 'error')
}
}
+
+ #setMinimizeButtonVisibility (visible) {
+ if (visible) {
+ this.elements.minimizeButton.show()
+ } else {
+ this.elements.minimizeButton.hide()
+ }
+ }
+
+ #toggleMinimize () {
+ const { messagesContainer } = this.elements
+
+ if (messagesContainer.css('display') === 'none') {
+ messagesContainer.show()
+ this.elements.minimizeButtonText.show()
+ this.elements.messageCountBadges.all.hide()
+ this.elements.minimizeButtonIcon.removeClass('fa-plus').addClass('fa-minus')
+ } else {
+ messagesContainer.hide()
+
+ for (const level in this.notificationsCount) {
+ const levelMessageCount = this.notificationsCount[level]
+
+ if (levelMessageCount) {
+ const levelBadge = this.elements.messageCountBadges[level]
+ levelBadge.show()
+ }
+ }
+
+ this.elements.minimizeButtonText.hide()
+ this.elements.minimizeButtonIcon.removeClass('fa-minus').addClass('fa-plus')
+ }
+ }
+
+ totalNotificationCount () {
+ return Object.values(this.notificationsCount).reduce((acc, currentValue) => {
+ return acc + currentValue
+ }, 0)
+ }
+
+ // Shows a loading indicator until all operations resolve
+ waitForAsyncOperation () {
+ this.elements.loadingToast.show()
+ this.waitingAsyncOperationCount++
+ }
}
module.exports = { Notifier, Notification }
diff --git a/app/views/layouts/_notifier.erb b/app/views/layouts/_notifier.erb
index 88036b5c04..127ba59afb 100644
--- a/app/views/layouts/_notifier.erb
+++ b/app/views/layouts/_notifier.erb
@@ -1,8 +1,17 @@
+
+
Saving
-
+
Saved
+
diff --git a/spec/system/all_casa_admins/patch_notes/index_spec.rb b/spec/system/all_casa_admins/patch_notes/index_spec.rb
index dfe40e2b22..edb4da50ed 100644
--- a/spec/system/all_casa_admins/patch_notes/index_spec.rb
+++ b/spec/system/all_casa_admins/patch_notes/index_spec.rb
@@ -13,7 +13,7 @@
click_on "Create"
end
- expect(page).to have_selector(".warn-indicator", text: "Cannot save an empty patch note")
+ expect(page).to have_selector(".warning-notification", text: "Cannot save an empty patch note")
end
end
diff --git a/spec/system/casa_cases/emancipation/show_spec.rb b/spec/system/casa_cases/emancipation/show_spec.rb
index e7331c2bd9..95a1b40898 100644
--- a/spec/system/casa_cases/emancipation/show_spec.rb
+++ b/spec/system/casa_cases/emancipation/show_spec.rb
@@ -29,7 +29,7 @@
expect(emancipation_category["data-is-open"]).to match(/true/)
find(".check-item").click
find(".emacipation-category-input-label-pair").click
- expect(page).to have_css(".success-indicator", text: "Unchecked #{emancipation_option.name}")
+ expect(page).to have_css(".success-notification", text: "Unchecked #{emancipation_option.name}")
expect(emancipation_category["data-is-open"]).to match(/true/)
end