Skip to content

Commit 335cd0e

Browse files
[FIX]: top nav highlight does not switch when using the back arrow (#460)
* feat(webview-controls): return to home page if not previous navigation in page * chore(webview-controls): add comments * chore(types): use electron's webview tag * Revert "feat(webview-controls): return to home page if not previous navigation in page" This reverts commit 4b2a265. * refactor(webview): store webview url in a new store * refactor(top-navbar): apply current active tab styles based on the current url in webview navigation store * refactor(extract-domain): return null if invalid url * refactor(types): remove WebviewType * refactor(extract-domain): use console.warn on error * refactor(web-navigation-store): use getters and set method * refactor(top-navbar): return inactive styles if not current url * fix(web-navigation-store): make observable on instantiation not on init * refactor: remove unused import * refactor(constants): add GOG_EMBED_URL * fix(top-navbar): remove trailing / * refactor(webview): use old gog regex * point proxy to main * proxy prettier --------- Co-authored-by: BrettCleary <27568879+BrettCleary@users.noreply.github.com>
1 parent 827c548 commit 335cd0e

File tree

11 files changed

+170
-53
lines changed

11 files changed

+170
-53
lines changed

jest.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = {
1616
'<rootDir>/coverage'
1717
],
1818
coverageReporters: ['text', 'html'],
19-
projects: ['<rootDir>/src/backend'],
19+
projects: ['<rootDir>/src/backend', '<rootDir>/src/frontend'],
2020

2121
rootDir: '.'
2222
}

src/common/types.ts

+5-15
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export interface GameStatus {
244244
}
245245

