Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion __mocks__/fixtures/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const mockWallet: Wallet = {
balance: 0,
user_id: mockUser.id,
token: "ICP",
address: "",
address: "0xd0 5AfA 87A5 99b8 AD8C ff71 b1eC 7129 e3Ed fe08 b9",
payouts: [mockPayout],
description: ""
}
22 changes: 22 additions & 0 deletions __tests__/components/cards/wallet/Overview.test.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in here is not formatted

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Overview from "@/components/cards/wallet/Overview";
import { mockWallet } from "@__mocks__/fixtures/wallet";
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";

const wallet = {
...mockWallet,
title: "some title",
};

describe("Overview component", () => {
it("Should render Overview component and all the required elements with props value", () => {
render(<Overview wallet={wallet} />);
expect(screen.getByTestId("overviewId")).toBeInTheDocument();
expect(screen.getByText(wallet.title)).toBeInTheDocument();
expect(screen.getByText("profile.wallets.balance")).toBeInTheDocument();
expect(screen.getByTestId("currencyId")).toBeInTheDocument();
expect(screen.getByTestId("coin")).toBeInTheDocument();
expect(screen.getByTestId("tag")).toBeInTheDocument();
});

});
37 changes: 37 additions & 0 deletions __tests__/components/cards/wallet/WalletHint.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import { Wallet } from "@/types/wallet";
import WalletHint from "@/components/cards/wallet/WalletHint";
import { mockWallet } from "@__mocks__/fixtures/wallet";

const wallet: Wallet = {
...mockWallet,
payouts: [
{ amount: 100, token: "ETH" },
{ amount: 200, token: "BTC" },
],
};

describe("WalletHint component", () => {
it("should render WalletHint component with the correct number of Hint components", () => {
render(<WalletHint wallet={wallet} />);
const textElements = screen.getAllByText("profile.wallet.payout.text");
expect(textElements).toHaveLength(wallet.payouts.length);
});

it("renders the correct number of Hint components", () => {
render(<WalletHint wallet={wallet} />);
const hints = screen.getAllByText("profile.wallet.payout.text");
expect(hints).toHaveLength(wallet.payouts.length);
Comment on lines +19 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It good already that you are checking the length; it might also be better if you can check the amount and the token is well rendered in the component

});

it("renders Currency components with correct values", () => {
render(<WalletHint wallet={wallet} />);
const currencyElements = screen.getAllByTestId("currencyId");
expect(currencyElements).toHaveLength(wallet.payouts.length);
wallet.payouts.forEach((payout, index) => {
const element = currencyElements[index];
expect(element).toHaveTextContent(new RegExp(`${payout.token}`));
});
});
});
24 changes: 24 additions & 0 deletions __tests__/components/cards/wallet/indext.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import CardsWallet from "@/components/cards/wallet";
import "@testing-library/jest-dom";
import { mockWallet } from "@__mocks__/fixtures/wallet";
import { screen } from "@testing-library/react";
import { renderWithRedux } from "@__mocks__/renderWithRedux";

// use the actual component when it is done tested
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I beleive we don't need this comment here.

jest.mock("@/components/sections/profile/modals/EditAddress", () => {
return <h1>hello</h1>;
});

jest.mock("@/hooks/useTypedDispatch.ts", () => ({
useDispatch: jest.fn(),
}));

describe("Wallet card component", () => {
it("renders the wallet component with all the children", () => {
renderWithRedux(<CardsWallet wallet={mockWallet} disabled={false} />);
expect(screen.getByTestId("cardWalletId")).toBeInTheDocument();
expect(screen.getByTestId("overviewId")).toBeInTheDocument();
expect(screen.getByTestId("cashoutAddressId")).toBeInTheDocument();
expect(screen.queryByText("profile.wallet.payout.text")).not.toBeNull();
});
});
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const config = {
"react-markdown": "<rootDir>/__mocks__/react-markdown.tsx",
[`^(${esModules})-.*`]: "<rootDir>/__mocks__/plugin.ts",
unified: "<rootDir>/__mocks__/unified.ts",
"^@/(.*)$": "<rootDir>/src/$1",
},
};

