Skip to content

Commit

Permalink
rework steps a bit for better dismissing modal
Browse files Browse the repository at this point in the history
  • Loading branch information
holic committed Oct 29, 2024
1 parent a55684b commit 9f7c977
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 91 deletions.
6 changes: 4 additions & 2 deletions packages/entrykit/src/AccountModalContent.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useConnectorClient } from "wagmi";
import { useAccount, useConnectorClient } from "wagmi";
import { ConnectWallet } from "./ConnectWallet";
import { ConnectedSteps } from "./onboarding/ConnectedSteps";
import { useEntryKitConfig } from "./EntryKitConfigProvider";
import { useRef } from "react";

export function AccountModalContent() {
const { chainId } = useEntryKitConfig();
const userClient = useConnectorClient({ chainId });
const initialAddress = useRef(useAccount().address);

if (userClient.status !== "success") {
return <ConnectWallet />;
}

return <ConnectedSteps userClient={userClient.data} />;
return <ConnectedSteps userClient={userClient.data} initialAddress={initialAddress.current} />;
}
23 changes: 19 additions & 4 deletions packages/entrykit/src/onboarding/Allowance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PendingIcon } from "../icons/PendingIcon";
import { useClaimGasPass } from "./useClaimGasPass";
import { Button } from "../ui/Button";
import { Balance } from "../ui/Balance";
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { minGasBalance } from "./common";

