Browse Source

UI-1604: Added Walkthroughs for SmartPBX

4.3
Jean-Roch Maitre 11 years ago
parent
commit
511453f50b
9 changed files with 501 additions and 31 deletions
  1. +54
    -1
      i18n/en-US.json
  2. +53
    -1
      i18n/fr-FR.json
  3. +7
    -0
      submodules/groups/groups.css
  4. +78
    -0
      submodules/groups/groups.js
  5. +84
    -1
      submodules/myOffice/myOffice.js
  6. +2
    -1
      submodules/strategy/strategy.css
  7. +110
    -0
      submodules/strategy/strategy.js
  8. +85
    -1
      submodules/users/users.js
  9. +28
    -26
      views/groups-row.html

+ 54
- 1
i18n/en-US.json View File

@ -105,6 +105,17 @@
"title": "Allow Call-Forward",
"headline": "Allow Call-Forward",
"description": "Enable this option if you want to allow this group's users to press their device \"Forward\" button to forward a call from this ring group. If this option is disabled, it will ignore the user's command."
},
"__comment": "UI-1604: Adding Walkthrough for new users",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Add a specific User Group by clicking on the button. The handy drag and drop allows you to add users, create a group name and add an extension number. Once complete, each User Group and its settings will be populated below.",
"2": "Once a User Group is created, it will pre-populate the area here. Make any necessary changes such as the group name, number of members and extension number.",
"3": "Purchase, Port and Assign numbers. Once complete, it will automatically be assigned to the specific User Group.",
"4": "Turn on/off and seamlessly manage any of the User Features specific to the User Group."
}
}
},
@ -612,6 +623,19 @@
"devices": {
"newDevice": "New Device",
"spareDevice": "Add from Spare Devices"
},
"__comment": "UI-1604: Adding Walkthrough for new users",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Add a specific User by clicking on the button and providing their information. Once complete, each user and their settings will be populated below.",
"2": "Once a user is created, it will pre-populate the area here. Make any necessary changes to the specific user within Users Settings",
"3": "Provide Users with their own unique direct dial extension numbers.",
"4": "Click the button to purchase, port, and assign numbers. Once complete, it will automatically be assigned to the specific user.",
"5": "Autoprovision one of our supported devices. The UI comes complete with pre-populated manufacturers and devices. Once complete it will automatically be assigned to the specific user.",
"6": "Manage what features Users can access. Turn on/off and manage any of the specific User Features."
}
}
},
@ -775,6 +799,24 @@
"cnam": "Caller-ID",
"dash_e911": "e911"
}
},
"__comment": "UI-1604: Walkthrough dashboard",
"__version": "3.21",
"walkthrough": {
"first": {
"steps": {
"1": "Setup your main company number within SmartPBX by purchasing or porting a number. This is different than User Phone Numbers because it represents the main phone number for the entire company."
}
},
"second": {
"steps": {
"1": "Set up your office hours phone strategy to your convenience. You can set up a 24 hour open office strategy or if your office is ever closed, create custom hours. You can even close your office during lunch hours.",
"2": "Is your office closed on holidays? Create specific dates or time frames when your office will be closed",
"3": "Virtual Receptionist allows you to seamlessly answer incoming calls. Add call routes to contact the appropriate department or person within the system. You can also create customized greetings using text-to-speech, uploading your own file or recording it over the phone.",
"4": "Create a main Conference Number for your business. Purchase, port or add an existing number and set up a Conference Number seamlessly."
}
}
}
},
@ -878,7 +920,18 @@
},
"__comment": "UI-1220: Adding a Main VMBox automatically when they first load the SmartPBX if they don't have one",
"__version": "3.19",
"mainVMBoxName": "Main Voicemail Box"
"mainVMBoxName": "Main Voicemail Box",
"__comment": "UI-1604: Walkthrough dashboard",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Review your entire office setup including your users, devices, numbers, main number and conference number",
"2": "Create and manage most of your services in the Users tab. Create new users, purchase port, and assign numbers, add an autoprovision devices, and manage User Features.",
"3": "Once you have created enough users, create user groups. This is extremely useful if you have users that work in the same department, such as a sales team.",
"4": "Create a main number for your business. Manage call handling with Virtual Receptionist, and route calls depending on Office Hours and Holidays"
}
}
},
"__comment": "UI-299, v3.19_s2: Added the Feature Codes tab to SmartPBX.",


