Skip to content

Commit

Permalink
- seperate arcade and wallet connector detection
Browse files Browse the repository at this point in the history
- detect when player has no arcade accounts, provide dialog
- improve arcade account deployment UX
  • Loading branch information
starknetdev committed Oct 3, 2023
1 parent 4fc8af1 commit 6e03d62
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 102 deletions.
45 changes: 16 additions & 29 deletions ui/src/app/components/ArcadeDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,15 @@ import React, { useEffect } from "react";
import { useState } from "react";
import useUIStore from "@/app/hooks/useUIStore";
import { Button } from "./buttons/Button";
import { PREFUND_AMOUNT, useBurner } from "../lib/burner";
import {
Connector,
useAccount,
useBalance,
useConnectors,
} from "@starknet-react/core";
import {
AccountInterface,
CallData,
TransactionFinalityStatus,
uint256,
Call,
Account,
Provider,
} from "starknet";
import { useBurner } from "../lib/burner";
import { Connector, useAccount, useConnectors } from "@starknet-react/core";
import { AccountInterface, CallData, uint256 } from "starknet";
import { useCallback } from "react";
import { useContracts } from "../hooks/useContracts";
import { balanceSchema } from "../lib/utils";
import { MIN_BALANCE } from "../lib/constants";
import PixelatedImage from "./animations/PixelatedImage";
import { getArcadeConnectors } from "../lib/connectors";

