Skip to content

Commit

Permalink
Fix margin trading page
Browse files Browse the repository at this point in the history
  • Loading branch information
lq0-github committed Nov 22, 2024
1 parent eaaeea8 commit a6b4dd1
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 35 deletions.
59 changes: 42 additions & 17 deletions screens/MarginTrading/components/MyTrading/MyTradingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,27 +95,52 @@ const MyMarginTradingPage = () => {
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{Object.values(marginAccountList).map((item, index) => {
const assetC = getAssetById(item.token_c_info.token_id);
const {
icon: iconC,
symbol: symbolC,
decimals: decimalsC,
price: priceC,
} = getAssetDetails(assetC);
const netValue =
parseTokenValue(item.token_c_info.balance, decimalsC) * (priceC || 0);
{(() => {
interface MergedCollateralData {
icon: string;
symbol: string;
totalValue: number;
}

return (
<div key={index} className="flex items-center justify-center mb-3">
<img src={iconC} alt="" className="w-4 h-4" />
<p className="ml-2 mr-8 text-xs text-gray-300">{symbolC}</p>
// 定义累加器对象的类型
type CollateralAccumulator = {
[tokenId: string]: MergedCollateralData;
};

const mergedCollateral = Object.values(
marginAccountList,
).reduce<CollateralAccumulator>((acc, item) => {
const assetC = getAssetById(item.token_c_info.token_id);
const { decimals: decimalsC, price: priceC } = getAssetDetails(assetC);
const tokenId = item.token_c_info.token_id;

const netValue =
parseTokenValue(item.token_c_info.balance, decimalsC) * (priceC || 0);

if (!acc[tokenId]) {
const { icon: iconC, symbol: symbolC } = getAssetDetails(assetC);
acc[tokenId] = {
icon: iconC,
symbol: symbolC,
totalValue: netValue,
};
} else {
acc[tokenId].totalValue += netValue;
}

return acc;
}, {});

return Object.entries(mergedCollateral).map(([tokenId, data], index) => (
<div key={tokenId} className="flex items-center justify-center mb-3">
<img src={data.icon} alt="" className="w-4 h-4" />
<p className="ml-2 mr-8 text-xs text-gray-300">{data.symbol}</p>
<div className="text-xs ml-auto">
${toInternationalCurrencySystem_number(netValue)}
${toInternationalCurrencySystem_number(data.totalValue)}
</div>
</div>
);
})}
));
})()}
</div>
)}
</div>
Expand Down
21 changes: 17 additions & 4 deletions screens/MarginTrading/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useAppDispatch } from "../../redux/hooks";
import { LayoutBox } from "../../components/LayoutContainer/LayoutContainer";
import MyMarginTrading from "./components/MyTrading";
import MarketMarginTrading from "./components/MarketTrading";

