@playpilot/tpi 8.16.1 → 8.17.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/dist/editorial.mount.js +9 -9
- package/dist/link-injections.js +2 -2
- package/dist/mount.js +9 -9
- package/package.json +1 -1
- package/src/lib/api/region.ts +11 -0
- package/src/lib/api/titles.ts +8 -2
- package/src/lib/data/translations.ts +5 -0
- package/src/lib/enums/Language.ts +2 -2
- package/src/lib/enums/Region.ts +30 -0
- package/src/routes/components/Explore/ExploreLayout.svelte +20 -0
- package/src/tests/lib/api/region.test.js +83 -53
- package/src/tests/lib/api/titles.test.js +27 -1
- package/src/tests/routes/components/Explore/ExploreLayout.test.js +22 -0
package/package.json
CHANGED
package/src/lib/api/region.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SupportedRegion } from '$lib/enums/Region'
|
|
1
2
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
2
3
|
import { track } from '$lib/tracking'
|
|
3
4
|
|
|
@@ -26,6 +27,16 @@ export async function getRegionBasedOnIp(timeout = 5000): Promise<string> {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export async function isUserRegionSupported(region: string = ''): Promise<boolean> {
|
|
31
|
+
try {
|
|
32
|
+
region ||= await getRegionBasedOnIp()
|
|
33
|
+
|
|
34
|
+
return !region || Object.values(SupportedRegion).some(supportedRegion => supportedRegion === region)
|
|
35
|
+
} catch {
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
function setSavedRegion(region: string): void {
|
|
30
41
|
if (!window.PlayPilotLinkInjections) return
|
|
31
42
|
|
package/src/lib/api/titles.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { APIPaginatedResult } from '$lib/types/api'
|
|
|
4
4
|
import { paramsToString } from '$lib/url'
|
|
5
5
|
import type { TitleData } from '../types/title'
|
|
6
6
|
import { api } from './api'
|
|
7
|
-
import { getRegionBasedOnIp } from './region'
|
|
7
|
+
import { getRegionBasedOnIp, isUserRegionSupported } from './region'
|
|
8
8
|
|
|
9
9
|
export async function fetchTitles(params: Record<string, any> = {}): Promise<APIPaginatedResult<TitleData>> {
|
|
10
10
|
const apiToken = getApiToken()
|
|
@@ -17,7 +17,13 @@ export async function fetchTitles(params: Record<string, any> = {}): Promise<API
|
|
|
17
17
|
include_count: 'false',
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
if (params.region !== null)
|
|
20
|
+
if (params.region !== null) {
|
|
21
|
+
const region = params.region || await getRegionBasedOnIp()
|
|
22
|
+
|
|
23
|
+
if (!await isUserRegionSupported(region)) return { next: '', previous: '', results: [] }
|
|
24
|
+
|
|
25
|
+
params.region = region
|
|
26
|
+
}
|
|
21
27
|
|
|
22
28
|
return await api<APIPaginatedResult<TitleData>>(`/titles/browse?api-token=${apiToken}&` + paramsToString(params))
|
|
23
29
|
}
|
|
@@ -296,6 +296,11 @@ export const translations = {
|
|
|
296
296
|
[Language.Swedish]: 'Nämnda i den här artikeln',
|
|
297
297
|
[Language.Danish]: 'Nævnt i denne artikel',
|
|
298
298
|
},
|
|
299
|
+
'Sorry Region Not Supported': {
|
|
300
|
+
[Language.English]: 'Sorry, your region is not supported',
|
|
301
|
+
[Language.Swedish]: 'Tyvärr stöds inte din region',
|
|
302
|
+
[Language.Danish]: 'Beklager, din region understøttes ikke',
|
|
303
|
+
},
|
|
299
304
|
|
|
300
305
|
// List titles
|
|
301
306
|
'List: Trending': {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const SupportedRegion = {
|
|
2
|
+
Argentina: 'ar',
|
|
3
|
+
Australia: 'au',
|
|
4
|
+
Austria: 'at',
|
|
5
|
+
Belgium: 'be',
|
|
6
|
+
Brazil: 'br',
|
|
7
|
+
Canada: 'ca',
|
|
8
|
+
Chile: 'cl',
|
|
9
|
+
Colombia: 'co',
|
|
10
|
+
Denmark: 'dk',
|
|
11
|
+
Finland: 'fi',
|
|
12
|
+
France: 'fr',
|
|
13
|
+
Germany: 'de',
|
|
14
|
+
India: 'in',
|
|
15
|
+
Ireland: 'ie',
|
|
16
|
+
Italy: 'it',
|
|
17
|
+
Mexico: 'mx',
|
|
18
|
+
Netherlands: 'nl',
|
|
19
|
+
Norway: 'no',
|
|
20
|
+
Peru: 'pe',
|
|
21
|
+
Poland: 'pl',
|
|
22
|
+
Portugal: 'pt',
|
|
23
|
+
Russia: 'ru',
|
|
24
|
+
Singapore: 'sg',
|
|
25
|
+
Spain: 'es',
|
|
26
|
+
Sweden: 'se',
|
|
27
|
+
Switzerland: 'ch',
|
|
28
|
+
UK: 'uk',
|
|
29
|
+
USA: 'us',
|
|
30
|
+
} as const
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { track } from '$lib/tracking'
|
|
7
7
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
8
8
|
import { fetchAds } from '$lib/api/ads'
|
|
9
|
+
import { isUserRegionSupported } from '$lib/api/region'
|
|
9
10
|
import { onMount, type Snippet } from 'svelte'
|
|
10
11
|
import Search from './Filter/Search.svelte'
|
|
11
12
|
import Filter from './Filter/Filter.svelte'
|
|
@@ -79,6 +80,14 @@
|
|
|
79
80
|
</div>
|
|
80
81
|
{/if}
|
|
81
82
|
|
|
83
|
+
{#await isUserRegionSupported() then isSupported}
|
|
84
|
+
{#if !isSupported}
|
|
85
|
+
<div class="unsupported-region">
|
|
86
|
+
{t('Sorry Region Not Supported')}
|
|
87
|
+
</div>
|
|
88
|
+
{/if}
|
|
89
|
+
{/await}
|
|
90
|
+
|
|
82
91
|
{@render children()}
|
|
83
92
|
</div>
|
|
84
93
|
|
|
@@ -165,4 +174,15 @@
|
|
|
165
174
|
width: 100%;
|
|
166
175
|
margin: margin(0.5) 0 margin(1.5);
|
|
167
176
|
}
|
|
177
|
+
|
|
178
|
+
.unsupported-region {
|
|
179
|
+
position: relative;
|
|
180
|
+
padding: margin(0.5) margin(1);
|
|
181
|
+
margin: margin(0.5) 0;
|
|
182
|
+
background: theme(warning);
|
|
183
|
+
border: 1px solid black;
|
|
184
|
+
border-radius: theme(border-radius);
|
|
185
|
+
font-weight: theme(font-bold);
|
|
186
|
+
color: black;
|
|
187
|
+
}
|
|
168
188
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
|
-
import { getRegionBasedOnIp } from '$lib/api/region'
|
|
3
|
+
import { getRegionBasedOnIp, isUserRegionSupported } from '$lib/api/region'
|
|
4
4
|
import { fakeFetch } from '../../helpers'
|
|
5
5
|
import { track } from '$lib/tracking'
|
|
6
6
|
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
@@ -9,7 +9,7 @@ vi.mock('$lib/tracking', () => ({
|
|
|
9
9
|
track: vi.fn(),
|
|
10
10
|
}))
|
|
11
11
|
|
|
12
|
-
describe('
|
|
12
|
+
describe('region.ts', () => {
|
|
13
13
|
beforeEach(() => {
|
|
14
14
|
vi.resetAllMocks()
|
|
15
15
|
fakeFetch()
|
|
@@ -18,79 +18,109 @@ describe('getRegionBasedOnIp', () => {
|
|
|
18
18
|
window.PlayPilotLinkInjections = {}
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
describe('getRegionBasedOnIp', () => {
|
|
22
|
+
it('Should return saved region if present', async () => {
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
window.PlayPilotLinkInjections = {
|
|
25
|
+
region: 'se',
|
|
26
|
+
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
expect(await getRegionBasedOnIp()).toBe('se')
|
|
29
|
+
expect(global.fetch).not.toHaveBeenCalled()
|
|
30
|
+
})
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
it('Should fetch region and return country code as lowercase', async () => {
|
|
33
|
+
fakeFetch({ response: { ip: '127.0.0.1', country: 'SE' }})
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
window.PlayPilotLinkInjections = {}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
const result = await getRegionBasedOnIp()
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
expect(global.fetch).toHaveBeenCalledWith('https://api.country.is/', expect.any(Object))
|
|
41
|
+
expect(result).toBe('se')
|
|
42
|
+
expect(window.PlayPilotLinkInjections.region).toBe('se')
|
|
43
|
+
})
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
it('Should return empty string if API returns no country, saved region was empty, and no fallback region is given', async () => {
|
|
46
|
+
fakeFetch({ response: { ip: '127.0.0.1' }})
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
window.PlayPilotLinkInjections = {}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
expect(await getRegionBasedOnIp()).toBe('')
|
|
52
|
+
})
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
it('Should return fallback region if fetch throws', async () => {
|
|
55
|
+
fakeFetch({ ok: false })
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
window.PlayPilotLinkInjections = {
|
|
59
|
+
config: { fallback_region: 'dk' },
|
|
60
|
+
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
expect(await getRegionBasedOnIp()).toBe('dk')
|
|
63
|
+
expect(global.fetch).toHaveBeenCalled()
|
|
64
|
+
expect(track).toHaveBeenCalledWith(TrackingEvent.RegionRequestFailed, null, { message: expect.any(String) })
|
|
65
|
+
})
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
it('Should not throw if PlayPilotLinkInjections is missing when saving region', async () => {
|
|
68
|
+
fakeFetch({ response: { ip: '127.0.0.1', country: 'NO' } })
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
expect(await getRegionBasedOnIp()).toBe('no')
|
|
71
|
+
})
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
it('Should use the fallback region if api request takes longer than the given timeout', async () => {
|
|
74
|
+
vi.useFakeTimers()
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
window.PlayPilotLinkInjections = {
|
|
78
|
+
config: { fallback_region: 'dk' },
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fakeFetch({ response: { ip: '127.0.0.1', country: 'NO' }, responseTime: 1000 })
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
const result = await getRegionBasedOnIp()
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
vi.advanceTimersByTime(2000)
|
|
83
86
|
|
|
84
|
-
|
|
87
|
+
expect(result).toBe('dk')
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
vi.useRealTimers()
|
|
90
|
+
})
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
it('Should use uk region when GB is returned by api endpoint', async () => {
|
|
93
|
+
fakeFetch({ response: { ip: '127.0.0.1', country: 'GB' } })
|
|
94
|
+
|
|
95
|
+
expect(await getRegionBasedOnIp()).toBe('uk')
|
|
96
|
+
})
|
|
89
97
|
})
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
describe('isUserRegionSupported', () => {
|
|
100
|
+
it('Should return false if region is not supported', async () => {
|
|
101
|
+
// @ts-ignore
|
|
102
|
+
window.PlayPilotLinkInjections.region = 'not'
|
|
103
|
+
|
|
104
|
+
expect(await isUserRegionSupported()).toBe(false)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('Should return true if region is supported', async () => {
|
|
108
|
+
// @ts-ignore
|
|
109
|
+
window.PlayPilotLinkInjections.region = 'se'
|
|
110
|
+
|
|
111
|
+
expect(await isUserRegionSupported()).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('Should return true if no region was returned', async () => {
|
|
115
|
+
fakeFetch({ response: { ip: '127.0.0.1', country: '' } })
|
|
116
|
+
|
|
117
|
+
expect(await isUserRegionSupported()).toBe(true)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('Should return true if region request failed', async () => {
|
|
121
|
+
fakeFetch({ ok: false })
|
|
93
122
|
|
|
94
|
-
|
|
123
|
+
expect(await isUserRegionSupported()).toBe(true)
|
|
124
|
+
})
|
|
95
125
|
})
|
|
96
126
|
})
|
|
@@ -5,6 +5,7 @@ import { fetchSimilarTitles, fetchTitleBySid, fetchTitles } from '$lib/api/title
|
|
|
5
5
|
import { title } from '$lib/fakeData'
|
|
6
6
|
import { getApiToken } from '$lib/token'
|
|
7
7
|
import { fakeFetch } from '../../helpers'
|
|
8
|
+
import { getRegionBasedOnIp, isUserRegionSupported } from '$lib/api/region'
|
|
8
9
|
|
|
9
10
|
vi.mock('$lib/token', () => ({
|
|
10
11
|
getApiToken: vi.fn(),
|
|
@@ -14,11 +15,20 @@ vi.mock('$lib/api/api', () => ({
|
|
|
14
15
|
api: vi.fn(),
|
|
15
16
|
}))
|
|
16
17
|
|
|
18
|
+
vi.mock('$lib/api/region', () => ({
|
|
19
|
+
getRegionBasedOnIp: vi.fn(),
|
|
20
|
+
isUserRegionSupported: vi.fn(),
|
|
21
|
+
}))
|
|
22
|
+
|
|
17
23
|
describe('$lib/api/titles', () => {
|
|
18
24
|
beforeEach(() => {
|
|
19
25
|
vi.resetAllMocks()
|
|
20
26
|
vi.mocked(getApiToken).mockReturnValue('some-token')
|
|
27
|
+
vi.mocked(isUserRegionSupported).mockResolvedValue(true)
|
|
28
|
+
|
|
21
29
|
fakeFetch()
|
|
30
|
+
|
|
31
|
+
window.PlayPilotLinkInjections.region = ''
|
|
22
32
|
})
|
|
23
33
|
|
|
24
34
|
describe('fetchTitles', () => {
|
|
@@ -38,7 +48,7 @@ describe('$lib/api/titles', () => {
|
|
|
38
48
|
})
|
|
39
49
|
|
|
40
50
|
it('Should include region if set', async () => {
|
|
41
|
-
|
|
51
|
+
vi.mocked(getRegionBasedOnIp).mockResolvedValue('nl')
|
|
42
52
|
|
|
43
53
|
await fetchTitles()
|
|
44
54
|
|
|
@@ -56,6 +66,22 @@ describe('$lib/api/titles', () => {
|
|
|
56
66
|
|
|
57
67
|
expect(api).toHaveBeenCalledWith('/titles/browse?api-token=some-token®ion=be&language=en-US&include_count=false')
|
|
58
68
|
})
|
|
69
|
+
|
|
70
|
+
it('Should not fetch and return empty results if region is not supported', async () => {
|
|
71
|
+
vi.mocked(isUserRegionSupported).mockResolvedValue(false)
|
|
72
|
+
|
|
73
|
+
await fetchTitles()
|
|
74
|
+
|
|
75
|
+
expect(api).not.toHaveBeenCalled()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('Should fetch if region is unsupported but region was given as null', async () => {
|
|
79
|
+
vi.mocked(isUserRegionSupported).mockResolvedValue(false)
|
|
80
|
+
|
|
81
|
+
await fetchTitles({ region: null })
|
|
82
|
+
|
|
83
|
+
expect(api).toHaveBeenCalled()
|
|
84
|
+
})
|
|
59
85
|
})
|
|
60
86
|
|
|
61
87
|
describe('fetchSimilarTitles', () => {
|
|
@@ -65,4 +65,26 @@ describe('ExploreLayout.svelte', () => {
|
|
|
65
65
|
|
|
66
66
|
expect(fetchAds).not.toHaveBeenCalled()
|
|
67
67
|
})
|
|
68
|
+
|
|
69
|
+
it('Should show message for unsupported regions', async () => {
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
window.PlayPilotLinkInjections.region = 'not'
|
|
72
|
+
|
|
73
|
+
const { getByText } = render(ExploreLayout, { children })
|
|
74
|
+
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(getByText('Sorry, your region is not supported')).toBeTruthy()
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('Should not show message for supported regions', async () => {
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
window.PlayPilotLinkInjections.region = 'se'
|
|
83
|
+
|
|
84
|
+
const { queryByText } = render(ExploreLayout, { children })
|
|
85
|
+
|
|
86
|
+
await new Promise(res => setTimeout(res, 10))
|
|
87
|
+
|
|
88
|
+
expect(queryByText('Sorry, your region is not supported')).not.toBeTruthy()
|
|
89
|
+
})
|
|
68
90
|
})
|