Skip to content

Commit 148ee81

Browse files
authored
Polish open and close position modals (#1188)
* Fix gap when using stat without a label * Prevent wrapping by using condensed label * Simplify props to just what's used * Code cleanups * Polish Term Completed badges in close modals * Add docblock
1 parent 7f429c7 commit 148ee81

File tree

7 files changed

+79
-61
lines changed

7 files changed

+79
-61
lines changed

apps/hyperdrive-trading/src/ui/base/components/Stat.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ export function Stat({
2525
"flex w-full items-center whitespace-pre-wrap ease-in-out",
2626
{
2727
"flex-col": !horizontal,
28-
"flex-row-reverse gap-2": horizontal,
28+
"flex-row-reverse": horizontal,
29+
"gap-2": horizontal && label,
2930
"gap-0.5": size === "xsmall",
3031
},
3132
)}

apps/hyperdrive-trading/src/ui/hyperdrive/MaturesOnCell/MaturesOnCell.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export function MaturesOnCell({
1313
const isTermComplete = maturity < (currentBlock?.timestamp || 0n);
1414
const maturityDateMS = maturity * 1000n;
1515

16-
const remainingTime = getRemainingTimeLabel(Number(maturity));
16+
const remainingTime = getRemainingTimeLabel({
17+
maturitySeconds: Number(maturity),
18+
});
1719

1820
return (
1921
<div className="daisy-stat flex flex-row p-0 xl:flex-col">

apps/hyperdrive-trading/src/ui/hyperdrive/getRemainingTimeLabel.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import { calculateTimeLeft } from "src/base/calculateTimeLeft";
22

3-
export function getRemainingTimeLabel(maturitySeconds: number): string {
3+
/**
4+
* @param options.maturitySeconds The timestamp in seconds when time runs out
5+
* @param options.condensed Show condensed labels when showing both hours and minutes
6+
* @returns string
7+
*/
8+
export function getRemainingTimeLabel({
9+
maturitySeconds,
10+
condensed = false,
11+
}: {
12+
maturitySeconds: number;
13+
condensed?: boolean;
14+
}): string {
415
const nowSeconds = Date.now() / 1000;
516
const isTermComplete = maturitySeconds < nowSeconds;
617
const { days, hours, minutes } = calculateTimeLeft(
@@ -16,6 +27,11 @@ export function getRemainingTimeLabel(maturitySeconds: number): string {
1627
return `${days} days left`;
1728
}
1829

30+
// Condensed only needed when showing both hours and minutes.
31+
if (hours > 0 && condensed) {
32+
return `${hours}h ${minutes}m left`;
33+
}
34+
1935
if (hours > 0) {
2036
return `${hours} hours, ${minutes} minutes left`;
2137
}

apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongModalButton/CloseLongModalButton.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Long } from "@delvtech/hyperdrive-viem";
2-
import { XMarkIcon } from "@heroicons/react/24/solid";
2+
import { CheckIcon, XMarkIcon } from "@heroicons/react/24/solid";
33
import {
44
EmptyExtensions,
55
HyperdriveConfig,
@@ -54,14 +54,26 @@ export function CloseLongModalButton({
5454
<div className="mt-5 flex w-full flex-wrap justify-between gap-4">
5555
<div
5656
className={classNames("daisy-badge daisy-badge-lg", {
57-
"text-success": isMature,
57+
"daisy-badge-neutral text-success": isMature,
5858
})}
5959
>
6060
<Stat
6161
horizontal
6262
size="small"
63-
label={isMature ? "" : "Term:"}
64-
value={getRemainingTimeLabel(Number(long.maturity))}
63+
label={isMature ? undefined : "Term:"}
64+
value={
65+
<span
66+
className={classNames("flex items-center", {
67+
"font-normal": isMature,
68+
})}
69+
>
70+
{isMature ? <CheckIcon className="mr-2 h-4" /> : undefined}
71+
{getRemainingTimeLabel({
72+
maturitySeconds: Number(long.maturity),
73+
condensed: true,
74+
})}
75+
</span>
76+
}
6577
/>
6678
</div>
6779
<div className="daisy-badge daisy-badge-lg">

apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongForm/OpenLongForm.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,18 +242,8 @@ export function OpenLongForm({
242242
spotRateAfterOpen={spotRateAfterOpen}
243243
curveFee={curveFee}
244244
activeToken={activeToken}
245-
long={{
246-
bondAmount: bondsReceived || 0n,
247-
assetId: 0n,
248-
baseAmountPaid: depositAmountAsBigInt || 0n,
249-
maturity: BigInt(
250-
Math.round(
251-
(Date.now() +
252-
Number(hyperdrive.poolConfig.positionDuration * 1000n)) /
253-
1000,
254-
),
255-
),
256-
}}
245+
amountPaid={depositAmountAsBigInt || 0n}
246+
bondAmount={bondsReceived || 0n}
257247
openLongPreviewStatus={openLongPreviewStatus}
258248
asBase={activeToken.address === baseToken.address}
259249
vaultSharePrice={poolInfo?.vaultSharePrice}

apps/hyperdrive-trading/src/ui/hyperdrive/longs/OpenLongPreview/OpenLongPreview.tsx

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Long, calculateAprFromPrice } from "@delvtech/hyperdrive-viem";
1+
import { calculateAprFromPrice } from "@delvtech/hyperdrive-viem";
22
import { ArrowRightIcon } from "@heroicons/react/16/solid";
33
import {
44
HyperdriveConfig,
@@ -20,7 +20,8 @@ import { useFixedRate } from "src/ui/hyperdrive/longs/hooks/useFixedRate";
2020

2121
interface OpenLongPreviewProps {
2222
hyperdrive: HyperdriveConfig;
23-
long: Long;
23+
bondAmount: bigint;
24+
amountPaid: bigint;
2425
openLongPreviewStatus: "error" | "idle" | "loading" | "success";
2526
spotRateAfterOpen: bigint | undefined;
2627
activeToken: TokenConfig<any>;
@@ -31,8 +32,9 @@ interface OpenLongPreviewProps {
3132

3233
export function OpenLongPreview({
3334
hyperdrive,
34-
long,
3535
openLongPreviewStatus,
36+
amountPaid,
37+
bondAmount,
3638
spotRateAfterOpen,
3739
activeToken,
3840
curveFee,
@@ -51,14 +53,23 @@ export function OpenLongPreview({
5153
const { fixedApr } = useFixedRate(hyperdrive.address);
5254

5355
const isBaseAmount = asBase || sharesToken.extensions.isSharesPeggedToBase;
56+
const amountPaidInBase = isBaseAmount
57+
? amountPaid
58+
: convertSharesToBase({
59+
sharesAmount: amountPaid,
60+
vaultSharePrice: vaultSharePrice,
61+
decimals: baseToken.decimals,
62+
});
63+
const yieldAtMaturity = bondAmount - amountPaidInBase;
64+
5465
return (
5566
<div className="flex flex-col gap-3.5 px-2">
5667
<div className="flex flex-col gap-3">
5768
<LabelValue
5869
label="You spend"
5970
value={
6071
<span>{`${formatBalance({
61-
balance: long.baseAmountPaid,
72+
balance: amountPaid,
6273
decimals: baseToken.decimals,
6374
places: baseToken.places,
6475
})} ${activeToken.symbol}`}</span>
@@ -71,7 +82,7 @@ export function OpenLongPreview({
7182
<Skeleton width={100} />
7283
) : (
7384
<span className="font-bold">{`${formatBalance({
74-
balance: long.bondAmount,
85+
balance: bondAmount,
7586
decimals: baseToken.decimals,
7687
places: baseToken.places,
7788
})} hy${baseToken.symbol}`}</span>
@@ -109,21 +120,13 @@ export function OpenLongPreview({
109120
className="gradient-text daisy-tooltip daisy-tooltip-top daisy-tooltip-left cursor-help border-b border-dashed border-current before:border"
110121
data-tip="Your net fixed rate after pool fees and slippage are applied."
111122
>
112-
{long.bondAmount > 0
123+
{bondAmount > 0
113124
? `${formatRate(
114125
calculateAprFromPrice({
115126
positionDuration:
116127
hyperdrive.poolConfig.positionDuration || 0n,
117-
baseAmount: isBaseAmount
118-
? long.baseAmountPaid
119-
: // TODO: move sharesAmountPaid into the sdk's Long interface
120-
// instead of converting here
121-
convertSharesToBase({
122-
sharesAmount: long.baseAmountPaid,
123-
vaultSharePrice: vaultSharePrice,
124-
decimals: activeToken.decimals,
125-
}),
126-
bondAmount: long.bondAmount,
128+
baseAmount: amountPaidInBase,
129+
bondAmount: bondAmount,
127130
}),
128131
baseToken.decimals,
129132
)}%`
@@ -142,30 +145,12 @@ export function OpenLongPreview({
142145
className="daisy-tooltip daisy-tooltip-top daisy-tooltip-left cursor-help before:border"
143146
data-tip={`Total ${baseToken.symbol} expected in return at the end of the term, excluding fees.`}
144147
>
145-
{long.bondAmount > 0 ? (
148+
{bondAmount > 0 ? (
146149
<span className="cursor-help border-b border-dashed border-success text-success">
147-
{long.bondAmount -
148-
(isBaseAmount
149-
? long.baseAmountPaid
150-
: convertSharesToBase({
151-
sharesAmount: long.baseAmountPaid,
152-
vaultSharePrice: vaultSharePrice,
153-
decimals: baseToken.decimals,
154-
}))
155-
? "+"
156-
: ""}
157-
{long.baseAmountPaid
150+
{yieldAtMaturity
158151
? // TODO: Add ROI here in parenthesis after the yield amount
159-
`${formatBalance({
160-
balance:
161-
long.bondAmount -
162-
(isBaseAmount
163-
? long.baseAmountPaid
164-
: convertSharesToBase({
165-
sharesAmount: long.baseAmountPaid,
166-
vaultSharePrice: vaultSharePrice,
167-
decimals: baseToken.decimals,
168-
})),
152+
`+${formatBalance({
153+
balance: yieldAtMaturity,
169154
decimals: baseToken.decimals,
170155
places: baseToken.places,
171156
})} ${baseToken.symbol}`

apps/hyperdrive-trading/src/ui/hyperdrive/shorts/CloseShortModalButton/CloseShortModalButton.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { OpenShort } from "@delvtech/hyperdrive-viem";
2-
import { XMarkIcon } from "@heroicons/react/24/solid";
2+
import { CheckIcon, XMarkIcon } from "@heroicons/react/24/solid";
33
import {
44
EmptyExtensions,
55
HyperdriveConfig,
@@ -51,14 +51,26 @@ export function CloseShortModalButton({
5151
<div className="mt-5 flex w-full flex-wrap justify-between gap-4">
5252
<div
5353
className={classNames("daisy-badge daisy-badge-lg", {
54-
"text-success": isMature,
54+
"daisy-badge-neutral text-success": isMature,
5555
})}
5656
>
5757
<Stat
5858
horizontal
5959
size="small"
60-
label={isMature ? "" : "Term:"}
61-
value={getRemainingTimeLabel(Number(short.maturity))}
60+
label={isMature ? undefined : "Term:"}
61+
value={
62+
<span
63+
className={classNames("flex items-center", {
64+
"font-normal": isMature,
65+
})}
66+
>
67+
{isMature ? <CheckIcon className="mr-2 h-4" /> : undefined}
68+
{getRemainingTimeLabel({
69+
maturitySeconds: Number(short.maturity),
70+
condensed: true,
71+
})}
72+
</span>
73+
}
6274
/>
6375
</div>
6476
<div className="daisy-badge daisy-badge-lg">

0 commit comments

Comments
 (0)