Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Add Portfolio to Overlay #1112

Merged
merged 19 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 56 additions & 20 deletions src/backend/storeManagers/storeManagerCommon/games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ import { access, chmod } from 'fs/promises'
import shlex from 'shlex'
import { showDialogBoxModalAuto } from '../../dialog/dialog'
import { createAbortController } from '../../utils/aborthandler/aborthandler'
import { app, BrowserWindow } from 'electron'
import {
app,
BrowserWindow,
BrowserWindowConstructorOptions,
WindowOpenHandlerResponse
} from 'electron'
import { gameManagerMap } from '../index'
const buildDir = resolve(__dirname, '../../build')
import { domainsAreEqual } from 'common/utils'
Expand All @@ -47,6 +52,24 @@ export function logFileLocation(appName: string) {
return join(gamesConfigPath, `${appName}-lastPlay.log`)
}

const openBlankWindow = (options: BrowserWindowConstructorOptions) => {
options.show = false
const browserGame = new BrowserWindow(options)

browserGame.webContents.on('will-navigate', async (...params) => {
import('@hyperplay/extension-importer').then((extensionImporter) => {
extensionImporter?.windowOpenHandlerForExtension(
params[0].url,
browserGame.webContents,
hpApi
)
browserGame.close()
})
})

return browserGame.webContents
}

