this repo has no description
1import type {
2 ArticlePage,
3 ChartsHubPage,
4 GenericPage,
5 SearchLandingPage,
6 SearchResultsPage,
7 ShelfBasedProductPage,
8 TopChartsPage,
9 TodayPage,
10 SeeAllPage,
11} from '@jet-app/app-store/api/models';
12import { StaticMessagePage } from '~/jet/models/static-message-page';
13import { isObject } from '~/utils/types';
14import { ErrorPage } from './error-page';
15import type { WebRenderablePage } from 'node_modules/@jet-app/app-store/src/api/models/web-renderable-page';
16
17/**
18 * The union of every type of page that the App Store Onyx app can render
19 */
20export type Page = (
21 | ArticlePage
22 | ChartsHubPage
23 | GenericPage
24 | SearchLandingPage
25 | SearchResultsPage
26 | ShelfBasedProductPage
27 | StaticMessagePage
28 | TopChartsPage
29 | TodayPage
30 | ErrorPage
31) &
32 // TS needs to be told this explicitly, even though all the above implement this
33 WebRenderablePage;
34
35/**
36 * Detects if {@linkcode page} is actually an {@linkcode AppEventDetailPage}
37 */
38export function isAppEventDetailPage(page: Page): page is GenericPage {
39 return (
40 'shelves' in page &&
41 page.shelves.some(({ contentType }) => contentType === 'appEventDetail')
42 );
43}
44
45/**
46 * Detects if {@linkcode page} is actually an {@linkcode ArticlePage}
47 */
48export function isArticlePage(page: Page): page is ArticlePage {
49 return 'card' in page && 'shelves' in page;
50}
51
52/**
53 * Detects if {@linkcode page} is actually a {@linkcode ChartsHubPage}
54 */
55export function isChartsHubPage(page: Page): page is ChartsHubPage {
56 return 'charts' in page;
57}
58
59/**
60 * Detects if {@linkcode page} is actually a {@linkcode GenericPage}
61 */
62export function isGenericPage(page: Page): page is GenericPage {
63 return 'shelves' in page;
64}
65
66/**
67 * Detects if {@linkcode page} is actually a {@linkcode ShelfBasedProductPage}
68 */
69export function isShelfBasedProductPage(
70 page: Page,
71): page is ShelfBasedProductPage {
72 return 'shelfMapping' in page && !('seeAllType' in page);
73}
74
75/**
76 * Detects if {@linkcode page} is actually a {@linkcode SeeAllPage}
77 */
78export function isSeeAllPage(page: Page): page is SeeAllPage {
79 return 'seeAllType' in page;
80}
81
82/**
83 * Detects if {@linkcode page} is actually a {@linkcode SearchLandingPage}
84 */
85export function isSearchLandingPage(page: Page): page is SearchLandingPage {
86 return 'adIncidents' in page;
87}
88
89/**
90 * Detects if {@linkcode page} is actually a {@linkcode SearchResultsPage}
91 */
92export function isSearchResultsPage(page: Page): page is SearchResultsPage {
93 return 'searchClearAction' in page || 'searchCancelAction' in page;
94}
95
96/**
97 * Detects if {@linkcode page} is actually a {@linkcode TopChartsPage}
98 */
99export function isTopChartsPage(page: Page): page is TopChartsPage {
100 return 'segments' in page && 'categories' in page;
101}
102
103/**
104 * Detects if {@linkcode page} is actually a {@linkcode TodayPage}
105 */
106export function isTodayPage(page: Page): page is TodayPage {
107 return 'titleDetail' in page;
108}
109
110/**
111 * Detects if {@linkcode page} is actually a {@linkcode StaticMessagePage}
112 */
113export function isStaticMessagePage(
114 page: GenericPage,
115): page is StaticMessagePage {
116 return 'pageType' in page && page.pageType === 'staticMessagePage';
117}
118
119export function isErrorPage(page: GenericPage) {
120 return 'pageType' in page && page.pageType === 'errorPage';
121}
122
123/**
124 * Type-guard that determines if the provided {@linkcode page} matches a renderable {@linkcode Page} definition
125 */
126export function isPage(page: unknown): page is Page {
127 if (!isObject(page)) {
128 return false;
129 }
130
131 return [
132 isAppEventDetailPage,
133 isArticlePage,
134 isChartsHubPage,
135 isGenericPage,
136 isShelfBasedProductPage,
137 isSearchLandingPage,
138 isSearchResultsPage,
139 isTopChartsPage,
140 isTodayPage,
141 isErrorPage,
142 isSeeAllPage,
143 ].some((specificPageTypePredicate) =>
144 specificPageTypePredicate(
145 // This type-cast reflects the fact that we don't really know if `page` is really a `Page`,
146 // but that we're going to use the type-guards of our `Page` members to see if `page` looks
147 // like one of them
148 page as Page,
149 ),
150 );
151}
152
153/**
154 * Type-assertion that determines if the provided {@linkcode page} matches a renderable {@linkcode Page} definition
155 */
156export function assertIsPage(page: unknown): asserts page is Page {
157 if (!isPage(page)) {
158 throw new Error(
159 'The view-model for the dispatched `Intent` does not match a known renderable shape',
160 );
161 }
162}
163
164/**
165 * Detects if {@linkcode page} has the Vision Pro pathname in it's URL.
166 */
167export function hasVisionProUrl(page: GenericPage) {
168 if (!page.canonicalURL) {
169 return false;
170 }
171
172 const url = new URL(page.canonicalURL);
173 return (
174 url.pathname.includes('/vision/apps-and-games') ||
175 url.pathname.includes('/vision/arcade')
176 );
177}