seo.ts
1 import type { Opt } from '@jet/environment/types/optional'; 2 import type { 3 ArcadeSeeAllGamesPage, 4 ArticlePage, 5 ChartsHubPage, 6 GenericPage, 7 ReviewsPage, 8 SearchLandingPage, 9 SearchResultsPage, 10 SeeAllPage, 11 ShelfBasedProductPage, 12 TodayPage, 13 TopChartsPage, 14 } from '@jet-app/app-store/api/models'; 15 import type { WebRenderablePage } from '@jet-app/app-store/api/models/web-renderable-page'; 16 import type { SEO as SEODependency } from '@jet-app/app-store/foundation/dependencies/seo'; 17 import type { AppStoreObjectGraph } from '@jet-app/app-store/foundation/runtime/app-store-object-graph'; 18 import type { DataContainer } from '@jet-app/app-store/foundation/media/data-structure'; 19 20 import type { SeoData } from '@amp/web-app-components/src/components/MetaTags/types'; 21 22 import type { Locale } from './locale'; 23 24 import { seoDataForAnyPage, updateCanonicalURL } from '~/utils/seo/common'; 25 import { seoDataForArticlePage } from '~/utils/seo/article-page'; 26 import { seoDataForChartsPage } from '~/utils/seo/charts-page'; 27 import { seoDataForChartsHubPage } from '~/utils/seo/charts-hub-page'; 28 import { seoDataForDeveloperPage } from '~/utils/seo/developer-page'; 29 import { seoDataForProductPage } from '~/utils/seo/product-page'; 30 import { seoDataForAppEventDetailPage } from '~/utils/seo/app-event-detail-page'; 31 import { seoDataForReviewsPage } from '~/utils/seo/reviews-page'; 32 import { seoDataForSearchLandingPage } from '~/utils/seo/search-landing-page'; 33 import { seoDataForSearchResultsPage } from '~/utils/seo/search-results-page'; 34 import { seoDataForEditorialShelfCollectionPage } from '~/utils/seo/editorial-shelf-collection-page'; 35 import { seoDataForArcadeSeeAllPage } from '~/utils/seo/arcade-see-all-page'; 36 import { seoDataForSeeAllPage } from '~/utils/seo/see-all-page'; 37 38 export class SEO implements SEODependency { 39 private locale: Locale; 40 41 constructor(locale: Locale) { 42 this.locale = locale; 43 } 44 45 private get i18n() { 46 if (this.locale.i18n) { 47 return this.locale.i18n; 48 } 49 50 throw new Error('`i18n` not yet configured '); 51 } 52 53 private getSEODataForGenericPage(page: GenericPage): Opt<SeoData> { 54 return { 55 ...seoDataForAnyPage(page, this.i18n), 56 }; 57 } 58 59 updateCanonicalURL(page: WebRenderablePage, canonicalURL: string): void { 60 updateCanonicalURL(page, canonicalURL); 61 } 62 63 /// MARK: Page SEO Data Hooks 64 65 getSEODataForAppEventPage( 66 objectGraph: AppStoreObjectGraph, 67 page: GenericPage, 68 ): Opt<SeoData> { 69 return { 70 ...seoDataForAnyPage(page, this.i18n), 71 ...seoDataForAppEventDetailPage( 72 page, 73 this.i18n, 74 objectGraph.locale.activeLanguage, 75 ), 76 }; 77 } 78 79 getSEODataForArcadeSeeAllPage( 80 _objectGraph: AppStoreObjectGraph, 81 page: ArcadeSeeAllGamesPage, 82 ): Opt<SeoData> { 83 return { 84 ...seoDataForAnyPage(page, this.i18n), 85 ...seoDataForArcadeSeeAllPage(page, this.i18n), 86 }; 87 } 88 89 getSEODataForArticlePage( 90 objectGraph: AppStoreObjectGraph, 91 page: ArticlePage, 92 response: Opt<DataContainer>, 93 ): Opt<SeoData> { 94 return { 95 ...seoDataForAnyPage(page, this.i18n), 96 ...seoDataForArticlePage( 97 objectGraph, 98 this.i18n, 99 page, 100 response, 101 objectGraph.locale.activeLanguage, 102 ), 103 }; 104 } 105 106 getSEODataForBundlePage( 107 objectGraph: AppStoreObjectGraph, 108 page: ShelfBasedProductPage, 109 data: Opt<DataContainer>, 110 ): Opt<SeoData> { 111 return this.getSEODataForProductPage(objectGraph, page, data); 112 } 113 114 getSEODataForChartsPage( 115 objectGraph: AppStoreObjectGraph, 116 page: TopChartsPage, 117 ): Opt<SeoData> { 118 return { 119 ...seoDataForAnyPage(page, this.i18n), 120 ...seoDataForChartsPage( 121 page, 122 this.i18n, 123 objectGraph.locale.activeLanguage, 124 ), 125 }; 126 } 127 128 getSEODataForChartsHubPage( 129 objectGraph: AppStoreObjectGraph, 130 page: ChartsHubPage, 131 ): Opt<SeoData> { 132 return { 133 ...seoDataForAnyPage(page, this.i18n), 134 ...seoDataForChartsHubPage( 135 page, 136 this.i18n, 137 objectGraph.locale.activeLanguage, 138 ), 139 }; 140 } 141 142 getSEODataForDeveloperPage( 143 objectGraph: AppStoreObjectGraph, 144 page: GenericPage, 145 response: Opt<DataContainer>, 146 ): Opt<SeoData> { 147 return { 148 ...seoDataForAnyPage(page, this.i18n), 149 ...seoDataForDeveloperPage(objectGraph, response, this.i18n), 150 }; 151 } 152 153 getSEODataForEditorialPage( 154 _objectGraph: AppStoreObjectGraph, 155 page: GenericPage, 156 ): Opt<SeoData> { 157 return this.getSEODataForGenericPage(page); 158 } 159 160 getSEODataForEditorialShelfCollectionPage( 161 _objectGraph: AppStoreObjectGraph, 162 page: GenericPage, 163 ): Opt<SeoData> { 164 return { 165 ...seoDataForAnyPage(page, this.i18n), 166 ...seoDataForEditorialShelfCollectionPage(page, this.i18n), 167 }; 168 } 169 170 getSEODataForGroupingPage( 171 _objectGraph: AppStoreObjectGraph, 172 page: GenericPage, 173 ): Opt<SeoData> { 174 return this.getSEODataForGenericPage(page); 175 } 176 177 getSEODataForProductPage( 178 objectGraph: AppStoreObjectGraph, 179 page: ShelfBasedProductPage, 180 data: Opt<DataContainer>, 181 ): Opt<SeoData> { 182 return { 183 ...seoDataForAnyPage(page, this.i18n), 184 ...seoDataForProductPage( 185 objectGraph, 186 page, 187 data, 188 this.i18n, 189 objectGraph.locale.activeLanguage, 190 ), 191 }; 192 } 193 194 getSEODataForReviewsPage( 195 objectGraph: AppStoreObjectGraph, 196 page: ReviewsPage, 197 productPage: ShelfBasedProductPage, 198 ): Opt<SeoData> { 199 return { 200 ...this.getSEODataForGenericPage(page), 201 ...seoDataForReviewsPage(this.i18n, page, productPage, objectGraph), 202 }; 203 } 204 205 getSEODataForRoomPage( 206 _objectGraph: AppStoreObjectGraph, 207 page: GenericPage, 208 ): Opt<SeoData> { 209 return { 210 ...seoDataForAnyPage(page, this.i18n), 211 }; 212 } 213 214 getSEODataForSearchLandingPage( 215 _objectGraph: AppStoreObjectGraph, 216 page: SearchLandingPage, 217 ): Opt<SeoData> { 218 return { 219 ...seoDataForAnyPage(page, this.i18n), 220 ...seoDataForSearchLandingPage(page, this.i18n), 221 }; 222 } 223 224 getSEODataForSearchResultsPage( 225 objectGraph: AppStoreObjectGraph, 226 page: SearchResultsPage, 227 ): Opt<SeoData> { 228 return { 229 ...seoDataForAnyPage(page, this.i18n), 230 ...seoDataForSearchResultsPage( 231 page, 232 this.i18n, 233 objectGraph.locale.activeLanguage, 234 ), 235 }; 236 } 237 238 getSEODataForTodayPage( 239 _objectGraph: AppStoreObjectGraph, 240 page: TodayPage, 241 ): Opt<SeoData> { 242 return seoDataForAnyPage(page, this.i18n); 243 } 244 245 getSEODataForSeeAllPage( 246 _objectGraph: AppStoreObjectGraph, 247 page: SeeAllPage, 248 ): Opt<SeoData> { 249 return { 250 ...seoDataForAnyPage(page, this.i18n), 251 ...seoDataForSeeAllPage(page, this.i18n), 252 }; 253 } 254 }