@dpgradio/creative 5.9.1 → 6.0.0

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 CHANGED
@@ -241,10 +241,12 @@ const image = new ImageGeneratorProperties('https://static.qmusic.be/acties/joe-
241
241
 
242
242
  This package provides a number of utility functions.
243
243
 
244
- | Function | Description |
245
- | ------------------------------- | ---------------------------------------------------------------------------------------- |
246
- | `loadScript(url, { timeout })` | Dynammically loads a JS script. |
247
- | `openLink(url)` | App-compatible link opener. |
248
- | `tap(value, callback)` | Invokes `callback` with the `value` and then returns `value`. |
249
- | `cdnImageUrl(endpoint[, size])` | Get a full image URL for an endpoint in a given size (`w480`, `w800`, `w1200`, `w2400`). |
250
- | `cdnUrl(endpoint)` | Get a full CDN URL for a given endpoint. |
244
+ | Function | Description |
245
+ | --------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
246
+ | `loadScript(url, { timeout })` | Dynammically loads a JS script. |
247
+ | `openLink(url)` | App-compatible link opener. |
248
+ | `tap(value, callback)` | Invokes `callback` with the `value` and then returns `value`. |
249
+ | `cdnImageUrl(endpoint[, size])` | Get a full image URL for an endpoint in a given size (`w480`, `w800`, `w1200`, `w2400`). |
250
+ | `cdnUrl(endpoint)` | Get a full CDN URL for a given endpoint. |
251
+ | `removePhoneNumberCountryPrefix(phoneNumber, [, prefix])` | Removes a country prefix from a phone number based on the station config `country_code`. |
252
+ | `onLocalStorageChange(key, callback)` | Calls `callback` when the value of `key` in `localStorage` changes. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dpgradio/creative",
3
- "version": "5.9.1",
3
+ "version": "6.0.0",
4
4
  "description": "Support package for standalone Javascript applications",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -0,0 +1,38 @@
1
+ import { describe, expect, test } from '@jest/globals'
2
+ import { onLocalStorageChange } from '../../utils/onLocalStorageChange.js'
3
+
4
+ describe('removing explicitly given prefixes', () => {
5
+ test('it returns the current value when immediate is set to true', () => {
6
+ localStorage.setItem('country_code', 'NL')
7
+
8
+ let result
9
+
10
+ onLocalStorageChange('country_code', (value) => (result = value), true)
11
+
12
+ expect(result).toBe('NL')
13
+ })
14
+
15
+ test('it watches for new values', async () => {
16
+ let result
17
+
18
+ onLocalStorageChange('country_code', (value) => (result = value))
19
+
20
+ // A local storage event is only fired when a change is made from another tab
21
+ // so, we fake it here
22
+ window.dispatchEvent(Object.assign(new Event('storage'), { key: 'country_code', newValue: 'BE' }))
23
+
24
+ expect(result).toBe('BE')
25
+ })
26
+
27
+ test('it watches replaces the current value with new values when immediate is true', () => {
28
+ localStorage.setItem('country_code', 'NL')
29
+
30
+ let result
31
+
32
+ onLocalStorageChange('country_code', (value) => (result = value), true)
33
+
34
+ window.dispatchEvent(Object.assign(new Event('storage'), { key: 'country_code', newValue: 'BE' }))
35
+
36
+ expect(result).toBe('BE')
37
+ })
38
+ })
@@ -13,6 +13,12 @@ describe('removing explicitly given prefixes', () => {
13
13
 
14
14
  expect(result).toBe('+33634542211')
15
15
  })
16
+
17
+ test('it does not fail when the given number is null', () => {
18
+ const result = removePhoneNumberCountryPrefix(null, '+31')
19
+
20
+ expect(result).toBeNull()
21
+ })
16
22
  })
17
23
 
