@webitel/ui-sdk 2.0.8 → 2.0.11-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "2.0.8",
3
+ "version": "2.0.11-1",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve-lib": "vue-cli-service serve",
@@ -44,7 +44,7 @@
44
44
  "vue-observe-visibility": "^1.0.0",
45
45
  "vue-router": "^3.2.0",
46
46
  "vuejs-datepicker": "^1.6.2",
47
- "webitel-sdk": "^0.1.91"
47
+ "webitel-sdk": "^0.1.128"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@babel/eslint-parser": "^7.17.0",
@@ -32,7 +32,7 @@ export default {
32
32
  color: {
33
33
  type: String,
34
34
  default: 'accent',
35
- options: ['accent', 'secondary', 'success', 'danger', 'transfer'],
35
+ options: ['accent', 'secondary', 'success', 'danger', 'transfer', 'job'],
36
36
  },
37
37
  disabled: {
38
38
  type: Boolean,
@@ -71,7 +71,7 @@ export default {
71
71
  return '';
72
72
  },
73
73
  loaderColor() {
74
- if (['success', 'transfer', 'danger'].includes(this.color)) return 'main';
74
+ if (['success', 'transfer', 'danger', 'job'].includes(this.color)) return 'main';
75
75
  return 'contrast';
76
76
  },
77
77
  },
@@ -159,6 +159,18 @@ export default {
159
159
  }
160
160
  }
161
161
 
162
+ &.job {
163
+ color: var(--btn-light-font-color);
164
+ background-color: var(--btn-job-color);
165
+ border-color: var(--btn-job-color);
166
+
167
+ &:hover,
168
+ &:active {
169
+ background-color: var(--btn-job--hover-color);
170
+ border-color: var(--btn-job--hover-color);
171
+ }
172
+ }
173
+
162
174
  &.danger {
163
175
  color: var(--btn-light-font-color);
164
176
  background-color: var(--btn-false-color);
@@ -230,6 +242,18 @@ export default {
230
242
  }
231
243
  }
232
244
 
245
+ &.job {
246
+ color: var(--btn-job-color);
247
+ border-color: var(--btn-job-color);
248
+
249
+ &:hover,
250
+ &:active {
251
+ color: var(--btn-job--hover-color);
252
+ border-color: var(--btn-job--hover-color);
253
+ background-color: transparent;
254
+ }
255
+ }
256
+
233
257
  &.danger {
234
258
  color: var(--btn-false-color);
235
259
  border-color: var(--btn-false-color);
@@ -29,7 +29,7 @@ export default {
29
29
  color: {
30
30
  type: String,
31
31
  default: 'default',
32
- options: ['default', 'contrast', 'active', 'accent', 'disabled', 'success', 'danger', 'transfer', 'hold', 'secondary-50'],
32
+ options: ['default', 'contrast', 'active', 'accent', 'disabled', 'success', 'danger', 'transfer', 'job', 'hold', 'secondary-50'],
33
33
  },
34
34
  iconPrefix: {
35
35
  type: String,
@@ -97,6 +97,10 @@ svg {
97
97
  fill: var(--icon-color-transfer);
98
98
  }
99
99
 
100
+ &-job .wt-icon__icon {
101
+ fill: var(--job-color);
102
+ }
103
+
100
104
  &-hold .wt-icon__icon {
101
105
  fill: var(--icon-color-hold);
102
106
  }
@@ -7,6 +7,7 @@
7
7
  :popper-class="[
8
8
  'wt-tooltip__popper',
9
9
  { 'wt-tooltip--contrast__popper': contrast },
10
+ popperClass,
10
11
  ]"
11
12
  :triggers="['hover', 'focus', 'touch']"
12
13
  class="wt-tooltip"
@@ -30,6 +31,10 @@ export default {
30
31
  type: String,
31
32
  default: 'auto',
32
33
  },
34
+ popperClass: {
35
+ type: String,
36
+ default: '',
37
+ },
33
38
  },
34
39
  };
