Skip to content

Commit

Permalink
wallet-ext: display balance for each token
Browse files Browse the repository at this point in the history
  • Loading branch information
pchrysochoidis committed May 26, 2022
1 parent 459ec5e commit 65f39e3
Show file tree
Hide file tree
Showing 32 changed files with 1,026 additions and 53 deletions.
13 changes: 13 additions & 0 deletions wallet/.stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-prettier-scss"
],
"overrides": [
{
"files": ["**/*.module.scss"],
"rules": {
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global"]
}
]
}
}
]
}
1 change: 1 addition & 0 deletions wallet/configs/ts/tsconfig.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"_images/*": ["./src/ui/assets/images/*"],
"_redux/*": ["./src/ui/app/redux/*"],
"_store": ["./src/ui/app/redux/store/"],
"_store/*": ["./src/ui/app/redux/store/*"],
"_hooks": ["./src/ui/app/hooks/"],
"_components/*": ["./src/ui/app/components/*"]
}
Expand Down
1 change: 1 addition & 0 deletions wallet/configs/webpack/webpack.config.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ const commonConfig: () => Promise<Configuration> = async () => {
}),
new DefinePlugin({
'typeof window': JSON.stringify(typeof {}),
'process.env.NODE_DEBUG': false,
}),
new ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
Expand Down
322 changes: 289 additions & 33 deletions wallet/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,15 @@
"@mysten/sui.js": "file:../sdk/typescript",
"@reduxjs/toolkit": "^1.8.1",
"bip39-light": "^1.0.7",
"bootstrap-icons": "^1.8.2",
"buffer": "^6.0.3",
"classnames": "^2.3.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-intl": "^6.0.2",
"react-redux": "^8.0.1",
"react-router-dom": "^6.3.0",
"rxjs": "^7.5.5",
"stream-browserify": "^3.0.0",
"tweetnacl": "^1.0.3",
"webextension-polyfill": "^0.9.0"
Expand Down
21 changes: 21 additions & 0 deletions wallet/src/ui/app/ApiProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { JsonRpcProvider } from '@mysten/sui.js';

// const DEFAULT_API_ENDPOINT = 'https://gateway.devnet.sui.io';
const DEFAULT_API_ENDPOINT = 'http://127.0.0.1:5001';

export default class ApiProvider {
private _apiProvider: JsonRpcProvider;

constructor() {
// TODO: allow overriding default endpoint
const apiEndpoint = DEFAULT_API_ENDPOINT;
this._apiProvider = new JsonRpcProvider(apiEndpoint);
}

public get instance() {
return this._apiProvider;
}
}
18 changes: 18 additions & 0 deletions wallet/src/ui/app/KeypairVault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { Ed25519Keypair } from '@mysten/sui.js';

import { getKeypairFromMnemonics } from '_shared/cryptography/mnemonics';