const openNewBrowserGameWindow = async (
browserUrl: string,
gameInfo: GameInfo
Expand All @@ -62,6 +85,35 @@ const openNewBrowserGameWindow = async (
logError(`Error importing proxy server ${err}`, LogPrefix.HyperPlay)
}
const hpOverlay = await getHpOverlay()
const urlParent = new URL(browserUrl)

function handleUrlOpen(
url: string,
contents: Electron.WebContents
): WindowOpenHandlerResponse {
const urlToOpen = new URL(url)
const protocol = urlToOpen.protocol

if (url === 'about:blank') {
return { action: 'allow', createWindow: openBlankWindow }
}

if (
['https:', 'http:'].includes(protocol) &&
domainsAreEqual(urlToOpen, urlParent)
) {
openNewBrowserGameWindow(url, gameInfo)
return { action: 'deny' }
}
return (
extensionImporter?.windowOpenHandlerForExtension(
url,
contents,
hpApi
) ?? { action: 'deny' }
)
}

return new Promise((res) => {
const browserGame = new BrowserWindow({
icon: icon,
Expand Down Expand Up @@ -120,7 +172,6 @@ const openNewBrowserGameWindow = async (
gameInfo.runner
}`

const urlParent = new URL(browserUrl)
const openNewBroswerGameWindowListener = (
ev: Electron.Event,
contents: Electron.WebContents
Expand All @@ -134,24 +185,9 @@ const openNewBrowserGameWindow = async (
)

/* this overrides the handler set in extension-importer but falls back to its behavior */
contents.setWindowOpenHandler(({ url }) => {
const urlToOpen = new URL(url)
const protocol = urlToOpen.protocol

if (
['https:', 'http:'].includes(protocol) &&
domainsAreEqual(urlToOpen, urlParent)
) {
openNewBrowserGameWindow(url, gameInfo)
return { action: 'deny' }
}
return (
extensionImporter?.windowOpenHandlerForExtension(
url,
contents,
hpApi
) ?? { action: 'deny' }
)
contents.setWindowOpenHandler((handler) => {
const { url } = handler
return handleUrlOpen(url, contents)
})
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.disabled {
cursor: not-allowed !important;
}
68 changes: 68 additions & 0 deletions src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useState } from 'react'
import styles from './index.module.scss'
import { t } from 'i18next'
import { NavBarOverlay, NavItem, Images } from '@hyperplay/ui'
import { Link, useLocation } from 'react-router-dom'

export function NavBarOverlayWrapper() {
const location = useLocation()
const { pathname } = location
const [collapsed, setCollapsed] = useState(false)
const comingSoonText = t('overlay.comingSoon', 'Coming Soon')

return (
<NavBarOverlay
linkItems={[
<NavItem
title={'Quests'}
route={'/quests'}
icon={<Images.QuestIcon fill="white" />}
key={'/quests'}
collapsed={collapsed}
currentRoute={pathname === '/' ? '/quests' : pathname}
component={Link}
to={'/quests'}
/>,
<NavItem
title={'Portfolio'}
route={'/portfolio'}
icon={
<Images.MetaMaskColored
fill="none"
width={22}
height={36}
opacity={pathname === '/portfolio' ? '100%' : '60%'}
/>
}
key={'/portfolio'}
collapsed={collapsed}
currentRoute={pathname}
component={Link}
to={'/portfolio'}
/>,
<NavItem
title={'Marketplace'}
route={'/marketplace'}
icon={<Images.Home fill="white" />}
key={'/marketplace'}
collapsed={collapsed}
currentRoute={pathname}
classNames={{ link: styles.disabled }}
secondaryTag={comingSoonText}
/>,
<NavItem
title={'Achievements'}
route={'/achievements'}
icon={<Images.TrophyOutline fill="white" />}
key={'/achievements'}
collapsed={collapsed}
currentRoute={pathname}
classNames={{ link: styles.disabled }}
secondaryTag={comingSoonText}
/>
]}
setCollapsed={setCollapsed}
collapsed={collapsed}
/>
)
}
71 changes: 13 additions & 58 deletions src/frontend/OverlayManager/Overlay/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect } from 'react'
import BrowserGameStyles from './index.module.scss'
import ToastManager from '../ToastManager'
import { PROVIDERS } from 'common/types/proxy-types'
Expand All @@ -9,17 +9,19 @@ import { t } from 'i18next'
import ExtensionManager from 'frontend/ExtensionManager'
import TransactionState from 'frontend/state/TransactionState'
import { BrowserGameProps } from '../types'
import { Button, NavBarOverlay, NavItem, Images } from '@hyperplay/ui'
import { Button } from '@hyperplay/ui'
import { QuestsViewer } from 'frontend/components/UI/QuestsViewer'
import { useFlags } from 'launchdarkly-react-client-sdk'
import libraryState from 'frontend/state/libraryState'
import classNames from 'classnames'
import { HashRouter, Route, Routes } from 'react-router-dom'
import MetaMaskPortfolio from 'frontend/screens/MetaMaskPortfolio'
import { NavBarOverlayWrapper } from './NavBarOverlayWrapper'

export const Overlay = observer(function ({
appName,
runner
}: BrowserGameProps) {
const [collapsed, setCollapsed] = useState(false)
const flags = useFlags()
const txnToastContainerStyle = {} as React.CSSProperties
if (OverlayState.title === 'HyperPlay Toasts') {
Expand Down Expand Up @@ -120,68 +122,21 @@ export const Overlay = observer(function ({
questsViewer = <QuestsViewer projectId={appName} />
}

const selectedRoute = '/quests'
const classNameMods: Record<string, boolean> = {}
classNameMods[BrowserGameStyles.hideOverlay] = !OverlayState.showOverlay

const comingSoonText = t('overlay.comingSoon', 'Coming Soon')

overlayItems = (
<div className={classNames(BrowserGameStyles.root, classNameMods)}>
<div className={BrowserGameStyles.bgFilter} />
<div className={BrowserGameStyles.contentContainer}>
<NavBarOverlay
linkItems={[
<NavItem
title={'Quests'}
route={'/quests'}
icon={<Images.QuestIcon fill="white" />}
key={'/quests'}
collapsed={collapsed}
currentRoute={selectedRoute}
/>,
<NavItem
title={'Marketplace'}
route={'/marketplace'}
icon={<Images.Home fill="white" />}
key={'/marketplace'}
collapsed={collapsed}
currentRoute={selectedRoute}
classNames={{ link: BrowserGameStyles.disabled }}
secondaryTag={comingSoonText}
/>,
<NavItem
title={'Achievements'}
route={'/achievements'}
icon={<Images.TrophyOutline fill="white" />}
key={'/achievements'}
collapsed={collapsed}
currentRoute={selectedRoute}
classNames={{ link: BrowserGameStyles.disabled }}
secondaryTag={comingSoonText}
/>,
<NavItem
title={'Portfolio'}
route={'/portfolio'}
icon={
<Images.MetaMaskColored
fill="none"
width={22}
height={36}
opacity={'60%'}
/>
}
key={'/portfolio'}
collapsed={collapsed}
currentRoute={selectedRoute}
classNames={{ link: BrowserGameStyles.disabled }}
secondaryTag={comingSoonText}
/>
]}
setCollapsed={setCollapsed}
collapsed={collapsed}
/>
{questsViewer}
<HashRouter>
<NavBarOverlayWrapper />
<Routes>
<Route path="/" element={questsViewer} />
<Route path="/quests" element={questsViewer} />
<Route path="/portfolio" element={<MetaMaskPortfolio />} />
</Routes>
</HashRouter>
<div className={BrowserGameStyles.rightSideContainer}>
{exitGameButton}
{extensionManager}
Expand Down
7 changes: 0 additions & 7 deletions src/frontend/screens/MetaMaskPortfolio/index.module.css

This file was deleted.

26 changes: 26 additions & 0 deletions src/frontend/screens/MetaMaskPortfolio/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import '@hyperplay/ui/utilities/_loading.scss';

.homeDiv {
height: 100%;
width: 100%;
position: relative;
}

.homeWebview {
height: 100%;
width: 100%;
position: absolute;
z-index: 1;
}

.hide {
display: none;
}

.loader {
@include shinyLoader;
height: 100%;
width: 100%;
position: absolute;
z-index: 0;
}
7 changes: 5 additions & 2 deletions src/frontend/screens/MetaMaskPortfolio/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import React from 'react'
import MetaMaskPortfolioStyles from './index.module.css'
import React, { useRef } from 'react'
import MetaMaskPortfolioStyles from './index.module.scss'
import { useParams } from 'react-router-dom'

const MetaMaskPortfolio = function () {
const trueAsStr = 'true' as unknown as boolean | undefined
const { page = '' } = useParams() as { page: string }
const webviewRef = useRef<HTMLWebViewElement>(null)

return (
<>
<div className={MetaMaskPortfolioStyles.homeDiv}>
<div className={MetaMaskPortfolioStyles.loader}></div>
<webview
className={MetaMaskPortfolioStyles.homeWebview}
src={`https://portfolio.metamask.io/${page}`}
allowpopups={trueAsStr}
partition={'persist:InPageWindowEthereumExternalWallet'}
ref={webviewRef}
/>
</div>
</>
Expand Down
Loading