Skip to content

Commit

Permalink
[Create Account] Fund account with Friend button behavior (#827)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeesunikim authored Apr 24, 2024
1 parent f39007d commit b7af0b1
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 101 deletions.
115 changes: 97 additions & 18 deletions src/app/(sidebar)/account/create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,78 @@
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import { Card, Text, Button } from "@stellar/design-system";
import { Keypair } from "@stellar/stellar-sdk";

import { useIsTestingNetwork } from "@/hooks/useIsTestingNetwork";
import { Routes } from "@/constants/routes";
import { useStore } from "@/store/useStore";
import { useFriendBot } from "@/query/useFriendBot";
import { useQueryClient } from "@tanstack/react-query";

import { useIsTestingNetwork } from "@/hooks/useIsTestingNetwork";

import { GenerateKeypair } from "@/components/GenerateKeypair";
import { ExpandBox } from "@/components/ExpandBox";
import { SuccessMsg } from "@/components/FriendBot/SuccessMsg";
import { ErrorMsg } from "@/components/FriendBot/ErrorMsg";

import "../styles.scss";

export default function CreateAccount() {
const { account } = useStore();
const router = useRouter();
const { account, network } = useStore();
const [secretKey, setSecretKey] = useState("");
const [showAlert, setShowAlert] = useState<boolean>(false);

const queryClient = useQueryClient();
const IS_TESTING_NETWORK = useIsTestingNetwork();
const IS_CUSTOM_NETWORK_WITH_HORIZON =
network.id === "custom" && network.horizonUrl;

const resetQuery = useCallback(
() =>
queryClient.resetQueries({
queryKey: ["friendBot"],
}),
[queryClient],
);

const resetStates = useCallback(() => {
account.reset();
resetQuery();
}, [resetQuery]);

const { error, isError, isFetching, isLoading, isSuccess, refetch } =
useFriendBot({
network,
publicKey: account.publicKey!,
});

useEffect(() => {
if (isError || isSuccess) {
setShowAlert(true);
}
}, [isError, isSuccess]);

useEffect(() => {
if (
account.registeredNetwork?.id &&
account.registeredNetwork.id !== network.id
) {
resetStates();
setShowAlert(false);
}
}, [account.registeredNetwork, network.id]);

const generateKeypair = () => {
resetStates();

const keypair = Keypair.random();

account.updatePublicKey(keypair.publicKey());
if (IS_TESTING_NETWORK) {
account.updateKeypair(keypair.publicKey(), keypair.secret());
} else {
account.updateKeypair(keypair.publicKey());
}

setSecretKey(keypair.secret());
};

Expand All @@ -43,30 +92,60 @@ export default function CreateAccount() {
</Text>
</div>
<div className="Account__CTA" data-testid="createAccount-buttons">
<Button size="md" variant="secondary" onClick={generateKeypair}>
<Button
disabled={isLoading || isFetching}
size="md"
variant="secondary"
onClick={generateKeypair}
>
Generate keypair
</Button>
{IS_TESTING_NETWORK ? (

{IS_TESTING_NETWORK || IS_CUSTOM_NETWORK_WITH_HORIZON ? (
<Button
size="md"
disabled={!account.publicKey || isLoading}
variant="tertiary"
onClick={() => router.push(Routes.ACCOUNT_FUND)}
isLoading={isLoading || isFetching}
onClick={() => {
resetQuery();
refetch();
}}
data-testid="fundAccount-button"
>
Fund account with Friendbot
</Button>
) : null}
</div>

<ExpandBox isExpanded={Boolean(account.publicKey)} offsetTop="xl">
<div className="Account__result">
<GenerateKeypair
publicKey={account.publicKey}
secretKey={secretKey}
/>
</div>
</ExpandBox>
{Boolean(account.publicKey) && (
<ExpandBox isExpanded={Boolean(account.publicKey)} offsetTop="xl">
<div className="Account__result">
<GenerateKeypair
publicKey={account.publicKey}
secretKey={IS_TESTING_NETWORK ? account.secretKey : secretKey}
/>
</div>
</ExpandBox>
)}
</div>
</Card>

<SuccessMsg
publicKey={account.publicKey!}
isVisible={Boolean(showAlert && isSuccess && account.publicKey)}
onClose={() => {
setShowAlert(false);
}}
/>

<ErrorMsg
isVisible={Boolean(showAlert && isError)}
errorMsg={error?.message}
onClose={() => {
setShowAlert(false);
}}
/>
</div>
);
}
86 changes: 46 additions & 40 deletions src/app/(sidebar)/account/fund/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
"use client";

import { useEffect, useState } from "react";
import { Alert, Card, Input, Text, Button } from "@stellar/design-system";
import { Card, Input, Text, Button } from "@stellar/design-system";
import Link from "next/link";
import { Routes } from "@/constants/routes";

import { shortenStellarAddress } from "@/helpers/shortenStellarAddress";
import { useIsTestingNetwork } from "@/hooks/useIsTestingNetwork";
import { useFriendBot } from "@/query/useFriendBot";
import { useStore } from "@/store/useStore";

import { validate } from "@/validate";

import { SuccessMsg } from "@/components/FriendBot/SuccessMsg";
import { ErrorMsg } from "@/components/FriendBot/ErrorMsg";

import "../styles.scss";

export default function FundAccount() {
Expand All @@ -23,11 +25,28 @@ export default function FundAccount() {

const IS_TESTING_NETWORK = useIsTestingNetwork();

const { error, isError, isLoading, isSuccess, refetch, isFetchedAfterMount } =
useFriendBot({
network: network.id,
publicKey: generatedPublicKey,
});
const {
error,
isError,
isFetching,
isLoading,
isSuccess,
refetch,
isFetchedAfterMount,
} = useFriendBot({
network,
publicKey: generatedPublicKey,
});

useEffect(() => {
if (
account.registeredNetwork?.id &&
account.registeredNetwork.id !== network.id
) {
account.reset();
setShowAlert(false);
}
}, [account.registeredNetwork, network.id]);

useEffect(() => {
if (isError || isSuccess) {
Expand Down Expand Up @@ -60,13 +79,12 @@ export default function FundAccount() {
</div>

<Input
id="generate-keypair-publickey"
id="fund-public-key-input"
fieldSize="md"
label="Public Key"
value={generatedPublicKey}
onChange={(e) => {
setGeneratedPublicKey(e.target.value);

const error = validate.publicKey(e.target.value);
setInlineErrorMessage(error || "");
}}
Expand All @@ -78,8 +96,8 @@ export default function FundAccount() {
<Button
disabled={!generatedPublicKey || Boolean(inlineErrorMessage)}
size="md"
variant={isFetchedAfterMount && isError ? "error" : "secondary"}
isLoading={isLoading}
variant="secondary"
isLoading={isLoading || isFetching}
onClick={() => {
if (!inlineErrorMessage) {
refetch();
Expand All @@ -90,12 +108,12 @@ export default function FundAccount() {
</Button>

<Button
disabled={!account.publicKey || isLoading}
disabled={!account.publicKey || isLoading || isFetching}
size="md"
variant="tertiary"
onClick={() => {
setInlineErrorMessage("");
setGeneratedPublicKey(account.publicKey);
setGeneratedPublicKey(account.publicKey!);
}}
>
Fill in with generated key
Expand All @@ -104,33 +122,21 @@ export default function FundAccount() {
</div>
</Card>

{showAlert && isFetchedAfterMount && isSuccess && (
<Alert
placement="inline"
variant="primary"
actionLabel="View on stellar.expert"
actionLink={`https://stellar.expert/explorer/${network.id}/account/${account.publicKey}`}
onClose={() => {
setShowAlert(false);
}}
title={`Successfully funded ${shortenStellarAddress(account.publicKey)} on
${network.id}`}
>
{""}
</Alert>
)}
{showAlert && isFetchedAfterMount && isError && (
<Alert
placement="inline"
variant="error"
onClose={() => {
setShowAlert(false);
}}
title={error?.message}
>
{""}
</Alert>
)}
<SuccessMsg
isVisible={Boolean(showAlert && isFetchedAfterMount && isSuccess)}
publicKey={generatedPublicKey}
onClose={() => {
setShowAlert(false);
}}
/>

<ErrorMsg
isVisible={Boolean(showAlert && isFetchedAfterMount && isError)}
errorMsg={error?.message}
onClose={() => {
setShowAlert(false);
}}
/>
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/(sidebar)/account/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function AccountTemplate({
navItems: [
{
route: Routes.ACCOUNT_CREATE,
label: "Create Account",
label: "Create Account Keypair",
},
{
route: Routes.ACCOUNT_FUND,
Expand Down
21 changes: 21 additions & 0 deletions src/components/FriendBot/ErrorMsg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Alert } from "@stellar/design-system";

export const ErrorMsg = ({
onClose,
isVisible,
errorMsg,
}: {
onClose: () => void | undefined;
isVisible: boolean;
errorMsg: string | undefined;
}) =>
isVisible ? (
<Alert
placement="inline"
variant="error"
onClose={onClose}
title={errorMsg}
>
{""}
</Alert>
) : null;
39 changes: 39 additions & 0 deletions src/components/FriendBot/SuccessMsg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Alert } from "@stellar/design-system";

import { useStore } from "@/store/useStore";

import { shortenStellarAddress } from "@/helpers/shortenStellarAddress";

export const SuccessMsg = ({
onClose,
publicKey,
isVisible,
}: {
onClose: () => void | undefined;
publicKey: string;
isVisible: boolean;
}) => {
const { network } = useStore();
const IS_STELLAR_EXPERT_ENABLED =
network.id === "testnet" || network.id === "mainnet";

return isVisible ? (
<Alert
placement="inline"
variant="success"
actionLabel={
IS_STELLAR_EXPERT_ENABLED ? "View on stellar.expert" : undefined
}
actionLink={
IS_STELLAR_EXPERT_ENABLED
? `https://stellar.expert/explorer/${network.id}/account/${publicKey}`
: undefined
}
onClose={onClose}
title={`Successfully funded ${shortenStellarAddress(publicKey)} on
${network.id}`}
>
{""}
</Alert>
) : null;
};
4 changes: 2 additions & 2 deletions src/components/GenerateKeypair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export const GenerateKeypair = ({
publicKey,
secretKey,
}: {
publicKey: string;
secretKey: string;
publicKey: string | undefined;
secretKey: string | undefined;
}) => {
return (
<div className="Account__keypair">
Expand Down
Loading

0 comments on commit b7af0b1

Please sign in to comment.