diff --git a/src/components/coin-analytics.tsx b/src/components/coin-analytics.tsx index 11caa55..4f7d03f 100644 --- a/src/components/coin-analytics.tsx +++ b/src/components/coin-analytics.tsx @@ -16,6 +16,7 @@ import { appCacheDir as getAppCacheDir } from "@tauri-apps/api/path"; import { useNavigate, useParams } from "react-router-dom"; import { currencyWrapper, + prettyNumberKeepNDigitsAfterDecimalPoint, prettyNumberToLocaleString, prettyPriceNumberToLocaleString, } from "@/utils/currency"; @@ -172,6 +173,11 @@ const App = ({ [currency, profit] ); + const maxPositionStr = useMemo( + () => prettyNumberKeepNDigitsAfterDecimalPoint(maxPosition, 8), + [maxPosition] + ); + const profitRate = useMemo( () => breakevenPrice === 0 @@ -434,9 +440,7 @@ const App = ({

max pos:{" "} - {Number.isInteger(maxPosition) - ? maxPosition - : maxPosition.toFixed(8).replace(/0+$/, "")} + {maxPositionStr}

diff --git a/src/components/comparison/index.tsx b/src/components/comparison.tsx similarity index 50% rename from src/components/comparison/index.tsx rename to src/components/comparison.tsx index 6b04527..cba9173 100644 --- a/src/components/comparison/index.tsx +++ b/src/components/comparison.tsx @@ -1,14 +1,17 @@ -import { useContext, useEffect, useMemo, useState } from "react"; -import "./index.css"; +import { useEffect, useMemo, useState } from "react"; import { CoinData, CurrencyRateDetail } from "@/middlelayers/types"; import { queryAllDataDates, queryCoinDataByUUID } from "@/middlelayers/charts"; import _ from "lodash"; import ViewIcon from "@/assets/icons/view-icon.png"; import HideIcon from "@/assets/icons/hide-icon.png"; -import { currencyWrapper, prettyNumberToLocaleString } from "@/utils/currency"; -import { useWindowSize } from "@/utils/hook"; +import { + currencyWrapper, + prettyNumberKeepNDigitsAfterDecimalPoint, + prettyNumberToLocaleString, + prettyPriceNumberToLocaleString, +} from "@/utils/currency"; import { parseDateToTS } from "@/utils/date"; -import { ButtonGroup, ButtonGroupItem } from "../ui/button-group"; +import { ButtonGroup, ButtonGroupItem } from "./ui/button-group"; import { Select, SelectContent, @@ -17,11 +20,19 @@ import { SelectLabel, SelectTrigger, SelectValue, -} from "../ui/select"; -import { LoadingContext } from '@/App' +} from "./ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "./ui/table"; type ComparisonData = { name: string; + type: "price" | "amount" | "value"; base: number; head: number; }; @@ -29,7 +40,6 @@ type ComparisonData = { type QuickCompareType = "7D" | "1M" | "1Q" | "1Y"; const App = ({ currency }: { currency: CurrencyRateDetail }) => { - const { setLoading } = useContext(LoadingContext); const [baseId, setBaseId] = useState(""); const [dateOptions, setDateOptions] = useState< { @@ -41,8 +51,6 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { const [currentQuickCompare, setCurrentQuickCompare] = useState(null); - const windowSize = useWindowSize(); - const baseDate = useMemo(() => { return _.find(dateOptions, { value: "" + baseId })?.label; }, [dateOptions, baseId]); @@ -56,17 +64,25 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { const [data, setData] = useState([]); - const [showDetail, setShowDetail] = useState(true); - - useEffect(() => { - // it is a hack - setLoading(true) - // sleep 150ms + const [shouldMaskValue, setShowDetail] = useState(false); - setTimeout(() => { - setLoading(false) - }, 150) - },[]) + const displayData = useMemo(() => { + return _(data) + .map((d) => ({ + name: d.name, + type: d.type, + base: showColumnVal(d, "base"), + head: showColumnVal(d, "head"), + cmp: prettyComparisonResult(d.base, d.head), + color: + prettyComparisonResult(d.base, d.head) === "-" + ? "black" + : getComparisonResultNumber(d.base, d.head) > 0 + ? "green" + : "red", + })) + .value(); + }, [data, shouldMaskValue]); useEffect(() => { loadAllSelectDates().then((data) => { @@ -99,14 +115,14 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { if (!baseId) { return; } - loadDataByUUID(baseId).then((data) => setBaseData(data)) + loadDataByUUID(baseId).then((data) => setBaseData(data)); }, [baseId]); useEffect(() => { if (!headId) { return; } - loadDataByUUID(headId).then((data) => setHeadData(data)) + loadDataByUUID(headId).then((data) => setHeadData(data)); }, [headId]); // update quick compare data ( baseId and headId ) @@ -182,7 +198,7 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { } function onViewOrHideClick() { - setShowDetail(!showDetail); + setShowDetail(!shouldMaskValue); } function loadData(base: CoinData[], head: CoinData[]): ComparisonData[] { @@ -192,26 +208,13 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { .uniq() .value(); - const others = "Others"; - - // add others to last - symbols.sort((a, b) => { - if (a === others) { - return 1; - } - if (b === others) { - return -1; - } - // origin order - return 0; - }); - // make total value and amount as the first two items const baseTotal = _(base).sumBy("value"); const headTotal = _(head).sumBy("value"); if (!_(symbols).isEmpty()) { res.push({ name: "Total Value", + type: "value", base: baseTotal, head: headTotal, }); @@ -221,33 +224,31 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { const baseItem = _.find(base, { symbol }); const headItem = _.find(head, { symbol }); - res.push({ - name: symbol + " Value", - base: baseItem?.value || 0, - head: headItem?.value || 0, - }); - - if (symbol === others) { - return; - } - res.push({ name: symbol + " Amount", + type: "amount", base: baseItem?.amount || 0, head: headItem?.amount || 0, }); res.push({ name: symbol + " Price", + type: "price", base: baseItem?.price || 0, head: headItem?.price || 0, }); + + res.push({ + name: symbol + " Value", + type: "value", + base: baseItem?.value || 0, + head: headItem?.value || 0, + }); }); return res; } async function loadDataByUUID(uuid: string): Promise { - // return queryCoinDataById(id); const data = await queryCoinDataByUUID(uuid); const reversedData = _(data).sortBy("value").reverse().value(); @@ -263,25 +264,26 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { function prettyComparisonResult(base: number, head: number): string { const per = getComparisonResultNumber(base, head); + const perStr = prettyNumberToLocaleString(per < 0 ? -per : per); - if (per === 0) { + if (perStr === "0.00" || perStr === "-0.00") { return "-"; } if (per > 0) { - return "↑ " + prettyNumber(per, false) + "%"; + return "↑ " + perStr + "%"; } - return "↓ " + -prettyNumber(per, false) + "%"; + return "↓ " + perStr + "%"; } function prettyNumber( number: number, - keepDecimal: boolean, - showRealNumber = true, + type: "price" | "amount" | "value", + shouldMask = false, convertCurrency = false ): string { - if (!showRealNumber) { + if (shouldMask) { return "***"; } if (!number) { @@ -292,7 +294,11 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { convertedNumber = currencyWrapper(currency)(number); } let res = "" + convertedNumber; - if (!keepDecimal) { + if (type === "price") { + res = prettyPriceNumberToLocaleString(convertedNumber); + } else if (type === "amount") { + res = prettyNumberKeepNDigitsAfterDecimalPoint(convertedNumber, 8); + } else if (type === "value") { res = prettyNumberToLocaleString(convertedNumber); } if (convertCurrency) { @@ -305,12 +311,14 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { item: ComparisonData, valType: "base" | "head" ): string { + const shouldMask = shouldMaskValue && item.type !== "price"; + const shouldConvertCurrency = + item.type === "price" || item.type === "value"; return prettyNumber( _(item).get(valType), - item.name.includes("Amount") || item.name.includes("Price"), - // don't hide price - showDetail || item.name.includes("Price"), - item.name.includes("Price") || item.name.includes("Value") + item.type, + shouldMask, + shouldConvertCurrency ); } @@ -320,143 +328,101 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => { return ( <> -
-
-
-
- - view-or-hide - -
-
- Quick Compare -
- - onQuickCompareButtonClick(val as QuickCompareType) - } - > - 7D - 1M - 1Q - 1Y - -
-
-
-
- +
+
+ -
- +
+ Quick Compare
-
- {_(data).isEmpty() ? ( - "No Data" - ) : ( -
+ onQuickCompareButtonClick(val as QuickCompareType) + } > -
- Name -
-
{baseDate}
-
- Difference -
-
{headDate}
-
+ 7D + 1M + 1Q + 1Y + +
+
+
+
+ +
+
+ +
+
+
+ {displayData.length === 0 && ( +
No Data
+ )} + {displayData.length > 0 && ( + + + + Name + {baseDate} + Difference + {headDate} + + + + {displayData.map((item, index) => ( + + {item.name} + {item.base} + + {item.cmp} + + {item.head} + + ))} + +
)} - {data.map((item, index) => ( -
-
- {item.name} -
-
- {showColumnVal(item, "base")} -
-
0 - ? "green" - : "red", - maxWidth: "200px", - }} - title={prettyComparisonResult(item.base, item.head)} - > - {prettyComparisonResult(item.base, item.head)} -
-
- {showColumnVal(item, "head")} -
-
- ))}
); diff --git a/src/components/comparison/index.css b/src/components/comparison/index.css deleted file mode 100644 index b9499e7..0000000 --- a/src/components/comparison/index.css +++ /dev/null @@ -1,46 +0,0 @@ -.comparison-container { - width: 80%; - margin-left: auto; - margin-right: auto; - white-space: nowrap; - font-family: Arial, sans-serif; -} - -.comparison-container .comparison-date-picker { - height: 50px; -} - -.comparison-container .comparison-date-picker .comparison-date-picker-item { - display: inline-block; - width: 50%; -} - -.comparison-container .comparison-row { - height: 30px; - margin-bottom: 10px; - font-size: 14px; -} - -.comparison-container .comparison-row:nth-child(3n + 2) { - background-color: #e6e6e6; -} - -.comparison-container .comparison-row:last-child { - margin-bottom: 0; -} - -.comparison-container .comparison-row .comparison-column { - display: inline-block; - width: 24%; - padding: 5px; - margin-right: 10px; - border-radius: 5px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - box-sizing: border-box; -} - -.comparison-container .comparison-row .comparison-column:last-child { - margin-right: 0; -} diff --git a/src/utils/currency.ts b/src/utils/currency.ts index a9b8d8b..5ae65d8 100644 --- a/src/utils/currency.ts +++ b/src/utils/currency.ts @@ -13,6 +13,16 @@ export function prettyNumberToLocaleString(value: number) { }) } +// keep n digits after decimal point +// 1 => 1 +// 1.23456 => 1.234 +// 1.23000 => 1.23 +export function prettyNumberKeepNDigitsAfterDecimalPoint(value: number, keep: number) { + return Number.isInteger(value) + ? "" + value + : value.toFixed(keep).replace(/0+$/, "") +} + // pretty to show price, if price >= 1, keep 3 digits after decimal point export function prettyPriceNumberToLocaleString(value: number) { if (value >= 1) {