Skip to content

Commit

Permalink
feat: fiat on ramp (#1670)
Browse files Browse the repository at this point in the history
* feat: adds Transak support

* WIP UI

* enhancement: position of transak window and browser window options

Co-authored-by: Jean Ribeiro <[email protected]>

* ui: layout and panes for buy view

* fix: only call function if darwin

* fix: use integers to set position

* remove buy sell router

* isolate most of transak code into a manager

* improve UI

* removes unused code

* disable feature flag

* add only available network

---------

Co-authored-by: Nicole O'Brien <[email protected]>
Co-authored-by: Tuditi <[email protected]>
Co-authored-by: Mark Nardi <[email protected]>
  • Loading branch information
4 people authored Jan 17, 2024
1 parent 6d65fb0 commit 499ec30
Show file tree
Hide file tree
Showing 29 changed files with 438 additions and 13 deletions.
1 change: 1 addition & 0 deletions .github/workflows/reusable_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ jobs:
env:
HARDCODE_NODE_ENV: true
AMPLITUDE_API_KEY: ${{ secrets.AMPLITUDE_API_KEY }}
TRANSAK_API_KEY: ${{ secrets.TRANSAK_API_KEY }}

- name: Build signed Electron app (MacOS)
run: yarn compile:${STAGE}:mac
Expand Down
3 changes: 2 additions & 1 deletion packages/desktop/components/AccountSwitcher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { PopupId, openPopup } from '@desktop/auxiliary/popup'
export let navbar: boolean = false
export let placement: 'bottom-start' | 'bottom-end' = 'bottom-start'
const menu: Menu | undefined = undefined
Expand Down Expand Up @@ -42,7 +43,7 @@
{items}
compact={navbar}
{...!navbar && { button: { text: localize('general.newAccount'), onClick: onCreateAccountClick } }}
placement="bottom-start"
{placement}
>
<Breadcrumb slot="anchor" tooltip={navbar ? localize('actions.switchAccount') : undefined}>
<div class="flex flex-row justify-center items-center space-x-2">
Expand Down
3 changes: 3 additions & 0 deletions packages/desktop/features/analytics.features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ const analyticsFeatures: IAnalyticsFeatures = {
enabled: true,
},
},
buySell: {
enabled: true,
},
},
loginRoute: {
enabled: true,
Expand Down
7 changes: 7 additions & 0 deletions packages/desktop/features/buy-sell.features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IFeatureFlag } from '@lib/features/interfaces'

const buySellFeatures: IFeatureFlag = {
enabled: false,
}

export default buySellFeatures
2 changes: 2 additions & 0 deletions packages/desktop/features/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import settingsFeatures from './settings.features'
import walletFeatures from './wallet.features'
import walletConnectFeatures from './wallet-connect.features'
import analyticsFeatures from './analytics.features'
import buySellFeatures from './buy-sell.features'
import { IDesktopFeatures } from './interfaces'