Expand Down
2 changes: 2 additions & 0 deletions jest.polyfills.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Object.defineProperties(globalThis, {

const { Blob, File } = require("node:buffer");
const { fetch, Headers, FormData, Request, Response } = require("undici");
const { clearImmediate } = require("node:timers");

Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Expand All @@ -30,4 +31,5 @@ Object.defineProperties(globalThis, {
FormData: { value: FormData },
Request: { value: Request },
Response: { value: Response },
clearImmediate: { value: clearImmediate },
});
153 changes: 0 additions & 153 deletions src/components/cards/Wallet.tsx

This file was deleted.

96 changes: 96 additions & 0 deletions src/components/cards/wallet/CashoutAddress.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you refactor this component in way that we have less of if else ? : ? : ? :

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't have any if else, we are using a ternary operator to avoid many if conditions

Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import ArrowButton from "@/components/ui/button/Arrow";
import { useTranslation } from "next-i18next";
import { useDispatch } from "@/hooks/useTypedDispatch";
import { setCurrentWallet } from "@/store/feature/user/wallets.slice";
import { toggleBodyScrolling } from "@/store/feature/ui.slice";
import { useSelector } from "@/hooks/useTypedSelector";
import { openVerificationModal } from "@/store/feature/kyc.slice";
import { Wallet } from "@/types/wallet";
import { useCallback, useMemo } from "react";

interface CashoutAddressProps {
wallet: Wallet;
setShowEditModal: (show: boolean) => void;
disabled: boolean;
setShowPayoutModal: (show: boolean) => void;
testId?:string
}

export default function CashoutAddress({ wallet, setShowEditModal, disabled, setShowPayoutModal, testId='cashoutAddressId' }: CashoutAddressProps) {
const { t } = useTranslation();
const dispatch = useDispatch();
const user = useSelector((state) => state.user.data);
const isKycVerified = user?.kycStatus === "VERIFIED";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you move this in a useMemo?

const address = useMemo(() => (wallet.address ? wallet.address.match(/.{1,4}/g) : null), [wallet.address]);
const cashable = useMemo(() => String(wallet.token).toUpperCase() !== "DAC", [wallet.token]);


const triggerEditAddress = useCallback(() => {
dispatch(setCurrentWallet(wallet));
setShowEditModal(true);
dispatch(toggleBodyScrolling(true));
}, [dispatch, setShowEditModal, wallet]);

const triggerCashout = useCallback(() => {
setShowPayoutModal(true);
dispatch(toggleBodyScrolling(true));
}, [setShowPayoutModal, dispatch]);

const triggerKYCVerification = useCallback(() => {
dispatch(
openVerificationModal({
description: t("kyc.payout.reason"),
completedActionText: t("kyc.payout.button.completed"),
completedAction: () => {
triggerCashout();
},
})
);
}, [dispatch, t, triggerCashout]);
const cashout = () => {
if (!isKycVerified) return triggerKYCVerification();
triggerCashout();
};
return (
<div className="px-7 pt-6 flex-1 pb-24 lg:pb-24" data-testId={testId}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix typo in data-testid attribute.

The data-testid attribute should be written in lowercase to ensure consistency and avoid potential issues.

-  <div className="px-7 pt-6 flex-1 pb-24 lg:pb-24" data-testId={testId}>
+  <div className="px-7 pt-6 flex-1 pb-24 lg:pb-24" data-testid={testId}>
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="px-7 pt-6 flex-1 pb-24 lg:pb-24" data-testId={testId}>
<div className="px-7 pt-6 flex-1 pb-24 lg:pb-24" data-testid={testId}>

{cashable ? (
<div className="text-sm text-gray-700">
{address ? (
<p className="leading-5 text-sm flex gap-x-2 gap-y-1 flex-wrap font-mono font-normal">
{address.map((part, k) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{address.map((part, k) => (
{address.map((part, i) => (

<span key={`address-${k}`} className="mr-2">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<span key={`address-${k}`} className="mr-2">
<span key={`address-${i}`} className="mr-2">

{part}
</span>
))}
</p>
) : (
<p>{wallet.description}</p>
)}
<div className="text-gray-700 text-sm mt-3">
<span className="cursor-pointer hover:underline" onClick={triggerEditAddress}>
{address ? t("profile.wallets.address-change") : t("profile.wallets.address-set")}
</span>
</div>
</div>
) : (
<div className="prose">
<p
dangerouslySetInnerHTML={{
__html: t("profile.wallets.uncashable", {
token: `${wallet.title}`,
link: "https://discord.gg/5yDZvVnpQQ",
}),
}}
/>
</div>
Comment on lines +76 to +85
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using dangerouslySetInnerHTML.

Using dangerouslySetInnerHTML can expose users to cross-site scripting (XSS) attacks. Consider using a safer alternative to render the message.

-  <p
-    dangerouslySetInnerHTML={{
-      __html: t("profile.wallets.uncashable", {
-        token: `${wallet.title}`,
-        link: "https://discord.gg/5yDZvVnpQQ",
-      }),
-    }}
-  />
+  <p>
+    {t("profile.wallets.uncashable", {
+      token: `${wallet.title}`,
+      link: <a href="https://discord.gg/5yDZvVnpQQ">https://discord.gg/5yDZvVnpQQ</a>,
+    })}
+  </p>

Committable suggestion was skipped due to low confidence.

Tools
Biome

[error] 78-78: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

)}
{cashable && (
<div className="right-2 absolute bottom-2 mt-5">
<ArrowButton disabled={!wallet.balance || !wallet.address || disabled} variant="outline-primary" minWidthClass="min-w-40" onClick={cashout}>
{t("profile.wallets.cash-out")}
</ArrowButton>
</div>
)}
</div>
);
}
Loading