Bug 1076764 - Added notifications for Loop contacts import. r=Standard8

This commit is contained in:
Nicolas Perriault 2015-01-16 12:26:25 +01:00
Родитель f1beadbd11
Коммит 51e3821d3b
10 изменённых файлов: 125 добавлений и 7 удалений

Просмотреть файл

@ -263,6 +263,11 @@ loop.contacts = (function(_, mozL10n) {
loop.shared.mixins.WindowCloseMixin
],
propTypes: {
notifications: React.PropTypes.instanceOf(
loop.shared.models.NotificationCollection).isRequired
},
/**
* Contacts collection object
*/
@ -389,10 +394,14 @@ loop.contacts = (function(_, mozL10n) {
service: "google"
}, (err, stats) => {
this.setState({ importBusy: false });
// TODO: bug 1076764 - proper error and success reporting.
if (err) {
throw err;
console.error("Contact import error", err);
this.props.notifications.errorL10n("import_contacts_failure_message");
return;
}
this.props.notifications.successL10n("import_contacts_success_message", {
total: stats.total
});
});
},

Просмотреть файл

@ -263,6 +263,11 @@ loop.contacts = (function(_, mozL10n) {
loop.shared.mixins.WindowCloseMixin
],
propTypes: {
notifications: React.PropTypes.instanceOf(
loop.shared.models.NotificationCollection).isRequired
},
/**
* Contacts collection object
*/
@ -389,10 +394,14 @@ loop.contacts = (function(_, mozL10n) {
service: "google"
}, (err, stats) => {
this.setState({ importBusy: false });
// TODO: bug 1076764 - proper error and success reporting.
if (err) {
throw err;
console.error("Contact import error", err);
this.props.notifications.errorL10n("import_contacts_failure_message");
return;
}
this.props.notifications.successL10n("import_contacts_success_message", {
total: stats.total
});
});
},

Просмотреть файл