const features: IDesktopFeatures = {
Expand All @@ -27,6 +28,7 @@ const features: IDesktopFeatures = {
settings: settingsFeatures,
wallet: walletFeatures,
walletConnect: walletConnectFeatures,
buySell: buySellFeatures,
}

export default features
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IAnalyticsFeatures extends IFeatureFlag {
wallet: {
sendFlow: IFeatureFlag
}
buySell: IFeatureFlag
}
loginRoute: IFeatureFlag
onboardingRoute: IFeatureFlag
Expand Down
11 changes: 10 additions & 1 deletion packages/desktop/lib/electron/apis/electron.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import NotificationManager from '../managers/notification.manager'
import PincodeManager from '../managers/pincode.manager'
import { bindMethodsAcrossContextBridge } from '../utils/context-bridge.utils'

import type { IAppSettings } from '@core/app/interfaces'
import type { IAppSettings, ITransakWindowData } from '@core/app/interfaces'
import type { IFeatureFlag } from '@lib/features/interfaces'
import { AppTheme } from '@core/app/enums'

Expand Down Expand Up @@ -250,4 +250,13 @@ export default {
killLedgerProcess(): void {
return ipcRenderer.send('kill-ledger-process')
},
openTransak(data: ITransakWindowData): Promise<void> {
return ipcRenderer.invoke('open-transak', data)
},
closeTransak(): Promise<void> {
return ipcRenderer.invoke('close-transak')
},
isSidebarExpanded(expanded: boolean): Promise<void> {
return ipcRenderer.invoke('is-sidebar-expanded', expanded)
},
}
2 changes: 2 additions & 0 deletions packages/desktop/lib/electron/constants/windows.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ export const windows: Window = {
main: null,
about: null,
error: null,
transak: null,
}

type Window = {
main: BrowserWindow | null
about: BrowserWindow | null
error: BrowserWindow | null
transak: BrowserWindow | null
}
142 changes: 142 additions & 0 deletions packages/desktop/lib/electron/managers/transak.manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { BrowserWindow, app } from 'electron'
import { windows } from '../constants/windows.constant'
import features from '@features/features'
import { ITransakManager, ITransakWindowData } from '@core/app'
import path from 'path'

const SIDEBAR_WIDTH_EXPANDED = 256
const SIDEBAR_WIDTH_CLOSED = 80
const BORDER_HEIGHT = 1
const WINDOWS_TITLEBAR_HEIGHT = 28
const NAVBAR_HEIGHT = 40
const DASHBOARD_CONTAINER_PADDING = 32

export default class TransakManager implements ITransakManager {
private sidebarExpanded = false
private htmlPath = app.isPackaged
? path.join(app.getAppPath(), '/public/transak.html')
: path.join(__dirname, '../transak.html')
private preloadPath = app.isPackaged
? path.join(app.getAppPath(), '/public/build/transak.preload.js')
: path.join(__dirname, 'transak.preload.js')

public setSidebarExpanded(isOpen: boolean): void {
this.sidebarExpanded = isOpen
}

public closeWindow(): void {
if (windows.transak) {
windows.transak.close()
windows.transak = null
}
}

public openWindow(data: ITransakWindowData): BrowserWindow {
if (windows.transak !== null) {
return windows.transak
}

windows.transak = new BrowserWindow({
parent: windows.main,
width: 480,
height: this.getWindowHeight(),
useContentSize: true,
titleBarStyle: 'hidden',
frame: false,
show: true,
fullscreenable: false,
transparent: true,
movable: false,
resizable: false,
minimizable: false,
skipTaskbar: true,
acceptFirstMouse: true,
hasShadow: false,
thickFrame: false,
roundedCorners: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
disableBlinkFeatures: 'Auxclick',
webviewTag: false,
enableWebSQL: false,
devTools: !app.isPackaged || features?.electron?.developerTools?.enabled,
preload: this.preloadPath,
},
})

if (process.platform === 'darwin') {
windows.transak.setWindowButtonVisibility(false)
}

this.positionWindow()
this.sizeWindow()
windows.main.on('move', () => this.positionWindow())
windows.main.on('resize', () => {
this.positionWindow()
this.sizeWindow()
})

windows.transak.once('closed', () => {
windows.transak = null
})

windows.transak.webContents.session.setPermissionRequestHandler((webContents, permission, callback) => {
if (permission === 'media') {
callback(true)
} else {
callback(false)
}
})

void windows.transak.loadFile(this.htmlPath)
windows.transak.webContents.on('did-finish-load', () => {
const _data = {
currency: data.currency,
address: data.address,
stage: app.isPackaged ? 'production' : 'staging',
apiKey: process.env.TRANSAK_API_KEY,
service: data.service,
}
windows.transak.webContents.send('transak-data', _data)
})

windows.transak.setMenu(null)

return windows.transak
}

public positionWindow(): void {
if (windows.transak && windows.transak) {
const [mainWindowX, mainWindowY] = windows.main.getPosition()
const [mainWindowWidth] = windows.main.getSize()
const [transakWidth] = windows.transak.getSize()

const sidebarWidth = this.sidebarExpanded ? SIDEBAR_WIDTH_EXPANDED : SIDEBAR_WIDTH_CLOSED
const dashboardWidth = mainWindowWidth - sidebarWidth
const transakX = Math.floor(mainWindowX + sidebarWidth + dashboardWidth / 2 - transakWidth / 2)
const topBarHeight = this.getTopBarHeight()
const transakY = mainWindowY + topBarHeight + DASHBOARD_CONTAINER_PADDING + BORDER_HEIGHT

windows.transak.setPosition(transakX, transakY)
}
}

private sizeWindow(): void {
const [transakWidth] = windows.transak.getSize()
const transakHeight = this.getWindowHeight()
windows.transak.setSize(transakWidth, transakHeight)
}

private getTopBarHeight(): number {
const titleBarHeight = process.platform === 'win32' ? WINDOWS_TITLEBAR_HEIGHT + BORDER_HEIGHT : 0
const topBarHeight = NAVBAR_HEIGHT + BORDER_HEIGHT + titleBarHeight
return topBarHeight
}

private getWindowHeight(): number {
const [, mainWindowHeight] = windows.main.getSize()
const topBarHeight = this.getTopBarHeight()
return mainWindowHeight - topBarHeight - (DASHBOARD_CONTAINER_PADDING + BORDER_HEIGHT) * 2
}
}
50 changes: 50 additions & 0 deletions packages/desktop/lib/electron/preloads/transak.preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { IpcRendererEvent, ipcRenderer } from 'electron'

