Untitled
unknown
plain_text
2 years ago
18 kB
9
Indexable
import { RefreshControl, ScrollView, StyleSheet, View } from 'react-native';
import React from 'react';
import Left_button from 'app/components/left_button';
import { Icons } from 'app/constant';
import vndcTheme from 'app/assets/themes/vndc_theme';
import AppText from 'app/components/app_text';
import { getBottomSpace } from 'app/libs/react-native-iphone-x-helper';
import Item, { ItemIdTransaction } from './components/item';
import I18n from 'react-native-i18n';
import {
DIC_WORKING_TYPE,
getCondition,
ORDER_STATUS,
TYPE_ORDER,
TYPE_SIDE,
} from '../futures_onus/constants/order';
import { useBaseQuoteToken } from 'app/store/actions/futures/market_info';
import {
useConfigSymbol,
useSelectTickSize,
} from 'app/store/actions/futures/exchange_info';
import {
formatBalance,
formatPriceWithTickSize,
formatTime,
formatVNDFee,
formatVNDPnl,
} from 'app/screens/futures_onus/helper';
import { getPositionsClose } from 'app/store/api/futures/private';
import ItemTrades from './components/item_trades';
import { BASE_TOKEN } from 'app/screens/futures_onus/constants/marketConfigs';
import Token_logo from 'app/components/token_logo';
import { onShowModalTooltips } from 'app/components/modal_tooltips';
import { forEach, isEmpty } from 'lodash';
import Big from 'big.js';
import Right_button from 'app/components/right_button';
import ModalShare from './components/modal_share';
import { Portal } from 'react-native-portalize';
// item
// id:1010186
// clientOrderId:""
// sequenceId:1880185
// symbol:BTCUSDT
// side:BUY
// positionSide:BOTH
// reduceOnly:false
// type:MARKET
// size:0.592
// filledSize:0.592
// price:0
// stopPrice:0
// workingType:MARK_PRICE
// priceProtect:false
// postOnly:false
// status:FILLED
// timeInForce:GTC
// eventTimestamp:1672804755866
// entryTimestamp:1672804755825
// userId:2bbf820e-da51-4f0b-a2bb-68b5cb437f45
// originType:""
// closePosition:false
// closeReason:""
// strategyId:""
const FuturesOnusHistoryDetailTransaction = React.memo(props => {
const { navigation } = props;
const item = navigation.getParam('item', {});
const tickSize = useSelectTickSize(item.symbol);
const { baseAsset, quoteAsset } = useBaseQuoteToken(item.symbol);
const dataConfig = useConfigSymbol(item.symbol);
const quotePrecision =
quoteAsset === BASE_TOKEN.VNDC ? 0 : +dataConfig.quotePrecision;
const modalShareRef = React.useRef(null);
const [trades, setTrades] = React.useState([]);
const leverage = React.useMemo(
() => trades?.[trades?.length - 1]?.leverage || 0,
[trades],
);
const [loading, setLoading] = React.useState(true);
const [refreshing, setRefreshing] = React.useState(false);
React.useLayoutEffect(() => {
getPositionsClose({ symbol: item?.symbol, orderId: item?.id }).then(res => {
if (res?.data && res?.data?.length > 0) {
setTrades(res.data);
}
setLoading(false);
});
}, []);
const isLiq = React.useMemo(() => {
return (
item?.autoCloseType === 'LIQUIDATION' &&
item?.filledSize > 0 &&
item?.type === TYPE_ORDER.MARKET
);
}, [item]);
const totalFee = React.useMemo(() => {
return +item.accumFee;
}, [item]);
const totalRealizedProfit = React.useMemo(() => {
return item.accumPnl;
}, [item]);
// giá đóng
const avgPrice = React.useMemo(() => {
return +item.avgPrice;
}, [item]);
//gia mở
const entryPrice = React.useMemo(() => {
const closePrice = avgPrice;
const sizeClose = item.filledSize;
const side = item?.side === TYPE_SIDE.BUY ? -1 : 1;
if (sizeClose === 0 || sizeClose === '0') {
return 0;
}
return new Big(closePrice * sizeClose * side - totalRealizedProfit)
.div(sizeClose * side)
.toNumber();
}, [trades, avgPrice, item]);
const liqPrice = React.useMemo(() => {
if (!isLiq) return 0;
if (+item.price) return +item.price;
return 0;
}, [item.price, isLiq]);
const prefixPnl = React.useMemo(() => {
return +totalRealizedProfit > 0 ? '+' : +totalRealizedProfit < 0 ? '-' : '';
}, [totalRealizedProfit]);
const strTypeBuySell = React.useMemo(() => {
//item?.reduceOnly true thì là lệnh đóng, còn false là lệnh mở
// lệnh đóng sẽ là lệnh mở của lệnh mở trước đó
if (item?.side === TYPE_SIDE.BUY) {
return I18n.t('futures_onus.long');
}
return I18n.t('futures_onus.short');
}, [item]);
const isOrderOpen = React.useMemo(() => {
return !(item?.reduceOnly || item?.closePosition);
}, [item]);
const strType = React.useMemo(() => {
//item?.reduceOnly true thì là lệnh đóng, còn false là lệnh mở
// lệnh đóng sẽ là lệnh mở của lệnh mở trước đó
if (item?.reduceOnly || item?.closePosition) {
return `${I18n.t('futures_onus.close_order')} ${
item?.side === TYPE_SIDE.BUY
? I18n.t('futures_onus.short')
: I18n.t('futures_onus.long')
}`;
}
return I18n.t('futures_onus.open_order');
}, [item]);
const dataInfoCode = React.useMemo(
() => [
{
title: I18n.t(
'futures_onus_history_detail_transaction.transaction_code',
),
value: item.id,
},
{
title: I18n.t('futures_onus_history_detail_transaction.create_time'),
value: formatTime(item?.entryTimestamp, 'HH:mm:ss yyyy-MM-dd', true),
},
],
[],
);
const dataInfoType = React.useMemo(
() => [
{
title: I18n.t('futures_onus_history_detail_transaction.type'),
renderValue: () => (
<View style={styles.row}>
<AppText style={styles.txt145}>
{isLiq
? I18n.t('futures_onus.type_liquidation')
: I18n.t(
`futures_onus.type_${item?.originType?.toLowerCase() ||
item?.type.toLowerCase()}`,
)}
</AppText>
{leverage > 0 ? (
<>
<View style={styles.dot} />
<AppText style={styles.txt145}>{leverage}x</AppText>
</>
) : null}
<View style={styles.dot} />
<AppText style={styles.txt145}>{strType}</AppText>
</View>
),
},
{
title: `${I18n.t('futures_onus.volume')} ${baseAsset}`,
value:
+item?.filledSize !== 0
? `${formatBalance(
item?.filledSize || item?.size,
dataConfig && +dataConfig.sizePrecision,
)} ${baseAsset}`
: '-',
},
{
title: `${I18n.t('futures_onus.volume')} ${quoteAsset}`,
value:
item?.filledSize && avgPrice
? `${formatVNDPnl(
quoteAsset === BASE_TOKEN.VNDC,
formatBalance(+item?.filledSize * +avgPrice, quotePrecision),
)} ${quoteAsset}`
: '-',
},
{
title: I18n.t('nami.price_open'),
value:
+entryPrice && leverage > 0
? `${formatPriceWithTickSize(entryPrice, tickSize)} ${quoteAsset}`
: '-',
isHide: !(+entryPrice && leverage > 0) || isOrderOpen,
},
{
title: isOrderOpen
? I18n.t('nami.price_open')
: I18n.t('nami.price_close'),
value: +avgPrice
? `${formatPriceWithTickSize(avgPrice, tickSize)} ${quoteAsset}`
: '-',
isHide: !isOrderOpen && isLiq,
},
{
title: I18n.t('futures_onus.liquidation_price'),
value: +liqPrice
? `${formatPriceWithTickSize(liqPrice, tickSize)} ${quoteAsset}`
: '-',
isHide: +(liqPrice || '0') === 0,
onPressInfo: () => {
onShowModalTooltips({
title: I18n.t('futures_onus.liquidation_price'),
message: I18n.t('futures_onus.description_liquid_price'),
});
},
},
{
title: I18n.t('futures_onus.condition'),
value:
+(item?.stopPrice || '0') !== 0
? `${I18n.t(
`futures_onus.${DIC_WORKING_TYPE[item.workingType]}`,
)} ${getCondition(
item.side,
item.originType || item.type,
)} ${formatPriceWithTickSize(
item?.stopPrice,
tickSize,
)} ${quoteAsset}`
: '-',
isHide: +(item?.stopPrice || '0') === 0,
},
{
title: I18n.t('futures_onus_history_detail_transaction.reduce_only'),
value: item?.reduceOnly
? I18n.t('futures_onus.yes')
: I18n.t('futures_onus.no'),
onPressInfo: () => {
onShowModalTooltips({
title: I18n.t('futures_onus.description_title_reduce_only'),
message: I18n.t('futures_onus.description_desc_reduce_only'),
});
},
isHide: !item?.reduceOnly,
},
],
[
avgPrice,
dataConfig,
prefixPnl,
isLiq,
strType,
isOrderOpen,
entryPrice,
leverage,
liqPrice,
],
);
const onRefresh = React.useCallback(() => {
setRefreshing(true);
getPositionsClose({ symbol: item?.symbol, orderId: item?.id }).then(res => {
if (res?.data && res?.data?.length > 0) {
setTrades(res.data);
}
setRefreshing(false);
});
}, []);
const dataInfoFee = React.useMemo(
() => [
{
title: I18n.t('futures_onus_history_detail_transaction.reason'),
value:
(item.status === ORDER_STATUS.CANCELED ||
item.status === ORDER_STATUS.REJECTED) &&
item.closeReason
? `${I18n.t(`futures_onus.${item.closeReason}`, {
defaultValue: item.closeReason,
})}`
: '',
isHide: !(item.status === ORDER_STATUS.REJECTED && item.closeReason),
},
{
title: I18n.t('futures_onus_history_detail_transaction.fee'),
value: !totalFee
? '-'
: quoteAsset === BASE_TOKEN.VNDC
? `${formatBalance(formatVNDFee(totalFee))} ${quoteAsset}`
: `${formatBalance(totalFee, quotePrecision)} ${quoteAsset}`,
},
{
title: I18n.t(
'futures_onus_history_detail_transaction.real_profit_loss',
),
value: prefixPnl
? `${prefixPnl}${formatBalance(
Math.abs(totalRealizedProfit),
quotePrecision,
)} ${quoteAsset}`
: '-',
styleValue: {
color:
totalRealizedProfit > 0
? vndcTheme.priceUp
: totalRealizedProfit < 0
? vndcTheme.priceDown
: vndcTheme.textColor,
},
},
],
[totalFee, totalRealizedProfit, prefixPnl, item, dataConfig],
);
React.useLayoutEffect(() => {
navigation.setParams({
onShare: () => {
let closePrice = avgPrice;
let side = item?.side === TYPE_SIDE.BUY ? -1 : 1;
let tpsl = (closePrice / entryPrice - 1) * leverage * side * 100;
let _item = {
...item,
entryPrice, //giá vào
closePrice, //giá đóng
leverage,
side: item.side === TYPE_SIDE.BUY ? TYPE_SIDE.SELL : TYPE_SIDE.BUY,
tpsl,
};
modalShareRef.current?.open(_item);
},
isShowShare: leverage > 0 && totalRealizedProfit !== 0 && !isLiq,
});
}, [
entryPrice,
avgPrice,
item,
trades,
totalRealizedProfit,
leverage,
isLiq,
]);
return (
<View style={styles.container}>
<View style={styles.mask} />
<ScrollView
contentContainerStyle={styles.contentContainerStyle}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor={vndcTheme.textColor_1}
/>
}>
<View style={styles.containerTop}>
<View style={styles.row}>
<View style={styles.containerLogo}>
<Token_logo token={quoteAsset} style={styles.logoBaseToken} />
<Token_logo token={baseAsset} style={styles.logoQuoteToken} />
</View>
<View>
<AppText style={styles.txtTitle}>{item.symbol}</AppText>
<AppText
style={styles.txt166}
color={
item.side === TYPE_SIDE.BUY
? vndcTheme.priceUp
: vndcTheme.priceDown
}>
{I18n.t('futures_onus_history_detail_transaction.order')}{' '}
{strTypeBuySell}
</AppText>
</View>
<View style={styles.space} />
<View
style={[
styles.tag,
{
backgroundColor:
item.status === ORDER_STATUS.FILLED
? '#0FA47C10'
: '#F6F6F610',
},
]}>
<AppText
style={styles.txt146}
color={
item.status === ORDER_STATUS.FILLED
? vndcTheme.priceUp
: vndcTheme.textColor
}>
{I18n.t(
`futures_onus.order_status_${
item?.status === ORDER_STATUS.CANCELED &&
Math.abs(+item.filledSize) > 0
? 'partiall_filled'
: item?.status?.toLowerCase()
}`,
{
defaultValue: '-',
},
)}
</AppText>
</View>
</View>
<View height={12} />
<View style={styles.divider} />
<View style={styles.rowId}>
<ItemIdTransaction item={dataInfoCode[0]} isCopy />
<View width={32} />
<ItemIdTransaction item={dataInfoCode[1]} />
</View>
<View style={styles.divider} />
{dataInfoType.map((i, index) => {
if (i.isHide) return null;
return <Item key={index} item={i} styleValue={i.styleValue} />;
})}
<View style={styles.divider} />
{dataInfoFee.map((i, index) => {
if (i.isHide) return null;
return <Item key={index} item={i} styleValue={i.styleValue} />;
})}
</View>
<View style={styles.containerDetailTransaction}>
<View height={22} />
<AppText style={styles.txtTitleDetail}>
{I18n.t('futures_onus_history_detail_transaction.match_history')}
</AppText>
{trades.map((e, i) => {
const isLast = i === trades.length - 1;
return (
<ItemTrades
key={i}
e={e}
baseAsset={baseAsset}
quoteAsset={quoteAsset}
dataConfig={dataConfig}
isLast={isLast}
isLiq={isLiq}
/>
);
})}
{trades.length === 0 && !loading ? (
<AppText style={styles.txtNoData}>
{I18n.t('futures_onus_history_detail_transaction.no_more')}
</AppText>
) : null}
</View>
</ScrollView>
<Portal>
<ModalShare ref={modalShareRef} />
</Portal>
</View>
);
});
FuturesOnusHistoryDetailTransaction.navigationOptions = props => {
const { navigation } = props;
const onShare = navigation.getParam('onShare', () => {});
const isShowShare = navigation.getParam('isShowShare', false);
return {
headerLeft: () => (
<Left_button
onPress={() => navigation.goBack()}
imageUrl={Icons.arrow_left}
/>
),
headerRight: () =>
isShowShare ? (
<Right_button
onPress={() => {
onShare && onShare();
}}
imageUrl={Icons.icon_share_16}
/>
) : null,
title: I18n.t('futures_onus_history_detail_transaction.order_details'),
headerStyle: {
backgroundColor: vndcTheme.backgroundColor_2,
elevation: 0,
shadowColor: 'transparent',
},
};
};
export default FuturesOnusHistoryDetailTransaction;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: vndcTheme.backgroundColor_1,
},
divider: {
height: 1,
backgroundColor: vndcTheme.line_2,
marginVertical: 5,
},
txtTitle: {
fontSize: 24,
fontWeight: '600',
},
contentContainerStyle: {
paddingBottom: getBottomSpace() + 16,
backgroundColor: vndcTheme.backgroundColor_1,
},
txtTitleDetail: {
fontSize: 18,
fontWeight: '600',
},
txtNoData: {
fontSize: 14,
fontWeight: '400',
paddingVertical: 24,
textAlign: 'center',
color: vndcTheme.textColor_1,
},
containerTop: {
backgroundColor: vndcTheme.backgroundColor_2,
paddingHorizontal: 15,
borderBottomLeftRadius: 16,
borderBottomRightRadius: 16,
overflow: 'hidden',
paddingVertical: 15,
},
mask: {
position: 'absolute',
width: '100%',
height: 300,
backgroundColor: vndcTheme.backgroundColor_2,
},
rowId: {
flexDirection: 'row',
paddingVertical: 10,
},
containerDetailTransaction: {
paddingHorizontal: 15,
},
containerLogo: {
width: 38,
height: 38,
marginRight: 10,
},
logoBaseToken: {
position: 'absolute',
right: 0,
bottom: 0,
width: 24,
height: 24,
},
logoQuoteToken: {
borderWidth: 2,
width: 28,
height: 28,
borderColor: vndcTheme.backgroundColor_1,
},
row: {
flexDirection: 'row',
alignItems: 'center',
},
txt166: {
fontSize: 16,
fontWeight: '600',
},
tag: {
paddingVertical: 3,
paddingHorizontal: 6,
borderRadius: 100,
},
txt146: {
fontSize: 14,
fontWeight: '600',
},
space: {
flex: 1,
},
txt145: {
fontSize: 14,
fontWeight: '500',
},
dot: {
width: 3,
height: 3,
borderRadius: 1.5,
backgroundColor: vndcTheme.line_1,
marginHorizontal: 6,
},
});
Editor is loading...