Skip to content

Commit

Permalink
Simplify confirm stack (#182)
Browse files Browse the repository at this point in the history
* - simplify confirm modal

* - show TX instead of transaction on orders table on mobile

* - rename StackInfo to StackDigest
- Move StackDigest above orders

* refactor StackModal
- extract StackFrequencyAndDates
- Rename StackOrdersProgress and move related orders componentd there

* update github action node, bun versions
  • Loading branch information
Diogomartf authored Jun 12, 2024
1 parent e05298d commit 7588fc2
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 113 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🧑🏻‍💻 Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: 🥷 Setup node and bun
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 21.1.0
- uses: oven-sh/setup-bun@v1
with:
node-version: lts/hydrogen
check-latest: true

bun-version: latest
- name: 🎪 Install dependencies
run: bun install --immutable

Expand Down
54 changes: 54 additions & 0 deletions packages/app/components/stack-modal/StackFrequencyAndDates.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
StackOrderProps,
stackIsComplete,
stackIsFinishedWithFunds,
totalOrderSlotsDone,
} from "@/models";
import { BodyText } from "@/ui";
import { formatFrequencyHours, formatTimestampToDateWithTime } from "@/utils";
import { ReactNode } from "react";

const StackDetail = ({
title,
children,
}: {
title: string;
children: ReactNode;
}) => (
<div className="space-y-1">
<BodyText size={1} className="text-em-low">
{title}
</BodyText>
<BodyText size={1}>{children}</BodyText>
</div>
);

export const StackFrequencyAndDates = ({ stackOrder }: StackOrderProps) => {
const orderSlots = stackOrder.orderSlots;
const firstSlot = orderSlots[0];
const lastSlot = orderSlots[orderSlots.length - 1];
const nextSlot = orderSlots[totalOrderSlotsDone(stackOrder)];

return (
<div className="grid grid-cols-2 gap-5 px-4 md:px-6 gap-x-8 md:grid-cols-4">
<StackDetail title="Starts on">
{formatTimestampToDateWithTime(firstSlot)}
</StackDetail>
<StackDetail title="Ends on">
{formatTimestampToDateWithTime(lastSlot)}
</StackDetail>
<StackDetail title="Frequency">
Every {formatFrequencyHours(Number(stackOrder.interval))}
</StackDetail>
<StackDetail title="Next order">
{stackIsComplete(stackOrder)
? "Complete"
: stackIsFinishedWithFunds(stackOrder)
? "Finished with funds"
: stackOrder.cancelledAt
? "Cancelled"
: formatTimestampToDateWithTime(nextSlot)}
</StackDetail>
</div>
);
};
123 changes: 42 additions & 81 deletions packages/app/components/stack-modal/StackModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import Link from "next/link";
import { ReactNode, useState } from "react";
import { useState } from "react";
import { cx } from "class-variance-authority";

