What has been done: - TT#23719, Conversations: Discover the conversations endpoint and investigate dev tests - TT#23812, Conversations: Implement store with needed states - TT#23813, Conversations: Implement minimal card component - TT#23814, Conversations: Implement store and api tests - TT#23815, Conversations: Implement action and api request Change-Id: I40231aded1309695d9a2ab15e196db7c83b62018changes/36/16436/16
parent
6ab38fcbb7
commit
256cd94cb5
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { getJsonBody } from './utils'
|
||||||
|
|
||||||
|
export function getConversations(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Vue.http.get('/api/conversations/?subscriber_id=' + id).then((result)=>{
|
||||||
|
resolve(getJsonBody(result.body)._embedded['ngcp:conversations']);
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div class="csc-collapsible">
|
||||||
|
<q-collapsible :icon="icon"
|
||||||
|
:label="label"
|
||||||
|
:sublabel="sublabel">
|
||||||
|
</q-collapsible>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { QCollapsible } from 'quasar-framework'
|
||||||
|
export default {
|
||||||
|
name: 'csc-collapsible',
|
||||||
|
props: [
|
||||||
|
'icon',
|
||||||
|
'label',
|
||||||
|
'sublabel'
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
QCollapsible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import '~variables'
|
||||||
|
.csc-collapsible
|
||||||
|
.q-collapsible
|
||||||
|
.q-item-icon
|
||||||
|
font-size 22px
|
||||||
|
padding-right 12px
|
||||||
|
color $secondary
|
||||||
|
.q-item-label
|
||||||
|
color black
|
||||||
|
font-size 18px
|
||||||
|
font-weight 400
|
||||||
|
</style>
|
@ -1,18 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<csc-page title="Conversations"></csc-page>
|
<csc-page :title="$t('pages.conversations.title')">
|
||||||
|
<q-card v-for="conversation in conversations" :key="conversation.caller"
|
||||||
|
class="conversation-card">
|
||||||
|
<csc-collapsible :icon="getCollapsibleIcons(conversation)"
|
||||||
|
:label="getCollapsibleLabel(conversation)"
|
||||||
|
:sublabel="conversation.start_time | readableDate">
|
||||||
|
</csc-collapsible>
|
||||||
|
<div v-if="hasCallOption(conversation.type)">
|
||||||
|
<q-card-separator />
|
||||||
|
<q-card-actions align="center">
|
||||||
|
<q-btn flat round small color="primary" icon="call">{{ $t('pages.conversations.buttons.call') }}</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</csc-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CscPage from '../CscPage'
|
import CscPage from '../CscPage'
|
||||||
|
import CscCollapsible from '../card/CscCollapsible'
|
||||||
|
import { QBtn, QCardActions, QCard,
|
||||||
|
QCardSeparator } from 'quasar-framework'
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
return {}
|
return {
|
||||||
|
conversations: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$store.dispatch('conversations/loadConversations').then(() => {
|
||||||
|
this.conversations = this.$store.state.conversations.
|
||||||
|
conversations;
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
CscPage
|
CscPage,
|
||||||
|
QBtn,
|
||||||
|
QCard,
|
||||||
|
QCardActions,
|
||||||
|
QCardSeparator,
|
||||||
|
CscCollapsible
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hasCallOption(type) {
|
||||||
|
return (['call', 'call forward', 'sms', 'voicemail']
|
||||||
|
.indexOf(type) > -1);
|
||||||
|
},
|
||||||
|
getCollapsibleIcons(item) {
|
||||||
|
let directionIcon = item.direction == 'out' ? 'call_made' :
|
||||||
|
'call_received';
|
||||||
|
switch (item.type) {
|
||||||
|
case 'call':
|
||||||
|
return 'phone ' + directionIcon;
|
||||||
|
break;
|
||||||
|
case 'call forward':
|
||||||
|
return 'call_merge ' + directionIcon;
|
||||||
|
break;
|
||||||
|
case 'voicemail':
|
||||||
|
return 'voicemail ' + directionIcon;
|
||||||
|
break;
|
||||||
|
case 'fax':
|
||||||
|
return 'insert_drive_file ' + directionIcon;
|
||||||
|
break;
|
||||||
|
case 'sms':
|
||||||
|
return 'txtsms ' + directionIcon;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getCollapsibleLabel(item) {
|
||||||
|
let prefix = item.status == 'ok' ? this.$t('pages.conversations.labels.successful')
|
||||||
|
: this.$t('pages.conversations.labels.unsuccessful');
|
||||||
|
let direction = item.direction == 'in' ? this.$t('pages.conversations.labels.from') : this.$t('pages.conversations.labels.to');
|
||||||
|
return `${prefix} ${item.type} ${direction} ${item.caller}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="stylus">
|
||||||
|
@import '~variables'
|
||||||
|
.conversation-card
|
||||||
|
padding 15px
|
||||||
|
.q-btn
|
||||||
|
margin-bottom -10px
|
||||||
</style>
|
</style>
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { date } from 'quasar'
|
||||||
|
const { formatDate } = date
|
||||||
|
|
||||||
|
export default function(value) {
|
||||||
|
var timeStamp = new Date(value);
|
||||||
|
return `${formatDate(timeStamp, 'MMMM D, YYYY')} at ${formatDate(timeStamp, 'h:mm a')}`;
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import NumberFilter from './number'
|
import NumberFilter from './number'
|
||||||
|
import DateFilter from './date'
|
||||||
|
|
||||||
Vue.filter('number', NumberFilter);
|
Vue.filter('number', NumberFilter);
|
||||||
|
Vue.filter('readableDate', DateFilter);
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { getConversations } from '../api/conversations';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
conversations: [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
loadConversations(state, options) {
|
||||||
|
let list = [];
|
||||||
|
_.forEach(options, function(item) {
|
||||||
|
delete item._links;
|
||||||
|
if (item.type == 'call') {
|
||||||
|
item.type = item.call_type != 'call' ? 'call forward'
|
||||||
|
: item.type;
|
||||||
|
};
|
||||||
|
list.push(item);
|
||||||
|
})
|
||||||
|
state.conversations = list;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
loadConversations(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
getConversations(localStorage.getItem('subscriberId'))
|
||||||
|
.then((result)=>{
|
||||||
|
context.commit('loadConversations', result);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueResource from 'vue-resource';
|
||||||
|
import { getConversations } from '../../src/api/conversations';
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
Vue.use(VueResource);
|
||||||
|
|
||||||
|
describe('Conversations', function(){
|
||||||
|
|
||||||
|
const subscriberId = 123;
|
||||||
|
|
||||||
|
it('should get all data regarding conversations', function(done){
|
||||||
|
|
||||||
|
let innerData = [{
|
||||||
|
"_links" : {
|
||||||
|
"collection" : {
|
||||||
|
"href" : "/api/conversations/"
|
||||||
|
},
|
||||||
|
"curies" : {
|
||||||
|
"href" : "http://purl.org/sipwise/ngcp-api/#rel-{rel}",
|
||||||
|
"name" : "ngcp",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
"ngcp:calls" : {
|
||||||
|
"href" : "/api/calls/5"
|
||||||
|
},
|
||||||
|
"ngcp:conversations" : {
|
||||||
|
"href" : "/api/conversations/5?type=call"
|
||||||
|
},
|
||||||
|
"profile" : {
|
||||||
|
"href" : "http://purl.org/sipwise/ngcp-api/"
|
||||||
|
},
|
||||||
|
"self" : {
|
||||||
|
"href" : "/api/conversations/5?type=call"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"call_id" : "cT1miqD5Nw",
|
||||||
|
"call_type" : "cfu",
|
||||||
|
"callee" : "vmu43993006@voicebox.local",
|
||||||
|
"caller" : "43993006",
|
||||||
|
"direction" : "out",
|
||||||
|
"duration" : "0:00:19.672",
|
||||||
|
"id" : 5,
|
||||||
|
"rating_status" : "ok",
|
||||||
|
"start_time" : "2017-11-10 08:51:10.452",
|
||||||
|
"status" : "ok",
|
||||||
|
"type" : "call"
|
||||||
|
}];
|
||||||
|
let data = {
|
||||||
|
"_embedded": {
|
||||||
|
"ngcp:conversations": innerData
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Vue.http.interceptors = [];
|
||||||
|
Vue.http.interceptors.unshift((request, next)=>{
|
||||||
|
next(request.respondWith(JSON.stringify(data), {
|
||||||
|
status: 200
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
getConversations(subscriberId).then((result)=>{
|
||||||
|
assert.deepEqual(result, innerData);
|
||||||
|
done();
|
||||||
|
}).catch((err)=>{
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import ConversationsModule from '../../src/store/conversations';
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
describe('Conversations', function(){
|
||||||
|
|
||||||
|
it('should load conversations', function(){
|
||||||
|
let state = {
|
||||||
|
conversations: [
|
||||||
|
]
|
||||||
|
};
|
||||||
|
let data = [
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
},
|
||||||
|
"call_type": "cfu",
|
||||||
|
"caller": "43993010",
|
||||||
|
"type": "call"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
},
|
||||||
|
"caller": "43993011",
|
||||||
|
"type": "fax"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ConversationsModule.mutations.loadConversations(state, data);
|
||||||
|
assert.deepEqual(state.conversations, [
|
||||||
|
{
|
||||||
|
"call_type": "cfu",
|
||||||
|
"caller": "43993010",
|
||||||
|
"type": "call forward"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caller": "43993011",
|
||||||
|
"type": "fax"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in new issue