+ 53
- 1
i18n/fr-FR.json View File

@ -101,6 +101,17 @@
"title": "Redirection d'appel",
"headline": "Autoriser la Redirection d'Appels",
"description": "Si cette option est activée, les utilisateurs de ce group pourront presser le bouton \"Redirection\" de leur téléphone afin de rediriger un appel de ce groupe. Si cette option est desactivée, ce groupe ignorera les commandes de redirections."
},
"__comment": "UI-1604: Adding Walkthrough for new users",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Ajouter un group en cliquant sur ce bouton. Vous pourrez dès lors sélectionner ses membres ainsi que lui assigner un nom et un numéro.",
"2": "Une fois créé, chaque groupe et ses options apparaîtront ici, et vous pourrez changer ces réglages en cliquant sur les cases associées.",
"3": "Cliquez sur cette case pour acheter, assigner ou porter des numéros. Une fois fait, ces numéros seront automatiquement liés à ce groupe.",
"4": "Enfin, cliquez sur cette case pour activer ou désactiver les fonctionnalités de ce groupe d'utilisateurs."
}
}
},
@ -576,6 +587,19 @@
"devices": {
"newDevice": "Nouveau Téléphone",
"spareDevice": "Ajouter depuis les Téléphones Disponibles"
},
"__comment": "UI-1604: Adding Walkthrough for new users",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Accèder à la création utilisateur via ce bouton. ",
"2": "Une fois compléter, chaque utilisateur et ses réglages seront affichés ici. Cliquez sur cette case pour changer ses informations.",
"3": "Fournissez un numéro unique d'extension à chacun de vos utilisateur ici.",
"4": "Cliquez sur cette case pour acheter, porter ou sélectionner un numéro disponible. Ils seront automatiquement assignés à cet utilisateur.",
"5": "Ajouter des téléphones à vos utilisateurs via cette case.",
"6": "Gérez les différentes fonctionnalités disponibles pour vos utilisateurs via ce menu."
}
}
},
@ -729,6 +753,23 @@
"cnam": "Caller-ID",
"dash_e911": "Adresse d'urgence (e911)"
}
},
"__comment": "UI-1604: Walkthrough dashboard",
"__version": "3.21",
"walkthrough": {
"first": {
"steps": {
"1": "Configurer votre numéro principal d'entreprise ici. Ce numéro est différent de vos numéros assignés à vos utilisateurs car il représente votre entreprise dans son ensemble."
}
},
"second": {
"steps": {
"1": "Configurez les heures d'ouverture de votre bureau ici. Vous avez le choix de laisser votre ligne ouverte 24h/24h ou bien de créer des horaires personnalisés. Vous pourrez même sélectionner des horaires de repas.",
"2": "Votre bureau ferme t'il pendant les vacances? Gérez tout cela dans cette section.",
"3": "Le \"Virtual Receptionist\" disponible dans ce menu vous permet de répondre intelligemment à tous les appels entrants sur votre numéro d'entreprise.",
"4": "Sélectionnez un numéro de conférence pour votre entreprise ici."
}
}
}
},
@ -830,7 +871,18 @@
},
"__comment": "UI-1220: Adding a Main VMBox automatically when they first load the SmartPBX if they don't have one",
"__version": "3.19",
"mainVMBoxName": "Répondeur Principal"
"mainVMBoxName": "Répondeur Principal",
"__comment": "UI-1604: Walkthrough dashboard",
"__version": "3.21",
"walkthrough": {
"steps": {
"1": "Observez les statistiques d'appels et plein d'autre informations en un coup d'oeil sur ce menu.",
"2": "Gérez les différents services de vos utilisateurs ici. Vous pourrez leur assigner des numéros, gérez leurs appareils téléphoniques et bien plus encore!",
"3": "Une fois les utilisateurs créés, dirigez-vous vers la section \"Groupes\". Ceci est très pratique pour les utilisateurs travaillant dans une même section (Marketing, Ventes...) afin de définir un répondeur global etc...",
"4": "Créer votre numéro d'entreprise dans cette section. Vous pourrez gérer les appels entrants et les router differemment en fonction de vos réglages d'horaires ou de vacances..."
}
}
},
"__comment": "UI-299, v3.19_s2: Added the Feature Codes tab to SmartPBX.",


