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

Implement transaction hashes retrieval and handle webapp wallet redirects #81

Merged
merged 20 commits into from
Jul 5, 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
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"camelcase",
"colocation",
"data-testid",
"dontcare",
"foodbank",
"hookform",
"kubb",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-testing-library": "^6.2.2",
"jsdom": "^24.1.0",
"next-router-mock": "^0.9.13",
"orval": "^6.30.2",
"postcss": "^8",
"prettier": "^3.2.5",
Expand All @@ -115,4 +116,4 @@
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0"
}
}
}
13 changes: 0 additions & 13 deletions src/app/_store/testEnv.tsx

This file was deleted.

6 changes: 4 additions & 2 deletions src/app/tests.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { screen, waitFor } from "@testing-library/react";
import { expect, test } from "vitest";
import { expect, test, vi } from "vitest";

import { NextNavigationMock, renderWithStore } from "@/test-env";

import { renderWithStore } from "./_store/testEnv";
import Homepage from "./page";

vi.mock("next/navigation", () => NextNavigationMock);
renderWithStore(<Homepage />);

test("Homepage", async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/common/assets/svgs/InfoIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const InfoIcon = (props: any) => {
<path
d="M10.0001 13.3327V9.99935M10.0001 6.66602H10.0084M18.3334 9.99935C18.3334 14.6017 14.6025 18.3327 10.0001 18.3327C5.39771 18.3327 1.66675 14.6017 1.66675 9.99935C1.66675 5.39698 5.39771 1.66602 10.0001 1.66602C14.6025 1.66602 18.3334 5.39698 18.3334 9.99935Z"
stroke="#475467"
stroke-width="1.66667"
strokeWidth="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/common/assets/svgs/banner-alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const BannerAlertSvg = () => (
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
strokeWidth="1.5"
stroke="white"
aria-hidden="true"
>
Expand Down
4 changes: 2 additions & 2 deletions src/common/assets/svgs/near-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const NearIcon = ({ width = 16, height = 16, ...props }: any) => (
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_454_78)">
<circle cx="8" cy="8" r="7.25" stroke="#292929" stroke-width="1.5" />
<g clipPath="url(#clip0_454_78)">
<circle cx="8" cy="8" r="7.25" stroke="#292929" strokeWidth="1.5" />
<path
d="M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z"
fill="#292929"
Expand Down
2 changes: 1 addition & 1 deletion src/common/assets/svgs/near-outline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const NearOutline = (props: any) => {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="9" cy="9" r="6.75" stroke="#292929" stroke-width="1.5" />
<circle cx="9" cy="9" r="6.75" stroke="#292929" strokeWidth="1.5" />
<path
d="M11.9509 5.25C11.6728 5.25 11.4153 5.39375 11.2697 5.63062L9.70187 7.95812C9.67925 7.99164 9.66959 8.03224 9.67469 8.07235C9.67979 8.11246 9.69932 8.14935 9.72961 8.17612C9.75991 8.2029 9.79892 8.21775 9.83935 8.21788C9.87979 8.21802 9.91889 8.20344 9.94937 8.17687L11.4925 6.83875C11.5015 6.8306 11.5127 6.82527 11.5247 6.82339C11.5367 6.82151 11.549 6.82318 11.5601 6.82819C11.5712 6.8332 11.5806 6.84133 11.5871 6.85159C11.5936 6.86184 11.597 6.87378 11.5969 6.88594V11.0766C11.5969 11.0894 11.5929 11.102 11.5856 11.1125C11.5782 11.1231 11.5677 11.1311 11.5556 11.1355C11.5435 11.1398 11.5304 11.1404 11.5179 11.137C11.5055 11.1336 11.4945 11.1265 11.4862 11.1166L6.82187 5.53281C6.74688 5.44415 6.65345 5.37291 6.5481 5.32407C6.44274 5.27522 6.328 5.24994 6.21187 5.25H6.04906C5.83714 5.25 5.63389 5.33419 5.48404 5.48404C5.33419 5.63389 5.25 5.83714 5.25 6.04906V11.9509C5.25 12.125 5.30683 12.2943 5.41184 12.4331C5.51686 12.5719 5.66432 12.6726 5.83182 12.7199C5.99931 12.7672 6.17767 12.7586 6.33979 12.6952C6.50191 12.6319 6.63893 12.5174 6.73 12.3691L8.29781 10.0416C8.32044 10.008 8.3301 9.96745 8.32499 9.92733C8.31989 9.88722 8.30037 9.85034 8.27007 9.82356C8.23977 9.79678 8.20077 9.78194 8.16033 9.7818C8.11989 9.78166 8.08079 9.79624 8.05031 9.82281L6.50719 11.1612C6.49813 11.1693 6.48693 11.1746 6.47494 11.1764C6.46295 11.1782 6.4507 11.1765 6.43967 11.1714C6.42864 11.1664 6.41931 11.1583 6.41282 11.148C6.40633 11.1378 6.40296 11.1259 6.40312 11.1137V6.9225C6.4031 6.90963 6.40705 6.89707 6.41443 6.88652C6.42181 6.87598 6.43227 6.86798 6.44437 6.8636C6.45647 6.85922 6.46963 6.85869 6.48205 6.86207C6.49447 6.86546 6.50554 6.87259 6.51375 6.8825L11.1775 12.4669C11.3294 12.6462 11.5525 12.7497 11.7875 12.75H11.9503C12.1622 12.7501 12.3655 12.666 12.5154 12.5163C12.6654 12.3666 12.7497 12.1635 12.75 11.9516V6.04906C12.7499 5.83716 12.6657 5.63397 12.5159 5.48413C12.366 5.3343 12.1628 5.25008 11.9509 5.25Z"
fill="#292929"
Expand Down
2 changes: 2 additions & 0 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { AxiosRequestConfig } from "axios";
import Big from "big.js";
import { utils } from "near-api-js";

export const RPC_NODE_URL = "https://free.rpc.fastnear.com";

// NETWORK
export const NETWORK = (process.env.NEXT_PUBLIC_NETWORK ||
"testnet") as Network;
Expand Down
9 changes: 7 additions & 2 deletions src/common/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import { setupWelldoneWallet } from "@near-wallet-selector/welldone-wallet";
import { setupXDEFI } from "@near-wallet-selector/xdefi";
import naxios from "@wpdas/naxios";

import { FULL_TGAS, NETWORK, SOCIAL_DB_CONTRACT_ID } from "@/common/constants";
import {
FULL_TGAS,
NETWORK,
RPC_NODE_URL,
SOCIAL_DB_CONTRACT_ID,
} from "@/common/constants";

// Naxios (Contract/Wallet) Instance
export const naxiosInstance = new naxios({
rpcNodeUrl: "https://free.rpc.fastnear.com",
rpcNodeUrl: RPC_NODE_URL,
contractId: SOCIAL_DB_CONTRACT_ID,
network: NETWORK,
walletSelectorModules: [
Expand Down
3 changes: 1 addition & 2 deletions src/common/contracts/potlock/donate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ export const getDonationsForDonor = (args: { donor_id: string }) =>
export const donateNearDirectly = (
args: DirectDonationArgs,
depositAmountYocto: string,
callbackUrl?: ChangeMethodArgs<DirectDonation>["callbackUrl"],
) =>
contractApi.call<typeof args, DirectDonation>("donate", {
args,
deposit: depositAmountYocto,
callbackUrl,
callbackUrl: window.location.href,
});
1 change: 1 addition & 0 deletions src/common/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as truncate } from "./truncate";
export { default as formatWithCommas } from "./formatWithCommas";
export * from "./yoctosToUsdWithFallback";
export * from "./converters";
export * from "./navigation";
42 changes: 42 additions & 0 deletions src/common/lib/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback, useMemo } from "react";

Check failure on line 2 in src/common/lib/navigation.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

src/app/tests.tsx

Error: [vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock ❯ src/common/lib/navigation.ts:2:31 Caused by: ReferenceError: Cannot access '__vi_import_2__' before initialization ❯ src/app/tests.tsx:2:50 ❯ src/common/lib/navigation.ts:2:31

Check failure on line 2 in src/common/lib/navigation.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

src/app/tests.tsx

Error: [vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock ❯ src/common/lib/navigation.ts:2:31 Caused by: ReferenceError: Cannot access '__vi_import_2__' before initialization ❯ src/app/tests.tsx:2:50 ❯ src/common/lib/navigation.ts:2:31
import { usePathname, useRouter, useSearchParams } from "next/navigation";

export type RouteParams = Record<string, string | null>;

/**
* Provides a method to update URL query parameters for the current route.
*
* @example
* const { syncRouteQuery } = useRouteQuerySync();
*
* // Sets `accountId` query parameter to "root.near"
* syncRouteQuery({ accountId: "root.near" });
*
* // Deletes `transactionHashes` query parameter
* syncRouteQuery({ transactionHashes: null });
*/
export const useRouteQuerySync = () => {
const router = useRouter();
const pathname = usePathname();
const currentQueryString = useSearchParams().toString();

const queryParams = useMemo(
() => new URLSearchParams(currentQueryString),
[currentQueryString],
);

const syncRouteQuery = useCallback(
(newParams: RouteParams) => {
Object.entries(newParams).forEach(([key, value]) =>
value ? queryParams.set(key, value) : queryParams.delete(key),
);

router.replace(`${pathname}?${queryParams.toString()}`);
},

[pathname, router, queryParams],
);

return { syncRouteQuery };
};
1 change: 1 addition & 0 deletions src/common/services/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./fetchNearPrice";
export * from "./transactions";
27 changes: 27 additions & 0 deletions src/common/services/transactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import axios from "axios";

import { RPC_NODE_URL } from "@/common/constants";
import { AccountId } from "@/common/types";

export type TxExecutionStatus =
| "NONE"
| "INCLUDED"
| "EXECUTED_OPTIMISTIC"
| "INCLUDED_FINAL"
| "EXECUTED"
| "FINAL";

export const getTransactionStatus = ({
wait_until = "EXECUTED_OPTIMISTIC",
...params
}: {
tx_hash: string;
sender_account_id: AccountId;
wait_until?: TxExecutionStatus;
}) =>
axios.post(RPC_NODE_URL, {
jsonrpc: "2.0",
id: "dontcare",
method: "tx",
params: { wait_until, ...params },
});
2 changes: 1 addition & 1 deletion src/modules/donation/components/DonationBreakdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ByTokenId } from "@/common/types";
import { TextWithIcon } from "@/common/ui/components";
import { TokenIcon } from "@/modules/core";

import { DonationFees } from "../hooks/fees";
import { DonationFees } from "../hooks";

export type DonationBreakdownProps = ByTokenId & {
fees: DonationFees;
Expand Down
2 changes: 1 addition & 1 deletion src/modules/donation/components/DonationConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { TotalTokenValue } from "@/modules/core";
import { ProfileLink } from "@/modules/profile";

import { DonationBreakdown } from "./DonationBreakdown";
import { useDonationFees } from "../hooks/fees";
import { useDonationFees } from "../hooks";
import { DonationInputs } from "../models";

export type DonationConfirmationProps = {
Expand Down
15 changes: 9 additions & 6 deletions src/modules/donation/components/DonationFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@ import { ModalErrorBody, useAvailableBalance } from "@/modules/core";
import { DonationConfirmation } from "./DonationConfirmation";
import { DonationPotAllocation } from "./DonationPotAllocation";
import { DonationProjectAllocation } from "./DonationProjectAllocation";
import { DonationSuccess } from "./DonationSuccess";
import { useDonationForm } from "../hooks/forms";
import { DonationSuccess, DonationSuccessProps } from "./DonationSuccess";
import { useDonationForm } from "../hooks";
import { DonationState, DonationSubmissionInputs } from "../models";

export type DonationFlowProps = DonationSubmissionInputs &
DonationState & {
DonationState &
Pick<DonationSuccessProps, "transactionHash"> & {
closeModal: VoidFunction;
};

export const DonationFlow: React.FC<DonationFlowProps> = ({
currentStep,
successResult: result,
transactionHash,
closeModal,
...props
}) => {
const searchParams = useSearchParams();
const transactionHashes = searchParams.get("transactionHashes");

const { isBalanceSufficient, minAmountError, form, isDisabled, onSubmit } =
useDonationForm({
Expand All @@ -47,7 +49,7 @@ export const DonationFlow: React.FC<DonationFlowProps> = ({
form,
};

const staticSuccessProps = { form, result, transactionHashes };
const staticSuccessProps = { form, result, transactionHash, closeModal };

switch (currentStep) {
case "allocation":
Expand All @@ -71,13 +73,14 @@ export const DonationFlow: React.FC<DonationFlowProps> = ({
}
}, [
balanceFloat,
closeModal,
currentStep,
form,
isBalanceSufficient,
minAmountError,
props,
result,
transactionHashes,
transactionHash,
]);

return (
Expand Down
30 changes: 19 additions & 11 deletions src/modules/donation/components/DonationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,35 @@ import { create, useModal } from "@ebay/nice-modal-react";

import { dispatch, useTypedSelector } from "@/app/_store";
import { walletApi } from "@/common/contracts";
import { useRouteQuerySync } from "@/common/lib";
import { Button, Dialog, DialogContent } from "@/common/ui/components";
import { cn } from "@/common/ui/utils";
import { useAuth } from "@/modules/auth/hooks/useAuth";
import { ModalErrorBody } from "@/modules/core";

import { DonationFlow } from "./DonationFlow";
import { DonationFlow, DonationFlowProps } from "./DonationFlow";
import { DonationParameters } from "../models";

export type DonationModalProps = DonationParameters & {};
export type DonationModalProps = DonationParameters &
Pick<DonationFlowProps, "transactionHash"> & {};

export const DonationModal = create((props: DonationModalProps) => {
const self = useModal();
const donationState = useTypedSelector(({ donation }) => donation);
const { isAuthenticated } = useAuth();
const { syncRouteQuery } = useRouteQuerySync();

const close = useCallback(() => {
self.hide();
dispatch.donation.reset();
self.remove();
}, [self]);

const state = useTypedSelector(({ donation }) => donation);

const { isAuthenticated } = useAuth();
syncRouteQuery({
donateTo: null,
donateToPot: null,
transactionHashes: null,
});
}, [self, syncRouteQuery]);

const onSignInClick = useCallback(() => {
walletApi.signInModal();
Expand All @@ -36,12 +43,13 @@ export const DonationModal = create((props: DonationModalProps) => {
<Dialog open={self.visible}>
<DialogContent
className={cn({
"max-w-130": state.currentStep !== "success",
"max-w-120": state.currentStep === "success",
"max-w-130": donationState.currentStep !== "success",
"max-w-120": donationState.currentStep === "success",
})}
contrastActions={state.currentStep === "success"}
contrastActions={donationState.currentStep === "success"}
onBackClick={
state.currentStep !== "allocation" && state.currentStep !== "success"
donationState.currentStep !== "allocation" &&
donationState.currentStep !== "success"
? dispatch.donation.previousStep
: undefined
}
Expand Down Expand Up @@ -86,7 +94,7 @@ export const DonationModal = create((props: DonationModalProps) => {
title="Unable to detect donation recipient."
/>
) : (
<DonationFlow closeModal={close} {...props} {...state} />
<DonationFlow closeModal={close} {...props} {...donationState} />
)}
</>
)}
Expand Down
17 changes: 10 additions & 7 deletions src/modules/donation/components/DonationSuccess.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ import {
import { ModalErrorBody, TotalTokenValue } from "@/modules/core";

import { DonationBreakdown } from "./DonationBreakdown";
import { useDonationFees } from "../hooks/fees";
import { useDonationFees } from "../hooks";
import { DonationInputs, DonationState } from "../models";

export type DonationSuccessProps = {
result?: DonationState["successResult"];
transactionHashes: string | null;
form: UseFormReturn<DonationInputs>;
result?: DonationState["successResult"];
transactionHash?: string;
closeModal: VoidFunction;
};

const staticResultIndicatorClassName =
Expand All @@ -35,7 +36,8 @@ const staticResultIndicatorClassName =
export const DonationSuccess = ({
form,
result,
transactionHashes,
transactionHash,
closeModal,
}: DonationSuccessProps) => {
const isResultLoading = result === undefined;
const [potAccountId] = form.watch(["potAccountId"]);
Expand Down Expand Up @@ -162,6 +164,7 @@ export const DonationSuccess = ({
) : (
<Link
href={`/user/${recipientAccount.id}/funding-raised`}
onClick={closeModal}
className="text-red-600"
>
View donation
Expand All @@ -175,9 +178,9 @@ export const DonationSuccess = ({
<DonationBreakdown tokenId={result.ft_id} {...{ fees }} />
)}

{transactionHashes && (
<TextWithIcon content={`Txn Hash : ${truncate(transactionHashes, 7)}`}>
<ClipboardCopyButton text={transactionHashes} />
{transactionHash && (
<TextWithIcon content={`Txn Hash : ${truncate(transactionHash, 7)}`}>
<ClipboardCopyButton text={transactionHash} />
</TextWithIcon>
)}
</DialogDescription>
Expand Down
Loading
Loading