Skip to content

Commit

Permalink
Merge branch 'main' into ECO-2195
Browse files Browse the repository at this point in the history
  • Loading branch information
xbtmatt authored Dec 4, 2024
2 parents f4266b9 + ca5b6ba commit a9370c5
Show file tree
Hide file tree
Showing 17 changed files with 242 additions and 153 deletions.
1 change: 1 addition & 0 deletions cfg/cspell-frontend-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ dockerenv
testid
ADBEEF
bytea
nominalize
98 changes: 98 additions & 0 deletions src/typescript/frontend/src/components/FormattedNumber.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { AnyNumberString } from "@sdk-types";
import { useLabelScrambler } from "./pages/home/components/table-card/animation-variants/event-variants";
import { toNominal } from "lib/utils/decimals";
import { useEffect, useMemo } from "react";

/**
* Sliding precision will show `decimals` decimals when Math.abs(number) is
* above 1 and `decimals` significant digits when the number is below 1.
*
* Fixed will always show `decimals` digits.
*/
export type FormattedNumberStyle = "sliding-precision" | "fixed";

const ScrambledNumberLabel = ({
value,
suffix = "",
prefix = "",
className = "",
}: {
value: string;
suffix?: string;
prefix?: string;
className?: string;
}) => {
const { ref, replay } = useLabelScrambler(value, suffix, prefix);
useEffect(() => {
replay();
}, [value, replay]);
return <span className={className} ref={ref}>{`${prefix}${value}${suffix}`}</span>;
};

/**
* Formats a number, string or bigint and scrambles it if desired.
*
* @param value the number to format and display
* @param decimals the number of decimals to show
* @param scramble whether or not to scramble the text upon change
* @param suffix the suffix that shouldn't be scrambled, if the value is scrambled
* @param prefix the prefix that shouldn't be scrambled, if the value is scrambled
* @param className the class name for the span wrapping the value
* @param style the formatter style
* @see {@link FormattedNumberStyle}
* @returns a component for the formatted number
*/
export const FormattedNumber = ({
value,
decimals = 2,
scramble = false,
nominalize = false,
suffix = "",
prefix = "",
className,
style = "sliding-precision",
}: (
| {
value: bigint;
nominalize: true;
}
| {
value: AnyNumberString;
nominalize?: undefined | false;
}
) & {
decimals?: number;
scramble?: boolean;
suffix?: string;
prefix?: string;
className?: string;
style?: FormattedNumberStyle;
}) => {
const displayValue = useMemo(() => {
if (nominalize && typeof value !== "bigint") {
throw new Error("Input value needs to be a bigint.");
}
const num = nominalize ? toNominal(value as bigint) : Number(value);
const format =
style === "fixed" || Math.abs(num) >= 1
? { maximumFractionDigits: decimals }
: { maximumSignificantDigits: decimals };
const formatter = new Intl.NumberFormat("en-US", format);
return formatter.format(num);
}, [value, decimals, nominalize, style]);

return scramble ? (
<ScrambledNumberLabel
value={displayValue}
prefix={prefix}
suffix={suffix}
className={className}
/>
) : (
<span className={className}>
{prefix}
{displayValue}
{suffix}
</span>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import React, { useEffect, useState } from "react";
import { translationFunction } from "context/language-context";
import { type MainInfoProps } from "../../types";
import { useEventStore } from "context/event-store-context";
import { useLabelScrambler } from "components/pages/home/components/table-card/animation-variants/event-variants";
import { motion } from "framer-motion";
import { getBondingCurveProgress } from "utils/bonding-curve";
import Button from "components/button";
import Link from "next/link";
import { ROUTES } from "router/routes";
import { useThemeContext } from "context";
import { FormattedNumber } from "components/FormattedNumber";

const statsTextClasses = "uppercase ellipses font-forma text-[24px]";

Expand All @@ -32,22 +32,20 @@ const BondingProgress = ({ data }: MainInfoProps) => {
}
}, [stateEvents]);

const { ref: bondingCurveRef } = useLabelScrambler(`${bondingProgress.toFixed(2)}`, "%");