@ -989,7 +989,8 @@ loop.panel = (function(_, mozL10n) {
this._renderRoomsOrCallTab(),
React.createElement(Tab, {name: "contacts"},
React.createElement(ContactsList, {selectTab: this.selectTab,
startForm: this.startForm})
startForm: this.startForm,
notifications: this.props.notifications})
),
React.createElement(Tab, {name: "contacts_add", hidden: true},
React.createElement(ContactDetailsForm, {ref: "contacts_add", mode: "add",

Просмотреть файл

@ -989,7 +989,8 @@ loop.panel = (function(_, mozL10n) {
{this._renderRoomsOrCallTab()}
<Tab name="contacts">
<ContactsList selectTab={this.selectTab}
startForm={this.startForm} />
startForm={this.startForm}
notifications={this.props.notifications} />
</Tab>
<Tab name="contacts_add" hidden={true}>
<ContactDetailsForm ref="contacts_add" mode="add"

Просмотреть файл

@ -263,6 +263,12 @@ p {
border: 1px solid #fbeed5;
}
.alert-success {
background: #5BC0A4;
border: 1px solid #5BC0A4;
color: #fff;
}
.notificationContainer > .details-error {
background: #fbebeb;
color: #d74345

Просмотреть файл

@ -422,6 +422,27 @@ loop.shared.models = (function(l10n) {
*/
errorL10n: function(messageId, l10nProps) {
this.error(l10n.get(messageId, l10nProps));
},
/**
* Adds a success notification to the stack and renders it.
*
* @return {String} message
*/
success: function(message) {
this.add({level: "success", message: message});
},
/**
* Adds a l10n success notification to the stack and renders it.
*
* @param {String} messageId L10n message id
* @param {Object} [l10nProps] An object with variables to be interpolated
* into the translation. All members' values must be
* strings or numbers.
*/
successL10n: function(messageId, l10nProps) {
this.success(l10n.get(messageId, l10nProps));
}
});

Просмотреть файл

@ -16,6 +16,7 @@ describe("loop.contacts", function() {
var fakeDoneButtonText = "Fake Done";
var sandbox;
var fakeWindow;
var notifications;
beforeEach(function(done) {
sandbox = sinon.sandbox.create();
@ -59,8 +60,11 @@ describe("loop.contacts", function() {
};
navigator.mozLoop.contacts = {getAll: sandbox.stub()};
notifications = new loop.shared.models.NotificationCollection();
listView = TestUtils.renderIntoDocument(
React.createElement(loop.contacts.ContactsList));
React.createElement(loop.contacts.ContactsList, {
notifications: notifications
}));
});
afterEach(function() {
@ -84,6 +88,34 @@ describe("loop.contacts", function() {
sinon.assert.calledOnce(fakeWindow.close);
});
});
describe("#handleImportButtonClick", function() {
it("should notify the end user from a succesful import", function() {
sandbox.stub(notifications, "successL10n");
navigator.mozLoop.startImport = function(opts, cb) {
cb(null, {total: 42});
};
listView.handleImportButtonClick();
sinon.assert.calledWithExactly(
notifications.successL10n,
"import_contacts_success_message",
{total: 42});
});
it("should notify the end user from any encountered error", function() {
sandbox.stub(notifications, "errorL10n");
navigator.mozLoop.startImport = function(opts, cb) {
cb(new Error("fake error"));
};
listView.handleImportButtonClick();
sinon.assert.calledWithExactly(notifications.errorL10n,
"import_contacts_failure_message");
});
});
});
describe("ContactDetailsForm", function() {

Просмотреть файл

@ -268,6 +268,22 @@
dispatcher: dispatcher,
roomStore: roomStore,
selectedTab: "rooms"})
),
React.createElement(Example, {summary: "Contact import success", dashed: "true", style: {width: "332px"}},
React.createElement(PanelView, {notifications: new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}]),
userProfile: {email: "test@example.com"},
mozLoop: mockMozLoopRooms,
dispatcher: dispatcher,
roomStore: roomStore,
selectedTab: "contacts"})
),
React.createElement(Example, {summary: "Contact import error", dashed: "true", style: {width: "332px"}},
React.createElement(PanelView, {notifications: new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}]),
userProfile: {email: "test@example.com"},
mozLoop: mockMozLoopRooms,
dispatcher: dispatcher,
roomStore: roomStore,
selectedTab: "contacts"})
)
),

Просмотреть файл

@ -269,6 +269,22 @@
roomStore={roomStore}
selectedTab="rooms" />
</Example>
<Example summary="Contact import success" dashed="true" style={{width: "332px"}}>
<PanelView notifications={new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}])}
userProfile={{email: "test@example.com"}}
mozLoop={mockMozLoopRooms}
dispatcher={dispatcher}
roomStore={roomStore}
selectedTab="contacts" />
</Example>
<Example summary="Contact import error" dashed="true" style={{width: "332px"}}>
<PanelView notifications={new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}])}
userProfile={{email: "test@example.com"}}
mozLoop={mockMozLoopRooms}
dispatcher={dispatcher}
roomStore={roomStore}
selectedTab="contacts" />
</Example>
</Section>
<Section name="IncomingCallView">

Просмотреть файл

@ -120,6 +120,13 @@ add_or_import_contact_title=Add or Import Contact
## for where these appear on the UI
import_contacts_button=Import
importing_contacts_progress_button=Importing…
import_contacts_failure_message=Some contacts could not be imported. Please try again.
## LOCALIZATION NOTE(import_contacts_success_message): Success notification message
## when user's contacts have been successfully imported.
## Semicolon-separated list of plural forms. See:
## http://developer.mozilla.org/en/docs/Localization_and_Plurals
## In this item, don't translate the part between {{..}}
import_contacts_success_message={{total}} contact was successfully imported.;{{total}} contacts were successfully imported.
## LOCALIZATION NOTE(sync_contacts_button): This button is displayed in place of
## importing_contacts_button once contacts have been imported once.
sync_contacts_button=Sync Contacts