Skip to content

Commit

Permalink
Credits funding for slot
Browse files Browse the repository at this point in the history
  • Loading branch information
broody committed Jan 14, 2025
1 parent 168bd74 commit 2b63360
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 42 deletions.
2 changes: 2 additions & 0 deletions packages/keychain/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Success } from "./success";
import { Pending } from "./pending";
import { Consent, Slot } from "./slot";
import { OcclusionDetector } from "./OcclusionDetector";
import { Fund } from "./slot/fund";

export function App() {
return (
Expand All @@ -19,6 +20,7 @@ export function App() {
<Route path="session" element={<Session />} />
<Route path="slot" element={<Slot />}>
<Route path="consent" element={<Consent />} />
<Route path="fund" element={<Fund />} />
</Route>
<Route path="success" element={<Success />} />
<Route path="failure" element={<Failure />} />
Expand Down
25 changes: 22 additions & 3 deletions packages/keychain/src/components/funding/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,34 @@ import { TokenPair } from "@cartridge/utils/api/cartridge";
import { formatEther } from "viem";
import {
ETH_CONTRACT_ADDRESS,
isIframe,
useCountervalue,
useCreditBalance,
useERC20Balance,
} from "@cartridge/utils";
import { useController } from "@/hooks/controller";
import { useEffect, useState } from "react";
import Controller from "@/utils/controller";

export type BalanceType = "credits" | "eth" | "strk";

type BalanceProps = {
showBalances: ("credits" | "eth" | "strk")[];
showBalances: BalanceType[];
};

export function Balance({ showBalances }: BalanceProps) {
const [username, setUsername] = useState<string>();
const [address, setAddress] = useState<string>();
const { controller } = useController();
const { balance: creditBalance } = useCreditBalance({
username: controller?.username(),
username: username,
interval: 3000,
});

const {
data: [eth],
} = useERC20Balance({
address: controller?.address,
address: address,
contractAddress: ETH_CONTRACT_ADDRESS,
provider: controller,
interval: 3000,
Expand All @@ -43,6 +51,17 @@ export function Balance({ showBalances }: BalanceProps) {
{ enabled: !!eth },
);

useEffect(() => {
const activeController = !isIframe()
? Controller.fromStore(import.meta.env.VITE_ORIGIN!)
: controller;

if (activeController) {
setUsername(activeController.username());
setAddress(activeController.address);
}
}, [controller]);

return (
<Card>
<CardHeader>
Expand Down
21 changes: 2 additions & 19 deletions packages/keychain/src/components/funding/PurchaseCredits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,6 @@ export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
},
} as Appearance;

// For when we need to support Payment Links
// useStripePaymentQuery(
// { referenceId },
// {
// enabled: !!referenceId && !error,
// refetchInterval: REFETCH_INTERVAL,
// retry: MAX_RETRIES,
// onSuccess: () => setState(PurchaseState.SUCCESS),
// onError: () => {
// setError(
// new Error(
// `Payment not received. Please try again. Reference ID: ${referenceId}`,
// ),
// );
// },
// },
// );

if (state === PurchaseState.STRIPE_CHECKOUT) {
return (
<Elements
Expand Down Expand Up @@ -130,13 +112,14 @@ export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
)
}
onBack={state === PurchaseState.SELECTION ? onBack : undefined}
hideNetwork
>
<Content gap={6}>
<Balance showBalances={["credits"]} />
<ErrorAlert
variant=""
title="WHAT ARE CREDITS"
description="Credits can be used to play games. They are not tokens and cannot be transferred or refunded."
description="Credits can be used to play games or pay for slot deployments. They are not tokens and cannot be transferred or refunded."
isExpanded
/>
</Content>
Expand Down
30 changes: 19 additions & 11 deletions packages/keychain/src/components/funding/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "@cartridge/ui-next";
import { DepositEth } from "./DepositEth";
import { PurchaseCredits } from "./PurchaseCredits";
import { Balance } from "./Balance";
import { Balance, BalanceType } from "./Balance";

const enum FundingState {
SHOW_OPTIONS,
Expand All @@ -19,15 +19,20 @@ const enum FundingState {
}

export type FundingProps = {
title?: React.ReactElement;
title?: React.ReactElement | string;
creditsOnly?: boolean;
onComplete?: (deployHash?: string) => void;
};

export function Funding({ onComplete, title }: FundingProps) {
export function Funding({ title, creditsOnly, onComplete }: FundingProps) {
const { controller } = useConnection();
const [state, setState] = useState<FundingState>(FundingState.SHOW_OPTIONS);
const showBalances: BalanceType[] = creditsOnly
? ["credits"]
: ["credits", "eth"];
const showCredits =
typeof document !== "undefined" && document.cookie.includes("credits=");
(typeof document !== "undefined" && document.cookie.includes("credits=")) ||
creditsOnly;

if (state === FundingState.FUND_ETH) {
return (
Expand All @@ -49,22 +54,25 @@ export function Funding({ onComplete, title }: FundingProps) {
title={title || (controller ? `Fund ${controller.username()}` : "")}
description={controller && <CopyAddress address={controller.address} />}
icon={<ArrowIcon variant="down" />}
hideNetwork
>
<Content gap={6}>
<Balance showBalances={["credits", "eth"]} />
<Balance showBalances={showBalances} />
</Content>
<Footer>
{showCredits && (
<Button onClick={() => setState(FundingState.FUND_CREDITS)}>
<CoinsIcon variant="line" size="sm" /> Purchase Credits
</Button>
)}
<Button
onClick={() => setState(FundingState.FUND_ETH)}
variant="secondary"
>
<EthereumIcon size="sm" className="mr-1" /> Deposit Eth
</Button>
{!creditsOnly && (
<Button
onClick={() => setState(FundingState.FUND_ETH)}
variant="secondary"
>
<EthereumIcon size="sm" className="mr-1" /> Deposit Eth
</Button>
)}
</Footer>
</Container>
);
Expand Down
16 changes: 13 additions & 3 deletions packages/keychain/src/components/slot/consent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import Controller from "@/utils/controller";
import { Button } from "@cartridge/ui-next";
import { Container, Footer } from "@/components/layout";
import { useCallback, useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";

export function Consent() {
const navigate = useNavigate();
const { pathname } = useLocation();
const [searchParams] = useSearchParams();
const callback_uri = searchParams.get("callback_uri")!;

Expand All @@ -25,9 +26,18 @@ export function Consent() {

useEffect(() => {
if (!Controller.fromStore(import.meta.env.VITE_ORIGIN!)) {
navigate("/slot", { replace: true });
navigate(
`/slot?returnTo=${encodeURIComponent(pathname)}${
callback_uri
? `&callback_uri=${encodeURIComponent(callback_uri)}`
: ""
}`,
{
replace: true,
},
);
}
}, [navigate]);
}, [navigate, callback_uri, pathname]);

return (
<Container
Expand Down
19 changes: 19 additions & 0 deletions packages/keychain/src/components/slot/fund.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect } from "react";
import { Funding } from "../funding";
import Controller from "@/utils/controller";
import { useLocation, useNavigate } from "react-router-dom";

export function Fund() {
const navigate = useNavigate();
const { pathname } = useLocation();

useEffect(() => {
if (!Controller.fromStore(import.meta.env.VITE_ORIGIN!)) {
navigate(`/slot?returnTo=${encodeURIComponent(pathname)}`, {
replace: true,
});
}
}, [navigate, pathname]);

return <Funding title="Fund Credits for Slot" creditsOnly={true} />;
}
17 changes: 11 additions & 6 deletions packages/keychain/src/components/slot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function Slot() {
case "/slot/auth/failure":
return <Navigate to="/failure" replace />;
case "/slot/consent":
case "/slot/fund":
return <Outlet />;
default:
return <Auth />;
Expand All @@ -37,13 +38,17 @@ function Auth() {

useEffect(() => {
if (user && controller) {
const query = Array.from(searchParams.entries()).reduce(
(prev, [key, val], i) =>
i === 0 ? `?${key}=${val}` : `${prev}&${key}=${val}`,
"",
);
const returnTo = searchParams.get("returnTo");
const otherParams = Array.from(searchParams.entries())
.filter(([key]) => key !== "returnTo")
.reduce(
(prev, [key, val], i) =>
i === 0 ? `?${key}=${val}` : `${prev}&${key}=${val}`,
"",
);

navigate(`/slot/consent${query}`, { replace: true });
const target = returnTo ? `${returnTo}${otherParams}` : "/slot";
navigate(target, { replace: true });
}
}, [user, controller, navigate, searchParams]);

Expand Down

0 comments on commit 2b63360

Please sign in to comment.