Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify confirm stack and orders table #182

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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