35
40
  </script>
@@ -41,4 +41,7 @@
41
41
 
42
42
  --btn-transfer-color: var(--transfer-color);
43
43
  --btn-transfer--hover-color: var(--transfer--hover-color);
44
- }
44
+
45
+ --btn-job-color: var(--job-color);
46
+ --btn-job--hover-color: var(--job--hover-color);
47
+ }
@@ -9,6 +9,7 @@
9
9
 
10
10
  --_hold-color-hue: 54;
11
11
  --_transfer-color-hue: 227;
12
+ --_job-color-hue: 209;
12
13
 
13
14
  // DEFAULT STATES OPACITY
14
15
  --_opacity--default: 0.8;
@@ -31,6 +32,7 @@
31
32
 
32
33
  --_hold-color: var(--_hold-color-hue), 80%, 50%;
33
34
  --_transfer-color: var(--_transfer-color-hue), 80%, 50%;
35
+ --_job-color: var(--_job-color-hue), 96%, 57%;
34
36
 
35
37
  // MAIN COLORS
36
38
  --accent-color: hsla(var(--_accent-color), 1);
@@ -78,6 +80,9 @@
78
80
  --transfer-color: hsla(var(--_transfer-color), var(--_opacity--default));
79
81
  --transfer--hover-color: hsla(var(--_transfer-color), var(--_opacity--hover));
80
82
 
83
+ --job-color: hsla(var(--_job-color), var(--_opacity--default));
84
+ --job--hover-color: hsla(var(--_job-color), var(--_opacity--hover));
85
+
81
86
  // SUBORDINATE COLORS
82
87
  --tag-bg-color: var(--accent-secondary-color);
83
88
 
