From 1cbab240ca2f3078831e36bbf4e555a21e1f4a41 Mon Sep 17 00:00:00 2001 From: amitpanwar789 Date: Sat, 25 May 2024 23:03:07 +0530 Subject: [PATCH] draft for desktop app --- frontend/package.json | 3 +- frontend/src/App.tsx | 2 +- frontend/src/basic/Main.tsx | 6 +- .../MakerForm/AutocompletePayments.tsx | 2 +- frontend/src/components/RobotAvatar/index.tsx | 4 +- frontend/src/contexts/AppContext.tsx | 10 ++- frontend/src/geo/Web.js | 2 +- frontend/src/models/Federation.model.ts | 3 +- frontend/src/services/Native/index.d.ts | 1 + .../System/SystemDesktopClient/index.ts | 71 +++++++++++++++++++ frontend/src/services/System/index.ts | 3 +- 11 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 frontend/src/services/System/SystemDesktopClient/index.ts diff --git a/frontend/package.json b/frontend/package.json index cb70fdf2..c5a94906 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "node --max-old-space-size=4096 ./node_modules/.bin/webpack --watch --progress --mode development", "test": "jest", - "build": "webpack --mode production", + "build": "webpack --config webpack.config.ts --mode development", + "builds": "react-scripts build", "lint": "eslint src/**/*.{ts,tsx}", "lint:fix": "eslint --fix 'src/**/*.{ts,tsx}'", "format": "prettier --write '**/**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ff4ed6fc..236650be 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -24,7 +24,7 @@ const App = (): JSX.Element => { - {window.NativeRobosats === undefined ? : } + {(window.NativeRobosats === undefined && window.DesktopRobosats === undefined )? : }
diff --git a/frontend/src/basic/Main.tsx b/frontend/src/basic/Main.tsx index b87d564a..137b874e 100644 --- a/frontend/src/basic/Main.tsx +++ b/frontend/src/basic/Main.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { MemoryRouter, BrowserRouter, Routes, Route } from 'react-router-dom'; +import { MemoryRouter,HashRouter ,BrowserRouter, Routes, Route } from 'react-router-dom'; import { Box, Slide, Typography, styled } from '@mui/material'; import { type UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext'; @@ -10,7 +10,9 @@ import Notifications from '../components/Notifications'; import { useTranslation } from 'react-i18next'; import { GarageContext, type UseGarageStoreType } from '../contexts/GarageContext'; -const Router = window.NativeRobosats === undefined ? BrowserRouter : MemoryRouter; +//const Router = window.NativeRobosats === undefined ? BrowserRouter : MemoryRouter; + +const Router = (window.NativeRobosats === undefined && window.DesktopRobosats === undefined)? BrowserRouter : window.DesktopRobosats === 'Desktop-App' ? HashRouter : MemoryRouter; const TestnetTypography = styled(Typography)({ height: 0, diff --git a/frontend/src/components/MakerForm/AutocompletePayments.tsx b/frontend/src/components/MakerForm/AutocompletePayments.tsx index 9d23504d..642151e3 100644 --- a/frontend/src/components/MakerForm/AutocompletePayments.tsx +++ b/frontend/src/components/MakerForm/AutocompletePayments.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import useAutocomplete from '@mui/base/useAutocomplete'; +import { useAutocomplete } from '@mui/base/useAutocomplete'; import { styled } from '@mui/material/styles'; import { Button, diff --git a/frontend/src/components/RobotAvatar/index.tsx b/frontend/src/components/RobotAvatar/index.tsx index 33fe8f5b..8c538d51 100644 --- a/frontend/src/components/RobotAvatar/index.tsx +++ b/frontend/src/components/RobotAvatar/index.tsx @@ -71,9 +71,9 @@ const RobotAvatar: React.FC = ({ useEffect(() => { if (shortAlias !== undefined) { - if (window.NativeRobosats === undefined) { + if (window.NativeRobosats === undefined) { setAvatarSrc( - `${hostUrl}/static/federation/avatars/${shortAlias}${small ? '.small' : ''}.webp`, + `${hostUrl.substring(hostUrl.indexOf("http://")+7)}/static/federation/avatars/${shortAlias}${small ? '.small' : ''}.webp`, ); } else { setAvatarSrc( diff --git a/frontend/src/contexts/AppContext.tsx b/frontend/src/contexts/AppContext.tsx index 45b4a84c..3ff4273c 100644 --- a/frontend/src/contexts/AppContext.tsx +++ b/frontend/src/contexts/AppContext.tsx @@ -40,6 +40,7 @@ export interface SlideDirection { export type TorStatus = 'ON' | 'STARTING' | 'STOPPING' | 'OFF'; export const isNativeRoboSats = !(window.NativeRobosats === undefined); +export const isDesktopRoboSats = !(window.DesktopRobosats === undefined); const pageFromPath = window.location.pathname.split('/')[1]; const isPagePathEmpty = pageFromPath === ''; @@ -77,15 +78,18 @@ const makeTheme = function (settings: Settings): Theme { const getHostUrl = (network = 'mainnet'): string => { let host = ''; let protocol = ''; - if (window.NativeRobosats === undefined) { + if(window.DesktopRobosats === 'Desktop-App'){ + host = defaultFederation.exp[network]['onion']; + protocol = 'http:'; + } + else if (window.NativeRobosats === undefined) { host = getHost(); protocol = location.protocol; } else { - host = defaultFederation.exp[network].Onion; + host = defaultFederation.exp[network]['onion']; protocol = 'http:'; } const hostUrl = `${protocol}//${host}`; - return hostUrl; }; diff --git a/frontend/src/geo/Web.js b/frontend/src/geo/Web.js index 973d15bb..d74fbfaf 100644 --- a/frontend/src/geo/Web.js +++ b/frontend/src/geo/Web.js @@ -1,6 +1,6 @@ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export const getWorldmapGeojson = async (apiClient, baseUrl) => { - return apiClient.get(baseUrl, '/static/assets/geo/countries-coastline-10km.geo.json'); + return apiClient.get(baseUrl.substring(baseUrl.indexOf("http://")+7), '/static/assets/geo/countries-coastline-10km.geo.json'); }; export default getWorldmapGeojson; diff --git a/frontend/src/models/Federation.model.ts b/frontend/src/models/Federation.model.ts index 7f72531e..ebbfd454 100644 --- a/frontend/src/models/Federation.model.ts +++ b/frontend/src/models/Federation.model.ts @@ -21,7 +21,8 @@ export class Federation { // Do not add `Local Dev` unless it is running on localhost return acc; } else { - acc[key] = new Coordinator(value, origin, settings, hostUrl); + acc[key] = new Coordinator(value, origin, settings, hostUrl.substring(hostUrl.indexOf("http://")+7)); + return acc; } }, diff --git a/frontend/src/services/Native/index.d.ts b/frontend/src/services/Native/index.d.ts index 680c8427..721255a3 100644 --- a/frontend/src/services/Native/index.d.ts +++ b/frontend/src/services/Native/index.d.ts @@ -5,6 +5,7 @@ declare global { ReactNativeWebView?: ReactNativeWebView; NativeRobosats?: NativeRobosats; RobosatsSettings: 'web-basic' | 'web-pro' | 'selfhosted-basic' | 'selfhosted-pro'; + DesktopRobosats: undefined | 'Desktop-App'; } } diff --git a/frontend/src/services/System/SystemDesktopClient/index.ts b/frontend/src/services/System/SystemDesktopClient/index.ts new file mode 100644 index 00000000..8b1051c9 --- /dev/null +++ b/frontend/src/services/System/SystemDesktopClient/index.ts @@ -0,0 +1,71 @@ +import { type SystemClient } from '..'; + +class SystemDesktopClient implements SystemClient { + public loading = false; + + public copyToClipboard: (value: string) => void = (value) => { + // navigator clipboard api needs a secure context (https) + // this function attempts to copy also on http contexts + // useful on the http i2p site and on torified browsers + if (navigator.clipboard !== undefined && window.isSecureContext) { + // navigator clipboard api method' + void navigator.clipboard.writeText(value); + } else { + // text area method + const textArea = document.createElement('textarea'); + textArea.value = value; + // make the textarea out of viewport + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + // here the magic happens + document.execCommand('copy'); + textArea.remove(); + } + }; + + // Cookies + public getCookie: (key: string) => string = (key) => { + let cookieValue = null; + if (document?.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the key we want? + if (cookie.substring(0, key.length + 1) === key + '=') { + cookieValue = decodeURIComponent(cookie.substring(key.length + 1)); + break; + } + } + } + + return cookieValue ?? ''; + }; + + public setCookie: (key: string, value: string) => void = (key, value) => { + document.cookie = `${key}=${value};path=/;SameSite=None;Secure`; + }; + + public deleteCookie: (key: string) => void = (key) => { + document.cookie = `${key}= ;path=/; expires = Thu, 01 Jan 1970 00:00:00 GMT`; + }; + + // Local storage + public getItem: (key: string) => string = (key) => { + const value = window.sessionStorage.getItem(key); + return value ?? ''; + }; + + public setItem: (key: string, value: string) => void = (key, value) => { + window.sessionStorage.setItem(key, value); + }; + + public deleteItem: (key: string) => void = (key) => { + window.sessionStorage.removeItem(key); + }; +} + +export default SystemDesktopClient; diff --git a/frontend/src/services/System/index.ts b/frontend/src/services/System/index.ts index 99d401a3..2d3a2349 100644 --- a/frontend/src/services/System/index.ts +++ b/frontend/src/services/System/index.ts @@ -1,5 +1,6 @@ import SystemNativeClient from './SystemNativeClient'; import SystemWebClient from './SystemWebClient'; +import SystemDesktopClient from './SystemDesktopClient'; export interface SystemClient { loading: boolean; @@ -17,4 +18,4 @@ export const systemClient: SystemClient = // react-native-web view of the RoboSats Android app. window.navigator.userAgent.includes('robosats') ? new SystemNativeClient() - : new SystemWebClient(); + : window.navigator.userAgent.includes('Electron')? new SystemDesktopClient() : new SystemWebClient();