Bug 972017 Part 1 - Add a new controller view for selecting between incoming and outgoing calls in the Loop Conversation window. Also, set up a bare-bones outgoing pending conversation view. r=mikedeboer

This commit is contained in:
Mark Banner 2014-09-30 20:44:04 +01:00
parent b743549be7
commit 631b97c2df
14 changed files with 468 additions and 56 deletions

View File

@ -30,8 +30,11 @@
<script type="text/javascript" src="loop/shared/js/mixins.js"></script>
<script type="text/javascript" src="loop/shared/js/views.js"></script>
<script type="text/javascript" src="loop/shared/js/feedbackApiClient.js"></script>
<script type="text/javascript" src="loop/shared/js/conversationStore.js"></script>
<script type="text/javascript" src="loop/js/conversationViews.js"></script>
<script type="text/javascript" src="loop/shared/js/websocket.js"></script>
<script type="text/javascript" src="loop/js/client.js"></script>
<script type="text/javascript" src="loop/js/conversationViews.js"></script>
<script type="text/javascript" src="loop/js/conversation.js"></script>
</body>
</html>

View File

@ -11,8 +11,9 @@ var loop = loop || {};
loop.conversation = (function(mozL10n) {
"use strict";
var sharedViews = loop.shared.views,
sharedModels = loop.shared.models;
var sharedViews = loop.shared.views;
var sharedModels = loop.shared.models;
var OutgoingConversationView = loop.conversationViews.OutgoingConversationView;
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
@ -109,26 +110,23 @@ loop.conversation = (function(mozL10n) {
render: function() {
/* jshint ignore:start */
var btnClassAccept = "btn btn-accept";
var btnClassDecline = "btn btn-error btn-decline";
var conversationPanelClass = "incoming-call";
var dropdownMenuClassesDecline = React.addons.classSet({
"native-dropdown-menu": true,
"conversation-window-dropdown": true,
"visually-hidden": !this.state.showDeclineMenu
});
return (
React.DOM.div({className: conversationPanelClass},
React.DOM.div({className: "call-window"},
React.DOM.h2(null, mozL10n.get("incoming_call_title2")),
React.DOM.div({className: "btn-group incoming-call-action-group"},
React.DOM.div({className: "btn-group call-action-group"},
React.DOM.div({className: "fx-embedded-incoming-call-button-spacer"}),
React.DOM.div({className: "fx-embedded-call-button-spacer"}),
React.DOM.div({className: "btn-chevron-menu-group"},
React.DOM.div({className: "btn-group-chevron"},
React.DOM.div({className: "btn-group"},
React.DOM.button({className: btnClassDecline,
React.DOM.button({className: "btn btn-error btn-decline",
onClick: this._handleDecline},
mozL10n.get("incoming_call_cancel_button")
),
@ -146,11 +144,11 @@ loop.conversation = (function(mozL10n) {
)
),
React.DOM.div({className: "fx-embedded-incoming-call-button-spacer"}),
React.DOM.div({className: "fx-embedded-call-button-spacer"}),
AcceptCallButton({mode: this._answerModeProps()}),
React.DOM.div({className: "fx-embedded-incoming-call-button-spacer"})
React.DOM.div({className: "fx-embedded-call-button-spacer"})
)
)
@ -489,6 +487,44 @@ loop.conversation = (function(mozL10n) {
},
});
/**
* Master controller view for handling if incoming or outgoing calls are
* in progress, and hence, which view to display.
*/
var ConversationControllerView = React.createClass({displayName: 'ConversationControllerView',
propTypes: {
// XXX Old types required for incoming call view.
client: React.PropTypes.instanceOf(loop.Client).isRequired,
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
.isRequired,
notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
.isRequired,
sdk: React.PropTypes.object.isRequired,
// XXX New types for OutgoingConversationView
store: React.PropTypes.instanceOf(loop.ConversationStore).isRequired
},
getInitialState: function() {
return this.props.store.attributes;
},
render: function() {
if (this.state.outgoing) {
return (OutgoingConversationView({
store: this.props.store}
));
}
return (IncomingConversationView({
client: this.props.client,
conversation: this.props.conversation,
notifications: this.props.notifications,
sdk: this.props.sdk}
));
}
});
/**
* Panel initialisation.
*/
@ -509,8 +545,18 @@ loop.conversation = (function(mozL10n) {
}
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
var conversationStore = new loop.ConversationStore();
// XXX For now key this on the pref, but this should really be
// set by the information from the mozLoop API when we can get it (bug 1072323).
var outgoingEmail = navigator.mozLoop.getLoopCharPref("outgoingemail");
if (outgoingEmail) {
conversationStore.set("outgoing", true);
conversationStore.set("calleeId", outgoingEmail);
}
// XXX Old class creation for the incoming conversation view, whilst
// we transition across (bug 1072323).
var client = new loop.Client();
var conversation = new sharedModels.ConversationModel(
{}, // Model attributes
@ -518,19 +564,22 @@ loop.conversation = (function(mozL10n) {
);
var notifications = new sharedModels.NotificationCollection();
window.addEventListener("unload", function(event) {
// Handle direct close of dialog box via [x] control.
navigator.mozLoop.releaseCallData(conversation.get("callId"));
});
// Obtain the callId and pass it to the conversation
// Obtain the callId and pass it through
var helper = new loop.shared.utils.Helper();
var locationHash = helper.locationHash();
if (locationHash) {
conversation.set("callId", locationHash.match(/\#incoming\/(.*)/)[1]);
}
React.renderComponent(IncomingConversationView({
window.addEventListener("unload", function(event) {
// Handle direct close of dialog box via [x] control.
navigator.mozLoop.releaseCallData(conversation.get("callId"));
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
React.renderComponent(ConversationControllerView({
store: conversationStore,
client: client,
conversation: conversation,
notifications: notifications,
@ -539,6 +588,7 @@ loop.conversation = (function(mozL10n) {
}
return {
ConversationControllerView: ConversationControllerView,
IncomingConversationView: IncomingConversationView,
IncomingCallView: IncomingCallView,
init: init

View File

@ -11,8 +11,9 @@ var loop = loop || {};
loop.conversation = (function(mozL10n) {
"use strict";
var sharedViews = loop.shared.views,
sharedModels = loop.shared.models;
var sharedViews = loop.shared.views;
var sharedModels = loop.shared.models;
var OutgoingConversationView = loop.conversationViews.OutgoingConversationView;
var IncomingCallView = React.createClass({
@ -109,26 +110,23 @@ loop.conversation = (function(mozL10n) {
render: function() {
/* jshint ignore:start */
var btnClassAccept = "btn btn-accept";
var btnClassDecline = "btn btn-error btn-decline";
var conversationPanelClass = "incoming-call";
var dropdownMenuClassesDecline = React.addons.classSet({
"native-dropdown-menu": true,
"conversation-window-dropdown": true,
"visually-hidden": !this.state.showDeclineMenu
});
return (
<div className={conversationPanelClass}>
<div className="call-window">
<h2>{mozL10n.get("incoming_call_title2")}</h2>
<div className="btn-group incoming-call-action-group">
<div className="btn-group call-action-group">
<div className="fx-embedded-incoming-call-button-spacer"></div>
<div className="fx-embedded-call-button-spacer"></div>
<div className="btn-chevron-menu-group">
<div className="btn-group-chevron">
<div className="btn-group">
<button className={btnClassDecline}
<button className="btn btn-error btn-decline"
onClick={this._handleDecline}>
{mozL10n.get("incoming_call_cancel_button")}
</button>
@ -146,11 +144,11 @@ loop.conversation = (function(mozL10n) {
</div>
</div>
<div className="fx-embedded-incoming-call-button-spacer"></div>
<div className="fx-embedded-call-button-spacer"></div>
<AcceptCallButton mode={this._answerModeProps()} />
<div className="fx-embedded-incoming-call-button-spacer"></div>
<div className="fx-embedded-call-button-spacer"></div>
</div>
</div>
@ -489,6 +487,44 @@ loop.conversation = (function(mozL10n) {
},
});
/**
* Master controller view for handling if incoming or outgoing calls are
* in progress, and hence, which view to display.
*/
var ConversationControllerView = React.createClass({
propTypes: {
// XXX Old types required for incoming call view.
client: React.PropTypes.instanceOf(loop.Client).isRequired,
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
.isRequired,
notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
.isRequired,
sdk: React.PropTypes.object.isRequired,
// XXX New types for OutgoingConversationView
store: React.PropTypes.instanceOf(loop.ConversationStore).isRequired
},
getInitialState: function() {
return this.props.store.attributes;
},
render: function() {
if (this.state.outgoing) {
return (<OutgoingConversationView
store={this.props.store}
/>);
}
return (<IncomingConversationView
client={this.props.client}
conversation={this.props.conversation}
notifications={this.props.notifications}
sdk={this.props.sdk}
/>);
}
});
/**
* Panel initialisation.
*/
@ -509,8 +545,18 @@ loop.conversation = (function(mozL10n) {
}
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
var conversationStore = new loop.ConversationStore();
// XXX For now key this on the pref, but this should really be
// set by the information from the mozLoop API when we can get it (bug 1072323).
var outgoingEmail = navigator.mozLoop.getLoopCharPref("outgoingemail");
if (outgoingEmail) {
conversationStore.set("outgoing", true);
conversationStore.set("calleeId", outgoingEmail);
}
// XXX Old class creation for the incoming conversation view, whilst
// we transition across (bug 1072323).
var client = new loop.Client();
var conversation = new sharedModels.ConversationModel(
{}, // Model attributes
@ -518,19 +564,22 @@ loop.conversation = (function(mozL10n) {
);
var notifications = new sharedModels.NotificationCollection();
window.addEventListener("unload", function(event) {
// Handle direct close of dialog box via [x] control.
navigator.mozLoop.releaseCallData(conversation.get("callId"));
});
// Obtain the callId and pass it to the conversation
// Obtain the callId and pass it through
var helper = new loop.shared.utils.Helper();
var locationHash = helper.locationHash();
if (locationHash) {
conversation.set("callId", locationHash.match(/\#incoming\/(.*)/)[1]);
}
React.renderComponent(<IncomingConversationView
window.addEventListener("unload", function(event) {
// Handle direct close of dialog box via [x] control.
navigator.mozLoop.releaseCallData(conversation.get("callId"));
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
React.renderComponent(<ConversationControllerView
store={conversationStore}
client={client}
conversation={conversation}
notifications={notifications}
@ -539,6 +588,7 @@ loop.conversation = (function(mozL10n) {
}
return {
ConversationControllerView: ConversationControllerView,
IncomingConversationView: IncomingConversationView,
IncomingCallView: IncomingCallView,
init: init

View File

@ -0,0 +1,100 @@
/** @jsx React.DOM */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global loop:true, React */
var loop = loop || {};
loop.conversationViews = (function(mozL10n) {
/**
* Displays details of the incoming/outgoing conversation
* (name, link, audio/video type etc).
*
* Allows the view to be extended with different buttons and progress
* via children properties.
*/
var ConversationDetailView = React.createClass({displayName: 'ConversationDetailView',
propTypes: {
calleeId: React.PropTypes.string,
},
render: function() {
document.title = this.props.calleeId;
return (
React.DOM.div({className: "call-window"},
React.DOM.h2(null, this.props.calleeId),
React.DOM.div(null, this.props.children)
)
);
}
});
/**
* View for pending conversations. Displays a cancel button and appropriate
* pending/ringing strings.
*/
var PendingConversationView = React.createClass({displayName: 'PendingConversationView',
propTypes: {
callState: React.PropTypes.string,
calleeId: React.PropTypes.string,
},
render: function() {
var pendingStateString;
if (this.props.callState === "ringing") {
pendingStateString = mozL10n.get("call_progress_pending_description");
} else {
pendingStateString = mozL10n.get("call_progress_connecting_description");
}
return (
ConversationDetailView({calleeId: this.props.calleeId},
React.DOM.p({className: "btn-label"}, pendingStateString),
React.DOM.div({className: "btn-group call-action-group"},
React.DOM.div({className: "fx-embedded-call-button-spacer"}),
React.DOM.button({className: "btn btn-cancel"},
mozL10n.get("initiate_call_cancel_button")
),
React.DOM.div({className: "fx-embedded-call-button-spacer"})
)
)
);
}
});
/**
* Master View Controller for outgoing calls. This manages
* the different views that need displaying.
*/
var OutgoingConversationView = React.createClass({displayName: 'OutgoingConversationView',
propTypes: {
store: React.PropTypes.instanceOf(
loop.ConversationStore).isRequired
},
getInitialState: function() {
return this.props.store.attributes;
},
render: function() {
return (PendingConversationView({
callState: this.state.callState,
calleeId: this.state.calleeId}
))
}
});
return {
PendingConversationView: PendingConversationView,
ConversationDetailView: ConversationDetailView,
OutgoingConversationView: OutgoingConversationView
};
})(document.mozL10n || navigator.mozL10n);

View File

@ -0,0 +1,100 @@
/** @jsx React.DOM */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global loop:true, React */
var loop = loop || {};
loop.conversationViews = (function(mozL10n) {
/**
* Displays details of the incoming/outgoing conversation
* (name, link, audio/video type etc).
*
* Allows the view to be extended with different buttons and progress
* via children properties.
*/
var ConversationDetailView = React.createClass({
propTypes: {
calleeId: React.PropTypes.string,
},
render: function() {
document.title = this.props.calleeId;
return (
<div className="call-window">
<h2>{this.props.calleeId}</h2>
<div>{this.props.children}</div>
</div>
);
}
});
/**
* View for pending conversations. Displays a cancel button and appropriate
* pending/ringing strings.
*/
var PendingConversationView = React.createClass({
propTypes: {
callState: React.PropTypes.string,
calleeId: React.PropTypes.string,
},
render: function() {
var pendingStateString;
if (this.props.callState === "ringing") {
pendingStateString = mozL10n.get("call_progress_pending_description");
} else {
pendingStateString = mozL10n.get("call_progress_connecting_description");
}
return (
<ConversationDetailView calleeId={this.props.calleeId}>
<p className="btn-label">{pendingStateString}</p>
<div className="btn-group call-action-group">
<div className="fx-embedded-call-button-spacer"></div>
<button className="btn btn-cancel">
{mozL10n.get("initiate_call_cancel_button")}
</button>
<div className="fx-embedded-call-button-spacer"></div>
</div>
</ConversationDetailView>
);
}
});
/**
* Master View Controller for outgoing calls. This manages
* the different views that need displaying.
*/
var OutgoingConversationView = React.createClass({
propTypes: {
store: React.PropTypes.instanceOf(
loop.ConversationStore).isRequired
},
getInitialState: function() {
return this.props.store.attributes;
},
render: function() {
return (<PendingConversationView
callState={this.state.callState}
calleeId={this.state.calleeId}
/>)
}
});
return {
PendingConversationView: PendingConversationView,
ConversationDetailView: ConversationDetailView,
OutgoingConversationView: OutgoingConversationView
};
})(document.mozL10n || navigator.mozL10n);

View File

@ -223,14 +223,14 @@
text-align: center;
}
/* Incoming call */
/* General Call (incoming or outgoing). */
/*
* Height matches the height of the docked window
* but the UI breaks when you pop out
* Bug 1040985
*/
.incoming-call {
.call-window {
display: flex;
flex-direction: column;
align-items: center;
@ -238,26 +238,27 @@
min-height: 230px;
}
.incoming-call-action-group {
.call-action-group {
display: flex;
padding: 2.5em 0 0 0;
width: 100%;
justify-content: space-around;
}
.incoming-call-action-group > .btn {
.call-action-group > .btn {
margin-left: .5em;
height: 26px;
}
.incoming-call-action-group .btn-group-chevron,
.incoming-call-action-group .btn-group {
.call-action-group .btn-group-chevron,
.call-action-group .btn-group {
width: 100%;
}
/* XXX Once we get the incoming call avatar, bug 1047435, the H2 should
* disappear from our markup, and we should remove this rule entirely.
*/
.incoming-call h2 {
.call-window h2 {
font-size: 1.5em;
font-weight: normal;
@ -266,7 +267,7 @@
margin: 0.83em 0;
}
.fx-embedded-incoming-call-button-spacer {
.fx-embedded-call-button-spacer {
display: flex;
flex: 1;
}

View File

@ -0,0 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global loop:true */
var loop = loop || {};
loop.ConversationStore = (function() {
var ConversationStore = Backbone.Model.extend({
defaults: {
outgoing: false,
calleeId: undefined,
callState: "gather"
},
});
return ConversationStore;
})();

View File

@ -16,6 +16,7 @@ browser.jar:
content/browser/loop/js/otconfig.js (content/js/otconfig.js)
content/browser/loop/js/panel.js (content/js/panel.js)
content/browser/loop/js/contacts.js (content/js/contacts.js)
content/browser/loop/js/conversationViews.js (content/js/conversationViews.js)
# Shared styles
content/browser/loop/shared/css/reset.css (content/shared/css/reset.css)
@ -58,6 +59,7 @@ browser.jar:
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
content/browser/loop/shared/js/utils.js (content/shared/js/utils.js)
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
# Shared libs
#ifdef DEBUG

View File

@ -68,8 +68,6 @@ describe("loop.conversation", function() {
});
describe("#init", function() {
var oldTitle;
beforeEach(function() {
sandbox.stub(React, "renderComponent");
sandbox.stub(document.mozL10n, "initialize");
@ -94,17 +92,63 @@ describe("loop.conversation", function() {
navigator.mozLoop);
});
it("should create the IncomingConversationView", function() {
it("should create the ConversationControllerView", function() {
loop.conversation.init();
sinon.assert.calledOnce(React.renderComponent);
sinon.assert.calledWith(React.renderComponent,
sinon.match(function(value) {
return TestUtils.isDescriptorOfType(value,
loop.conversation.IncomingConversationView);
loop.conversation.ConversationControllerView);
}));
});
});
describe("ConversationControllerView", function() {
var store, conversation, client, ccView, oldTitle;
function mountTestComponent() {
return TestUtils.renderIntoDocument(
loop.conversation.ConversationControllerView({
client: client,
conversation: conversation,
notifications: notifications,
sdk: {},
store: store
}));
}
beforeEach(function() {
oldTitle = document.title;
client = new loop.Client();
conversation = new loop.shared.models.ConversationModel({}, {
sdk: {}
});
store = new loop.ConversationStore();
});
afterEach(function() {
ccView = undefined;
document.title = oldTitle;
});
it("should display the OutgoingConversationView for outgoing calls", function() {
store.set({outgoing: true});
ccView = mountTestComponent();
TestUtils.findRenderedComponentWithType(ccView,
loop.conversationViews.OutgoingConversationView);
});
it("should display the IncomingConversationView for incoming calls", function() {
store.set({outgoing: false});
ccView = mountTestComponent();
TestUtils.findRenderedComponentWithType(ccView,
loop.conversation.IncomingConversationView);
});
});
describe("IncomingConversationView", function() {

View File

@ -34,11 +34,13 @@
<!-- App scripts -->
<script src="../../content/shared/js/utils.js"></script>
<script src="../../content/shared/js/feedbackApiClient.js"></script>
<script src="../../content/shared/js/conversationStore.js"></script>
<script src="../../content/shared/js/models.js"></script>
<script src="../../content/shared/js/mixins.js"></script>
<script src="../../content/shared/js/views.js"></script>
<script src="../../content/shared/js/websocket.js"></script>
<script src="../../content/js/client.js"></script>
<script src="../../content/js/conversationViews.js"></script>
<script src="../../content/js/conversation.js"></script>
<script type="text/javascript;version=1.8" src="../../content/js/contacts.js"></script>
<script src="../../content/js/panel.js"></script>

View File

@ -32,10 +32,13 @@
<script src="../content/shared/libs/lodash-2.4.1.js"></script>
<script src="../content/shared/libs/backbone-1.1.2.js"></script>
<script src="../content/shared/js/feedbackApiClient.js"></script>
<script src="../content/shared/js/conversationStore.js"></script>
<script src="../content/shared/js/utils.js"></script>
<script src="../content/shared/js/models.js"></script>
<script src="../content/shared/js/mixins.js"></script>
<script src="../content/shared/js/views.js"></script>
<script src="../content/shared/js/websocket.js"></script>
<script src="../content/js/conversationViews.js"></script>
<script src="../content/js/client.js"></script>
<script src="../standalone/content/js/webapp.js"></script>
<script type="text/javascript;version=1.8" src="../content/js/contacts.js"></script>

View File

@ -138,8 +138,8 @@
background-size: cover;
}
.incoming-call-action-group .btn-group-chevron,
.incoming-call-action-group .btn-group {
.call-action-group .btn-group-chevron,
.call-action-group .btn-group {
/* Prevent box overflow due to long string */
max-width: 120px;
}

View File

@ -15,6 +15,7 @@
var PanelView = loop.panel.PanelView;
// 1.2. Conversation Window
var IncomingCallView = loop.conversation.IncomingCallView;
var DesktopPendingConversationView = loop.conversationViews.PendingConversationView;
// 2. Standalone webapp
var HomeView = loop.webapp.HomeView;
@ -63,6 +64,12 @@
});
mockConversationModel.startSession = noop;
var mockWebSocket = new loop.CallConnectionWebSocket({
url: "fake",
callId: "fakeId",
websocketToken: "fakeToken"
});
var notifications = new loop.shared.models.NotificationCollection();
var errNotifications = new loop.shared.models.NotificationCollection();
errNotifications.error("Error!");
@ -223,12 +230,21 @@
Section({name: "PendingConversationView"},
Example({summary: "Pending conversation view (connecting)", dashed: "true"},
React.DOM.div({className: "standalone"},
PendingConversationView(null)
PendingConversationView({websocket: mockWebSocket})
)
),
Example({summary: "Pending conversation view (ringing)", dashed: "true"},
React.DOM.div({className: "standalone"},
PendingConversationView({callState: "ringing"})
PendingConversationView({websocket: mockWebSocket, callState: "ringing"})
)
)
),
Section({name: "PendingConversationView (Desktop)"},
Example({summary: "Connecting", dashed: "true",
style: {width: "260px", height: "265px"}},
React.DOM.div({className: "fx-embedded"},
DesktopPendingConversationView({callState: "gather", calleeId: "Mr Smith"})
)
)
),
@ -446,6 +462,9 @@
React.renderComponent(App(null), body);
_renderComponentsInIframes();
// Put the title back, in case views changed it.
document.title = "Loop UI Components Showcase";
});
})();

View File

@ -15,6 +15,7 @@
var PanelView = loop.panel.PanelView;
// 1.2. Conversation Window
var IncomingCallView = loop.conversation.IncomingCallView;
var DesktopPendingConversationView = loop.conversationViews.PendingConversationView;
// 2. Standalone webapp
var HomeView = loop.webapp.HomeView;
@ -63,6 +64,12 @@
});
mockConversationModel.startSession = noop;
var mockWebSocket = new loop.CallConnectionWebSocket({
url: "fake",
callId: "fakeId",
websocketToken: "fakeToken"
});
var notifications = new loop.shared.models.NotificationCollection();
var errNotifications = new loop.shared.models.NotificationCollection();
errNotifications.error("Error!");
@ -223,12 +230,21 @@
<Section name="PendingConversationView">
<Example summary="Pending conversation view (connecting)" dashed="true">
<div className="standalone">
<PendingConversationView />
<PendingConversationView websocket={mockWebSocket}/>
</div>
</Example>
<Example summary="Pending conversation view (ringing)" dashed="true">
<div className="standalone">
<PendingConversationView callState="ringing"/>
<PendingConversationView websocket={mockWebSocket} callState="ringing"/>
</div>
</Example>
</Section>
<Section name="PendingConversationView (Desktop)">
<Example summary="Connecting" dashed="true"
style={{width: "260px", height: "265px"}}>
<div className="fx-embedded">
<DesktopPendingConversationView callState={"gather"} calleeId="Mr Smith" />
</div>
</Example>
</Section>
@ -446,6 +462,9 @@
React.renderComponent(<App />, body);
_renderComponentsInIframes();
// Put the title back, in case views changed it.
document.title = "Loop UI Components Showcase";
});
})();