@viibe/impulse-integration-js 2.2.0 → 2.2.4

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/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Viibe SDK
2
+
3
+ Viibe SDK allows to display a call iframe directly within your host application.
4
+
5
+ The call iframe allows to
6
+
7
+ - initiate a call
8
+ - schedule a call
9
+ - display past sessions
10
+
11
+ ### Constructor
12
+
13
+ `const viibe = new Viibe({host, source})`
14
+
15
+ **Options**
16
+
17
+ `host` **(string, mandatory)**
18
+
19
+ The ViiBE subdomain you want to display.
20
+
21
+ i.e : [`example.viibe.pro`](http://example.viibe.pro)
22
+
23
+ `source` **(string, mandatory)**
24
+
25
+ The source where your want to integrate ViiBE.
26
+
27
+ The source will be added to the created ticket for reference.
28
+
29
+ i.e: `example`
30
+
31
+ ### Create a Call
32
+
33
+ ⚠️ You will need a ViiBE token to display our iframe without login step.
34
+
35
+ `viibe.createCallIframe(options): HTMLElement`
36
+
37
+ This method will create an iframe element which will display a initialization call page of your viibe subdomain. The iframe should be appended to the host application's DOM.
38
+
39
+ `viibe.createCallURL(options): string`
40
+
41
+ The method will generate the URL to the call page (used by `createCallUrl` ). The host application can use this URL to display the call frame in a popin or modal instead of an iframe.
42
+
43
+ #### Options
44
+
45
+ Both above methods support the same options:
46
+
47
+ `links[]` **(array, optional)**
48
+
49
+ The list of contacts to add to the call. The contacts are only prefilled and can be removed by the user before initiating the call. Other contacts can be added by the user via an input.
50
+
51
+ Each item is an object with the following format:
52
+
53
+ `category` **(string, mandatory)**
54
+
55
+ The type of contact (`email`, `expertise`, or `phone`)
56
+
57
+ `value` **(string, mandatory)**
58
+
59
+ The contact itself;
60
+
61
+ - for `email` category, should be a valid email
62
+ - for `phone` category, should be a full phone number (including national prefix)
63
+ - for `expertise` category, should be an `id_expertise`
64
+
65
+ `ticket`
66
+
67
+ Represents the host application entity the call will be attached to. Viibe calls should typically be attached to a ticket, conversation or issue within the host application
68
+
69
+ `integration`
70
+
71
+ `id` **(string, mandatory)**
72
+
73
+ The external ID corresponding to ticket
74
+
75
+ `title` **(string, optional)**
76
+
77
+ The ticket title (will overwrite any existing ticket title)
78
+
79
+ `token` **(string, optional)**
80
+
81
+ A valid Viibe JWT token. If none is provided or the token is invalid, a `authentication:error` event will be triggered, and a "Login" button will be displayed within the iframe.
82
+
83
+ `locale` **(string, optional)**
84
+
85
+ An **ISO 639-1** language code.
86
+
87
+ `components` **(array, optional)**
88
+
89
+ A list of visible components among `call`, `schedule` and `session` (example: `['call','schedule']`)
90
+
91
+ `o2m` **(boolean, optional, default = false)**
92
+
93
+ Whether or not the user can call an expertise (i.e. a group of experts)
94
+
95
+ `clipboard` **(boolean, optional, default = false)**
96
+
97
+ If true, the user won't be able to edit the list of callees (links)
98
+
99
+ ### Authentication
100
+
101
+ While the iframe should contain a "Login" button if you don't pass a token or your token is invalid, the Viibe SDK allows to open an authentication popup to obtain a Viibe JWT token to be passed to the call iframe:
102
+
103
+ `viibe.authenticate(provider): Promise<string>`
104
+
105
+ The `provider` param depends on the third-party authentication methods setup for your Viibe domain.
106
+
107
+ ### Events
108
+
109
+ The host application can register event listeners to react to events occuring in the call iframe
110
+
111
+ `viibe.on(event, handler)`
112
+
113
+ `handler` will receive the event emitted by the call iframe
114
+
115
+ **Supported events**
116
+
117
+ - event `resize`
118
+ - handler payload `{height: number}`
119
+
120
+ Triggered when the height of the iframe content changes. The host app should likely resize the iframe to the appropriate size
121
+
122
+ - event `click:session`
123
+ - handler payload `{uuid: string, slug: string}`
124
+
125
+ Triggered when the user clicks on a past session. The host app may open a modal or popup to display the session `{host}/session/{uuid}/{slug}`
126
+
127
+ - event `click:call`
128
+ - handler payload `{uuid: string, slug: string}`
129
+
130
+ Triggered when the user clicks on an ongoing call. The host app may open a modal or popup to join the call (`{host}/call/{slug}/{uuid}`)
131
+
132
+ - event `authentication:error`
133
+ - handler payload: `error: string`
134
+
135
+ Triggered when the user is not authenticated. The host app may display a login button in place of the iframe (`{host}/api/auth/login/{provider}`). Otherwise the iframe should display a "login" button with username / password method
136
+
137
+ - event `authentication:token`
138
+ - handler payload: `{token: string}`
139
+
140
+ Triggered when the user was successfully authenticated from an authenticate() call, or when the authentication token has changed within the app
141
+
142
+ **Example**
143
+
144
+ ```jsx
145
+ viibe.on('authentication:error', (error) => {
146
+ console.log('authentication:error', error)
147
+ if (error === 'not authenticated') {
148
+ element.innerHTML = '';
149
+ }
150
+ });
151
+
152
+ viibe.on('click:session', (event) => {
153
+ console.log('click:session', event)
154
+ });
155
+
156
+ viibe.on('click:call', (event) => {
157
+ console.log('click:call', event)
158
+ });
159
+
160
+ viibe.on('resize', (event) => {
161
+ console.log('resize', event)
162
+ });
163
+ ```
164
+
165
+ ## Iframe API
166
+
167
+ ### Global Query Parameters
168
+
169
+ *Dev note: to be handled globally, either in integration boot or in IntegrationLayout*
170
+
171
+ - `locale` **(string, optional)** : language to display the app into (e.g. `fr-FR`)
172
+ - `source` **(string, optional)** : identifier for the host application (e.g. `zendesk`, `mdynamics`, `salesforce`)
173
+ - `token` **(string, optional)** : a Viibe token to authenticate the user
174
+
175
+ **Legacy intercom parameters**
176
+
177
+ To be kept for backward compatibility, but should be isolated to the `postMessage` module
178
+
179
+ - `uuid` **(string)** : the UUID of the iframe, typically generated by viibe.js for interframe com
180
+ - `data` **(boolean)** : whether the host page will send initial postMessage data to the frame
181
+ - `resize` **(boolean)** : whether the frame should emit postMessages when its content changes size
182
+
183
+ ### Call Parameters
184
+
185
+ *Dev note: to be handled at component level via a vue-router router*
186
+
187
+ The "call feature" is actually attached to a ticket, and allows to create, renew or schedule calls within this ticket
188
+
189
+ **Ticket identifier**
190
+
191
+ Tickets displayed in integration iframes are usually identified by the host id (or `thirdPartyId`). Either of the following params must be present.
192
+
193
+ - `thirdPartyId` **(string)** : an identifier of the host ticket to attach the Viibe ticket to (currently via `[ticket.integration.id](http://ticket.integration.id)`)
194
+ - `slug` **(string)** : a viibe ticket slug (currently not supported)
195
+
196
+ **Call modifiers**
197
+
198
+ The following parameters are passed from the host to the iframe to alter the current ticket
199
+
200
+ - `title` **(string, optional)** : the title of the ticket, saved to the viibe ticket every time a call is created or scheduled.
201
+ - `links` **(array, optional)** : a list of links to display in the "call" and "schedule" forms (i.e. to be added to the associated session on "call", "renew" or "schedule"). The array values are separated by comma (`,`) where each value has a `category` (e.g. `email`, `phone`, `username`, `expertise`, ...) and a `value` separated by a colon (example: `links=email:clement@viibe.co,username:charles,phone:+3361867999999`)
202
+
203
+ **UI options (call feature only)**
204
+
205
+ - `components` **(array, optional)**: a list of strings indicating the UI components to enable among `"call"`, `"schedule"` and `"session"` (default: all, example: `components=call,schedule,session`)
206
+ - `clipboard` **(boolean, optional)**: controls whether the "smart input" to add new links is visible or not
207
+ - `o2m` **(boolean, optional)** : controls whether the user can make one-to-many calls (i.e. can call expertises)
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (()=>{"use strict";var t={d:(e,n)=>{for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function n(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}t.r(e),t.d(e,{default:()=>o});const o=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.host=e.host,this.origin=/^localhost/.test(this.host)?"http://".concat(this.host):"https://".concat(this.host),this.source=e.source,this.handlers={},window.addEventListener("message",this.onMessage.bind(this))}var e,o;return e=t,o=[{key:"createCallIframe",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.host)throw new Error("fillHost");if(!this.source)throw new Error("fillSource");var e=this.createCallUrl(t),n=document.createElement("iframe");return n.style="border: 0;width: calc(100% - 1rem);margin: 0.5rem;",n.src=e,n.allow="geolocation;autoplay;microphone;camera;midi;encrypted-media;clipboard-write;",n}},{key:"createCallUrl",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.links,n=t.ticket,o=t.token,a=t.locale,r="".concat(this.origin,"/integration/features/call"),i=["resize=true"];if(i.push("source=".concat(this.source)),null!=n&&n.integration&&i.push("thirdPartyId=".concat(n.integration.id)),e){var c=e.map((function(t){return"".concat(t.category,":").concat(t.value)})).join(",");i.push("links=".concat(c))}return o&&i.push("token=".concat(o)),a&&i.push("locale=".concat(a)),r+"?"+i.join("&")}},{key:"isViibeEvent",value:function(t){return Boolean(t.isTrusted&&0===t.origin.indexOf(this.origin))}},{key:"dispatch",value:function(t,e){var n=this.handlers[t];return n?n.map((function(t){return t(e)})):null}},{key:"onMessage",value:function(t){return this.isViibeEvent(t)?t.data&&t.data.event&&t.data.payload?this.dispatch(t.data.event,t.data.payload):t.data&&t.data.token?this.dispatch("authentication:token",t.data.token):t.data&&t.data.error?this.dispatch("authentication:error",t.data.error):null:null}},{key:"on",value:function(t,e){(this.handlers[t]=this.handlers[t]||[]).push(e)}},{key:"authenticate",value:function(t){var e=this,n="".concat(this.origin,"/api/auth/login/").concat(t),o=window.screen.width/2-240,a=window.screen.height/2-300,r=["toolbar=no","location=no","directories=no","status=no","menubar=no","scrollbars=no","resizable=no","copyhistory=no","width=".concat(480),"height=".concat(600),"top=".concat(a),"left=".concat(o)];return new Promise((function(t,o){var a=window.open(n,"Authorization",r.join(", ")),i=setInterval((function(){a.closed&&(s(),c())}),100),c=function(){o("User closed window")},s=function(){window.removeEventListener("message",l),clearInterval(i)},l=function(n){if(!e.isViibeEvent(n))return null;n.data.token&&(s(),t(n.data.token)),n.data.error&&(s(),o(n.data.error))};window.addEventListener("message",l)}))}}],o&&n(e.prototype,o),t}();module.exports=e})();
1
+ (()=>{var t={579:t=>{function e(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var n=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.host=e.host,this.origin=/^localhost/.test(this.host)?"http://".concat(this.host):"https://".concat(this.host),this.source=e.source,this.handlers={},window.addEventListener("message",this.onMessage.bind(this))}var n,o;return n=t,o=[{key:"createCallIframe",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.host)throw new Error("fillHost");if(!this.source)throw new Error("fillSource");var e=this.createCallUrl(t),n=document.createElement("iframe");return n.style="border: 0;width: calc(100% - 1rem);margin: 0.5rem;",n.src=e,n.allow="geolocation;autoplay;microphone;camera;midi;encrypted-media;clipboard-write;",n}},{key:"createCallUrl",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.clipboard,n=void 0!==e&&e,o=t.components,i=t.links,a=t.o2m,r=void 0!==a&&a,s=t.ticket,c=t.token,l=t.locale,u="".concat(this.origin,"/integration/features/call"),d=new URLSearchParams({resize:"true",source:this.source});if(null!=s&&s.title&&d.set("title",s.title),null!=s&&s.integration&&d.set("thirdPartyId",s.integration.id),i){var h=i instanceof Array?i.map((function(t){return"".concat(t.category,":").concat(t.value)})).join(","):String(i);d.set("links",h)}if(c&&d.set("token",c),l&&d.set("locale",l),o){var f=o instanceof Array?o.join(","):String(o);d.set("components",f)}return d.set("clipboard",Boolean(n)),d.set("o2m",Boolean(r)),u+"?".concat(d)}},{key:"isViibeEvent",value:function(t){return Boolean(t.isTrusted&&0===t.origin.indexOf(this.origin))}},{key:"dispatch",value:function(t,e){var n=this.handlers[t];return n?n.map((function(t){return t(e)})):null}},{key:"onMessage",value:function(t){return this.isViibeEvent(t)?t.data&&t.data.event&&t.data.payload?this.dispatch(t.data.event,t.data.payload):t.data&&t.data.token?this.dispatch("authentication:token",t.data.token):t.data&&t.data.error?this.dispatch("authentication:error",t.data.error):null:null}},{key:"on",value:function(t,e){(this.handlers[t]=this.handlers[t]||[]).push(e)}},{key:"authenticate",value:function(t){var e=this,n="".concat(this.origin,"/api/auth/login/").concat(t),o=window.screen.width/2-240,i=window.screen.height/2-300,a=["toolbar=no","location=no","directories=no","status=no","menubar=no","scrollbars=no","resizable=no","copyhistory=no","width=".concat(480),"height=".concat(600),"top=".concat(i),"left=".concat(o)];return new Promise((function(t,o){var i=window.open(n,"Authorization",a.join(", ")),r=setInterval((function(){i.closed&&(c(),s())}),100),s=function(){o("User closed window")},c=function(){window.removeEventListener("message",l),clearInterval(r)},l=function(n){if(!e.isViibeEvent(n))return null;n.data.token&&(c(),t(n.data.token)),n.data.error&&(c(),o(n.data.error))};window.addEventListener("message",l)}))}}],o&&e(n.prototype,o),t}();"undefined"!=typeof window&&(window.Viibe=n),t.exports=n}},e={},n=function n(o){var i=e[o];if(void 0!==i)return i.exports;var a=e[o]={exports:{}};return t[o](a,a.exports,n),a.exports}(579);module.exports=n})();
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@viibe/impulse-integration-js",
3
- "version": "2.2.0",
3
+ "version": "2.2.4",
4
4
  "description": "ViiBE integration in js native",