export type Props = {
Expand All @@ -17,10 +17,25 @@ export function Allowance({ isActive, isExpanded, userAddress }: Props) {
const allowance = useAllowance(userAddress);
const claimGasPass = useClaimGasPass();

// TODO: improve pending state since this is kicked off automatically and showing a pending button is weird
// I assumed `queryClient.isMutating` would be useful to avoid multiple mutations at once,
// but it seems like it's doing something else internally where kicking off a mutation
// twice immediately (i.e. two renders) results in both returning 2 pending mutations.
//
// I also tried moving this into `useSetupSession` with `onMutate`, etc, but that seems
// to just mimick what I am seeing with the behavior of `useMutation`.
//
// Working around this with a ref :(
const isMutatingRef = useRef(false);
useEffect(() => {
if (isActive && claimGasPass.status === "idle" && allowance.isSuccess && allowance.data < minGasBalance) {
claimGasPass.mutate(userAddress);
if (
isActive &&
claimGasPass.status === "idle" &&
allowance.isSuccess &&
allowance.data < minGasBalance &&
!isMutatingRef.current
) {
isMutatingRef.current = true;
claimGasPass.mutate(userAddress, { onSettled: () => (isMutatingRef.current = false) });
}
}, [allowance.data, allowance.isSuccess, claimGasPass, isActive, userAddress]);

Expand Down
72 changes: 67 additions & 5 deletions packages/entrykit/src/onboarding/ConnectedSteps.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,78 @@
import { useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { ConnectedClient } from "../common";
import { useSteps } from "./useSteps";
import { twMerge } from "tailwind-merge";
import { usePrerequisites } from "./usePrerequisites";
import { Wallet } from "./Wallet";
import { Allowance } from "./Allowance";
import { Session } from "./Session";
import { Step } from "./common";
import { Address } from "viem";
import { useAccountModal } from "../useAccountModal";

export type Props = {
userClient: ConnectedClient;
initialAddress: Address | undefined;
};

export function ConnectedSteps({ userClient }: Props) {
const steps = useSteps(userClient);
export function ConnectedSteps({ userClient, initialAddress }: Props) {
const userAddress = userClient.account.address;
const { data: prerequisites } = usePrerequisites(userAddress);

// TODO: detect if just connected and, if so, dismiss
const { closeAccountModal } = useAccountModal();
const isNewConnection = userAddress !== initialAddress;

const initialPrerequisites = useRef(prerequisites);
useEffect(() => {
if (prerequisites == null) return;
if (initialPrerequisites.current == null) {
initialPrerequisites.current = prerequisites;
}

if (prerequisites.complete) {
if (isNewConnection || !initialPrerequisites.current.complete) {
closeAccountModal();
}
}
}, [closeAccountModal, isNewConnection, prerequisites]);

const { hasAllowance, isSpender, hasDelegation } = prerequisites ?? {};

const steps = useMemo((): readonly Step[] => {
if (!userAddress) {
return [
{
id: "wallet",
isComplete: false,
content: () => null,
},
];
}

return [
{
id: "wallet",
isComplete: true,
content: (props) => <Wallet {...props} userAddress={userAddress} />,
},
{
id: "allowance",
isComplete: !!hasAllowance,
content: (props) => <Allowance {...props} userAddress={userAddress} />,
},
{
id: "session",
isComplete: !!isSpender && !!hasDelegation,
content: (props) => (
<Session
{...props}
userClient={userClient}
registerSpender={!isSpender}
registerDelegation={!hasDelegation}
/>
),
},
];
}, [hasAllowance, hasDelegation, isSpender, userAddress, userClient]);

const [selectedStepId] = useState<null | string>(null);
const nextStep = steps.find((step) => step.content != null && !step.isComplete);
Expand Down
43 changes: 23 additions & 20 deletions packages/entrykit/src/onboarding/Session.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Button } from "../ui/Button";
import { useSetupSession } from "./useSetupSession";
import { useAccountModal } from "../useAccountModal";
import { ConnectedClient } from "../common";
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { useSessionAccount } from "../useSessionAccount";

export type Props = {
Expand All @@ -14,35 +13,44 @@ export type Props = {
};

export function Session({ isActive, isExpanded, userClient, registerSpender, registerDelegation }: Props) {
const { closeAccountModal } = useAccountModal();
const sessionAccount = useSessionAccount(userClient.account.address);
const sessionAddress = sessionAccount.data?.address;
const setup = useSetupSession();

const isReady = !registerDelegation && !registerDelegation;
const hasSession = !registerDelegation && !registerDelegation;

// I assumed `queryClient.isMutating` would be useful to avoid multiple mutations at once,
// but it seems like it's doing something else internally where kicking off a mutation
// twice immediately (i.e. two renders) results in both returning 2 pending mutations.
//
// I also tried moving this into `useSetupSession` with `onMutate`, etc, but that seems
// to just mimick what I am seeing with the behavior of `useMutation`.
//
// Working around this with a ref :(
const isMutatingRef = useRef(false);
useEffect(() => {
if (isActive && setup.status === "idle" && sessionAddress && !isReady) {
if (isActive && setup.status === "idle" && sessionAddress && !hasSession && !isMutatingRef.current) {
isMutatingRef.current = true;
setup.mutate(
{
userClient,
sessionAddress,
registerSpender,
registerDelegation,
},
{ onSuccess: closeAccountModal },
{ onSettled: () => (isMutatingRef.current = false) },
);
}
}, [closeAccountModal, isActive, isReady, registerDelegation, registerSpender, sessionAddress, setup, userClient]);
}, [isActive, hasSession, registerDelegation, registerSpender, sessionAddress, setup, userClient]);

return (
<div className="flex flex-col gap-4">
<div className="flex justify-between gap-4">
<div>
<div>Session</div>
<div className="font-mono text-white">{isReady ? "Enabled" : "Set up"}</div>
<div className="font-mono text-white">{hasSession ? "Enabled" : "Set up"}</div>
</div>
{isReady ? (
{hasSession ? (
<Button variant={isActive ? "primary" : "secondary"} className="flex-shrink-0 text-sm p-1 w-28" disabled>
{/* TODO: revoke */}
Disable
Expand All @@ -55,17 +63,12 @@ export function Session({ isActive, isExpanded, userClient, registerSpender, reg
onClick={
sessionAddress
? () =>
setup.mutate(
{
userClient,
sessionAddress,
registerSpender,
registerDelegation,
},
{
onSuccess: closeAccountModal,
},
)
setup.mutate({
userClient,
sessionAddress,
registerSpender,
registerDelegation,
})
: undefined
}
>
Expand Down
1 change: 0 additions & 1 deletion packages/entrykit/src/onboarding/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { parseEther } from "viem";

export type Step = {
id: string;
label: string;
isComplete: boolean;
content: (props: { isActive: boolean; isExpanded: boolean }) => ReactNode;
};
Expand Down
5 changes: 3 additions & 2 deletions packages/entrykit/src/onboarding/useClaimGasPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";

export function useClaimGasPass() {
const queryClient = useQueryClient();

// TODO: add types for RPC methods
// TODO: use client.request once this is behind proxyd
const { passIssuerTransport } = useEntryKitConfig();

const mutationKey = ["claimGasPass"];
return useMutation({
mutationKey,
onError: (error) => console.error(error),
mutationKey: ["claimGasPass"],
mutationFn: async (userAddress: Address) => {
const transport = passIssuerTransport({ retryCount: 0 });
await transport.request({
Expand Down
4 changes: 3 additions & 1 deletion packages/entrykit/src/onboarding/usePrerequisites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function usePrerequisites(userAddress: Address | undefined) {

// TODO: rework this so it uses other hooks so we avoid having to clear two caches when e.g. topping up

return useQuery(
const prereqs = useQuery(
getPrequisitesQueryOptions({
queryClient,
client,
Expand All @@ -65,4 +65,6 @@ export function usePrerequisites(userAddress: Address | undefined) {
}),
queryClient,
);
// console.log("prereqs", prereqs.isFetching, prereqs.isRefetching, prereqs.isFetchedAfterMount);
return prereqs;
}
4 changes: 3 additions & 1 deletion packages/entrykit/src/onboarding/useSetupSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ export function useSetupSession() {
const { worldAddress, paymasterAddress } = useEntryKitConfig();
const queryClient = useQueryClient();

const mutationKey = ["setupSession"];
return useMutation({
mutationKey,
onError: (error) => console.error(error),
mutationKey: ["setupSession"],
mutationFn: async ({
userClient,
sessionAddress,
Expand Down Expand Up @@ -106,5 +107,6 @@ export function useSetupSession() {
queryClient.invalidateQueries({ queryKey: ["getPrerequisites"] }),
]);
},
retry: 0,
});
}
55 changes: 0 additions & 55 deletions packages/entrykit/src/onboarding/useSteps.tsx

This file was deleted.

0 comments on commit 9f7c977

Please sign in to comment.