18
24
  jest.mock('../../config/config.js', () => ({
package/src/app/hybrid.js CHANGED
@@ -13,20 +13,22 @@ class Hybrid {
13
13
  // Hook this on window so it can be required in multiple packs
14
14
  window._hybridEventSubscriptions = window._hybridEventSubscriptions || {}
15
15
 
16
- this.appInfo = this.detectApp(window.appVersion || navigator.userAgent)
17
-
18
16
  this._cachedRadioTokenOnLoad = undefined
19
17
  this.on('appLoad', (context) => {
20
18
  this._cachedRadioTokenOnLoad = context?.radioToken ?? null
21
19
  })
22
20
  }
23
21
 
22
+ appInfo() {
23
+ return this.detectApp(window.appVersion || navigator.userAgent)
24
+ }
25
+
24
26
  isNativeApp() {
25
- return this.appInfo.platform !== 'browser'
27
+ return this.appInfo().platform !== 'browser'
26
28
  }
27
29
 
28
30
  isVersion({ android, ios }) {
29
- const { platform, buildName, buildVersion } = this.appInfo
31
+ const { platform, buildName, buildVersion } = this.appInfo()
30
32
 
31
33
  return (
32
34
  (platform === 'Android' && android[buildName] && android[buildName] <= parseInt(buildVersion, 10)) ||
package/src/index.js CHANGED
@@ -14,3 +14,5 @@ export { default as openLink } from './utils/openLink.js'
14
14
  export { default as tap } from './utils/tap.js'
15
15
  export { cdnImageUrl, cdnUrl } from './utils/cdnUrl.js'
16
16
  export { removePhoneNumberCountryPrefix } from './utils/phoneNumber.js'
17
+ export { setupAirbrake, gtmFilter } from './utils/setupAirbrake.js'
18
+ export { onLocalStorageChange } from './utils/onLocalStorageChange.js'
@@ -0,0 +1,11 @@
1
+ export const onLocalStorageChange = (key, callback, immediate) => {
2
+ window.addEventListener('storage', (change) => {
3
+ if (change.key == key) {
4
+ callback(change.newValue)
5
+ }
6
+ })
7
+
8
+ if (immediate) {
9
+ callback(localStorage.getItem(key))
10
+ }
11
+ }
@@ -6,6 +6,10 @@ const prefixes = {
6
6
  }
7
7
 
8
8
  export const removePhoneNumberCountryPrefix = (phoneNumber, prefix = null) => {
9
+ if (!phoneNumber) {
10
+ return phoneNumber
11
+ }
12
+
9
13
  prefix ||= prefixes[config('country_code')]
10
14
 
11
15
  if (prefix) {
@@ -0,0 +1,41 @@
1
+ export const setupAirbrake = async (
2
+ AirbrakeNotifier,
3
+ { projectId, projectKey, version, environment = 'production' },
4
+ app = null
5
+ ) => {
6
+ if (!projectId || !Number.isInteger(projectId)) {
7
+ return
8
+ }
9
+
10
+ const airbrake = new AirbrakeNotifier({ projectId, projectKey, environment })
11
+
12
+ airbrake.addFilter(gtmFilter)
13
+
14
+ if (version) {
15
+ airbrake.addFilter((notice) => {
16
+ notice.context = {
17
+ ...notice.context,
18
+ version,
19
+ }
20
+ return notice
21
+ })
22
+ }
23
+
24
+ if (app) {
25
+ app.config.errorHandler = (error, _vm, info) => airbrake.notify({ error, params: { info } })
26
+ }
27
+
28
+ return airbrake
29
+ }
30
+
31
+ export const rejectErrorMessagesContaining = (notice, phrases) =>
32
+ phrases.some((phrase) => notice.errors[0]?.message?.includes(phrase)) ? null : notice
33
+
34
+ export const rejectErrorsFromFilesContaining = (notice, phrases) =>
35
+ phrases.some((phrase) => notice.errors[0]?.backtrace.some((backtraceItem) => backtraceItem.file.includes(phrase)))
36
+ ? null
37
+ : notice
38
+
39
+ export const gtmFilter = (notice) =>
40
+ rejectErrorMessagesContaining(notice, ['dpg_snowplow', '__tcfapi']) &&
41
+ rejectErrorsFromFilesContaining(notice, ['mychannels', 'gtm.js'])