246246
export type GlobalConfigVersion = 'auto' | 'v0'
247+
247248
export interface InstallProgress {
248249
bytes: string
249250
eta?: string
@@ -253,6 +254,7 @@ export interface InstallProgress {
253254
diskSpeed?: number
254255
file?: string
255256
}
257+
256258
export interface InstalledInfo {
257259
executable: string
258260
install_path: string
@@ -281,6 +283,7 @@ export type UserInfo = {
281283
displayName: string
282284
user: string
283285
}
286+
284287
export interface WineInstallation {
285288
bin: string
286289
name: string
@@ -565,21 +568,6 @@ interface GamepadActionArgsWithoutMetadata {
565568
metadata?: undefined
566569
}
567570

568-
type ElWebview = {
569-
canGoBack: () => boolean
570-
canGoForward: () => boolean
571-
goBack: () => void
572-
goForward: () => void
573-
reload: () => void
574-
isLoading: () => boolean
575-
getURL: () => string
576-
copy: () => string
577-
selectAll: () => void
578-
findInPage: (text: string | RegExp) => void
579-
}
580-
581-
export type WebviewType = HTMLWebViewElement & ElWebview
582-
583571
export type InstallPlatform =
584572
| LegendaryInstallPlatform
585573
| GogInstallPlatform
@@ -601,6 +589,7 @@ export interface Tools {
601589
}
602590

603591
export type DMStatus = 'done' | 'error' | 'abort' | 'paused'
592+
604593
export interface DMQueueElement {
605594
type: 'update' | 'install'
606595
params: InstallParams
@@ -678,6 +667,7 @@ export interface GameScoreInfo {
678667
score: string
679668
urlid: string
680669
}
670+
681671
export interface PCGamingWikiInfo {
682672
steamID: string
683673
howLongToBeatID: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { extractMainDomain } from 'frontend/helpers/extract-main-domain'
2+
3+
describe('extractMainDomain', () => {
4+
it('should correctly extract main domain without subdomain', () => {
5+
const url = 'https://epicgames.com/store'
6+
const mainDomain = extractMainDomain(url)
7+
expect(mainDomain).toEqual('epicgames.com')
8+
})
9+
10+
it('should correctly extract main domain with www subdomain', () => {
11+
const url = 'https://www.epicgames.com/store'
12+
const mainDomain = extractMainDomain(url)
13+
expect(mainDomain).toEqual('epicgames.com')
14+
})
15+
16+
it('should correctly extract main domain with multiple subdomains', () => {
17+
const url = 'https://sub.sub.epicgames.com/store'
18+
const mainDomain = extractMainDomain(url)
19+
expect(mainDomain).toEqual('epicgames.com')
20+
})
21+
22+
it('should return the full domain when no subdomains present', () => {
23+
const url = 'https://example.com'
24+
const mainDomain = extractMainDomain(url)
25+
expect(mainDomain).toEqual('example.com')
26+
})
27+
28+
it('return null when url is invalid', () => {
29+
jest.spyOn(console, 'warn').mockImplementationOnce(jest.fn)
30+
const url = 'invalid url'
31+
const mainDomain = extractMainDomain(url)
32+
expect(mainDomain).toEqual(null)
33+
})
34+
})

src/frontend/components/UI/TopNavBar/index.tsx

+23-17
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,34 @@ import { observable } from 'mobx'
1010
import { useTranslation } from 'react-i18next'
1111
import ContextProvider from 'frontend/state/ContextProvider'
1212
import { NavLink, useLocation } from 'react-router-dom'
13+
import {
14+
EPIC_STORE_URL,
15+
GOG_STORE_URL,
16+
HYPERPLAY_STORE_URL
17+
} from 'frontend/constants'
18+
import webviewNavigationStore from 'frontend/store/WebviewNavigationStore'
19+
import { extractMainDomain } from '../../../helpers/extract-main-domain'
1320

1421
const TopNavBar = observer(() => {
1522
const { t } = useTranslation()
1623

1724
const { showMetaMaskBrowserSidebarLinks } = useContext(ContextProvider)
1825
const [badgeText, setBadgeText] = useState('0')
19-
const { pathname, search } = useLocation()
26+
const { pathname } = useLocation()
2027
const pagesToShowStoreNavOptions = [
2128
'/hyperplaystore',
2229
'/gogstore',
2330
'/epicstore',
24-
'/store-page/'
31+
'/store-page'
2532
]
26-
const searchParams = new URLSearchParams(search)
27-
const queryParam = searchParams.get('store-url')
28-
let isEpicStore = false
29-
if (queryParam !== null) {
30-
const storeUrl = new URL(queryParam)
31-
isEpicStore = storeUrl.host === 'store.epicgames.com'
32-
}
3333

3434
const showStoreNavOptions = pagesToShowStoreNavOptions.includes(pathname)
3535

3636
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
3737
function setBadgeString(err: any, text: string) {
3838
setBadgeText(text)
3939
}
40+
4041
useEffect(() => {
4142
const removeHandleSetBadgeText =
4243
window.api.handleSetBadgeTextInRenderer(setBadgeString)
@@ -45,14 +46,19 @@ const TopNavBar = observer(() => {
4546
removeHandleSetBadgeText()
4647
}
4748
}, [])
48-
function getStoreTextStyle(storePath: string, isActive?: boolean) {
49+
50+
function getStoreTextStyle(viewURL: string) {
51+
const { currentUrl } = webviewNavigationStore
4952
const inactiveStyle = { color: 'var(--color-neutral-400)' }
5053
const activeStyle = { color: '' }
51-
if (isActive !== undefined && isActive) {
52-
return activeStyle
53-
}
54-
return pathname === storePath ? activeStyle : inactiveStyle
54+
// initial value of currentUrl is ''
55+
if (!currentUrl) return inactiveStyle
56+
const viewURLMainDomain = extractMainDomain(viewURL)
57+
const currentURLMainDomain = extractMainDomain(currentUrl)
58+
const isActive = viewURLMainDomain === currentURLMainDomain
59+
return isActive ? activeStyle : inactiveStyle
5560
}
61+
5662
return (
5763
<div className={styles.navBar}>
5864
<div>
@@ -73,7 +79,7 @@ const TopNavBar = observer(() => {
7379
<Button
7480
type="link"
7581
size="small"
76-
style={getStoreTextStyle('/hyperplaystore')}
82+
style={getStoreTextStyle(HYPERPLAY_STORE_URL)}
7783
>
7884
HyperPlay
7985
</Button>
@@ -82,7 +88,7 @@ const TopNavBar = observer(() => {
8288
<Button
8389
type="link"
8490
size="small"
85-
style={getStoreTextStyle('/epicstore', isEpicStore)}
91+
style={getStoreTextStyle(EPIC_STORE_URL)}
8692
>
8793
{t('Epic Games', 'Epic Games')}
8894
</Button>
@@ -91,7 +97,7 @@ const TopNavBar = observer(() => {
9197
<Button
9298
type="link"
9399
size="small"
94-
style={getStoreTextStyle('/gogstore')}
100+
style={getStoreTextStyle(GOG_STORE_URL)}
95101
>
96102
{t('GOG', 'GOG')}
97103
</Button>

src/frontend/components/UI/WebviewControls/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import {
55
Replay
66
} from '@mui/icons-material'
77
import cx from 'classnames'
8+
import { WebviewTag } from 'electron'
89
import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react'
910
import { useTranslation } from 'react-i18next'
10-
import { WebviewType } from 'common/types'
1111
import SvgButton from '../SvgButton'
1212
import './index.css'
1313

1414
interface WebviewControlsProps {
15-
webview: WebviewType | null
15+
webview: WebviewTag | null
1616
initURL: string
1717
openInBrowser: boolean
1818
}

src/frontend/constants.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const EPIC_LOGIN_URL = 'https://legendary.gl/epiclogin'
2+
export const HYPERPLAY_STORE_URL = 'https://store.hyperplay.xyz?isLauncher=true'
3+
export const EPIC_STORE_URL = 'https://www.epicgames.com/store'
4+
export const GOG_STORE_URL = `https://gog.com`
5+
export const WIKI_URL = 'https://docs.hyperplaygaming.com/'
6+
export const GOG_LOGIN_URL =
7+
'https://auth.gog.com/auth?client_id=46899977096215655&redirect_uri=https%3A%2F%2Fembed.gog.com%2Fon_login_success%3Forigin%3Dclient&response_type=code&layout=galaxy'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export function extractMainDomain(url: string) {
2+
try {
3+
const domain = new URL(url).hostname
4+
const parts = domain.split('.')
5+
6+
if (parts.length >= 2) {
7+
return parts.slice(-2).join('.')
8+
}
9+
10+
return domain
11+
} catch (e) {
12+
console.warn(e)
13+
return null
14+
}
15+
}

src/frontend/jest.config.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// eslint-disable-next-line @typescript-eslint/no-var-requires
2+
const { compilerOptions } = require('../../tsconfig')
3+
4+
module.exports = {
5+
displayName: 'Frontend',
6+
7+
moduleDirectories: ['node_modules', '<rootDir>'],
8+
// Module file extensions for importing
9+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
10+
testPathIgnorePatterns: ['./node_modules/'],
11+
resetMocks: true,
12+
13+
rootDir: '../..',
14+
15+
// The root of your source code, typically /src
16+
// `<rootDir>` is a token Jest substitutes
17+
roots: ['<rootDir>/src/frontend'],
18+
19+
testMatch: ['**/__tests__/**/*.test.{ts,tsx}'],
20+
// Jest transformations -- this adds support for TypeScript
21+
// using ts-jest
22+
transform: {
23+
'^.+\\.tsx?$': 'ts-jest'
24+
},
25+
26+
modulePaths: [compilerOptions.baseUrl]
27+
}

src/frontend/screens/WebView/index.tsx

+34-17
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@ import React, {
77
} from 'react'
88
import { useTranslation } from 'react-i18next'
99
import { useNavigate, useLocation, useParams } from 'react-router'
10+
import { DidNavigateEvent, WebviewTag } from 'electron'
1011

1112
import { UpdateComponent } from 'frontend/components/UI'
1213
import WebviewControls from 'frontend/components/UI/WebviewControls'
1314
import ContextProvider from 'frontend/state/ContextProvider'
14-
import { Runner, WebviewType } from 'common/types'
15+
import webviewNavigationStore from 'frontend/store/WebviewNavigationStore'
16+
import { Runner } from 'common/types'
1517
import './index.css'
1618
import LoginWarning from '../Login/components/LoginWarning'
1719
import authStore from 'frontend/store/AuthStore'
1820
import { observer } from 'mobx-react-lite'
21+
import {
22+
EPIC_LOGIN_URL,
23+
EPIC_STORE_URL,
24+
GOG_LOGIN_URL,
25+
GOG_STORE_URL,
26+
HYPERPLAY_STORE_URL,
27+
WIKI_URL
28+
} from '../../constants'
1929

2030
function urlIsHpUrl(url: string) {
2131
const urlToTest = new URL(url)
@@ -35,39 +45,34 @@ function WebView() {
3545
message: t('loading.website', 'Loading Website')
3646
}))
3747
const navigate = useNavigate()
38-
const webviewRef = useRef<WebviewType>(null)
48+
const webviewRef = useRef<WebviewTag>(null)
3949

4050
let lang = i18n.language
4151
if (i18n.language === 'pt') {
4252
lang = 'pt-BR'
4353
}
4454

45-
const epicLoginUrl = 'https://legendary.gl/epiclogin'
46-
4755
const hyperplayStore =
48-
'https://store.hyperplay.xyz?isLauncher=true' +
56+
HYPERPLAY_STORE_URL +
4957
(authStore.authToken !== '' ? '&qamode=' + authStore.authToken : '')
5058

51-
const epicStore = `https://www.epicgames.com/store/${lang}/`
52-
const gogStore = `https://gog.com`
53-
const wikiURL = 'https://docs.hyperplaygaming.com/'
59+
const epicStore = `${EPIC_STORE_URL}/${lang}/`
5460
const gogEmbedRegExp = new RegExp('https://embed.gog.com/on_login_success?')
55-
const gogLoginUrl =
56-
'https://auth.gog.com/auth?client_id=46899977096215655&redirect_uri=https%3A%2F%2Fembed.gog.com%2Fon_login_success%3Forigin%3Dclient&response_type=code&layout=galaxy'
5761

5862
const trueAsStr = 'true' as unknown as boolean | undefined
5963
const { runner } = useParams() as { runner: Runner }
6064

6165
const urls = {
6266
'/hyperplaystore': hyperplayStore,
6367
'/epicstore': epicStore,
64-
'/gogstore': gogStore,
65-
'/wiki': wikiURL,
66-
'/loginEpic': epicLoginUrl,
67-
'/loginGOG': gogLoginUrl,
68-
'/loginweb/legendary': epicLoginUrl,
69-
'/loginweb/gog': gogLoginUrl
68+
'/gogstore': GOG_STORE_URL,
69+
'/wiki': WIKI_URL,
70+
'/loginEpic': EPIC_LOGIN_URL,
71+
'/loginGOG': GOG_LOGIN_URL,
72+
'/loginweb/legendary': EPIC_LOGIN_URL,
73+
'/loginweb/gog': GOG_LOGIN_URL
7074
}
75+
7176
let startUrl = Object.prototype.hasOwnProperty.call(urls, pathname)
7277
? urls[pathname]
7378
: ''
@@ -82,7 +87,7 @@ function WebView() {
8287
}
8388
}
8489

85-
const isEpicLogin = runner === 'legendary' && startUrl === epicLoginUrl
90+
const isEpicLogin = runner === 'legendary' && startUrl === EPIC_LOGIN_URL
8691
const [preloadPath, setPreloadPath] = useState('')
8792

8893
useEffect(() => {
@@ -193,6 +198,18 @@ function WebView() {
193198
}
194199
}, [startUrl])
195200

201+
useEffect(() => {
202+
const handleNavigation = (event: DidNavigateEvent) => {
203+
webviewNavigationStore.setCurrentUrl(event.url)
204+
}
205+
206+
webviewRef.current?.addEventListener('did-navigate', handleNavigation)
207+
208+
return () => {
209+
webviewRef.current?.removeEventListener('did-navigate', handleNavigation)
210+
}
211+
}, [webviewRef])
212+
196213
const onLoginWarningClosed = () => {
197214
setShowLoginWarningFor(null)
198215
}

0 commit comments

Comments
 (0)