@playpilot/tpi 6.2.0 → 6.2.2

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": "@playpilot/tpi",
3
- "version": "6.2.0",
3
+ "version": "6.2.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -10,12 +10,14 @@ export async function getRegionBasedOnIp(timeout = 5000): Promise<string> {
10
10
 
11
11
  const data: { ip: string, country: string } = await response.json()
12
12
 
13
- const country = data?.country?.toLowerCase()
14
- if (!country) throw new Error('No country was returned by api.country.is')
13
+ let region = data?.country?.toLowerCase()
14
+ if (!region) throw new Error('No country was returned by api.country.is')
15
15
 
16
- setSavedRegion(country)
16
+ if (region === 'gb') region = 'uk'
17
17
 
18
- return country
18
+ setSavedRegion(region)
19
+
20
+ return region
19
21
  } catch (error: any) {
20
22
  track(TrackingEvent.RegionRequestFailed, null, { message: error.message })
21
23
 
@@ -1,16 +1,4 @@
1
1
  [
2
- {
3
- "slug": "100",
4
- "name": "All",
5
- "categories": {
6
- "movie": 100,
7
- "series": 100,
8
- "documentary": 100,
9
- "kids": 100,
10
- "cinema": 100,
11
- "podcasts": 100
12
- }
13
- },
14
2
  {
15
3
  "slug": "999",
16
4
  "name": "Unscripted",
@@ -0,0 +1,23 @@
1
+ <div class="empty">
2
+ <p>
3
+ <strong>No results were found</strong><br>
4
+ Sorry, we couldn't find anything matching your filter.
5
+ </p>
6
+ </div>
7
+
8
+ <style lang="scss">
9
+ p {
10
+ margin: 0;
11
+ }
12
+
13
+ strong {
14
+ font-size: theme(font-size-large);
15
+ }
16
+
17
+ .empty {
18
+ max-width: theme(explore-header-max-width, 600px);
19
+ padding: margin(2);
20
+ border-radius: theme(border-radius-large);
21
+ background: theme(lighter);
22
+ }
23
+ </style>
@@ -16,15 +16,16 @@
16
16
  import ListTitleSkeleton from '../ListTitleSkeleton.svelte'
17
17
  import Filter from './Filter/Filter.svelte'
18
18
  import Search from './Filter/Search.svelte'
19
+ import Empty from './Empty.svelte'
19
20
 
20
21
  const filter: ExploreFilter = $state({})
21
22
 
22
23
  let element: HTMLElement | null = null
23
24
  let titles: TitleData[] = $state([])
24
- let page = 1
25
- let searchQuery = ''
25
+ let page = $state(1)
26
26
  let debounce: ReturnType<typeof setTimeout> | null = null
27
27
  let latestRequestId = 0
28
+ let searchQuery = $state('')
28
29
  let promise = $state(getTitlesForFilter())
29
30
  let height: string | null = $state(null)
30
31
  let width = $state(0)
@@ -70,8 +71,6 @@
70
71
 
71
72
  const response = await fetchTitles(params)
72
73
 
73
- if (!response?.results) throw new Error('Something went wrong when fetching titles in Explore')
74
-
75
74
  if (requestId === latestRequestId) titles = [...titles, ...response.results]
76
75
 
77
76
  return response
@@ -129,7 +128,7 @@
129
128
 
130
129
  {#key grid}
131
130
  <Search oninput={search} />
132
- <Filter {filter} limit={!grid} onchange={setFilter} />
131
+ <Filter {filter} limit={!grid} onchange={setFilter} showSorting={!searchQuery} />
133
132
  {/key}
134
133
  </div>
135
134
 
@@ -155,8 +154,12 @@
155
154
  <Button size="large" onclick={fetchMoreTitles}>Show more</Button>
156
155
  </div>
157
156
  {/if}
157
+
158
+ {#if !titles?.length && page === 1}
159
+ <Empty />
160
+ {/if}
158
161
  {:catch}
159
- Something went wrong
162
+ <p>Something went wrong</p>
160
163
  {/await}
161
164
  </div>
162
165
 
@@ -165,8 +168,9 @@
165
168
  background: theme(explore-background, light);
166
169
  border-radius: theme(border-radius-large);
167
170
  max-width: theme(explore-max-width, 1200px);
171
+ min-height: 75vh;
168
172
  margin: 0 auto;
169
- padding: theme(explore-padding, margin(1) margin(1) margin(2));
173
+ padding: theme(explore-padding, margin(1) margin(1) margin(6));
170
174
  overflow: auto;
171
175
  font-family: theme(font-family);
172
176
  font-family: theme(detail-font-family, font-family);
@@ -8,15 +8,16 @@
8
8
  import Button from '../../Button.svelte'
9
9
  import IconArrow from '../../Icons/IconArrow.svelte'
10
10
  import IconFilter from '../../Icons/IconFilter.svelte'
11
- import { scale } from 'svelte/transition'
11
+ import { fly, scale } from 'svelte/transition'
12
12
 
13
13
  interface Props {
14
14
  filter: ExploreFilter
15
15
  onchange?: () => void
16
16
  limit?: boolean
17
+ showSorting?: boolean
17
18
  }
18
19
 
19
- const { filter, onchange = () => null, limit = true }: Props = $props()
20
+ const { filter, onchange = () => null, limit = true, showSorting = true }: Props = $props()
20
21
 
21
22
  const shownItemsLimit = 3
22
23
  const items = [{
@@ -67,9 +68,11 @@
67
68
  </Button>
68
69
  {/if}
69
70
 
70
- <div class="sorting">
71
- <FilterSorting {filter} {onchange} />
72
- </div>
71
+ {#if showSorting}
72
+ <div class="sorting" transition:fly={{ x: 5, duration: 100 }}>
73
+ <FilterSorting {filter} {onchange} />
74
+ </div>
75
+ {/if}
73
76
  </div>
74
77
  </div>
75
78
 
@@ -28,6 +28,6 @@
28
28
  display: block;
29
29
  width: 100%;
30
30
  height: auto;
31
- color: theme(detail-text-color, text-color-alt);
31
+ color: transparent;
32
32
  }
33
33
  </style>
@@ -87,4 +87,10 @@ describe('getRegionBasedOnIp', () => {
87
87
 
88
88
  vi.useRealTimers()
89
89
  })
90
+
91
+ it('Should use uk region when GB is returned by api endpoint', async () => {
92
+ fakeFetch({ response: { ip: '127.0.0.1', country: 'GB' } })
93
+
94
+ expect(await getRegionBasedOnIp()).toBe('uk')
95
+ })
90
96
  })
@@ -172,4 +172,40 @@ describe('Explore.svelte', () => {
172
172
 
173
173
  expect(fetchTitles).toHaveBeenCalledWith({ page: 1, page_size: 24, ordering: '-new' })
174
174
  })
175
+
176
+ it('Should show empty message if no titles are returned for first page', async () => {
177
+ vi.mocked(fetchTitles).mockResolvedValue({ results: [], next: null, previous: null })
178
+
179
+ const { getByText } = render(Explore)
180
+
181
+ await waitFor(() => {
182
+ expect(getByText('No results were found')).toBeTruthy()
183
+ })
184
+ })
185
+
186
+ it('Should not show empty message if no titles are returned for pages past the first page', async () => {
187
+ vi.mocked(fetchTitles).mockResolvedValue({ results: [title], next: 'truthy', previous: null })
188
+
189
+ const { getByText, queryByText } = render(Explore)
190
+
191
+ await waitFor(() => getByText('Show more'))
192
+
193
+ vi.mocked(fetchTitles).mockResolvedValue({ results: [], next: null, previous: null })
194
+
195
+ await fireEvent.click(getByText('Show more'))
196
+
197
+ await waitFor(() => {
198
+ expect(queryByText('No results were found')).not.toBeTruthy()
199
+ })
200
+ })
201
+
202
+ it('Should show error message if api responded with error', async () => {
203
+ vi.mocked(fetchTitles).mockRejectedValueOnce(null)
204
+
205
+ const { getByText } = render(Explore)
206
+
207
+ await waitFor(() => {
208
+ expect(getByText('Something went wrong')).toBeTruthy()
209
+ })
210
+ })
175
211
  })
@@ -55,4 +55,16 @@ describe('Filter.svelte', () => {
55
55
 
56
56
  expect(fetchProviders).toHaveBeenCalled()
57
57
  })
58
+
59
+ it('Should not show sortings when showSortings is false', () => {
60
+ const { container } = render(Filter, { filter: {}, showSorting: false })
61
+
62
+ expect(container.querySelector('.sorting')).not.toBeTruthy()
63
+ })
64
+
65
+ it('Should show sortings when showSortings is true', () => {
66
+ const { container } = render(Filter, { filter: {}, showSorting: true })
67
+
68
+ expect(container.querySelector('.sorting')).toBeTruthy()
69
+ })
58
70
  })