mirror of https://github.com/certusone/oyster.git
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:
parent
18ee623ef5
commit
61cf44e95a
|
@ -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>
|
||||
|
|
|
@ -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} />
|
||||
))}
|
||||
|
|
Loading…
Reference in New Issue