import { orderPairSymbolsText, totalOrderSlotsDone } from "@/models/order";
import { orderPairSymbolsText } from "@/models/order";
import {
Modal,
ModalFooter,
Expand All @@ -13,40 +13,40 @@ import {
ModalContent,
BodyText,
ModalHeader,
TitleText,
ModalBaseProps,
DialogContent,
DialogFooterActions,
Dialog,
} from "@/ui";
import {
formatFrequencyHours,
formatTimestampToDateWithTime,
} from "@/utils/datetime";

import {
StackOrder,
StackOrderProps,
calculateStackAveragePrice,
totalStackOrdersDone,
totalStacked,
totalFundsUsed,
stackIsFinishedWithFunds,
stackIsComplete,
stackRemainingFunds,
} from "@/models/stack-order";
import { formatTokenValue } from "@/utils/token";
import { getDCAOrderContract } from "@stackly/sdk";
import { getExplorerLink } from "@/utils/transaction";
import { useEthersSigner } from "@/utils/ethers";

import {
DialogConfirmTransactionLoading,
FromToStackTokenPair,
TokenLogoPair,
TransactionLink,
} from "@/components";
import { StackProgress } from "@/components/stack-modal/StackProgress";
import { StackOrdersTable } from "@/components/stack-modal/StackOrdersTable";

import { StackOrdersProgress } from "@/components/stack-modal/StackOrdersProgress";
import { StackFrequencyAndDates } from "@/components/stack-modal/StackFrequencyAndDates";

import { formatTokenValue } from "@/utils/token";
import { getDCAOrderContract } from "@stackly/sdk";
import { getExplorerLink } from "@/utils/transaction";
import { useEthersSigner } from "@/utils/ethers";

import { ModalId, useModalContext, useNetworkContext } from "@/contexts";
import { TransactionLink } from "./TransactionLink";

import { Transaction } from "@/models/stack";

interface StackModalProps extends ModalBaseProps {
Expand Down Expand Up @@ -75,11 +75,6 @@ export const StackModal = ({

const [cancellationTx, setCancellationTx] = useState<Transaction>();

const orderSlots = stackOrder.orderSlots;
const firstSlot = orderSlots[0];
const lastSlot = orderSlots[orderSlots.length - 1];
const nextSlot = orderSlots[totalOrderSlotsDone(stackOrder)];

const stackRemainingFundsWithTokenText = `${stackRemainingFunds(
stackOrder
)} ${stackOrder.sellToken.symbol}`;
Expand Down Expand Up @@ -183,43 +178,15 @@ export const StackModal = ({
</div>
</ModalHeader>
<ModalContent className="px-0 space-y-4 md:px-0">
<div className="grid grid-cols-2 gap-5 px-4 md:px-6 gap-x-8 md:grid-cols-4">
<StackDetail title="Starts on">
{formatTimestampToDateWithTime(firstSlot)}
</StackDetail>
<StackDetail title="Ends on">
{formatTimestampToDateWithTime(lastSlot)}
</StackDetail>
<StackDetail title="Frequency">
Every {formatFrequencyHours(Number(stackOrder.interval))}
</StackDetail>
<StackDetail title="Next order">
{stackIsComplete(stackOrder)
? "Complete"
: stackIsFinishedWithFunds(stackOrder)
? "Finished with funds"
: stackOrder.cancelledAt
? "Cancelled"
: formatTimestampToDateWithTime(nextSlot)}
</StackDetail>
</div>
<StackFrequencyAndDates stackOrder={stackOrder} />
<div className="w-full my-4 border-b border-surface-50"></div>
{stackIsFinishedWithFunds(stackOrder) && (
<div className="px-4 md:px-6">
<HasRemainingFundsAlertMessage
remainingFundsWithSymbol={stackRemainingFundsWithTokenText}
/>
</div>
)}
<WarningHasRemainingFunds
stackOrder={stackOrder}
stackRemainingFundsWithTokenText={stackRemainingFundsWithTokenText}
/>
<div className="px-4 space-y-4 md:px-6">
<TitleText size={2} weight="bold">
Orders
</TitleText>
<StackProgress stackOrder={stackOrder} />
<StackInfo stackOrder={stackOrder} />
{totalStackOrdersDone(stackOrder) > 0 && (
<StackOrdersTable stackOrder={stackOrder} />
)}
<StackDigest stackOrder={stackOrder} />
<StackOrdersProgress stackOrder={stackOrder} />
</div>
</ModalContent>
<ModalFooter
Expand Down Expand Up @@ -289,7 +256,7 @@ export const StackModal = ({
);
};

const StackInfo = ({ stackOrder }: StackOrderProps) => (
const StackDigest = ({ stackOrder }: StackOrderProps) => (
<div className="flex flex-col justify-between gap-2 px-4 py-3 md:px-6 md:items-center md:flex-row bg-surface-25 rounded-2xl">
<FromToStackTokenPair
fromToken={stackOrder.sellToken}
Expand All @@ -307,29 +274,23 @@ const StackInfo = ({ stackOrder }: StackOrderProps) => (
</div>
);

const HasRemainingFundsAlertMessage = ({
remainingFundsWithSymbol,
}: {
remainingFundsWithSymbol: string;
}) => (
<div className="p-3 text-center rounded-lg bg-danger-75">
<BodyText className="text-em-med">
This contract has {remainingFundsWithSymbol} remaining funds.
</BodyText>
</div>
);
interface WarningHasRemainingFundsProps extends StackOrderProps {
stackRemainingFundsWithTokenText: string;
}

const StackDetail = ({
title,
children,
}: {
title: string;
children: ReactNode;
}) => (
<div className="space-y-1">
<BodyText size={1} className="text-em-low">
{title}
</BodyText>
<BodyText size={1}>{children}</BodyText>
</div>
);
const WarningHasRemainingFunds = ({
stackOrder,
stackRemainingFundsWithTokenText,
}: WarningHasRemainingFundsProps) => {
if (!stackIsFinishedWithFunds(stackOrder)) return;

return (
<div className="px-4 md:px-6">
<div className="p-3 text-center rounded-lg bg-danger-75">
<BodyText className="text-em-med">
This contract has {stackRemainingFundsWithTokenText} remaining funds.
</BodyText>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
totalOrderSlotsDone,
} from "@/models/order";
import { OrdersProgressBar } from "@/components/OrdersProgressBar";
import { BodyText } from "@/ui";
import { BodyText, TitleText } from "@/ui";
import { TokenIcon } from "@/components/TokenIcon";
import {
StackOrderProps,
Expand All @@ -14,26 +14,37 @@ import {
stackIsComplete,
} from "@/models/stack-order";
import { formatTokenValue } from "@/utils/token";
import { StackOrdersTable } from "@/components/stack-modal/StackOrdersTable";

export const StackProgress = ({ stackOrder }: StackOrderProps) => (
<div className="space-y-2">
<div className="flex flex-col justify-between space-y-1 md:space-y-0 md:items-center md:flex-row">
<OrdersExecuted stackOrder={stackOrder} />
<div className="flex items-center space-x-1">
<BodyText size="responsive" className="text-em-low">
Total funds used:{" "}
<span className="text-em-high">
{formatTokenValue(totalFundsUsed(stackOrder), 2)}{" "}
<span className="text-xs">of</span>{" "}
{totalFundsAmountWithTokenText(stackOrder)}
</span>
</BodyText>
<TokenIcon size="xs" token={stackOrder.sellToken} />
export const StackOrdersProgress = ({ stackOrder }: StackOrderProps) => (
<>
<div>
<TitleText size={2} weight="bold" className="mb-2">
Orders
</TitleText>
<div className="space-y-2">
<div className="flex flex-col justify-between space-y-1 md:space-y-0 md:items-center md:flex-row">
<OrdersExecuted stackOrder={stackOrder} />
<div className="flex items-center space-x-1">
<BodyText size="responsive" className="text-em-low">
Total funds used:{" "}
<span className="text-em-high">
{formatTokenValue(totalFundsUsed(stackOrder), 2)}{" "}
<span className="text-xs">of</span>{" "}
{totalFundsAmountWithTokenText(stackOrder)}
</span>
</BodyText>
<TokenIcon size="xs" token={stackOrder.sellToken} />
</div>
</div>
<OrdersProgressBar stackOrder={stackOrder} />
<TotalStackEstimationText stackOrder={stackOrder} />
</div>
</div>
<OrdersProgressBar stackOrder={stackOrder} />
<TotalStackEstimationText stackOrder={stackOrder} />
</div>
{totalStackOrdersDone(stackOrder) > 0 && (
<StackOrdersTable stackOrder={stackOrder} />
)}
</>
);

const TotalStackEstimationText = ({ stackOrder }: StackOrderProps) => {
Expand Down
12 changes: 10 additions & 2 deletions packages/app/components/stack-modal/StackOrdersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ export const StackOrdersTable = ({ stackOrder }: StackOrderProps) => {
<TableHeader>
<TableRow>
<TableHead className="py-1 md:table-cell">
<BodyText size={1}>Transaction</BodyText>
<BodyText size={1}>
<span className="hidden md:inline-block">Transaction</span>
<span className="md:hidden">Tx</span>
</BodyText>
</TableHead>
<TableHead>
<BodyText size={1}>Time</BodyText>
Expand Down Expand Up @@ -127,7 +130,12 @@ const TableCowBody = ({
target="_blank"
href={cowExplorerUrl(chainId, cowOrder.uid)}
>
{addressShortner(cowOrder.uid)}
<span className="md:hidden">
{addressShortner(cowOrder.uid, 2)}
</span>
<span className="hidden md:inline-block">
{addressShortner(cowOrder.uid)}
</span>
</Link>
</BodyText>
</TableCell>
Expand Down
11 changes: 6 additions & 5 deletions packages/app/components/stackbox/ConfirmStackModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ export const ConfirmStackModal = ({
<span className="text-em-high">
{amountPerOrder} {fromToken.symbol}
</span>
, every {FREQUENCY_OPTIONS[frequency]}
<br />
<span className="text-em-high">
every {FREQUENCY_OPTIONS[frequency]}
</span>
</TitleText>
</div>
<div className="w-full p-5 space-y-2 bg-surface-25 rounded-xl">
Expand All @@ -220,15 +223,13 @@ export const ConfirmStackModal = ({
<BodyText>{format(endTime, "dd MMM yy, HH:mm")}</BodyText>
</div>
<div className="flex items-center justify-between">
<BodyText className="text-em-med">
Total funds to be used
</BodyText>
<BodyText className="text-em-med">Total funds</BodyText>
<BodyText className="text-end">
{amount} {fromToken.symbol}
</BodyText>
</div>
<div className="flex items-center justify-between">
<BodyText className="text-em-med">Stack fee</BodyText>
<BodyText className="text-em-med">Fee</BodyText>
<BodyText>0.25%</BodyText>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions packages/app/utils/token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const addressShortner = (address: string) =>
address.slice(0, 4) + "..." + address.slice(-4);
export const addressShortner = (address: string, elements: number = 4) =>
address.slice(0, elements) + "..." + address.slice(-elements);

export const formatTokenValue = (
value: number | string,
Expand Down

0 comments on commit 7588fc2

Please sign in to comment.