const MarginTrading = () => {
const dispatch = useAppDispatch();
const [activeTab, setActiveTab] = useState("market");
const [activeTab, setActiveTab] = useState(() => {
const savedTab = localStorage.getItem("marginTradingTab");
return savedTab || "market";
});

const handleTabChange = (tab: string) => {
setActiveTab(tab);
localStorage.setItem("marginTradingTab", tab);
};

const getTabClassName = (tabName) => {
const baseClass = "py-2.5 px-24 text-base";
const activeClass = "bg-primary rounded-md text-dark-200";
Expand All @@ -19,11 +28,15 @@ const MarginTrading = () => {
<button
type="button"
className={getTabClassName("market")}
onClick={() => setActiveTab("market")}
onClick={() => handleTabChange("market")}
>
Market
</button>
<button type="button" className={getTabClassName("my")} onClick={() => setActiveTab("my")}>
<button
type="button"
className={getTabClassName("my")}
onClick={() => handleTabChange("my")}
>
Yours
</button>
</div>
Expand Down
148 changes: 134 additions & 14 deletions screens/Trading/components/ChangeCollateralMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,66 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
setAddLeverage(0);
}
};
const handleInputValidation = (value: string) => {
if (value.startsWith("-")) return false;
if (!/^\d*\.?\d*$/.test(value)) return false;
if (value.includes(".")) {
const decimals = value.split(".")[1];
if (decimals.length > 8) return false;
}
return true;
};

const handleAddChange = (event) => {
const { value } = event.target;
if (value === "" || value === ".") {
setInputValue(NaN);
setAddedValue(0);
setAddLeverage(0);
return;
}
if (!handleInputValidation(value)) {
return;
}
const numValue = parseFloat(value);
const maxAmount = getMaxAvailableAmount();
if (numValue > maxAmount) {
setInputValue(maxAmount);
const syntheticEvent = {
target: { value: String(maxAmount) },
};
handleCollateralChange(syntheticEvent, true);
return;
}
setInputValue(numValue);
handleCollateralChange(event, true);
};

const handleDeleteChange = (event) => {
const { value } = event.target;
if (value === "" || value === ".") {
setInputValue(NaN);
setAddedValue(0);
setAddLeverage(0);
return;
}
if (!handleInputValidation(value)) {
return;
}
const numValue = parseFloat(value);
const tokenCInfoBalance = parseTokenValue(rowData.data.token_c_info.balance, decimalsC);
const maxRemovable = calculateMaxRemovable();
const actualMaxRemovable = Math.min(tokenCInfoBalance, maxRemovable);
if (numValue > actualMaxRemovable) {
setInputValue(actualMaxRemovable);
const syntheticEvent = {
target: { value: String(actualMaxRemovable) },
};
handleCollateralChange(syntheticEvent, false);
return;
}
setInputValue(numValue);
handleCollateralChange(event, false);
};

const assetD = getAssetById(rowData.data.token_d_info.token_id);
const assetC = getAssetById(rowData.data.token_c_info.token_id);
const assetP = getAssetById(rowData.data.token_p_id);
Expand Down Expand Up @@ -137,31 +188,88 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
const handleAddCollateralClick = async () => {
try {
await increaseCollateral({ pos_id, token_c_id, amount, assets });
localStorage.setItem("marginTradingTab", "my");
} catch (error) {
console.error("Error adding collateral:", error);
}
};
const handleDeleteCollateralClick = async () => {
try {
await decreaseCollateral({ pos_id, token_c_id, amount, assets });
localStorage.setItem("marginTradingTab", "my");
} catch (error) {
console.error("Error deleted collateral:", error);
}
};
const getMaxAvailableAmount = () => {
const currentLeverage = leverage || 1;
const targetMinLeverage = 1;
const rawMaxAmount = Number(balance) / priceC;
const getNewLeverageAfterAdd = (addAmount: number) => {
const tokenCInfoBalance = parseTokenValue(rowData.data.token_c_info.balance, decimalsC);
const tokenDInfoBalance = parseTokenValue(rowData.data.token_d_info.balance, decimalsD);
const newCollateral = tokenCInfoBalance + addAmount;
return calculateLeverage(tokenDInfoBalance, priceD, newCollateral, priceC);
};
let left = 0;
let right = rawMaxAmount;
let result = 0;
while (left <= right) {
const mid = (left + right) / 2;
const newLeverage = getNewLeverageAfterAdd(mid);
if (newLeverage >= targetMinLeverage) {
result = mid;
left = mid + 0.0001; // 增加精度
} else {
right = mid - 0.0001;
}
}
return Math.min(rawMaxAmount, result);
};
const calculateMaxRemovable = () => {
const tokenCInfoBalance = parseTokenValue(rowData.data.token_c_info.balance, decimalsC);
const tokenDInfoBalance = parseTokenValue(rowData.data.token_d_info.balance, decimalsD);
const maxLeverage = 10;
let left = 0;
let right = tokenCInfoBalance;
let result = 0;
while (left <= right) {
const mid = (left + right) / 2;
const remainingCollateral = tokenCInfoBalance - mid;
const newLeverage = calculateLeverage(tokenDInfoBalance, priceD, remainingCollateral, priceC);
if (newLeverage <= maxLeverage) {
result = mid;
left = mid + 0.0001;
} else {
right = mid - 0.0001;
}
}
return result;
};
// const validateAmount = (amount: number) => {
// if (isNaN(amount) || amount <= 0) return false;
// const maxAmount = getMaxAvailableAmount();
// if (amount > maxAmount) return false;
// const tokenCInfoBalance = parseTokenValue(rowData.data.token_c_info.balance, decimalsC);
// const tokenDInfoBalance = parseTokenValue(rowData.data.token_d_info.balance, decimalsD);
// const newCollateral = tokenCInfoBalance + amount;
// const newLeverage = calculateLeverage(tokenDInfoBalance, priceD, newCollateral, priceC);
// return newLeverage >= 1;
// };
const handleLeverAddClick = (value) => {
if (selectedLever === value) {
setSelectedLever(null);
setInputValue(NaN);
return;
}
setSelectedLever(value);
const maxAmount = getMaxAvailableAmount();
let newInputValue;
if (value === "Max") {
const maxPercentage = Number(balance) / priceC;
newInputValue = Number(maxPercentage);
newInputValue = maxAmount;
} else {
const percentage = parseFloat(value);
newInputValue = (Number(balance) * percentage) / 100 / priceC;
newInputValue = (maxAmount * percentage) / 100;
}
setInputValue(newInputValue);
handleCollateralChange({ target: { value: newInputValue } }, true);
Expand All @@ -173,13 +281,15 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
return;
}
setSelectedLever(value);
const maxRemovable = calculateMaxRemovable();
const tokenCInfoBalance = parseTokenValue(rowData.data.token_c_info.balance, decimalsC);
const actualMaxRemovable = Math.min(tokenCInfoBalance, maxRemovable);
let newInputValue;
if (value === "Max") {
const maxPercentage = collateralTotal / priceC;
newInputValue = Number(maxPercentage);
newInputValue = actualMaxRemovable;
} else {
const percentage = parseFloat(value);
newInputValue = (collateralTotal * percentage) / 100 / priceC;
newInputValue = (actualMaxRemovable * percentage) / 100;
}
setInputValue(newInputValue);
handleCollateralChange({ target: { value: newInputValue } }, false);
Expand Down Expand Up @@ -248,11 +358,17 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
<div className=" bg-dark-600 border border-dark-500 pt-3 pb-2.5 pr-3 pl-2.5 rounded-md flex items-center justify-between mb-1.5">
<div>
<input
type="number"
step="any"
value={String(inputValue)}
onChange={handleAddChange}
type="text"
value={Number.isNaN(inputValue) ? "" : String(inputValue)}
onChange={
ChangeCollateralTab === "Add" ? handleAddChange : handleDeleteChange
}
placeholder="0"
className="w-full bg-transparent outline-none"
inputMode="decimal"
autoComplete="off"
autoCorrect="off"
spellCheck="false"
/>
<p className="text-gray-300 text-xs mt-1.5">
Add: ${Number.isNaN(inputValue) ? 0 : inputValue * priceC}
Expand All @@ -264,7 +380,11 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
<p className="text-base ml-1">{symbolC}</p>
</div>
<p className="text-xs text-gray-300 mt-1.5">
Max Available: <span className="text-white"> ${balance}</span>
Max Available:{" "}
<span className="text-white">
{" "}
${toInternationalCurrencySystem_number(getMaxAvailableAmount() * priceC)}
</span>
</p>
</div>
</div>
Expand Down Expand Up @@ -381,7 +501,7 @@ const ChangeCollateralMobile = ({ open, onClose, rowData, collateralTotal }) =>
<p className="text-xs text-gray-300 mt-1.5">
Max Available:{" "}
<span className="text-white">
${toInternationalCurrencySystem_number(collateralTotal)}
${toInternationalCurrencySystem_number(calculateMaxRemovable() * priceC)}
</span>
</p>
</div>
Expand Down

0 comments on commit a6b4dd1

Please sign in to comment.