Skip to content

Commit

Permalink
Add ability to send emails and notifications from the Messaging Center (
Browse files Browse the repository at this point in the history
mozilla#3259)

Note that until we implement recipient filters, the recipient of the messages is the sender.

Also included:
- Factor out check-box CSS
- Make .notification selectors in style.css and main.js more specific
  • Loading branch information
mathjazz authored Jul 2, 2024
1 parent cd0a3fd commit 4fd99f4
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 42 deletions.
36 changes: 36 additions & 0 deletions pontoon/base/static/css/check-box.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#main .check-list {
cursor: pointer;
list-style: none;
margin: 0;
display: inline-block;
text-align: left;

.check-box {
padding: 8px 0;
}

.check-box:last-child {
padding-bottom: 0;
}

.check-box-wrapper {
color: var(--light-grey-7);
display: table;
font-size: 16px;
font-weight: 300;
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
width: 342px;
}

.check-box-wrapper:hover {
color: var(--white-1);
}

.fa {
margin-left: 27px;
margin-right: 0;
}
}
6 changes: 3 additions & 3 deletions pontoon/base/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ tfoot td a {
text-align: left;
}

.notification {
body > header > .notification {
background: var(--tooltip-background);
color: var(--status-translated);
cursor: pointer;
Expand All @@ -530,14 +530,14 @@ tfoot td a {
z-index: 100;
}

.notification li {
body > header > .notification li {
font-size: 14px;
line-height: 60px;
list-style: none;
text-align: center;
}

.notification li.error {
body > header > .notification li.error {
color: var(--status-error);
}

Expand Down
4 changes: 2 additions & 2 deletions pontoon/base/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var Pontoon = (function (my) {
* Close notification
*/
closeNotification: function () {
$('.notification').animate(
$('body > header > .notification').animate(
{
top: '-60px',
},
Expand All @@ -107,7 +107,7 @@ var Pontoon = (function (my) {
*/
endLoader: function (text, type, duration) {
if (text) {
$('.notification')
$('body > header > .notification')
.html('<li class="' + (type || '') + '">' + text + '</li>')
.removeClass('hide')
.animate(
Expand Down
37 changes: 0 additions & 37 deletions pontoon/contributors/static/css/settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -154,43 +154,6 @@
font-style: italic;
}

#main .check-list {
cursor: pointer;
list-style: none;
margin: 0;
display: inline-block;
text-align: left;
}

#main .check-list .check-box {
padding: 8px 0;
}

#main .check-list .check-box:last-child {
padding-bottom: 0;
}

#main .check-list .check-box-wrapper {
color: var(--light-grey-7);
display: table;
font-size: 16px;
font-weight: 300;
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
width: 342px;
}

#main .check-list .check-box-wrapper:hover {
color: var(--white-1);
}

#main .check-list .fa {
margin-left: 27px;
margin-right: 0;
}

.errorlist {
color: var(--status-error);
font-style: italic;
Expand Down
10 changes: 10 additions & 0 deletions pontoon/messaging/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django import forms

from pontoon.base.forms import HtmlField


class MessageForm(forms.Form):
notification = forms.BooleanField(required=False)
email = forms.BooleanField(required=False)
subject = forms.CharField()
body = HtmlField()
92 changes: 92 additions & 0 deletions pontoon/messaging/static/css/messaging.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
.messaging {
.menu #compose li:hover {
background: inherit;
}

#compose {
padding: 20px;
box-sizing: border-box;

h3 {
color: var(--white-1);
font-size: 22px;
letter-spacing: 0;

.stress {
color: var(--status-translated);
}
}

.controls {
margin: 0;
}

.errors {
visibility: hidden;

p {
color: var(--status-error);
font-size: 13px;
padding-top: 5px;
text-transform: uppercase;
}
}

.message-type,
.message-editor {
margin: 20px 0;
}

.message-type {
.check-list {
.check-box-wrapper {
text-align: left;
}

.fa {
margin: 2px 10px 0 0;
float: left;
}
}

[type='checkbox'] {
display: none;
}
}

.field {
color: var(--light-grey-7);
font-size: 16px;
margin-bottom: 20px;
text-align: left;
}

label {
display: block;
margin-bottom: 5px;
}

input,
textarea {
background: var(--black-3);
float: none;
font-size: 16px;
padding: 4px;
width: 100%;
box-sizing: border-box;
}

textarea {
border-radius: 3px;
height: 150px;
}

.message-editor .subtitle {
color: var(--light-grey-7);
float: right;
font-size: 13px;
padding-top: 5px;
text-transform: uppercase;
}
}
}
64 changes: 64 additions & 0 deletions pontoon/messaging/static/js/messaging.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
$(function () {
// Toggle check box
$('.check-box').click(function () {
const self = $(this);

const name = self.data('attribute');
$(`[type=checkbox][name=${name}]`).click();

self.toggleClass('enabled');
});

const container = $('#main .container');

function isValidForm($form, isNotification, isEmail, subject, body) {
$form.find('.errors').css('visibility', 'hidden');

if (!isNotification && !isEmail) {
$form.find('.message-type .errors').css('visibility', 'visible');
}

if (!subject) {
$form
.find('.message-editor .subject .errors')
.css('visibility', 'visible');
}

if (!body) {
$form.find('.message-editor .body .errors').css('visibility', 'visible');
}

return (isNotification || isEmail) && subject && body;
}

// Send message
container.on('click', '#send-message .send', function (e) {
e.preventDefault();
const $form = $('#send-message');

const isNotification = $('.message-type .check-box.notification').is(
'.enabled',
);
const isEmail = $('.message-type .check-box.email').is('.enabled');
const subject = $form.find('[name=subject]').val();
const body = $form.find('[name=body]').val();

// Validate form
if (!isValidForm($form, isNotification, isEmail, subject, body)) {
return;
}

// Submit form
$.ajax({
url: $form.prop('action'),
type: $form.prop('method'),
data: $form.serialize(),
success: function () {
Pontoon.endLoader('Message sent.');
},
error: function () {
Pontoon.endLoader('Oops, something went wrong.', 'error');
},
});
});
});
93 changes: 93 additions & 0 deletions pontoon/messaging/templates/messaging/messaging.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{% extends 'base.html' %}
{% import "widgets/checkbox.html" as Checkbox %}
{% import 'heading.html' as Heading %}
{% import "contributors/widgets/notifications_menu.html" as Notifications with context %}

{% block title %}Messaging Center{% endblock %}

{% block class %}messaging{% endblock %}

{% block heading %}
{{ Heading.heading(title='Messaging Center', subtitle='Send emails and notifications to localizers') }}
{% endblock %}

{% block bottom %}
<section id="main">
<div class="container">
<section class="clearfix">
<div class="menu permanent left-column">
<ul>
<li class="selected">
<a href="#compose" data-target="#compose">Compose</a>
</li>
<li class="horizontal-separator"></li>
<li>
<a href="#sent" data-target="#sent">
<span class="name">Sent</span>
<span class="count">{{ messages|length }}</span>
</a>
</li>
</ul>
</div>

<div class="menu permanent right-column">
<section id="compose" class="selected">
<form id="send-message" method="POST" action="{{ url('pontoon.messaging.send_message') }}">
{% csrf_token %}

<h3><span class="stress">#1</span> Message type</h3>
<div class="message-type">
<ul class="check-list">
{{ Checkbox.checkbox('Notification', class='notification', attribute='notification') }}
<input type="checkbox" name="notification">
{{ Checkbox.checkbox('Email', class='email', attribute='email') }}
<input type="checkbox" name="email">
</ul>

<div class="errors">
<p>You must select at least one message type</p>
</div>
</div>

<h3><span class="stress">#2</span> Message editor</h3>
<div class="message-editor">
<div class="field clearfix subject">
<label for="subject">Subject</label>
<input type="text" name="subject" required="" id="subject">
<div class="errors">
<p>Your message must include a subject</p>
</div>
</div>

<div class="field clearfix body">
<label for="body">Body</label>
<textarea name="body" cols="40" rows="10" required="" id="body"></textarea>
<div class="subtitle">
<p>Supports html</p>
</div>
<div class="errors">
<p>Your message must include a body</p>
</div>
</div>
</div>

<menu class="controls">
<button class="button active send">Send</button>
</menu>
</form>
</section>
<section id="sent">
</section>
</div>
</section>
</div>
</section>
{% endblock %}

{% block extend_css %}
{% stylesheet 'messaging' %}
{% endblock %}

{% block extend_js %}
{% javascript 'messaging' %}
{% endblock %}
Loading

0 comments on commit 4fd99f4

Please sign in to comment.