const MAX_RETRIES = 10;
const RETRY_DELAY = 2000; // 2 seconds
Expand All @@ -45,12 +34,7 @@ export const ArcadeDialog = () => {
const { ethContract } = useContracts();
const [balances, setBalances] = useState<Record<string, bigint>>({});

const arcadeConnectors = useCallback(() => {
return available.filter(
(connector) =>
typeof connector.id === "string" && connector.id.includes("0x")
);
}, [available]);
const arcadeConnectors = getArcadeConnectors(available);

const fetchBalanceWithRetry = async (
accountName: string,
Expand All @@ -76,13 +60,12 @@ export const ArcadeDialog = () => {

const getBalances = async () => {
const localBalances: Record<string, bigint> = {};
const balancePromises = arcadeConnectors().map((account) => {
const balancePromises = arcadeConnectors.map((account) => {
return fetchBalanceWithRetry(account.name).then((balance) => {
localBalances[account.name] = balance;
return balance;
});
});
console.log(balancePromises);
await Promise.all(balancePromises);
setBalances(localBalances);
};
Expand Down Expand Up @@ -124,7 +107,7 @@ export const ArcadeDialog = () => {
)}
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 overflow-hidden my-6">
{arcadeConnectors().map((account, index) => {
{arcadeConnectors.map((account, index) => {
const masterAccount = getMasterAccount(account.name);
return (
<ArcadeAccountCard
Expand All @@ -134,7 +117,7 @@ export const ArcadeDialog = () => {
address={address!}
walletAccount={walletAccount!}
masterAccountAddress={masterAccount}
arcadeConnectors={arcadeConnectors()}
arcadeConnectors={arcadeConnectors}
genNewKey={genNewKey}
balance={balances[account.name]}
getBalance={getBalance}
Expand All @@ -149,13 +132,17 @@ export const ArcadeDialog = () => {
</div>
</div>
{(isDeploying || isGeneratingNewKey) && (
<div className="fixed inset-0 opacity-80 bg-terminal-black z-50 m-2 w-full h-full flex justify-center items-center">
<h3 className="loading-ellipsis">
<div className="fixed inset-0 opacity-80 bg-terminal-black z-50 m-2 w-full h-full">
<PixelatedImage
src={"/scenes/intro/arcade-account.png"}
pixelSize={5}
/>
<h3 className="loading-ellipsis absolute top-1/2 right-1/3">
{isSettingPermissions
? "Setting Permissions"
: isGeneratingNewKey
? "Generating New Key"
: "Deploying Account"}
: "Deploying Arcade Account"}
</h3>
</div>
)}
Expand Down
23 changes: 6 additions & 17 deletions ui/src/app/components/TopUpDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,26 @@ import { useConnectors } from "@starknet-react/core";
import Storage from "../lib/storage";
import { BurnerStorage } from "../types";
import { useBurner } from "../lib/burner";
import { getArcadeConnectors, getWalletConnectors } from "../lib/connectors";

export const TopUpDialog = () => {
const { account: walletAccount, address, connector } = useAccount();
const { connect, connectors } = useConnectors();
const { connect, available } = useConnectors();
const showTopUpDialog = useUIStore((state) => state.showTopUpDialog);
const topUpAccount = useUIStore((state) => state.topUpAccount);
const setTopUpAccount = useUIStore((state) => state.setTopUpAccount);
const { topUp, isToppingUp } = useBurner();

const arcadeConnectors = () =>
connectors.filter(
(connector) =>
typeof connector.id === "string" && connector.id.includes("0x")
);

const walletConnectors = () =>
connectors.filter(
(connector) =>
typeof connector.id !== "string" || !connector.id.includes("0x")
);
const arcadeConnectors = getArcadeConnectors(available);
const walletConnectors = getWalletConnectors(available);

let storage: BurnerStorage = Storage.get("burners") || {};
const masterConnected = address === storage[topUpAccount]?.masterAccount;

const arcadeConnector = arcadeConnectors().find(
const arcadeConnector = arcadeConnectors.find(
(connector) => connector.name === topUpAccount
);

console.log(arcadeConnector);
console.log(masterConnected);

return (
<>
<div className="fixed inset-0 opacity-80 bg-terminal-black z-40" />
Expand All @@ -47,7 +36,7 @@ export const TopUpDialog = () => {
</p>
<div className="flex flex-col items-center gap-5">
<p className="m-2 text-sm xl:text-xl 2xl:text-2xl">Connect Master</p>
{walletConnectors().map((connector, index) => (
{walletConnectors.map((connector, index) => (
<Button
disabled={masterConnected}
onClick={() => connect(connector)}
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/components/adventurer/DeathDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const DeathDialog = () => {
src={"/scenes/intro/skulls.png"}
pixelSize={rank <= 100 ? 10 : 20}
setImageLoading={setImageLoading}
fill={true}
/>

<div className="absolute inset-0 bg-black opacity-50"></div>
Expand Down
98 changes: 54 additions & 44 deletions ui/src/app/components/animations/PixelatedImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import React, { useEffect, useRef, useState } from "react";
interface PixelatedImageProps {
src: string;
pixelSize: number;
setImageLoading: (imageLoaded: boolean) => void;
setImageLoading?: (imageLoaded: boolean) => void;
fill?: boolean;
}

const PixelatedImage: React.FC<PixelatedImageProps> = ({
src,
pixelSize,
setImageLoading,
fill,
}) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
Expand All @@ -32,56 +34,64 @@ const PixelatedImage: React.FC<PixelatedImageProps> = ({
}, []);

useEffect(() => {
const image = new Image();
image.src = src;

image.onload = () => {
setImageLoading(true);
const canvas = canvasRef.current;
if (!canvas) return;

const ctx = canvas.getContext("2d");
if (!ctx) return;

const { width, height } = dimensions;

ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);

const scaledWidth = Math.ceil(width / pixelSize);
const scaledHeight = Math.ceil(height / pixelSize);
let maxTimeout = 0;

for (let y = 0; y < scaledHeight; y++) {
for (let x = 0; x < scaledWidth; x++) {
const timeout = Math.random() * 100;
maxTimeout = Math.max(maxTimeout, timeout);
setTimeout(() => {
// Updated drawImage method to scale the image to the canvas size
ctx.drawImage(
image,
x * (image.width / scaledWidth),
y * (image.height / scaledHeight),
image.width / scaledWidth,
image.height / scaledHeight,
x * pixelSize,
y * pixelSize,
pixelSize,
pixelSize
);
}, timeout);
const pixelateImage = () => {
const image = new Image();
image.src = src;

image.onload = () => {
setImageLoading && setImageLoading(true);
const canvas = canvasRef.current;
if (!canvas) return;

const ctx = canvas.getContext("2d");
if (!ctx) return;

const { width, height } = dimensions;

const aspectRatio = image.width / image.height;

const newHeight = fill ? height : Math.min(height, image.width);
const newWidth = fill ? width : newHeight / aspectRatio;

ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);

const scaledWidth = Math.ceil(newWidth / pixelSize);
const scaledHeight = Math.ceil(newHeight / pixelSize);
let maxTimeout = 0;

for (let y = 0; y < scaledHeight; y++) {
for (let x = 0; x < scaledWidth; x++) {
const timeout = Math.random() * 100;
maxTimeout = Math.max(maxTimeout, timeout);
setTimeout(() => {
// Updated drawImage method to scale the image to the canvas size
ctx.drawImage(
image,
x * (image.width / scaledWidth),
y * (image.height / scaledHeight),
image.width / scaledWidth,
image.height / scaledHeight,
x * pixelSize,
y * pixelSize,
pixelSize,
pixelSize
);
}, timeout);
}
}
}

setTimeout(() => {
setImageLoading(false);
}, maxTimeout);
setTimeout(() => {
setImageLoading && setImageLoading(true);
}, maxTimeout);
};
};
pixelateImage();
}, [src, pixelSize, dimensions]);

return (
<canvas
className="absolute"
className="absolute animate-pulse"
ref={canvasRef}
width={dimensions.width}
height={dimensions.height}
Expand Down
67 changes: 59 additions & 8 deletions ui/src/app/components/intro/ArcadeIntro.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,73 @@
import { useState } from "react";
import { useAccount, useConnectors } from "@starknet-react/core";
import { useBurner } from "@/app/lib/burner";
import { Button } from "../buttons/Button";
import useUIStore from "@/app/hooks/useUIStore";
import PixelatedImage from "../animations/PixelatedImage";
import { getWalletConnectors } from "@/app/lib/connectors";

export const ArcadeIntro = () => {
const { create } = useBurner();
const { address } = useAccount();
const { connect, available } = useConnectors();
const isWrongNetwork = useUIStore((state) => state.isWrongNetwork);
const { getMasterAccount, create, isDeploying, isSettingPermissions } =
useBurner();
const walletConnectors = getWalletConnectors(available);
return (
<>
<div className="fixed inset-0 opacity-80 bg-terminal-black z-40" />
<div className="fixed text-center sm:top-1/8 sm:left-1/8 sm:left-1/4 sm:w-3/4 sm:w-1/2 h-3/4 border-4 bg-terminal-black z-50 border-terminal-green p-4 overflow-y-auto">
<h3 className="mt-4">Create Arcade Account</h3>
<p className="m-2 text-sm xl:text-xl 2xl:text-2xl">
Welcome Adventurer! In order to begin your journey you will need to
create an arcade account.
</p>
<Button onClick={() => create()} disabled={isWrongNetwork}>
CREATE
</Button>
<div className="flex flex-col gap-5 items-center">
<p className="m-2 text-sm xl:text-xl 2xl:text-2xl">
Greetings! Behold, the revelation of Arcade Accounts, the key to
supercharging onchain games! These promise swift transactions,
unleashing a 10x surge in your gameplay speed.
</p>
<p className="text-sm xl:text-xl 2xl:text-2xl">
Fear not, for they're guarded by a labyrinth of security features,
fit for even the wiliest of adventurers!
</p>
<p className=" text-sm xl:text-xl 2xl:text-2xl">
Connect using a wallet provider.
</p>
<div className="flex flex-col w-1/4">
{walletConnectors.map((connector, index) => (
<Button
disabled={address !== undefined}
onClick={() => connect(connector)}
key={index}
>
{connector.id === "braavos" || connector.id === "argentX"
? `Connect ${connector.id}`
: "Login With Email"}
</Button>
))}
</div>
<p className=" text-sm xl:text-xl 2xl:text-2xl">
Create Arcade Account (Fund, deploy & initiate security permissions)
</p>
<Button
onClick={() => create()}
disabled={isWrongNetwork}
className="w-1/4"
>
CREATE
</Button>
{isDeploying && (
<div className="fixed inset-0 opacity-80 bg-terminal-black z-50 m-2 w-full h-full">
<PixelatedImage
src={"/scenes/intro/arcade-account.png"}
pixelSize={5}
/>
<h3 className="loading-ellipsis absolute top-1/2 right-1/3">
{isSettingPermissions
? "Setting Permissions"
: "Deploying Arcade Account"}
</h3>
</div>
)}
</div>
</div>
</>
);
Expand Down
16 changes: 15 additions & 1 deletion ui/src/app/lib/connectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { InjectedConnector } from "@starknet-react/core";
import { useCallback } from "react";
import { InjectedConnector, Connector } from "@starknet-react/core";
// import { WebWalletConnector } from "@argent/starknet-react-webwallet-connector";

export const argentConnector = new InjectedConnector({
Expand All @@ -13,6 +14,19 @@ export const braavosConnector = new InjectedConnector({
},
});

export const getArcadeConnectors = (available: Connector[]) => {
return available.filter(
(connector) =>
typeof connector.id === "string" && connector.id.includes("0x")
);
};

export const getWalletConnectors = (available: Connector[]) =>
available.filter(
(connector) =>
typeof connector.id !== "string" || !connector.id.includes("0x")
);

function argentWebWalletUrl() {
switch (process.env.NEXT_PUBLIC_NETWORK) {
case "dev":
Expand Down
Loading

0 comments on commit 6e03d62

Please sign in to comment.