Skip to content

Commit

Permalink
Refactor code structure and fix balance display bug
Browse files Browse the repository at this point in the history
  • Loading branch information
truemiller committed Mar 27, 2024
1 parent d88692d commit f1f7ac5
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 104 deletions.
4 changes: 1 addition & 3 deletions electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ const {
BrowserWindow,
Tray,
Menu,
shell,
Notification,
ipcMain,
} = require('electron');
const { spawn, exec } = require('child_process');
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const os = require('os');
const next = require('next');
const http = require('http');

const { isDockerRunning } = require('./docker');
const {
setupDarwin,
setupUbuntu,
Expand Down
92 changes: 27 additions & 65 deletions frontend/components/Setup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { CopyOutlined } from '@ant-design/icons';
import { Button, Input, message, Spin, Typography } from 'antd';
import crypto from 'crypto';
import { useContext, useEffect, useMemo, useState } from 'react';

import { copyToClipboard } from '@/common-util';
Expand All @@ -26,14 +25,10 @@ export const Setup = () => {
switch (setupObject.state) {
case SetupScreen.Welcome:
return <SetupWelcome />;
case SetupScreen.Backup:
return <SetupBackup />;
case SetupScreen.Import:
return <SetupImport />;
case SetupScreen.Password:
return <SetupPassword />;
case SetupScreen.Recovery:
return <SetupRecovery />;
case SetupScreen.Backup:
return <SetupBackup />;
case SetupScreen.Finalizing:
return <SetupFinalizing />;
default:
Expand All @@ -49,60 +44,20 @@ const SetupWelcome = () => {
return (
<Wrapper vertical>
<Typography.Title>Welcome</Typography.Title>
<Button onClick={() => goto(SetupScreen.Backup)}>Create Wallet</Button>
<Button disabled>Import Wallet</Button>
</Wrapper>
);
};

const SetupBackup = () => {
const { goto } = useSetup();
const [mnemonic] = useState(
'test test test test test test test test test test test test',
);
return (
<Wrapper vertical>
<Typography.Title>Backup</Typography.Title>
<Typography.Text>
Please write down the following mnemonic phrase and keep it safe.
</Typography.Text>
<Input.TextArea readOnly value={mnemonic} style={{ resize: 'none' }} />
<Button
onClick={() =>
copyToClipboard(mnemonic).then(() =>
message.success('Copied successfully!'),
)
}
>
<CopyOutlined /> Copy to clipboard
</Button>
<Button onClick={() => goto(SetupScreen.Password)}>Next</Button>
</Wrapper>
);
};

const SetupImport = () => {
const { goto } = useSetup();
return (
<Wrapper vertical>
<Typography.Title>Import</Typography.Title>
<Typography.Text>
Enter your mnemonic phrase to import your account
</Typography.Text>
<Input.TextArea />
<Button onClick={() => goto(SetupScreen.Password)}>Next</Button>
<Button onClick={() => goto(SetupScreen.Password)}>Create Account</Button>
<Button disabled>Import</Button>
</Wrapper>
);
};

const SetupPassword = () => {
const { goto, setPasswordHash } = useSetup();
const { goto } = useSetup();
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);

const passwordHash = useMemo(
() => crypto.createHash('sha256').update(password).digest('hex'),
[password],
);
const handleClick = () => {
goto(SetupScreen.Backup);
};

return (
<Wrapper vertical>
Expand All @@ -113,28 +68,35 @@ const SetupPassword = () => {
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button
onClick={() => {
setPasswordHash(passwordHash);
goto(SetupScreen.Recovery);
}}
>
<Button onClick={handleClick} loading={isLoading}>
Next
</Button>
</Wrapper>
);
};

const SetupRecovery = () => {
const SetupBackup = () => {
const { goto } = useSetup();
const [mnemonic] = useState(
'test test test test test test test test test test test test',
);
return (
<Wrapper vertical>
<Typography.Title>Recovery</Typography.Title>
<Typography.Title>Backup</Typography.Title>
<Typography.Text>
Please enter a public key that you can use to recover your wallet.
Please write down the following mnemonic phrase and keep it safe.
</Typography.Text>
<Input.TextArea />
<Button onClick={() => goto(SetupScreen.Finalizing)}>Recover</Button>
<Input.TextArea readOnly value={mnemonic} style={{ resize: 'none' }} />
<Button
onClick={() =>
copyToClipboard(mnemonic).then(() =>
message.success('Copied successfully!'),
)
}
>
<CopyOutlined /> Copy to clipboard
</Button>
<Button onClick={() => goto(SetupScreen.Finalizing)}>Next</Button>
</Wrapper>
);
};
Expand Down
33 changes: 33 additions & 0 deletions frontend/context/UserBalanceProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createContext, PropsWithChildren, useState } from 'react';
import { useInterval } from 'usehooks-ts';

import { useAppInfo } from '@/hooks';
import { EthersService } from '@/service';

export const UserBalanceContext = createContext<{
balance: number;
}>({
balance: 0,
});

export const UserBalanceProvider = ({ children }: PropsWithChildren) => {
const { userPublicKey } = useAppInfo();
const [balance, setBalance] = useState<number>(0);

const updateBalance = () => {
if (userPublicKey)
EthersService.getEthBalance(userPublicKey, 'http://localhost:8545').then(
(res) => setBalance(res),
);
};

useInterval(() => {
updateBalance();
}, 5000);

return (
<UserBalanceContext.Provider value={{ balance }}>
{children}
</UserBalanceContext.Provider>
);
};
2 changes: 1 addition & 1 deletion frontend/hooks/useAppInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Address } from '@/types';
export const useAppInfo = () => {
const { appInfo } = useContext(AppInfoContext);

const userPublicKey: Address | undefined = appInfo?.account.key;
const userPublicKey: Address | undefined = appInfo?.account?.key;

return {
userPublicKey,
Expand Down
7 changes: 7 additions & 0 deletions frontend/hooks/useUserBalance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useContext } from 'react';

import { UserBalanceContext } from '@/context/UserBalanceProvider';

export const useUserBalance = () => {
return useContext(UserBalanceContext);
};
21 changes: 12 additions & 9 deletions frontend/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ import {
ServicesProvider,
SetupProvider,
} from '@/context';
import { UserBalanceProvider } from '@/context/UserBalanceProvider';
import { mainTheme } from '@/theme';

export default function App({ Component, pageProps }: AppProps) {
return (
<AppInfoProvider>
<ServicesProvider>
<ConfigProvider theme={mainTheme}>
<PageStateProvider>
<SetupProvider>
<Component {...pageProps} />
</SetupProvider>
</PageStateProvider>
</ConfigProvider>
</ServicesProvider>
<UserBalanceProvider>
<ServicesProvider>
<ConfigProvider theme={mainTheme}>
<PageStateProvider>
<SetupProvider>
<Component {...pageProps} />
</SetupProvider>
</PageStateProvider>
</ConfigProvider>
</ServicesProvider>
</UserBalanceProvider>
</AppInfoProvider>
);
}
37 changes: 28 additions & 9 deletions frontend/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Receive, Send } from '@/components/Wallet';
import { serviceTemplates } from '@/constants';
import { PageState } from '@/enums';
import { usePageState, useServices } from '@/hooks';
import { useUserBalance } from '@/hooks/useUserBalance';
import { ServicesService } from '@/service';

const { useToken } = theme;
Expand Down Expand Up @@ -50,8 +51,10 @@ const Main = () => {
const { token } = useToken();
const { setPageState } = usePageState();
const { services } = useServices();
const { balance } = useUserBalance();

const [serviceButtonState, setServiceButtonState] = useState({
isFunded: false,
isLoading: false,
isRunning: false,
});
Expand Down Expand Up @@ -80,15 +83,16 @@ const Main = () => {
const handleStart = useCallback(() => {
setServiceButtonState({ ...serviceButtonState, isLoading: true });
if (services.length > 0) {
ServicesService.startDeployment(services[0].hash).then(() => {
return ServicesService.startDeployment(services[0].hash).then(() => {
setServiceButtonState({ ...serviceButtonState, isRunning: true });
});
}
ServicesService.createService({ serviceTemplate, deploy: true }).then(
() => {
setServiceButtonState({ ...serviceButtonState, isLoading: false });
},
);
return ServicesService.createService({
serviceTemplate,
deploy: true,
}).then(() => {
setServiceButtonState({ ...serviceButtonState, isLoading: false });
});
}, [serviceButtonState, serviceTemplate, services]);

const handleStop = useCallback(() => {
Expand All @@ -100,6 +104,12 @@ const Main = () => {
}, [serviceButtonState, services]);

const serviceToggleButton = useMemo(() => {
if (!serviceButtonState.isFunded)
return (
<Button type="text" disabled>
Not funded
</Button>
);
if (serviceButtonState.isLoading)
return (
<Button type="text" loading>
Expand All @@ -123,14 +133,21 @@ const Main = () => {
);
}, [handleStart, handleStop, serviceButtonState]);

// Service button interval
useInterval(() => {
setServiceButtonState((prev) => ({ ...prev, isFunded: balance > 1 }));

if (services.length <= 0) {
setServiceButtonState({ isLoading: false, isRunning: false });
setServiceButtonState((prev) => ({
...prev,
isLoading: false,
isRunning: false,
}));
return;
}

if (services[0]) {
ServicesService.getServiceStatus(services[0].hash).then((res) => {
ServicesService.getDeployment(services[0].hash).then((res) => {
res.status === DeploymentStatus.DEPLOYED
? setServiceButtonState((prev) => ({ ...prev, isRunning: true }))
: setServiceButtonState((prev) => ({ ...prev, isRunning: false }));
Expand All @@ -157,7 +174,9 @@ const Main = () => {
<Flex vertical>
<Typography style={{ margin: 0 }}>
<span style={{ fontSize: 32, fontWeight: 900 }}>$</span>
<span style={{ fontSize: 64, fontWeight: 900 }}>2,101</span>
<span style={{ fontSize: 64, fontWeight: 900 }}>
{balance.toFixed(2)}
</span>
</Typography>
<Typography
style={{ display: 'flex', flexWrap: 'nowrap', fontSize: 18 }}
Expand Down
55 changes: 55 additions & 0 deletions frontend/service/Account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { BACKEND_URL } from '@/constants';

/**
* Gets account status "is_setup"
*/
const getAccount = () =>
fetch(`${BACKEND_URL}/account`).then((res) => res.json());

/**
* Creates a local user account
*/
const createAccount = (password: string) =>
fetch(`${BACKEND_URL}/account`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ password }),
}).then((res) => res.json());

/**
* Updates user's password
*/
const updateAccount = (oldPassword: string, newPassword: string) =>
fetch(`${BACKEND_URL}/account`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
old_password: oldPassword,
new_password: newPassword,
}),
}).then((res) => res.json());

/**
* Logs in a user
*/
const loginAccount = (password: string) =>
fetch(`${BACKEND_URL}/account/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
password,
}),
}).then((res) => res.json());

export const AccountService = {
getAccount,
createAccount,
updateAccount,
loginAccount,
};
Loading

0 comments on commit f1f7ac5

Please sign in to comment.