@@ -0,0 +1,185 @@
1
+ import { ChatActions, CallActions, JobState } from 'webitel-sdk';
2
+ import i18n from '../../../locale/i18n';
3
+ import BaseStoreModule from '../../../store/BaseStoreModules/BaseStoreModule';
4
+ import endChatSound from '../assets/audio/end-chat.wav';
5
+ import newChatSound from '../assets/audio/new-chat.wav';
6
+ import newMessageSound from '../assets/audio/new-message.wav';
7
+ import ringingSound from '../assets/audio/ringing.mp3';
8
+ import notificationIcon from '../assets/img/notification-icon.png';
9
+
10
+ const NOTIFICATION_VISIBLE_INTERVAL = 2000;
11
+
12
+ const getNotificationSound = (action) => {
13
+ switch (action) {
14
+ case ChatActions.UserInvite:
15
+ case JobState.Distribute:
16
+ return new Audio(newChatSound);
17
+ case ChatActions.Message:
18
+ return new Audio(newMessageSound);
19
+ case ChatActions.Close:
20
+ return new Audio(endChatSound);
21
+ case CallActions.Ringing:
22
+ // eslint-disable-next-line no-case-declarations
23
+ const audio = new Audio(ringingSound);
24
+ audio.loop = true;
25
+ return audio;
26
+ default:
27
+ return false;
28
+ }
29
+ };
30
+
31
+ const getCurrentTabId = () => localStorage.getItem('currentTabId');
32
+
33
+ const setCurrentTabId = (value) => localStorage.setItem('currentTabId', value);
34
+
35
+ export default class NotificationsStoreModule extends BaseStoreModule {
36
+ state = {
37
+ thisTabId: null, // this tab
38
+ currentTabId: null, // current tab is localStorage
39
+ broadcastChannel: null, // in order to reset the tab title with unread number
40
+ unreadCount: 0,
41
+ currentlyPlaying: false,
42
+ };
43
+
44
+ getters = {
45
+ IS_MAIN_TAB: (state) => state.thisTabId === state.currentTabId,
46
+ IS_SOUND_ALLOWED: (state, getters) => getters.IS_MAIN_TAB && !state.currentlyPlaying,
47
+ };
48
+
49
+ actions = {
50
+ // private
51
+ _SUBSCRIBE_TAB_CLOSING: (context) => {
52
+ window.addEventListener('storage', () => {
53
+ if (!getCurrentTabId()) {
54
+ setCurrentTabId(context.state.thisTabId);
55
+ }
56
+ context.commit('SET_CURRENT_TAB_ID', getCurrentTabId());
57
+ });
58
+ },
59
+
60
+ _SETUP_THIS_TAB_ID: (context) => {
61
+ const thisTabId = Math.random().toString();
62
+ context.commit('SET_THIS_TAB_ID', thisTabId);
63
+ setCurrentTabId(thisTabId);
64
+ context.commit('SET_CURRENT_TAB_ID', thisTabId);
65
+ },
66
+
67
+ _SETUP_UNREAD_COUND_BROADCAST_LISTENING: (context) => {
68
+ const broadcastChannel = new BroadcastChannel('WtAppNotifications');
69
+ broadcastChannel.addEventListener('message', ({ data }) => {
70
+ context.dispatch('_SET_UNREAD_COUNT', data.count);
71
+ });
72
+
73
+ document.documentElement.addEventListener('click', () => {
74
+ context.dispatch('_RESET_UNREAD_COUNT');
75
+ });
76
+ context.commit('SET_BROADCAST_CHANNEL', broadcastChannel);
77
+ },
78
+
79
+ _SET_UNREAD_COUNT: (context, count) => {
80
+ context.commit('SET_UNREAD_COUNT', count);
81
+ context.dispatch('_SET_TAB_TITLE');
82
+ },
83
+
84
+ _RESET_UNREAD_COUNT: (context) => {
85
+ if (context.state.unreadCount === 0) return;
86
+ const count = 0;
87
+ context.dispatch('_SET_UNREAD_COUNT', count);
88
+ context.state.broadcastChannel.postMessage({ count });
89
+ },
90
+
91
+ _SET_TAB_TITLE: (context) => {
92
+ const count = context.state.unreadCount;
93
+ const titleText = document.title.replace(/\s*\(.*?\)\s*/g, '');
94
+ document.title = count ? `(${count}) ${titleText}` : titleText;
95
+ },
96
+
97
+ _REMOVE_CURRENT_TAB_ID: () => {
98
+ localStorage.removeItem('currentTabId');
99
+ },
100
+
101
+ // public
102
+ INITIALIZE: (context) => Promise
103
+ .allSettled([
104
+ context.dispatch('_SETUP_THIS_TAB_ID'),
105
+ context.dispatch('_SETUP_UNREAD_COUND_BROADCAST_LISTENING'),
106
+ context.dispatch('_SUBSCRIBE_TAB_CLOSING'),
107
+ ]),
108
+
109
+ DESTROY: (context) => Promise
110
+ .allSettled([
111
+ context.dispatch('STOP_SOUND'),
112
+ context.dispatch('_REMOVE_CURRENT_TAB_ID'),
113
+ ]),
114
+
115
+ PLAY_SOUND: (context, {
116
+ action,
117
+ sound = getNotificationSound(action),
118
+ }) => {
119
+ if (context.getters.IS_SOUND_ALLOWED
120
+ && !localStorage.getItem('wtIsPlaying')
121
+ ) {
122
+ const audio = sound instanceof Audio ? sound : new Audio(sound);
123
+ audio.addEventListener('ended', () => {
124
+ context.dispatch('STOP_SOUND');
125
+ }, { once: true });
126
+ audio.play();
127
+ localStorage.setItem('wtIsPlaying', 'true');
128
+ context.commit('SET_CURRENTLY_PLAYING', audio);
129
+ }
130
+ },
131
+
132
+ STOP_SOUND: (context) => {
133
+ const { currentlyPlaying } = context.state;
134
+ if (currentlyPlaying) currentlyPlaying.pause();
135
+ localStorage.removeItem('wtIsPlaying');
136
+ context.commit('RESET_CURRENTLY_PLAYING');
137
+ },
138
+
139
+ SEND_NOTIFICATION: (context, {
140
+ locale,
141
+ text = i18n.t(locale),
142
+ icon = notificationIcon,
143
+ interval = NOTIFICATION_VISIBLE_INTERVAL,
144
+ }) => {
145
+ const notification = new Notification(text, { icon });
146
+
147
+ notification.addEventListener('click', () => {
148
+ window.focus();
149
+ }, { once: true });
150
+
151
+ setTimeout(() => {
152
+ notification.close();
153
+ }, interval);
154
+ },
155
+
156
+ INCREMENT_UNREAD_COUNT: (context) => {
157
+ const count = context.state.unreadCount + 1;
158
+ context.dispatch('_SET_UNREAD_COUNT', count);
159
+ context.state.broadcastChannel.postMessage({ count });
160
+ },
161
+ };
162
+
163
+ mutations = {
164
+ SET_THIS_TAB_ID: (state, thisTabId) => {
165
+ state.thisTabId = thisTabId;
166
+ },
167
+
168
+ SET_CURRENT_TAB_ID: (state, currentTabId) => {
169
+ state.currentTabId = currentTabId;
170
+ },
171
+
172
+ SET_BROADCAST_CHANNEL: (state, channel) => {
173
+ state.broadcastChannel = channel;
174
+ },
175
+ SET_CURRENTLY_PLAYING: (state, sound) => {
176
+ state.currentlyPlaying = sound;
177
+ },
178
+ RESET_CURRENTLY_PLAYING: (state) => {
179
+ state.currentlyPlaying = false;
180
+ },
181
+ SET_UNREAD_COUNT: (state, count) => {
182
+ state.unreadCount = count;
183
+ },
184
+ };
185
+ }
@@ -0,0 +1,130 @@
1
+ import audio from '../../assets/audio/new-message.wav';
2
+ import NotificationsStoreModule from '../NotificationsStoreModule';
3
+ import '../../../../../tests/mocks/broadcastChannelMock';
4
+
5
+ const notificationsModule = new NotificationsStoreModule().getModule();
6
+
7
+ const state = {
8
+ thisTabId: null,
9
+ broadcastChannel: new BroadcastChannel('WtAppNotifications'),
10
+ unreadCount: 0,
11
+ currentlyPlaying: false,
12
+ wtIsPlaying: false,
13
+ };
14
+
15
+ describe('features/notifications store: actions', () => {
16
+ const context = {
17
+ dispatch: jest.fn(),
18
+ commit: jest.fn(),
19
+ getters: {
20
+ IS_MAIN_TAB: () => true,
21
+ IS_SOUND_ALLOWED: () => true,
22
+ },
23
+ rootGetters: {
24
+ 'workspace/TASK_ON_WORKSPACE': { channelId: 'id' },
25
+ },
26
+ };
27
+
28
+ beforeEach(() => {
29
+ context.state = { ...state };
30
+ context.dispatch.mockClear();
31
+ context.commit.mockClear();
32
+ });
33
+
34
+ it('INITIALIZE action dispatches _SETUP_THIS_TAB_ID action', () => {
35
+ notificationsModule.actions.INITIALIZE(context);
36
+ expect(context.dispatch.mock.calls[0][0]).toContain('_SETUP_THIS_TAB_ID');
37
+ });
38
+
39
+ it('INITIALIZE action dispatches _SETUP_UNREAD_COUND_BROADCAST_LISTENING action', () => {
40
+ notificationsModule.actions.INITIALIZE(context);
41
+ expect(context.dispatch.mock.calls[1][0]).toContain('_SETUP_UNREAD_COUND_BROADCAST_LISTENING');
42
+ });
43
+
44
+ it('INITIALIZE action dispatches _SETUP_THIS_TAB_ID action', () => {
45
+ notificationsModule.actions.INITIALIZE(context);
46
+ expect(context.dispatch).toHaveBeenCalledWith('_SETUP_THIS_TAB_ID');
47
+ });
48
+
49
+ it('DESTROY action dispatches STOP_SOUND action', () => {
50
+ notificationsModule.actions.DESTROY(context);
51
+ expect(context.dispatch).toHaveBeenCalledWith('STOP_SOUND');
52
+ });
53
+
54
+ it('DESTROY action dispatches _REMOVE_CURRENT_TAB_ID action', () => {
55
+ notificationsModule.actions.DESTROY(context);
56
+ expect(context.dispatch).toHaveBeenCalledWith('_REMOVE_CURRENT_TAB_ID');
57
+ });
58
+
59
+ it('INCREMENT_UNREAD_COUNT action dispatches _SET_UNREAD_COUNT and increases unreadCount', () => {
60
+ notificationsModule.actions.INCREMENT_UNREAD_COUNT(context);
61
+ expect(context.dispatch).toHaveBeenCalledWith('_SET_UNREAD_COUNT', context.state.unreadCount + 1);
62
+ });
63
+
64
+ it('_SETUP_UNREAD_COUND_BROADCAST_LISTENING action commits SET_BROADCAST_CHANNEL mutation', () => {
65
+ notificationsModule.actions._SETUP_UNREAD_COUND_BROADCAST_LISTENING(context);
66
+ expect(context.commit.mock.calls[0][0]).toContain('SET_BROADCAST_CHANNEL');
67
+ });
68
+
69
+ it('_SUBSCRIBE_TAB_CLOSING action commits SET_CURRENT_TAB_ID mutation', async () => {
70
+ await notificationsModule.actions._SUBSCRIBE_TAB_CLOSING(context);
71
+ window.dispatchEvent(new Event('storage'));
72
+ expect(context.commit).toHaveBeenCalledWith('SET_CURRENT_TAB_ID', 'null');
73
+ });
74
+
75
+ it('PLAY_SOUND action commits SET_CURRENTLY_PLAIYNG mutation with sound', async () => {
76
+ const sound = new Audio(audio);
77
+ await notificationsModule.actions.PLAY_SOUND(context, { sound });
78
+ expect(context.commit).toHaveBeenCalledWith('SET_CURRENTLY_PLAYING', sound);
79
+ });
80
+
81
+ it('_SET_UNREAD_COUNT dispatches _SET_TAB_TITLE action', () => {
82
+ const unreadCount = 5;
83
+ notificationsModule.actions._SET_UNREAD_COUNT(context, unreadCount);
84
+ expect(context.dispatch).toHaveBeenCalledWith('_SET_TAB_TITLE');
85
+ });
86
+
87
+ it('_SETUP_THIS_TAB_ID commits SET_THIS_TAB_ID mutation', () => {
88
+ notificationsModule.actions._SETUP_THIS_TAB_ID(context);
89
+ expect(context.commit.mock.calls[0][0]).toBe('SET_THIS_TAB_ID');
90
+ });
91
+
92
+ it('_SETUP_THIS_TAB_ID commits SET_CURRENT_TAB_ID mutation', () => {
93
+ notificationsModule.actions._SETUP_THIS_TAB_ID(context);
94
+ expect(context.commit.mock.calls[1][0]).toBe('SET_CURRENT_TAB_ID');
95
+ });
96
+
97
+ it('_SET_UNREAD_COUNT action commits _SET_UNREAD_COUNT mutation with count', () => {
98
+ const unreadCount = 5;
99
+ notificationsModule.actions._SET_UNREAD_COUNT(context, unreadCount);
100
+ expect(context.commit).toHaveBeenCalledWith('SET_UNREAD_COUNT', unreadCount);
101
+ });
102
+
103
+ it('_RESET_UNREAD_COUNT action does not dispatch if unread count is 0', () => {
104
+ notificationsModule.actions._RESET_UNREAD_COUNT(context);
105
+ expect(context.dispatch).not.toHaveBeenCalledWith('_SET_UNREAD_COUNT');
106
+ });
107
+
108
+ it('_RESET_UNREAD_COUNT action dispatches _SET_UNREAD_COUNT passing unread count equal to 0', () => {
109
+ context.state.unreadCount = 1;
110
+ notificationsModule.actions._RESET_UNREAD_COUNT(context);
111
+ expect(context.dispatch).toHaveBeenCalledWith('_SET_UNREAD_COUNT', 0);
112
+ });
113
+
114
+ it('PLAY_SOUND action sets localStorage wtIsPlaying to true', () => {
115
+ const sound = new Audio(audio);
116
+ notificationsModule.actions.PLAY_SOUND(context, { sound });
117
+ expect(localStorage.getItem('wtIsPlaying')).toBeTruthy();
118
+ });
119
+
120
+ it('STOP_SOUND action commits RESET_CURRENTLY_PLAYING mutation', () => {
121
+ notificationsModule.actions.STOP_SOUND(context);
122
+ expect(context.commit).toHaveBeenCalledWith('RESET_CURRENTLY_PLAYING');
123
+ });
124
+
125
+ it('STOP_SOUND action removes localStorage wtIsPlaying', () => {
126
+ localStorage.setItem('wtIsPlaying', 'true');
127
+ notificationsModule.actions.STOP_SOUND(context);
128
+ expect(localStorage.getItem('wtIsPlaying')).toBeFalsy();
129
+ });
130
+ });
@@ -0,0 +1,49 @@
1
+ import NotificationsStoreModule from '../NotificationsStoreModule';
2
+ import '../../../../../tests/mocks/broadcastChannelMock';
3
+
4
+ const notificationsModule = new NotificationsStoreModule().getModule();
5
+
6
+ const state = {
7
+ thisTabId: null,
8
+ broadcastChannel: new BroadcastChannel('WtAppNotifications'),
9
+ unreadCount: 0,
10
+ currentlyPlaying: false,
11
+ wtIsPlaying: false,
12
+ };
13
+
14
+ describe('features/notifications store: mutations', () => {
15
+ it('SET_THIS_TAB_ID sets thisTabId to state', () => {
16
+ const thisTabId = 'thisTabId';
17
+ notificationsModule.mutations.SET_THIS_TAB_ID(state, thisTabId);
18
+ expect(state.thisTabId).toBe(thisTabId);
19
+ });
20
+ it('SET_CURRENT_TAB_ID sets currentTabId to state', () => {
21
+ const currentTabId = 'currentTabId';
22
+ notificationsModule.mutations.SET_CURRENT_TAB_ID(state, currentTabId);
23
+ expect(state.currentTabId).toBe(currentTabId);
24
+ });
25
+
26
+ it('SET_BROADCAST_CHANNEL sets broadcastChannel to state', () => {
27
+ const state = { broadcastChannel: null };
28
+ const channel = new BroadcastChannel('test channel');
29
+ notificationsModule.mutations.SET_BROADCAST_CHANNEL(state, channel);
30
+ expect(state.broadcastChannel).toEqual(channel);
31
+ });
32
+
33
+ it('SET_CURRENTLY_PLAIYNG mutation sets currentlyPlaying to state', () => {
34
+ const wtIsPlaying = true;
35
+ notificationsModule.mutations.SET_CURRENTLY_PLAYING(state, wtIsPlaying);
36
+ expect(state.currentlyPlaying).toBe(true);
37
+ });
38
+
39
+ it('RESET_CURRENTLY_PLAYING mutation sets currentlyPlaying to false in state', () => {
40
+ notificationsModule.mutations.RESET_CURRENTLY_PLAYING(state);
41
+ expect(state.currentlyPlaying).toBe(false);
42
+ });
43
+
44
+ it('_SET_UNREAD_COUNT mutation sets unreadCount to state', () => {
45
+ const unreadCount = 15;
46
+ notificationsModule.mutations.SET_UNREAD_COUNT(state, unreadCount);
47
+ expect(state.unreadCount).toEqual(unreadCount);
48
+ });
49
+ });