зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1102170 - Share a room url by email when Loop direct call fails. r=Standard8
This commit is contained in:
Родитель
437abd21ee
Коммит
db9bde32fb
|
@ -27,6 +27,13 @@ loop.conversationViews = (function(mozL10n) {
|
|||
return contact.email.find(e => e.pref) || contact.email[0];
|
||||
}
|
||||
|
||||
function _getContactDisplayName(contact) {
|
||||
if (contact.name && contact.name[0]) {
|
||||
return contact.name[0];
|
||||
}
|
||||
return _getPreferredEmail(contact).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information about the call
|
||||
* Caller avatar, name & conversation creation date
|
||||
|
@ -107,14 +114,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var contactName;
|
||||
|
||||
if (this.props.contact.name &&
|
||||
this.props.contact.name[0]) {
|
||||
contactName = this.props.contact.name[0];
|
||||
} else {
|
||||
contactName = _getPreferredEmail(this.props.contact).value;
|
||||
}
|
||||
var contactName = _getContactDisplayName(this.props.contact);
|
||||
|
||||
document.title = contactName;
|
||||
|
||||
|
@ -262,7 +262,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
emailLinkButtonDisabled: true
|
||||
});
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchEmailLink());
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: navigator.mozLoop.userProfile.email,
|
||||
roomName: _getContactDisplayName(this.props.contact)
|
||||
}));
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
|
|
@ -27,6 +27,13 @@ loop.conversationViews = (function(mozL10n) {
|
|||
return contact.email.find(e => e.pref) || contact.email[0];
|
||||
}
|
||||
|
||||
function _getContactDisplayName(contact) {
|
||||
if (contact.name && contact.name[0]) {
|
||||
return contact.name[0];
|
||||
}
|
||||
return _getPreferredEmail(contact).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information about the call
|
||||
* Caller avatar, name & conversation creation date
|
||||
|
@ -107,14 +114,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var contactName;
|
||||
|
||||
if (this.props.contact.name &&
|
||||
this.props.contact.name[0]) {
|
||||
contactName = this.props.contact.name[0];
|
||||
} else {
|
||||
contactName = _getPreferredEmail(this.props.contact).value;
|
||||
}
|
||||
var contactName = _getContactDisplayName(this.props.contact);
|
||||
|
||||
document.title = contactName;
|
||||
|
||||
|
@ -262,7 +262,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
emailLinkButtonDisabled: true
|
||||
});
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchEmailLink());
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: navigator.mozLoop.userProfile.email,
|
||||
roomName: _getContactDisplayName(this.props.contact)
|
||||
}));
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
|
|
@ -76,10 +76,12 @@ loop.shared.actions = (function() {
|
|||
}),
|
||||
|
||||
/**
|
||||
* Fetch a new call url from the server, intended to be sent over email when
|
||||
* Fetch a new room url from the server, intended to be sent over email when
|
||||
* a contact can't be reached.
|
||||
*/
|
||||
FetchEmailLink: Action.define("fetchEmailLink", {
|
||||
FetchRoomEmailLink: Action.define("fetchRoomEmailLink", {
|
||||
roomOwner: String,
|
||||
roomName: String
|
||||
}),
|
||||
|
||||
/**
|
||||
|
|
|
@ -210,7 +210,7 @@ loop.store = loop.store || {};
|
|||
"retryCall",
|
||||
"mediaConnected",
|
||||
"setMute",
|
||||
"fetchEmailLink"
|
||||
"fetchRoomEmailLink"
|
||||
]);
|
||||
|
||||
this.setStoreState({
|
||||
|
@ -323,18 +323,21 @@ loop.store = loop.store || {};
|
|||
},
|
||||
|
||||
/**
|
||||
* Fetches a new call URL intended to be sent over email when a contact
|
||||
* Fetches a new room URL intended to be sent over email when a contact
|
||||
* can't be reached.
|
||||
*/
|
||||
fetchEmailLink: function() {
|
||||
// XXX This is an empty string as a conversation identifier. Bug 1015938 implements
|
||||
// a user-set string.
|
||||
this.client.requestCallUrl("", function(err, callUrlData) {
|
||||
fetchRoomEmailLink: function(actionData) {
|
||||
this.mozLoop.rooms.create({
|
||||
roomName: actionData.roomName,
|
||||
roomOwner: actionData.roomOwner,
|
||||
maxSize: loop.store.MAX_ROOM_CREATION_SIZE,
|
||||
expiresIn: loop.store.DEFAULT_EXPIRES_IN
|
||||
}, function(err, createdRoomData) {
|
||||
if (err) {
|
||||
this.trigger("error:emailLink");
|
||||
return;
|
||||
}
|
||||
this.setStoreState({"emailLink": callUrlData.callUrl});
|
||||
this.setStoreState({"emailLink": createdRoomData.roomUrl});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
|
|
@ -16,6 +16,20 @@ loop.store = loop.store || {};
|
|||
*/
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
/**
|
||||
* Maximum size given to createRoom; only 2 is supported (and is
|
||||
* always passed) because that's what the user-experience is currently
|
||||
* designed and tested to handle.
|
||||
* @type {Number}
|
||||
*/
|
||||
var MAX_ROOM_CREATION_SIZE = loop.store.MAX_ROOM_CREATION_SIZE = 2;
|
||||
|
||||
/**
|
||||
* The number of hours for which the room will exist - default 8 weeks
|
||||
* @type {Number}
|
||||
*/
|
||||
var DEFAULT_EXPIRES_IN = loop.store.DEFAULT_EXPIRES_IN = 24 * 7 * 8;
|
||||
|
||||
/**
|
||||
* Room validation schema. See validate.js.
|
||||
* @type {Object}
|
||||
|
@ -61,13 +75,13 @@ loop.store = loop.store || {};
|
|||
* designed and tested to handle.
|
||||
* @type {Number}
|
||||
*/
|
||||
maxRoomCreationSize: 2,
|
||||
maxRoomCreationSize: MAX_ROOM_CREATION_SIZE,
|
||||
|
||||
/**
|
||||
* The number of hours for which the room will exist - default 8 weeks
|
||||
* @type {Number}
|
||||
*/
|
||||
defaultExpiresIn: 24 * 7 * 8,
|
||||
defaultExpiresIn: DEFAULT_EXPIRES_IN,
|
||||
|
||||
/**
|
||||
* Registered actions.
|
||||
|
|
|
@ -56,7 +56,10 @@ describe("loop.conversationViews", function () {
|
|||
},
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
callback(null, new Blob([new ArrayBuffer(10)], {type: "audio/ogg"}));
|
||||
})
|
||||
}),
|
||||
userProfile: {
|
||||
email: "bob@invalid.tld"
|
||||
}
|
||||
};
|
||||
|
||||
fakeWindow = {
|
||||
|
@ -241,12 +244,15 @@ describe("loop.conversationViews", function () {
|
|||
describe("CallFailedView", function() {
|
||||
var store, fakeAudio;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
var contact = {email: [{value: "test@test.tld"}]};
|
||||
|
||||
function mountTestComponent(options) {
|
||||
options = options || {};
|
||||
return TestUtils.renderIntoDocument(
|
||||
loop.conversationViews.CallFailedView({
|
||||
dispatcher: dispatcher,
|
||||
store: store,
|
||||
contact: {email: [{value: "test@test.tld"}]}
|
||||
contact: options.contact
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -266,7 +272,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should dispatch a retryCall action when the retry button is pressed",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
var retryBtn = view.getDOMNode().querySelector('.btn-retry');
|
||||
|
||||
|
@ -279,7 +285,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should dispatch a cancelCall action when the cancel button is pressed",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
var cancelBtn = view.getDOMNode().querySelector('.btn-cancel');
|
||||
|
||||
|
@ -290,9 +296,9 @@ describe("loop.conversationViews", function () {
|
|||
sinon.match.hasOwn("name", "cancelCall"));
|
||||
});
|
||||
|
||||
it("should dispatch a fetchEmailLink action when the cancel button is pressed",
|
||||
it("should dispatch a fetchRoomEmailLink action when the email button is pressed",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
var emailLinkBtn = view.getDOMNode().querySelector('.btn-email');
|
||||
|
||||
|
@ -300,12 +306,32 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "fetchEmailLink"));
|
||||
sinon.match.hasOwn("name", "fetchRoomEmailLink"));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("roomOwner", fakeMozLoop.userProfile.email));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("roomName", "test@test.tld"));
|
||||
});
|
||||
|
||||
it("should name the created room using the contact name when available",
|
||||
function() {
|
||||
view = mountTestComponent({contact: {
|
||||
email: [{value: "test@test.tld"}],
|
||||
name: ["Mr Fake ContactName"]
|
||||
}});
|
||||
|
||||
var emailLinkBtn = view.getDOMNode().querySelector('.btn-email');
|
||||
|
||||
React.addons.TestUtils.Simulate.click(emailLinkBtn);
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("roomName", "Mr Fake ContactName"));
|
||||
});
|
||||
|
||||
it("should disable the email link button once the action is dispatched",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
var emailLinkBtn = view.getDOMNode().querySelector('.btn-email');
|
||||
React.addons.TestUtils.Simulate.click(emailLinkBtn);
|
||||
|
||||
|
@ -314,7 +340,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should compose an email once the email link is received", function() {
|
||||
var composeCallUrlEmail = sandbox.stub(sharedUtils, "composeCallUrlEmail");
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
store.setStoreState({emailLink: "http://fake.invalid/"});
|
||||
|
||||
sinon.assert.calledOnce(composeCallUrlEmail);
|
||||
|
@ -324,7 +350,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should close the conversation window once the email link is received",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
store.setStoreState({emailLink: "http://fake.invalid/"});
|
||||
|
||||
|
@ -333,7 +359,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should display an error message in case email link retrieval failed",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
store.trigger("error:emailLink");
|
||||
|
||||
|
@ -342,7 +368,7 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
it("should allow retrying to get a call url if it failed previously",
|
||||
function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
store.trigger("error:emailLink");
|
||||
|
||||
|
@ -350,7 +376,7 @@ describe("loop.conversationViews", function () {
|
|||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
view = mountTestComponent();
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
|
|
|
@ -42,6 +42,9 @@ describe("loop.store.ConversationStore", function () {
|
|||
calls: {
|
||||
setCallInProgress: sandbox.stub(),
|
||||
clearCallInProgress: sandbox.stub()
|
||||
},
|
||||
rooms: {
|
||||
create: sandbox.stub()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -701,20 +704,29 @@ describe("loop.store.ConversationStore", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#fetchEmailLink", function() {
|
||||
describe("#fetchRoomEmailLink", function() {
|
||||
it("should request a new call url to the server", function() {
|
||||
store.fetchEmailLink(new sharedActions.FetchEmailLink());
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(client.requestCallUrl);
|
||||
sinon.assert.calledWith(client.requestCallUrl, "");
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.create);
|
||||
sinon.assert.calledWithMatch(fakeMozLoop.rooms.create, {
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
});
|
||||
});
|
||||
|
||||
it("should update the emailLink attribute when the new call url is received",
|
||||
it("should update the emailLink attribute when the new room url is received",
|
||||
function() {
|
||||
client.requestCallUrl = function(callId, cb) {
|
||||
cb(null, {callUrl: "http://fake.invalid/"});
|
||||
fakeMozLoop.rooms.create = function(roomData, cb) {
|
||||
cb(null, {roomUrl: "http://fake.invalid/"});
|
||||
};
|
||||
store.fetchEmailLink(new sharedActions.FetchEmailLink());
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState("emailLink")).eql("http://fake.invalid/");
|
||||
});
|
||||
|
@ -722,10 +734,13 @@ describe("loop.store.ConversationStore", function () {
|
|||
it("should trigger an error:emailLink event in case of failure",
|
||||
function() {
|
||||
var trigger = sandbox.stub(store, "trigger");
|
||||
client.requestCallUrl = function(callId, cb) {
|
||||
cb("error");
|
||||
fakeMozLoop.rooms.create = function(roomData, cb) {
|
||||
cb(new Error("error"));
|
||||
};
|
||||
store.fetchEmailLink(new sharedActions.FetchEmailLink());
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(trigger);
|
||||
sinon.assert.calledWithExactly(trigger, "error:emailLink");
|
||||
|
|
Загрузка…
Ссылка в новой задаче