feat: First screen attempt: Try to come up with a clever way to visualize your margin order and just get something up there. Next up, move to a better order flow.

This commit is contained in:
Mr. Dummy Tester 2020-12-23 15:21:58 -06:00
parent 18ee623ef5
commit 61cf44e95a
2 changed files with 154 additions and 23 deletions

View File

@ -1,28 +1,29 @@
import { Button, Select, Slider } from 'antd';
import React from 'react';
import { IPosition } from '.';
import { NumericInput } from '../../components/Input/numeric';
import { TokenIcon } from '../../components/TokenIcon';
import tokens from '../../config/tokens.json';
import { LABELS } from '../../constants/labels';
const { Option } = Select;
interface EditableAssetProps {
interface IEditableAssetProps {
label: string;
itemAssetKey: string;
itemAssetValueKey: string;
assetKey: string;
setItem: (item: any) => void;
item: any;
}
function EditableAsset({ label, itemAssetKey, itemAssetValueKey, setItem, item }: EditableAssetProps) {
console.log('Now looking at', item);
if (!item[itemAssetKey]) {
function EditableAsset({ label, assetKey, setItem, item }: IEditableAssetProps) {
if (!item[assetKey]?.type) {
return (
<Select
size='large'
showSearch
style={{ margin: '5px 0px' }}
placeholder={label}
onChange={(v) => setItem({ ...item, [itemAssetKey]: tokens.find((t) => t.mintAddress === v) })}
onChange={(v) =>
setItem({ ...item, [assetKey]: { ...(item[assetKey] || {}), type: tokens.find((t) => t.mintAddress === v) } })
}
>
{tokens.map((token) => (
<Option key={token.mintAddress} value={token.mintAddress} name={token.tokenName} title={token.tokenName}>
@ -38,33 +39,45 @@ function EditableAsset({ label, itemAssetKey, itemAssetValueKey, setItem, item }
return (
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'flex-start' }}>
<NumericInput
value={item[itemAssetValueKey]}
value={item[assetKey].value}
style={{
fontSize: 20,
boxShadow: 'none',
borderColor: 'transparent',
outline: 'transparent',
}}
onChange={(v: number) => {
setItem({ ...item, [assetKey]: { ...(item[assetKey] || {}), value: v } });
}}
placeholder='0.00'
/>
<TokenIcon mintAddress={item[itemAssetKey]?.mintAddress} />
<TokenIcon mintAddress={item[assetKey]?.type?.mintAddress} />
</div>
);
}
}
export default function MarginTradePosition({ item, setItem }: { item: any; setItem?: (item: any) => void }) {
export default function MarginTradePosition({ item, setItem }: { item: IPosition; setItem?: (item: any) => void }) {
return (
<div className='trading-item'>
<div>
{setItem && (
<EditableAsset
item={item}
setItem={setItem}
label={LABELS.TRADING_TABLE_TITLE_MY_COLLATERAL}
itemAssetKey={'collateralType'}
itemAssetValueKey={'collateralValue'}
/>
<Select
size='large'
showSearch
style={{ margin: '5px 0px' }}
placeholder={LABELS.TRADING_TABLE_TITLE_MY_COLLATERAL}
onChange={(v) => setItem({ ...item, collateral: tokens.find((t) => t.mintAddress === v) })}
>
{tokens.map((token) => (
<Option key={token.mintAddress} value={token.mintAddress} name={token.tokenName} title={token.tokenName}>
<div key={token.mintAddress} style={{ display: 'flex', alignItems: 'center' }}>
<TokenIcon mintAddress={token.mintAddress} />
{token.tokenName}
</div>
</Option>
))}
</Select>
)}
</div>
<div>
@ -72,14 +85,26 @@ export default function MarginTradePosition({ item, setItem }: { item: any; setI
<EditableAsset
item={item}
setItem={setItem}
label={LABELS.TRADING_TABLE_TITLE_MY_COLLATERAL}
itemAssetKey={'assetType'}
itemAssetValueKey={'assetValue'}
label={LABELS.TRADING_TABLE_TITLE_DESIRED_ASSET}
assetKey={'asset'}
/>
)}
</div>
<div>
<Slider tooltipVisible={true} defaultValue={1} dots={true} max={5} min={1} step={1} tooltipPlacement={'top'} />
{setItem && (
<Slider
tooltipVisible={true}
defaultValue={1}
dots={true}
max={5}
min={1}
step={1}
tooltipPlacement={'top'}
onChange={(v: number) => {
setItem({ ...item, leverage: v });
}}
/>
)}
</div>
<div>123</div>
<div>123</div>

View File

@ -1,11 +1,116 @@
import React, { useState } from 'react';
import { LABELS } from '../../constants';
import './style.less';
import { Card } from 'antd';
import { Card, Progress, Slider, Statistic } from 'antd';
import MarginTradePosition from './MarginTradePosition';
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
export interface IToken {
mintAddress: string;
tokenName: string;
tokenSymbol: string;
}
export interface IPosition {
id?: number | null;
leverage: number;
collateral?: IToken;
asset?: {
type: IToken;
value: number;
};
}
export function Breakdown({ item }: { item: IPosition }) {
let myPart = (item.asset?.value || 0) / item.leverage;
const brokeragePart = (item.asset?.value || 0) - myPart;
const brokerageColor = 'brown';
const myColor = 'blue';
const gains = 'green';
const losses = 'red';
const [myGain, setMyGain] = useState<number>(0);
const profitPart = (myPart + brokeragePart) * (myGain / 100);
let progressBar = null;
if (profitPart > 0) {
// normalize...
const total = profitPart + myPart + brokeragePart;
progressBar = (
<Progress
percent={(myPart / total) * 100 + (brokeragePart / total) * 100}
success={{ percent: (brokeragePart / total) * 100, strokeColor: brokerageColor }}
strokeColor={myColor}
trailColor={gains}
showInfo={false}
/>
);
} else {
// now, we're eating away your profit...
myPart += profitPart; // profit is negative
const total = myPart + brokeragePart;
if (myPart < 0) {
progressBar = <p>Your position has been liquidated at this price swing.</p>;
} else
progressBar = (
<Progress
showInfo={false}
success={{ percent: (brokeragePart / total) * 100, strokeColor: brokerageColor }}
trailColor={myColor}
/>
);
}
return (
<div>
<Slider
tooltipVisible={true}
defaultValue={0}
dots={true}
max={100}
min={-100}
step={5}
tooltipPlacement={'top'}
onChange={(v: number) => {
setMyGain(v);
}}
style={{ marginBottom: '20px' }}
/>
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center' }}>
<Card>
<Statistic
title='Leverage'
value={brokeragePart}
precision={2}
valueStyle={{ color: brokerageColor }}
suffix={item.asset?.type.tokenName}
/>
</Card>
<Card>
<Statistic
title='My Collateral Value'
value={myPart}
precision={2}
valueStyle={{ color: myColor }}
suffix={item.asset?.type.tokenName}
/>
</Card>
<Card>
<Statistic
title='Profit/Loss'
value={profitPart}
precision={2}
valueStyle={{ color: profitPart > 0 ? gains : losses }}
suffix={item.asset?.type.tokenSymbol}
prefix={profitPart > 0 ? <ArrowUpOutlined /> : <ArrowDownOutlined />}
/>
</Card>
</div>
{progressBar}
</div>
);
}
export const MarginTrading = () => {
const [newPosition, setNewPosition] = useState<any>({ id: null });
const [newPosition, setNewPosition] = useState<IPosition>({ id: null, leverage: 1 });
const positions: any[] = [];
return (
@ -22,6 +127,7 @@ export const MarginTrading = () => {
<div>{LABELS.TRADING_TABLE_TITLE_ACTIONS}</div>
</div>
<MarginTradePosition key={newPosition.id} item={newPosition} setItem={setNewPosition} />
<Breakdown item={newPosition} />
{positions.map((item) => (
<MarginTradePosition key={item.id} item={item} />
))}