interface TransakData {
apiKey: string
currency: string
address: string
stage: 'production' | 'staging'
service: 'BUY' | 'SELL'
}

window.addEventListener('DOMContentLoaded', () => {
ipcRenderer.on('transak-data', (_: IpcRendererEvent, data: TransakData) => {
window.document.documentElement.style.height = '100%'
window.document.body.style.margin = '0'
window.document.body.style.padding = '0'
window.document.body.style.width = '100dvw'
window.document.body.style.height = '100dvh'
window.document.body.style.borderRadius = '16px'
window.document.body.style.display = 'flex'
window.document.body.style.alignItems = 'center'
window.document.body.style.justifyContent = 'center'

if (window.document.getElementById('transakIframe')) {
return
}

const { apiKey, currency, address, stage, service } = data
const transakUrl = stage === 'production' ? 'https://global.transak.com' : 'https://global-stg.transak.com'

const iframe = window.document.createElement('iframe')
iframe.id = 'transakIframe'
iframe.src = `${transakUrl}/?apiKey=${apiKey}&defaultFiatCurrency=${currency}&walletAddress=${address}&productsAvailed=${service}&cryptoCurrencyCode=IOTA&network=miota&themeColor=7C41C9&hideMenu=true`
iframe.style.width = '100%'
iframe.style.height = '100%'
iframe.style.border = 'none'
iframe.style.borderRadius = '16px'
iframe.allow = 'camera;microphone;payment'
iframe.sandbox.add('allow-scripts', 'allow-same-origin')

window.document.body.appendChild(iframe)

window.addEventListener('message', (message) => {
if (message.source !== iframe.contentWindow) return

if (message?.data?.event_id === 'TRANSAK_ORDER_SUCCESSFUL') {
void ipcRenderer.invoke('close-transak')
}
})
})
})
42 changes: 33 additions & 9 deletions packages/desktop/lib/electron/processes/main.process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { windows } from '../constants/windows.constant'
import AutoUpdateManager from '../managers/auto-update.manager'
import KeychainManager from '../managers/keychain.manager'
import NftDownloadManager from '../managers/nft-download.manager'
import TransakManager from '../managers/transak.manager'
import { contextMenu } from '../menus/context.menu'
import { initMenu } from '../menus/menu'
import { initialiseAnalytics } from '../utils/analytics.utils'
Expand Down Expand Up @@ -337,16 +338,21 @@ ipcMain.on(LedgerApiMethod.SignMessage, (_e, messageHex, bip32Path) => {
ledgerProcess?.postMessage({ method: LedgerApiMethod.SignMessage, payload: [messageHex, bip32Path] })
})

export function getOrInitWindow(windowName: string): BrowserWindow {
export function getOrInitWindow(windowName: string, ...args: unknown[]): BrowserWindow {
if (!windows[windowName]) {
if (windowName === 'main') {
return createMainWindow()
}
if (windowName === 'about') {
return openAboutWindow()
}
if (windowName === 'error') {
return openErrorWindow()
switch (windowName) {
case 'main':
return createMainWindow()
case 'about':
return openAboutWindow()
case 'error':
return openErrorWindow()
case 'transak':
return transakManager?.openWindow(
args[0] as { currency: string; address: string; service: 'BUY' | 'SELL' }
)
default:
throw Error(`Window ${windowName} not found`)
}
}
return windows[windowName]
Expand Down Expand Up @@ -496,6 +502,24 @@ ipcMain.on('notification-activated', (ev, contextData) => {
windows.main.webContents.send('notification-activated', contextData)
})

// Transak

const transakManager = features?.buySell?.enabled ? new TransakManager() : null
ipcMain.handle('open-transak', (_, data) => {
getOrInitWindow('transak', data)
})

ipcMain.handle('close-transak', () => {
transakManager?.closeWindow()
})

ipcMain.handle('is-sidebar-expanded', (_, expanded) => {
if (transakManager) {
transakManager.setSidebarExpanded(expanded)
transakManager.positionWindow()
}
})

/**
* Create about window
* @returns {BrowserWindow} About window
Expand Down
10 changes: 10 additions & 0 deletions packages/desktop/public/transak.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; frame-src https://global-stg.transak.com https://global.transak.com; object-src 'none';">
</head>
<body>
</body>
</html>
2 changes: 2 additions & 0 deletions packages/desktop/views/dashboard/Dashboard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
import { Wallet } from './wallet'
import { Settings } from '../settings'
import { Background } from '@views/components'
import { BuySell } from './buy-sell'
const tabs = {
wallet: Wallet,
settings: Settings,
collectibles: Collectibles,
governance: Governance,
developer: Developer,
buySell: BuySell,
}
let previousAccountIndex = get(selectedAccountIndex)
Expand Down
Loading

0 comments on commit 499ec30

Please sign in to comment.