export default class KeypairVault {
private _keypair: Ed25519Keypair | null = null;

public set mnemonic(mnemonic: string) {
this._keypair = new Ed25519Keypair(getKeypairFromMnemonics(mnemonic));
}

public getAccount(): string | null {
return this._keypair?.getPublicKey().toSuiAddress() || null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.address {
font-size: 15px;
font-weight: 700;
color: #404040;
}

.copy-icon {
margin-left: 6px;
cursor: pointer;
}
59 changes: 59 additions & 0 deletions wallet/src/ui/app/components/account-address/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useCallback, useEffect, useMemo, useState } from 'react';

import BsIcon from '_components/bs-icon';
import { useAppSelector } from '_hooks';

import st from './AccountAddress.module.scss';

const COPY_CHECKMARK_MILLIS = 600;

// TODO: make copy to clipboard reusable
function AccountAddress() {
const address = useAppSelector(
({ account: { address } }) => address && `0x${address}`
);
const shortenAddress = useMemo(() => {
if (!address) {
return '';
}
return `${address.substring(0, 7)}...${address.substring(
address.length - 7
)}`;
}, [address]);
const [copied, setCopied] = useState(false);
const copyToClipboard = useCallback(async () => {
if (!address) {
return;
}
await navigator.clipboard.writeText(address);
setCopied(true);
}, [address]);
useEffect(() => {
let timeout: number;
if (copied) {
timeout = window.setTimeout(
() => setCopied(false),
COPY_CHECKMARK_MILLIS
);
}
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, [copied]);
return address ? (
<span className={st.address} title={address} onClick={copyToClipboard}>
{shortenAddress}
<BsIcon
className={st['copy-icon']}
icon={`clipboard${copied ? '-check' : ''}`}
/>
</span>
) : null;
}

export default AccountAddress;
27 changes: 27 additions & 0 deletions wallet/src/ui/app/components/alert/Alert.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
$error-color: #8b1111;

.container {
display: flex;
flex-flow: row nowrap;
padding: 8px;
border: 1px solid;
border-radius: 4px;
align-items: center;

&.error {
border-color: $error-color;
}
}

.icon {
align-self: flex-start;
font-size: 20px;

.error & {
color: $error-color;
}
}

.message {
margin-left: 12px;
}
27 changes: 27 additions & 0 deletions wallet/src/ui/app/components/alert/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import cl from 'classnames';
import { memo } from 'react';

import BsIcon from '_components/bs-icon';

import type { ReactNode } from 'react';

import st from './Alert.module.scss';

export type AlertProps = {
children: ReactNode | ReactNode[];
className?: string;
};

function Alert({ children, className }: AlertProps) {
return (
<div className={cl(st.container, st.error, className)}>
<BsIcon className={st.icon} icon="exclamation-circle" />
<div className={st.message}>{children}</div>
</div>
);
}

export default memo(Alert);
16 changes: 16 additions & 0 deletions wallet/src/ui/app/components/bs-icon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import cl from 'classnames';
import { memo } from 'react';

export type BsIconProps = {
className?: string;
icon: string;
};

function BsIcon({ className, icon }: BsIconProps) {
return <i className={cl(className, `bi-${icon}`, 'bi')}></i>;
}

export default memo(BsIcon);
37 changes: 37 additions & 0 deletions wallet/src/ui/app/components/coin-balance/CoinBalance.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.container {
display: flex;
padding: 24px 16px;
align-self: stretch;
flex: 1;
border-radius: 4px;
background-color: #f0f0f0;
box-shadow: 0 0 3px 0 #00000050;
position: relative;

& + .container {
margin-top: 12px;
}
}

.type {
position: absolute;
top: 2px;
right: 3px;
font-size: 8px;
font-weight: 700;
letter-spacing: -0.6px;
color: #8bc3df;
}

.value {
font-size: 16px;
font-weight: 600;
}

.symbol {
font-size: 16px;
font-weight: 200;
text-transform: uppercase;
letter-spacing: -0.4px;
margin-left: 4px;
}
39 changes: 39 additions & 0 deletions wallet/src/ui/app/components/coin-balance/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { memo, useMemo } from 'react';
import { useIntl } from 'react-intl';

import st from './CoinBalance.module.scss';

export type CoinProps = {
type: string;
balance: number;
};

function CoinBalance({ type, balance }: CoinProps) {
const symbol = useMemo(
() => type.substring(type.lastIndexOf(':') + 1),
[type]
);
const intl = useIntl();
const balanceFormatted = useMemo(
() =>
intl.formatNumber(balance, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
[intl, balance]
);
return (
<div className={st.container}>
<span className={st.type}>{type}</span>
<span>
<span className={st.value}>{balanceFormatted}</span>
<span className={st.symbol}>{symbol}</span>
</span>
</div>
);
}

export default memo(CoinBalance);
30 changes: 30 additions & 0 deletions wallet/src/ui/app/components/header/Header.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.container {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-around;
align-self: stretch;
}

.link {
margin-left: 8px;
line-height: 32px;
min-width: 54px;

&:first-child {
margin-left: 0;
}
}

.icon {
padding: 12px;
font-size: 24px;
display: block;
color: black;
transition: all 200ms ease-in-out;

.active > & {
font-size: 30px;
color: #4caad8;
}
}
32 changes: 32 additions & 0 deletions wallet/src/ui/app/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import cl from 'classnames';
import { memo } from 'react';
import { NavLink } from 'react-router-dom';

import BsIcon from '_components/bs-icon';

import st from './Header.module.scss';

function makeLinkCls({ isActive }: { isActive: boolean }) {
return cl(st.link, { [st.active]: isActive });
}

function Header() {
return (
<div className={st.container}>
<NavLink to="./tokens" className={makeLinkCls} title="Tokens">
<BsIcon className={st.icon} icon="coin" />
</NavLink>
<NavLink to="./nfts" className={makeLinkCls} title="NFTs">
<BsIcon className={st.icon} icon="collection" />
</NavLink>
<NavLink to="./settings" className={makeLinkCls} title="Settings">
<BsIcon className={st.icon} icon="gear" />
</NavLink>
</div>
);
}

export default memo(Header);
16 changes: 16 additions & 0 deletions wallet/src/ui/app/components/loading/LoadingIndicator.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.spinner {
display: inline-block;
width: 1em;
height: 1em;
vertical-align: middle;
border: 2px solid #2386b8;
border-right-color: transparent;
border-radius: 50%;
animation: 0.75s linear infinite spinner-animation;
}

@keyframes spinner-animation {
to {
transform: rotate(360deg);
}
}
Loading

0 comments on commit 65f39e3

Please sign in to comment.