return (
<div className="flex flex-col w-fit">
<div className="flex justify-between gap-[8px] mb-[.2em]">
<div className={statsTextClasses + " text-light-gray font-pixelar text-[32px]"}>
{t("Bonding progress:")}
</div>
<div className={statsTextClasses + " text-white"}>
<div
className="text-ec-blue font-pixelar text-[32px] text-end min-w-[3.5em]"
ref={bondingCurveRef}
>
{bondingProgress.toFixed(2)}%
</div>
</div>
<FormattedNumber
value={bondingProgress}
className={
statsTextClasses + " text-ec-blue font-pixelar text-[32px] text-end min-w-[3.5em]"
}
suffix="%"
scramble
/>
</div>
{bondingProgress >= 100 ? (
<Link
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, { useEffect, useState } from "react";

import { translationFunction } from "context/language-context";
import { toCoinDecimalString } from "lib/utils/decimals";
import AptosIconBlack from "components/svg/icons/AptosBlack";
import { type MainInfoProps } from "../../types";
import { useEventStore } from "context/event-store-context";
import { useLabelScrambler } from "components/pages/home/components/table-card/animation-variants/event-variants";
import { isMarketStateModel } from "@sdk/indexer-v2/types";
import BondingProgress from "./BondingProgress";
import { useThemeContext } from "context";
Expand All @@ -16,6 +14,7 @@ import { toExplorerLink } from "lib/utils/explorer-link";
import { emoji } from "utils";
import { motion } from "framer-motion";
import { truncateAddress } from "@sdk/utils";
import { FormattedNumber } from "components/FormattedNumber";

const statsTextClasses = "uppercase ellipses font-forma text-[24px]";

Expand Down Expand Up @@ -44,10 +43,6 @@ const MainInfo = ({ data }: MainInfoProps) => {
}
}, [stateEvents]);

const { ref: marketCapRef } = useLabelScrambler(toCoinDecimalString(marketCap, 2));
const { ref: dailyVolumeRef } = useLabelScrambler(toCoinDecimalString(dailyVolume, 2));
const { ref: allTimeVolumeRef } = useLabelScrambler(toCoinDecimalString(allTimeVolume, 2));

const { isMobile } = useMatchBreakpoints();

const explorerLink = toExplorerLink({
Expand Down Expand Up @@ -118,7 +113,7 @@ const MainInfo = ({ data }: MainInfoProps) => {
<div className={statsTextClasses + " text-light-gray"}>{t("Market Cap:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
<div ref={marketCapRef}>{toCoinDecimalString(marketCap, 2)}</div>
<FormattedNumber value={marketCap} nominalize scramble />
&nbsp;
<AptosIconBlack className="icon-inline mb-[0.3ch]" />
</div>
Expand All @@ -129,7 +124,7 @@ const MainInfo = ({ data }: MainInfoProps) => {
<div className={statsTextClasses + " text-light-gray"}>{t("24 hour vol:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
<div ref={dailyVolumeRef}>{toCoinDecimalString(dailyVolume, 2)}</div>
<FormattedNumber value={dailyVolume} nominalize scramble />
&nbsp;
<AptosIconBlack className="icon-inline mb-[0.3ch]" />
</div>
Expand All @@ -140,7 +135,7 @@ const MainInfo = ({ data }: MainInfoProps) => {
<div className={statsTextClasses + " text-light-gray"}>{t("All-time vol:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
<div ref={allTimeVolumeRef}>{toCoinDecimalString(allTimeVolume, 2)}</div>
<FormattedNumber value={allTimeVolume} nominalize scramble />
&nbsp;
<AptosIconBlack className="icon-inline mb-[0.3ch]" />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Column, Row } from "components/layout/components/FlexContainers";
import { SwapButton } from "./SwapButton";
import { type SwapComponentProps } from "components/pages/emojicoin/types";
import { toActualCoinDecimals, toDisplayCoinDecimals } from "lib/utils/decimals";
import { useScramble } from "use-scramble";
import { DEFAULT_SWAP_GAS_COST, useGetGasWithDefault } from "lib/hooks/queries/use-simulate-swap";
import { useEventStore } from "context/event-store-context";
import { useTooltip } from "@hooks/index";
Expand All @@ -26,6 +25,7 @@ import { getMaxSlippageSettings } from "utils/slippage";
import { Emoji } from "utils/emoji";
import { EmojiPill } from "components/EmojiPill";
import { useCalculateSwapPrice } from "lib/hooks/use-calculate-swap-price";
import { FormattedNumber } from "components/FormattedNumber";

const SimulateInputsWrapper = ({ children }: PropsWithChildren) => (
<div className="flex flex-col relative gap-[19px]">{children}</div>
Expand Down Expand Up @@ -106,30 +106,11 @@ export default function SwapComponent({
setEmojicoinType(emojicoinType);
}, [marketAddress, setEmojicoinType]);

const outputAmountString = toDisplayCoinDecimals({
num: isLoading ? previous : outputAmount,
decimals: OUTPUT_DISPLAY_DECIMALS,
});

const availableAptBalance = useMemo(
() => (aptBalance - gasCost > 0 ? aptBalance - gasCost : 0n),
[gasCost, aptBalance]
);

const { ref, replay } = useScramble({
text: new Intl.NumberFormat().format(Number(outputAmountString)),
overdrive: false,
overflow: true,
speed: isLoading ? 0.4 : 1000,
scramble: isLoading ? 5 : 0,
range: [48, 58],
playOnMount: false,
});

useEffect(() => {
replay();
}, [isLoading, replay]);

useEffect(() => {
if (netProceeds === 0n || error) {
setIsLoading(true);
Expand All @@ -138,8 +119,7 @@ export default function SwapComponent({
setPrevious(netProceeds);
setOutputAmount(netProceeds);
setIsLoading(false);
replay();
}, [netProceeds, replay, isSell, error]);
}, [netProceeds, isSell, error]);

const sufficientBalance = useMemo(() => {
if (!account || (isSell && !emojicoinBalance) || (!isSell && !aptBalance)) return false;
Expand Down Expand Up @@ -264,9 +244,8 @@ export default function SwapComponent({
<FlipInputsArrow
onClick={() => {
setInputAmount(outputAmount);
// This is done as to not display an old value if the swap simulation fails.
setOutputAmount(0n);
setPrevious(0n);
setOutputAmount(inputAmount);
setPrevious(inputAmount);
setIsSell((v) => !v);
}}
/>
Expand All @@ -281,7 +260,12 @@ export default function SwapComponent({
style={{ opacity: isLoading ? 0.6 : 1 }}
>
{/* Scrambled swap result output below. */}
<div ref={ref}></div>
<FormattedNumber
value={isLoading ? previous : outputAmount}
nominalize
scramble
decimals={OUTPUT_DISPLAY_DECIMALS}
/>
</div>
</div>
</Column>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ const toTableItem = ({
}: SwapEventModel & { shouldAnimateAsInsertion?: boolean }) => ({
item: {
...getRankFromEvent(swap),
apt: swap.quoteVolume.toString(),
emoji: swap.baseVolume.toString(),
apt: swap.quoteVolume,
emoji: swap.baseVolume,
date: new Date(Number(transaction.time / 1000n)),
type: swap.isSell ? "sell" : "buy",
priceQ64: swap.avgExecutionPriceQ64.toString(),
priceQ64: swap.avgExecutionPriceQ64,
swapper: swap.swapper,
version: transaction.version.toString(),
version: transaction.version,
},
shouldAnimateAsInsertion,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import React, { useMemo, type PropsWithChildren } from "react";
import { type TableRowDesktopProps } from "./types";
import { toCoinDecimalString } from "lib/utils/decimals";
import { toNominalPrice } from "@sdk/utils/nominal-price";
import { ExplorerLink } from "components/link/component";
import { darkColors } from "theme";
Expand All @@ -12,6 +11,7 @@ import { motion } from "framer-motion";
import { emoji } from "utils";
import { Emoji } from "utils/emoji";
import { useNameResolver } from "@hooks/use-name-resolver";
import { FormattedNumber } from "components/FormattedNumber";

type TableRowTextItemProps = {
className: string;
Expand Down Expand Up @@ -99,10 +99,10 @@ const TableRow = ({
</td>
<td className={`w-[5%] md:w-[4.7%] ${Height}`}></td>
<TableRowTextItem className={`w-[22%] md:w-[18%] ${Height}`}>
<span className="ellipses">{toCoinDecimalString(item.apt, 3)}</span>
<FormattedNumber value={item.apt} className="ellipses" decimals={3} nominalize />
</TableRowTextItem>
<TableRowTextItem className={`w-[22%] md:w-[18%] ${Height}`}>
<span className="ellipses">{toCoinDecimalString(item.emoji, 3)}</span>
<FormattedNumber value={item.emoji} className="ellipses" decimals={3} nominalize />
</TableRowTextItem>
<td className={`w-[0%] md:w-[0.3%] ${Height}`}></td>
<TableRowTextItem
Expand All @@ -120,7 +120,12 @@ const TableRow = ({
className={`w-[22%] md:w-[18%] ${Height} md:ml-[3ch] xl:ml-[0.5ch] xl:mr-[-0.5ch]`}
color={item.type === "sell" ? darkColors.pink : darkColors.green}
>
{toNominalPrice(item.priceQ64).toFixed(9)}
<FormattedNumber
value={toNominalPrice(item.priceQ64)}
className="ellipses"
decimals={9}
style="fixed"
/>
</TableRowTextItem>
<td className={`group/explorer w-[22%] md:w-[18%] border-r-[1px] z-[2] ${Height}`}>
<ExplorerLink className="flex w-full h-full" value={item.version} type="txn">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ export type TableRowDesktopProps = {
item: {
rankIcon: string;
rankName: string;
apt: string;
emoji: string;
apt: bigint;
emoji: bigint;
type: string;
priceQ64: string;
priceQ64: bigint;
date: Date;
version: AnyNumberString;
swapper: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const marketDataToProps = (markets: HomePageProps["markets"]): PropsWithT
symbol: m.market.symbolData.symbol,
marketID: Number(m.market.marketID),
emojis: m.market.emojis,
staticMarketCap: m.state.instantaneousStats.marketCap.toString(),
staticVolume24H: m.dailyVolume.toString(),
staticMarketCap: m.state.instantaneousStats.marketCap,
staticVolume24H: m.dailyVolume,
}));

export const stateEventsToProps = (
Expand All @@ -47,8 +47,8 @@ export const stateEventsToProps = (
symbol,
emojis,
marketID: Number(marketID),
staticMarketCap: marketCap.toString(),
staticVolume24H: (volume24H ?? 0).toString(),
staticMarketCap: marketCap,
staticVolume24H: volume24H ?? 0n,
trigger: e.market.trigger,
searchEmojisKey: toSearchEmojisKey(searchEmojis),
};
Expand Down
Loading

0 comments on commit a9370c5

Please sign in to comment.