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();