Skip to content

Commit

Permalink
Merge branch 'rc-1.17.0' into refactor/adjust-delegate-registration-form
Browse files Browse the repository at this point in the history
  • Loading branch information
shahin-hq authored Oct 23, 2024
2 parents c70e22a + 2bf0e7b commit 8e49385
Show file tree
Hide file tree
Showing 23 changed files with 639 additions and 354 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arkvault",
"version": "1.15.0",
"version": "1.17.0",
"engines": {
"node": ">=20.12.2"
},
Expand Down
55 changes: 48 additions & 7 deletions src/app/components/MultiEntryItem/MultiEntryItem.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
import React, { ReactNode } from "react";
import cn from "classnames";

interface Properties {
titleSlot?: ReactNode;
bodySlot?: ReactNode;
rightSlot?: ReactNode;
dataTestId?: string;
size?: "sm" | "md";
}

export const MultiEntryItem = ({ titleSlot, bodySlot, rightSlot, dataTestId }: Properties): JSX.Element => (
export const MultiEntryItem = ({
titleSlot,
bodySlot,
rightSlot,
dataTestId,
size = "sm",
}: Properties): JSX.Element => (
<div
data-testid={dataTestId}
className="mb-3 overflow-hidden rounded border border-theme-secondary-300 bg-white last:mb-0 dark:border-theme-secondary-800 dark:bg-black sm:rounded-none sm:border-x-0 sm:border-b-0 sm:border-dashed sm:bg-transparent sm:pt-3 sm:dark:bg-transparent"
className={cn(
"mb-3 overflow-hidden rounded border border-theme-secondary-300 bg-white last:mb-0 dark:border-theme-secondary-800 dark:bg-black",
{
"md:rounded-none md:border-x-0 md:border-b-0 md:border-dashed md:bg-transparent md:pt-3 md:dark:bg-transparent":
size === "md",
"sm:rounded-none sm:border-x-0 sm:border-b-0 sm:border-dashed sm:bg-transparent sm:pt-3 sm:dark:bg-transparent":
size === "sm",
},
)}
>
<div className="flex flex-col items-center space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0">
<div className="flex w-full min-w-0 flex-1 flex-col sm:w-auto sm:items-start sm:space-x-0 sm:space-y-1">
<div className="flex w-full flex-1 flex-row items-center justify-between bg-theme-secondary-100 px-4 py-3 dark:bg-theme-secondary-900 sm:bg-transparent sm:p-0 dark:sm:bg-transparent">
<div
className={cn("flex flex-col items-center space-y-4", {
"md:flex-row md:space-x-4 md:space-y-0": size === "md",
"sm:flex-row sm:space-x-4 sm:space-y-0": size === "sm",
})}
>
<div
className={cn("flex w-full min-w-0 flex-1 flex-col", {
"md:w-auto md:items-start md:space-x-0 md:space-y-1": size === "md",
"sm:w-auto sm:items-start sm:space-x-0 sm:space-y-1": size === "sm",
})}
>
<div
className={cn(
"flex w-full flex-1 flex-row items-center justify-between bg-theme-secondary-100 px-4 py-3 dark:bg-theme-secondary-900",
{
"md:bg-transparent md:p-0 dark:md:bg-transparent": size === "md",
"sm:bg-transparent sm:p-0 dark:sm:bg-transparent": size === "sm",
},
)}
>
{titleSlot}
</div>
<div className="px-4 pb-4 pt-3 sm:w-full sm:p-0">{bodySlot}</div>
<div
className={cn("px-4 pb-4 pt-3", {
"md:w-full md:p-0": size === "md",
"sm:w-full sm:p-0": size === "sm",
})}
>
{bodySlot}
</div>
</div>
<div className="hidden sm:block">{rightSlot}</div>
<div className={cn("hidden", { "md:block": size === "md", "sm:block": size === "sm" })}>{rightSlot}</div>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { RecipientsList } from "./RecipientsList";
import { RecipientItem } from "./RecipientsModal.contracts";
import { render, screen } from "@testing-library/react";

const recipients: RecipientItem[] = [
{
address: "FJKDSALJFKASLJFKSDAJD333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 1",
amount: 150,
},
{
address: "AhFJKDSALJFKASLJFKSDEAJ333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 2",
amount: 100,
},
];

describe("RecipientsList", () => {
it("should render", () => {
const ticker = "DARK";

render(<RecipientsList recipients={recipients} ticker={ticker} />);

expect(screen.getAllByTestId("RecipientsListItem").length).toBe(recipients.length);
expect(screen.getByText(recipients[0].alias)).toBeInTheDocument();
expect(screen.getByText(recipients[0].amount + ` ${ticker}`)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useTranslation } from "react-i18next";
import { InfoDetail, MultiEntryItem } from "@/app/components/MultiEntryItem/MultiEntryItem";
import { Address } from "@/app/components/Address";
import { Amount } from "@/app/components/Amount";
import React from "react";
import { RecipientsProperties } from "@/domains/transaction/components/RecipientsModal/RecipientsModal.contracts";

export const RecipientsList = ({ recipients, ticker }: RecipientsProperties): JSX.Element => {
const { t } = useTranslation();

return (
<>
{recipients.map((recipient, index) => (
<MultiEntryItem
key={index}
size="md"
dataTestId="RecipientsListItem"
titleSlot={
<div className="flex w-full items-center justify-between">
<div className="whitespace-nowrap text-sm font-semibold leading-[17px] text-theme-secondary-700 dark:text-theme-secondary-500">
{t("COMMON.RECIPIENT_#", { count: index + 1 })}
</div>
</div>
}
bodySlot={
<div className="space-y-4">
<InfoDetail
label="Address"
body={
<Address
address={recipient.address}
walletName={recipient.alias}
showCopyButton
walletNameClass="leading-[17px] text-sm"
addressClass="leading-[17px] text-sm text-theme-secondary-500 dark:text-theme-secondary-700"
/>
}
/>
<InfoDetail
label="Value"
body={
<Amount
ticker={ticker}
value={recipient.amount as number}
className="text-sm font-semibold leading-[17px] text-theme-secondary-900 dark:text-theme-secondary-200"
/>
}
/>
</div>
}
/>
))}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface RecipientItem {
address: string;
alias?: string;
amount?: number;
isDelegate?: boolean;
}

export interface RecipientsProperties {
recipients: RecipientItem[];
ticker: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import { RecipientItem } from "./RecipientsModal.contracts";
import { screen } from "@testing-library/react";
import { RecipientsModal } from "./RecipientsModal";
import { renderResponsive } from "@/utils/testing-library";

const recipients: RecipientItem[] = [
{
address: "FJKDSALJFKASLJFKSDAJD333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 1",
amount: 150,
},
{
address: "AhFJKDSALJFKASLJFKSDEAJ333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 2",
amount: 100,
},
];

describe("RecipientsModal", () => {
it("should render `RecipientsLists` in `sm` screen", () => {
renderResponsive(
<RecipientsModal recipients={recipients} ticker="DARK" isOpen={true} onClose={vi.fn()} />,
"sm",
);

expect(screen.getAllByTestId("RecipientsListItem").length).toBeTruthy();
expect(screen.queryByTestId("TableWrapper")).not.toBeInTheDocument();
});

it("should render `RecipientsTable` in `lg` screen", () => {
renderResponsive(
<RecipientsModal recipients={recipients} ticker="DARK" isOpen={true} onClose={vi.fn()} />,
"lg",
);

expect(screen.getByTestId("TableWrapper")).toBeInTheDocument();
expect(screen.queryAllByTestId("RecipientsListItem").length).toBe(0);
});

it("should show number of recipients in the modal title", () => {
renderResponsive(
<RecipientsModal recipients={recipients} ticker="DARK" isOpen={true} onClose={vi.fn()} />,
"sm",
);

expect(screen.getByTestId("RecipientsModal--RecipientsCount")).toHaveTextContent(recipients.length);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import { Modal } from "@/app/components/Modal";
import { useTranslation } from "react-i18next";
import { useBreakpoint } from "@/app/hooks";
import { RecipientsTable } from "@/domains/transaction/components/RecipientsModal/RecipientsTable";
import { RecipientsList } from "@/domains/transaction/components/RecipientsModal/RecipientsList";
import { RecipientItem } from "@/domains/transaction/components/RecipientsModal/RecipientsModal.contracts";

interface Properties {
isOpen: boolean;
onClose: () => void;
recipients: RecipientItem[];
ticker: string;
}

const ModalTitle = ({ count }: { count: number }) => {
const { t } = useTranslation();

return (
<span className="inline-flex items-center gap-1 font-semibold leading-5">
<span>{t("COMMON.RECIPIENTS")} </span>
<span
className="text-theme-secondary-500 dark:text-theme-secondary-500"
data-testid="RecipientsModal--RecipientsCount"
>
({count})
</span>
</span>
);
};

export const RecipientsModal: React.FC<Properties> = ({ isOpen, onClose, recipients, ticker }) => {
const { isMdAndAbove } = useBreakpoint();

return (
<Modal
isOpen={isOpen}
size="3xl"
title={<ModalTitle count={recipients.length} />}
onClose={onClose}
noButtons
data-testid="RecipientsModal"
>
<div className="mt-2.5 md:mt-[18px]">
{isMdAndAbove ? (
<RecipientsTable recipients={recipients} ticker={ticker} />
) : (
<RecipientsList recipients={recipients} ticker={ticker} />
)}
</div>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { RecipientItem } from "./RecipientsModal.contracts";
import { RecipientsTable } from "./RecipientsTable";
import { render, screen } from "@testing-library/react";

const recipients: RecipientItem[] = [
{
address: "FJKDSALJFKASLJFKSDAJD333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 1",
amount: 150,
},
{
address: "AhFJKDSALJFKASLJFKSDEAJ333FKFKDSAJFKSAJFKLASJKDFJ",
alias: "Recipient 2",
amount: 100,
},
];

describe("RecipientsTable", () => {
it("should render", () => {
const ticker = "DARK";

render(<RecipientsTable recipients={recipients} ticker={ticker} />);

expect(screen.getByTestId("TableWrapper")).toBeInTheDocument();
expect(screen.getByText(recipients[0].alias)).toBeInTheDocument();
expect(screen.getByText(recipients[0].amount + ` ${ticker}`)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { FC, useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Column } from "react-table";
import { TableWrapper } from "@/app/components/Table/TableWrapper";
import { Table, TableCell, TableRow } from "@/app/components/Table";
import { Address } from "@/app/components/Address";
import { Amount } from "@/app/components/Amount";
import {
RecipientItem,
RecipientsProperties,
} from "@/domains/transaction/components/RecipientsModal/RecipientsModal.contracts";

export const RecipientsTable: FC<RecipientsProperties> = ({ recipients, ticker }) => {
const { t } = useTranslation();

const columns = useMemo<Column<RecipientItem>[]>(
() => [
{
Header: "#",
headerClassName: "no-border",
},
{
Header: t("COMMON.ADDRESS"),
accessor: "alias",
headerClassName: "no-border",
},
{
Header: t("COMMON.AMOUNT"),
accessor: "amount",
className: "justify-end",
headerClassName: "no-border",
},
],
[t],
);

const renderTableRow = useCallback(
(recipient: RecipientItem, index: number) => (
<TableRow key={index} border className="relative">
<TableCell variant="start" innerClassName="pl-6">
<span className="text-sm font-semibold leading-[17px] text-theme-text">{index + 1}</span>
</TableCell>

<TableCell>
<Address
walletName={recipient.alias}
address={recipient.address}
truncateOnTable
showCopyButton
walletNameClass="text-sm text-theme-secondary-900 dark:text-theme-secondary-200 leading-[17px]"
addressClass="text-sm text-theme-secondary-700 dark:text-theme-secondary-500 leading-[17px] flex items-center h-5"
/>
</TableCell>

<TableCell variant="end" innerClassName="justify-end pr-6">
<span className="whitespace-nowrap text-sm font-semibold leading-[17px]">
<Amount ticker={ticker} value={recipient.amount as number} />
</span>
</TableCell>
</TableRow>
),
[ticker],
);

return (
<TableWrapper>
<Table className="with-x-padding overflow-hidden rounded-xl" columns={columns} data={recipients}>
{renderTableRow}
</Table>
</TableWrapper>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./RecipientsModal";
Loading

0 comments on commit 8e49385

Please sign in to comment.