5
5
  "main": "index.js",
6
+ "publishConfig": {
7
+ "access":"public"
8
+ },
6
9
  "scripts": {
7
10
  "build": "webpack --mode production",
8
11
  "prepublish": "npm run build",
9
- "test": "echo \"Error: no test specified\" && exit 1",
10
- "publish:public": "npm publish --access public"
12
+ "test": "echo \"Error: no test specified\" && exit 1"
11
13
  },
12
14
  "author": "Viibe",
13
15
  "license": "ISC",
package/src/index.js CHANGED
@@ -24,26 +24,50 @@ class Viibe {
24
24
  }
25
25
 
26
26
  createCallUrl(options = {}) {
27
- const { links, ticket, token, locale } = options
27
+ const {
28
+ clipboard = false,
29
+ components,
30
+ links,
31
+ o2m = false,
32
+ ticket,
33
+ token,
34
+ locale
35
+ } = options
28
36
 
29
37
  let src = `${this.origin}/integration/features/call`
30
38
 
31
- const params = ['resize=true']
39
+ const params = new URLSearchParams({
40
+ resize: 'true',
41
+ source: this.source,
42
+ });
32
43
 
33
- params.push(`source=${this.source}`)
34
-
35
- if (ticket?.integration) params.push(`thirdPartyId=${ticket.integration.id}`)
44
+ if (ticket?.title) params.set('title', ticket.title)
45
+ if (ticket?.integration) params.set('thirdPartyId', ticket.integration.id)
36
46
 
37
47
  if (links) {
38
- const linksToParams = links.map(link => `${link.category}:${link.value}`).join(',')
39
- params.push(`links=${linksToParams}`)
48
+ let linksParams = (links instanceof Array)
49
+ ? links.map(link => `${link.category}:${link.value}`).join(',')
50
+ : String(links)
51
+
52
+ params.set('links', linksParams)
40
53
  }
41
54
 
42
- if (token) params.push(`token=${token}`)
55
+ if (token) params.set('token', token)
56
+
57
+ if (locale) params.set('locale', locale)
58
+
59
+ if (components) {
60
+ let componentsParams = (components instanceof Array)
61
+ ? components.join(',')
62
+ : String(components)
63
+
64
+ params.set('components', componentsParams)
65
+ }
43
66
 
44
- if (locale) params.push(`locale=${locale}`)
67
+ params.set('clipboard', Boolean(clipboard))
68
+ params.set('o2m', Boolean(o2m))
45
69
 
46
- src += '?' + params.join('&')
70
+ src += `?${params}`;
47
71
 
48
72
  return src
49
73
  }
@@ -111,11 +135,16 @@ class Viibe {
111
135
  return new Promise((resolve, reject) => {
112
136
  const win = window.open(src, 'Authorization', windowParams.join(', '))
113
137
 
138
+ if(!win) {
139
+ reject('Failed to open window')
140
+ }
141
+
114
142
  const closeCheck = setInterval(() => {
115
143
  if(win.closed) {
116
144
  destroy();
117
145
  onClose();
118
146
  }
147
+
119
148
  }, 100)
120
149
 
121
150
  const onClose = () => {
@@ -148,6 +177,9 @@ class Viibe {
148
177
 
149
178
  }
150
179
 
151
- export default Viibe
152
-
153
- // window.Viibe = Viibe
180
+ if(typeof window !== 'undefined') {
181
+ window.Viibe = Viibe
182
+ }
183
+ if(typeof module !== 'undefined') {
184
+ module.exports = Viibe
185
+ }