+ 7
- 0
submodules/groups/groups.css View File

@ -131,6 +131,13 @@
cursor: pointer;
}
#groups_container .groups-grid .walkthrough-group {
/* Hack to wrap right group for walkthrough */
display: inline;
padding-top:15px;
padding-bottom:15px;
}
#groups_container .groups-grid .groups-rows .grid-cell:last-child:not(.active):hover { border-right: 1px solid #dcdcdc; }
#groups_container .groups-grid .grid-row .grid-cell:not(:last-child) { white-space: nowrap; }


+ 78
- 0
submodules/groups/groups.js View File

@ -48,6 +48,8 @@ define(function(require){
parent
.empty()
.append(template);
self.groupsCheckWalkthrough();
if(_groupId) {
var cells = parent.find('.grid-row[data-id=' + _groupId + '] .grid-cell');
@ -1554,6 +1556,66 @@ define(function(require){
});
},
groupsCheckWalkthrough: function() {
var self = this;
self.groupsHasWalkthrough(function() {
self.groupsShowWalkthrough(function() {
self.groupsUpdateWalkthroughFlagUser();
});
});
},
groupsHasWalkthrough: function(callback) {
var self = this,
flag = self.helpSettings.user.get('showGroupsWalkthrough');
if(flag !== false) {
callback && callback();
}
},
groupsUpdateWalkthroughFlagUser: function(callback) {
var self = this,
userToSave = self.helpSettings.user.set('showGroupsWalkthrough', false);
self.groupsUpdateOriginalUser(userToSave, function(user) {
callback && callback(user);
});
},
groupsShowWalkthrough: function(callback) {
var self = this,
mainTemplate = $('#voip_container'),
rowFirstGroup = mainTemplate.find('.grid-row:not(.title):first'),
steps = [
{
element: mainTemplate.find('.add-group')[0],
intro: self.i18n.active().groups.walkthrough.steps['1'],
position: 'right'
},
{
element: rowFirstGroup.find('.walkthrough-group')[0],
intro: self.i18n.active().groups.walkthrough.steps['2'],
position: 'right'
},
{
element: rowFirstGroup.find('.phone-number')[0],
intro: self.i18n.active().groups.walkthrough.steps['3'],
position: 'bottom'
},
{
element: rowFirstGroup.find('.features')[0],
intro: self.i18n.active().groups.walkthrough.steps['4'],
position: 'left'
}
];
monster.ui.stepByStep(steps, function() {
callback && callback();
});
},
groupsListCallflows: function(callback) {
var self = this;
@ -1971,6 +2033,22 @@ define(function(require){
groupsRemoveOverlay: function() {
$('body').find('#groups_container_overlay').remove();
},
groupsUpdateOriginalUser: function(userToUpdate, callback) {
var self = this;
self.callApi({
resource: 'user.update',
data: {
userId: userToUpdate.id,
accountId: monster.apps.auth.originalAccount.id,
data: userToUpdate
},
success: function(savedUser) {
callback && callback(savedUser.data);
}
});
}
};


+ 84
- 1
submodules/myOffice/myOffice.js View File

@ -9,7 +9,8 @@ define(function(require){
requests: {},
subscribe: {
'voip.myOffice.render': 'myOfficeRender'
'voip.myOffice.render': 'myOfficeRender',
'myaccount.closed': 'myOfficeMyAccountClosed'
},
chartColors: [
@ -864,6 +865,72 @@ define(function(require){
loadNumberDetails(callerIdNumberSelect.val());
},
myOfficeMyAccountClosed: function() {
var self = this;
// ghetto way before we add the self.isVisible method
if($('#voip_container').length) {
// First we check if the user hasn't seen the walkthrough already
// if he hasn't we show the walkthrough, and once they're done with it, we update their user doc so they won't see the walkthrough again
self.myOfficeHasWalkthrough(function() {
self.myOfficeShowWalkthrough(function() {
self.myOfficeUpdateWalkthroughFlagUser();
});
});
}
},
myOfficeHasWalkthrough: function(callback) {
var self = this,
flag = self.helpSettings.user.get('showDashboardWalkthrough');
if(flag !== false) {
callback && callback();
}
},
// Triggers firstUseWalkthrough. First we render the dropdown, then we show a greeting popup, and once they click go, we render the step by step.
myOfficeShowWalkthrough: function(callback) {
var self = this,
mainTemplate = $('#voip_container'),
steps = [
{
element: mainTemplate.find('.category#myOffice')[0],
intro: self.i18n.active().myOffice.walkthrough.steps['1'],
position: 'right'
},
{
element: mainTemplate.find('.category#users')[0],
intro: self.i18n.active().myOffice.walkthrough.steps['2'],
position: 'right'
},
{
element: mainTemplate.find('.category#groups')[0],
intro: self.i18n.active().myOffice.walkthrough.steps['3'],
position: 'right'
},
{
element: mainTemplate.find('.category#strategy')[0],
intro: self.i18n.active().myOffice.walkthrough.steps['4'],
position: 'right'
}
];
monster.ui.stepByStep(steps, function() {
callback && callback();
});
},
myOfficeUpdateWalkthroughFlagUser: function(callback) {
var self = this,
userToSave = self.helpSettings.user.set('showDashboardWalkthrough', false);
self.myOfficeUpdateOriginalUser(userToSave, function(user) {
callback && callback(user);
});
},
/* API Calls */
myOfficeGetNumber: function(number, success, error) {
var self = this;
@ -931,6 +998,22 @@ define(function(require){
callback && callback(data.data);
}
});
},
myOfficeUpdateOriginalUser: function(userToUpdate, callback) {
var self = this;
self.callApi({
resource: 'user.update',
data: {
userId: userToUpdate.id,
accountId: monster.apps.auth.originalAccount.id,
data: userToUpdate
},
success: function(savedUser) {
callback && callback(savedUser.data);
}
});
}
};


+ 2
- 1
submodules/strategy/strategy.css View File

@ -3,7 +3,8 @@
}
#strategy_container .element-container:not(:first-of-type) {
margin-top: 10px;
margin-bottom: 5px;
margin-top: 5px;
}
#strategy_container .element-header-outer {


+ 110
- 0
submodules/strategy/strategy.js View File

@ -204,9 +204,13 @@ define(function(require){
template.find('.element-container.strategy-hours,.element-container.strategy-holidays,.element-container.strategy-calls').hide();
template.find('.element-container.helper').css('display', 'block');
template.find('.element-container.main-number').css('margin-top', '10px');
self.strategyCheckFirstWalkthrough();
} else {
template.find('.element-container.helper').css('display', 'none');
template.find('.element-container.main-number').css('margin-top', '0px');
self.strategyCheckSecondWalkthrough();
}
if(openElement) {
@ -224,6 +228,93 @@ define(function(require){
self.strategyCreateFeatureCodes();
},
strategyCheckFirstWalkthrough: function() {
var self = this,
flagName = 'showStrategyFirstWalkthrough';
self.strategyHasWalkthrough(flagName, function() {
self.strategyShowFirstWalkthrough(function() {
self.strategyUpdateWalkthroughFlagUser(flagName);
});
});
},
strategyCheckSecondWalkthrough: function() {
var self = this,
flagName = 'showStrategySecondWalkthrough';
self.strategyHasWalkthrough(flagName, function() {
self.strategyShowSecondWalkthrough(function() {
self.strategyUpdateWalkthroughFlagUser(flagName);
});
});
},
strategyHasWalkthrough: function(name, callback) {
var self = this,
flag = self.helpSettings.user.get(name);
if(flag !== false) {
callback && callback();
}
},
strategyUpdateWalkthroughFlagUser: function(flagName, callback) {
var self = this,
userToSave = self.helpSettings.user.set(flagName, false);
self.strategyUpdateOriginalUser(userToSave, function(user) {
callback && callback(user);
});
},
strategyShowFirstWalkthrough: function(callback) {
var self = this,
mainTemplate = $('#strategy_container'),
steps = [
{
element: mainTemplate.find('.element-container.main-number')[0],
intro: self.i18n.active().strategy.walkthrough.first.steps['1'],
position: 'bottom'
}
];
monster.ui.stepByStep(steps, function() {
callback && callback();
});
},
strategyShowSecondWalkthrough: function(callback) {
var self = this,
mainTemplate = $('#strategy_container'),
steps = [
{
element: mainTemplate.find('.element-container.strategy-hours')[0],
intro: self.i18n.active().strategy.walkthrough.second.steps['1'],
position: 'bottom'
},
{
element: mainTemplate.find('.element-container.strategy-holidays')[0],
intro: self.i18n.active().strategy.walkthrough.second.steps['2'],
position: 'bottom'
},
{
element: mainTemplate.find('.element-container.strategy-calls')[0],
intro: self.i18n.active().strategy.walkthrough.second.steps['3'],
position: 'top'
},
{
element: mainTemplate.find('.element-container.strategy-confnum')[0],
intro: self.i18n.active().strategy.walkthrough.second.steps['4'],
position: 'top'
}
];
monster.ui.stepByStep(steps, function() {
callback && callback();
});
},
strategyBindEvents: function(template, strategyData) {
var self = this,
containers = template.find('.element-container'),
@ -302,6 +393,7 @@ define(function(require){
container.find('.element-content').empty()
.append(template);
callback && callback();
});
break;
@ -565,6 +657,8 @@ define(function(require){
container.parents('#strategy_container').find('.element-container:not(.main-number,.strategy-confnum)').show();
container.parents('#strategy_container').find('.element-container.helper').hide();
container.parents('#strategy_container').find('.element-container.main-number').css('margin-top', '0px');
self.strategyCheckSecondWalkthrough();
} else {
headerSpan.html(self.i18n.active().strategy.noNumberTitle);
container.parents('#strategy_container').find('.element-container:not(.main-number,.strategy-confnum)').hide();
@ -2480,6 +2574,22 @@ define(function(require){
_strategyOnCurrentAccountUpdated: function(accountData) {
var self = this;
$('#strategy_custom_hours_timezone').text(timezone.formatTimezone(accountData.timezone));
},
strategyUpdateOriginalUser: function(userToUpdate, callback) {
var self = this;
self.callApi({
resource: 'user.update',
data: {
userId: userToUpdate.id,
accountId: monster.apps.auth.originalAccount.id,
data: userToUpdate
},
success: function(savedUser) {
callback && callback(savedUser.data);
}
});
}
};


+ 85
- 1
submodules/users/users.js View File

@ -61,6 +61,8 @@ define(function(require){
.empty()
.append(template);
self.usersCheckWalkthrough();
if(_userId) {
var cells = parent.find('.grid-row[data-id=' + _userId + '] .grid-cell');
@ -83,6 +85,76 @@ define(function(require){
});
},
usersCheckWalkthrough: function() {
var self = this;
self.usersHasWalkthrough(function() {
self.usersShowWalkthrough(function() {
self.usersUpdateWalkthroughFlagUser();
});
});
},
usersHasWalkthrough: function(callback) {
var self = this,
flag = self.helpSettings.user.get('showUsersWalkthrough');
if(flag !== false) {
callback && callback();
}
},
usersUpdateWalkthroughFlagUser: function(callback) {
var self = this,
userToSave = self.helpSettings.user.set('showUsersWalkthrough', false);
self.usersUpdateOriginalUser(userToSave, function(user) {
callback && callback(user);
});
},
usersShowWalkthrough: function(callback) {
var self = this,
mainTemplate = $('#voip_container'),
rowFirstUser = mainTemplate.find('.grid-row:not(.title):first'),
steps = [
{
element: mainTemplate.find('.add-user')[0],
intro: self.i18n.active().users.walkthrough.steps['1'],
position: 'right'
},
{
element: rowFirstUser.find('.name')[0],
intro: self.i18n.active().users.walkthrough.steps['2'],
position: 'right'
},
{
element: rowFirstUser.find('.extension')[0],
intro: self.i18n.active().users.walkthrough.steps['3'],
position: 'bottom'
},
{
element: rowFirstUser.find('.phone-number')[0],
intro: self.i18n.active().users.walkthrough.steps['4'],
position: 'bottom'
},
{
element: rowFirstUser.find('.devices')[0],
intro: self.i18n.active().users.walkthrough.steps['5'],
position: 'left'
},
{
element: rowFirstUser.find('.features')[0],
intro: self.i18n.active().users.walkthrough.steps['6'],
position: 'left'
}
];
monster.ui.stepByStep(steps, function() {
callback && callback();
});
},
usersFormatUserData: function(dataUser, _mainDirectory, _mainCallflow, _vmbox, _vmboxes) {
var self = this,
formattedUser = {
@ -3352,15 +3424,27 @@ define(function(require){
});
},
usersUpdateOriginalUser: function(user, callback) {
var self = this;
self.usersUpdateUserAPI(user, callback, monster.apps.auth.originalAccount.id);
},
usersUpdateUser: function(userData, callback) {
var self = this;
userData = self.usersCleanUserData(userData);
self.usersUpdateUserAPI(userData, callback, self.accountId);
},
usersUpdateUserAPI: function(userData, callback, accountId) {
var self = this;
self.callApi({
resource: 'user.update',
data: {
accountId: self.accountId,
accountId: accountId,
userId: userData.id,
data: userData
},


+ 28
- 26
views/groups-row.html View File

@ -1,39 +1,41 @@
<div class="grid-row" data-id="{{id}}" data-search="{{name}} {{#each extra.listCallerId}}{{this}} {{formatPhoneNumber this}} {{/each}}" data-callflow_id="{{extra.callflowId}}" data-base_callflow_id="{{extra.baseCallflowId}}" data-name="{{name}}">
<div class="groups-cells">
<div class="name grid-cell" data-type="name">{{ name }}</div>
<div class="members grid-cell" data-type="members">{{ endpoints }}</div>
<div class="extension grid-cell" data-type="extensions">
{{#if extra.extension}}
{{ extra.extension }}
<div class="walkthrough-group">
<div class="name grid-cell" data-type="name">{{ name }}</div>
<div class="members grid-cell" data-type="members">{{ endpoints }}</div>
<div class="extension grid-cell" data-type="extensions">
{{#if extra.extension}}
{{ extra.extension }}
{{#if extra.additionalExtensions}}
<i class="icon-telicon-multiple-items"></i>
{{/if}}
{{else}}
{{ i18n.groups.noExtension }}
{{/if}}
{{#if extra.additionalExtensions}}
<i class="icon-telicon-multiple-items"></i>
{{/if}}
{{else}}
{{ i18n.groups.noExtension }}
{{/if}}
</div>
</div>
<div class="phone-number grid-cell" data-type="numbers">
{{#if extra.mainNumber}}
{{formatPhoneNumber extra.mainNumber}}
{{formatPhoneNumber extra.mainNumber}}
{{#if extra.additionalNumbers}}
<i class="icon-telicon-multiple-items"></i>
{{/if}}
{{else}}
{{ i18n.groups.noNumber }}
{{/if}}
{{#if extra.additionalNumbers}}
<i class="icon-telicon-multiple-items"></i>
{{/if}}
{{else}}
{{ i18n.groups.noNumber }}
{{/if}}
</div>
<div class="features grid-cell right-aligned" data-type="features">
{{#if extra.hasFeatures}}
{{#each extra.mapFeatures}}
{{#if this.active}}
<i class="{{this.icon}} {{this.iconColor}}"></i>
{{/if}}
{{/each}}
{{else}}
{{ i18n.users.noUserFeatures }}
{{/if}}
{{#each extra.mapFeatures}}
{{#if this.active}}
<i class="{{this.icon}} {{this.iconColor}}"></i>
{{/if}}
{{/each}}
{{else}}
{{ i18n.users.noUserFeatures }}
{{/if}}
</div>
</div>


Loading…
Cancel
Save