Skip to content

Commit

Permalink
move components and introduce bare modal
Browse files Browse the repository at this point in the history
  • Loading branch information
coindegen committed Sep 9, 2024
1 parent 18d4247 commit e90af96
Show file tree
Hide file tree
Showing 37 changed files with 349 additions and 34 deletions.
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-tailwindcss"]
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@usecapsule/viem-v2-integration": "^1.22.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"geist": "^1.3.1",
"input-otp": "^1.2.4",
"lucide-react": "^0.438.0",
"next": "14.2.7",
Expand All @@ -35,6 +36,8 @@
"eslint": "^8",
"eslint-config-next": "14.2.7",
"postcss": "^8",
"prettier": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.6",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
Expand Down
3 changes: 3 additions & 0 deletions public/dream_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/app/assets/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FC, SVGProps } from "react";

export const DreamLogo: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="52"
height="56"
viewBox="0 0 52 56"
fill="none"
{...props}
>
<path
d="M46.6503 10.5366L30.3854 1.17583C27.6611 -0.393848 24.2702 -0.393848 21.546 1.18729L5.38445 10.5481C2.6947 12.1178 1.01648 15.0165 1.00498 18.1215L0.94751 37.8399C0.94751 40.9792 2.62573 43.9009 5.34997 45.4706L21.6149 54.8313C22.9713 55.6104 24.5001 56 26.0174 56C27.5347 56 29.0865 55.599 30.4428 54.8084L46.6043 45.4476C49.3056 43.8894 50.9838 40.9792 50.9953 37.8742L51.0528 18.1559C51.0528 15.0165 49.3746 12.1063 46.6503 10.5366ZM7.69488 14.5124L13.6491 11.0637C14.5457 10.5481 15.9366 10.8231 17.7872 11.8886L34.0522 21.2494C35.3626 22.0056 36.1672 23.4034 36.1557 24.9043L36.0982 44.68C36.1327 46.1007 35.6844 46.4903 34.512 47.1663L31.2245 49.0682V34.4141C31.2245 31.2747 29.5463 28.353 26.822 26.7834L10.5571 17.4226C9.33862 16.7237 7.60292 16.3227 5.9362 16.506C6.29253 15.681 6.90175 14.9707 7.69488 14.5124ZM5.54538 37.1753L5.59136 22.1316C5.59136 21.3754 5.83274 21.2379 5.90171 21.1921C6.44196 20.8827 7.6489 21.0431 8.24663 21.3869L20.6034 28.502L5.53388 37.1753H5.54538ZM7.4305 41.3802L25.1323 31.1945C26.0634 31.9851 26.6266 33.1537 26.6266 34.4141V51.3826C25.707 51.5201 24.7415 51.3483 23.9139 50.867L7.4305 41.3802ZM19.5804 7.62641L23.8564 5.15159C24.5116 4.77349 25.2472 4.57871 25.9714 4.57871C26.6956 4.57871 27.4312 4.76203 28.0749 5.14013L44.3399 14.5009C45.6503 15.2571 46.4549 16.6549 46.4434 18.1559L46.3859 37.8742C46.3859 39.3637 45.5813 40.7501 44.2824 41.4948L40.6846 43.5801L40.7421 24.9158C40.7421 21.7764 39.0638 18.8548 36.3396 17.2851L19.5804 7.62641Z"
fill="black"
/>
</svg>
);
1 change: 1 addition & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
--cpsl-font-family: var(--font-geist-sans);
}

@media (prefers-color-scheme: dark) {
Expand Down
9 changes: 4 additions & 5 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });
import { GeistSans } from "geist/font/sans";
import { GeistMono } from "geist/font/mono";

export const metadata: Metadata = {
title: "Create Next App",
Expand All @@ -15,8 +14,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<html lang="en" className={`${GeistSans.variable} ${GeistMono.variable}`}>
<body>{children}</body>
</html>
);
}
File renamed without changes.
248 changes: 248 additions & 0 deletions src/app/login/components/CapsuleBare.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
"use client";

import { useRouter } from "next/navigation";
import { GeistSans } from "geist/font/sans";

import Capsule, {
CapsuleModal,
ConstructorOpts,
Environment,
Network,
OAuthMethod,
WalletType,
} from "@usecapsule/react-sdk";
import { type FC, useCallback, useEffect, useState } from "react";
import "@usecapsule/react-sdk/styles.css";

import { DreamLogo } from "@/app/assets/logo";

import Image from "next/image";

// import { CapsuleModalExampleWrapper } from "./CapsuleModalExampleWrapper";

import { useToast } from "./core/toast/use-toast";
import { Button } from "./core";
import { signEvmMessage } from "./CapsuleSigningExamples";
import { CapsuleLoggedIn } from "./CapsuleLoggedIn";

const FOREGROUND_COLOR = "#87CEEB";
const BACKGROUND_COLOR = "#ffffff";

const CAPSULE_API_KEY = process.env.NEXT_PUBLIC_CAPSULE_API_KEY;

const CAPSULE_ENVIRONMENT = Environment.DEVELOPMENT;

// Step 3: (Optional) Customize the Capsule SDK integration
// These options allow you to tailor the look and feel of the Capsule integration
// For a full list of constructor options, visit:
// https://docs.usecapsule.com/integration-guide/customize-capsule#constructor-options
const constructorOpts: ConstructorOpts = {
emailPrimaryColor: FOREGROUND_COLOR,
githubUrl: "",
linkedinUrl: "",
xUrl: "https://x.com/theDreamOS",
homepageUrl: "https://dreamos.app",
supportUrl: "",
supportedWalletTypes: {
[WalletType.EVM]: true,
[WalletType.SOLANA]: true,
},
};

// Step 4: Initialize the Capsule client
// Create a new Capsule instance with your environment, API key, and optional constructor parameters
const capsuleClient = new Capsule(
CAPSULE_ENVIRONMENT,
CAPSULE_API_KEY,
constructorOpts,
);

export const CapsuleBare: FC<{}> = () => {
const { toast } = useToast();
const [isLoading, setIsLoading] = useState<boolean>(false);

const router = useRouter();

const [isUserLoggedIn, setIsUserLoggedIn] = useState<boolean>(false);
const [isCapsuleModalOpen, setIsCapsuleModalOpen] = useState<boolean>(false);

const [userRecoverySecret] = useState<string>("");

const [message, setMessage] = useState<string>("");

const [signature, setSignature] = useState<string>("");
const [selectedSigner, setSelectedSigner] = useState<string>("");

const [walletId, setWalletId] = useState<string>("");
const [walletAddress, setWalletAddress] = useState<string>("");

const backgroundColor = BACKGROUND_COLOR;
const foregroundColor = FOREGROUND_COLOR;

const checkLoginStatus = useCallback(async () => {
try {
const isLoggedIn = await capsuleClient.isFullyLoggedIn();

if (isLoggedIn) {
const wallets = capsuleClient.getWallets();
setWalletId(Object.values(wallets)[0].id!);
setWalletAddress(Object.values(wallets)[0].address!);
toast({
title: "Logged In",
description:
"You're logged in and ready to sign messages with Capsule.",
});
}
setIsUserLoggedIn(isLoggedIn);
} catch (err) {
console.error("Capsule login status check failed:", err);
toast({
title: "Capsule Login Check Error",
description:
"Failed to check Capsule login status. See console for details.",
variant: "destructive",
});
}
}, [toast]);

// Step 6: Check user's login status
// This effect runs on component mount to determine if the user is already logged in
useEffect(() => {
checkLoginStatus();
}, [checkLoginStatus]);

// Step 7: Handle opening the Capsule Modal
// Simply set the isCapsuleModalOpen state to true to display the modal
const handleModalOpen = () => {
setIsCapsuleModalOpen(true);
};

// Step 8: Handle Capsule Modal closure
// This function is called when the modal is closed, either by the user or after successful login
// You can perform any necessary cleanup or trigger app-specific actions here
const handleModalClose = async () => {
setIsCapsuleModalOpen(false);
checkLoginStatus();
};

// todo: uncomment
// Step 9: Handle message signing
// This function demonstrates how to sign a message using Capsule
const handleSignMessage = async () => {
setIsLoading(true);
try {
const signature = await signEvmMessage(
capsuleClient,
selectedSigner,
message,
);
setSignature(signature);
toast({
title: "Capsule Message Signed",
description: "Message has been signed successfully using Capsule.",
duration: 3000,
});
} catch (error) {
console.error("Capsule message signing failed:", error);
toast({
title: "Capsule Signing Error",
description:
"Failed to sign message with Capsule. See console for details.",
duration: 3000,
variant: "destructive",
});
} finally {
setIsLoading(false);
}
};

// todo: make sure this resets the UI
const handleLogout = async () => {
await capsuleClient.logout();
toast({
title: "Dream Logout",
description: "You have been successfully logged out from DreamOS.",
});
router.push("/");
resetState();
// router.refresh();
};

// Helper function to reset the component state
const resetState = () => {
setMessage("");
isCapsuleModalOpen && setIsCapsuleModalOpen(false);
};

// Render the appropriate component based on the authentication state
return isUserLoggedIn ? (
<CapsuleLoggedIn
isLoading={isLoading}
signature={signature}
walletId={walletId}
walletAddress={walletAddress}
userRecoverySecret={userRecoverySecret}
message={message}
selectedSigner={selectedSigner}
isUserLoggedIn={isUserLoggedIn}
setSelectedSigner={setSelectedSigner}
setMessage={(e: any) => setMessage(e.target.value)}
handleLogout={handleLogout}
handleSignMessage={handleSignMessage}
/>
) : (
<>
<CapsuleModal
bareModal={true}
logo={"/dream_logo.svg"}
theme={{
backgroundColor,
foregroundColor,
oAuthLogoVariant: "dark",
}}
capsule={capsuleClient}
// networks={[
// Network.ETHEREUM,
// Network.ARBITRUM,
// Network.BASE,
// Network.OPTIMISM,
// Network.POLYGON,
// ]}
isOpen={true}
onClose={handleModalClose}
appName="DreamOS Test Task"
oAuthMethods={[
OAuthMethod.GOOGLE,
OAuthMethod.TWITTER,
OAuthMethod.DISCORD,
OAuthMethod.APPLE,
]}
disableEmailLogin={false}
disablePhoneLogin={true}
onRampConfig={{
network: "ethereum",
asset: "eth",
providers: [
{ id: "STRIPE" },
// Uncomment the following to add Ramp as a provider
// {
// id: "RAMP",
// hostApiKey: "your-ramp-api-key",
// },
],
testMode: true,
}}
// onModalStepChange={(val) => {
// console.log("modal step change", val);
// }}
// onExpandModalChange={(val) => {
// console.log("modal expand change", val);
// }}
// createWalletOverride={async (capsule) => {
// console.log("overriding wallet", capsule);
// return { walletIds: ["123"] };
// }}
/>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,17 @@ export const CapsuleComponent: FC<{}> = () => {
// handleSignMessage={() => {}}
// />
<>
<Button onClick={handleModalOpen} className="w-full sm:w-auto text-sm">
{/* <Button onClick={handleModalOpen} className="w-full sm:w-auto text-sm">
<Image
src="https://www.dreamos.app/img/icon/welcome.svg"
alt="DreamOS logo"
width={128}
height={128}
/>
</Button>
</Button> */}

<CapsuleModal
bareModal={true}
logo="https://www.dreamos.app/img/icon/welcome.svg"
theme={{
backgroundColor,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Fragment } from "react";
import { CapsuleBare } from "./components/CapsuleBare";

export default function Login() {
return (
<main className="flex h-full min-h-screen bg-background p-12">
<div className="flex w-full flex-col items-center justify-between">
<div className="z-10 w-full max-w-5xl flex-col items-start justify-between text-sm lg:flex">
<div className="text-3xl font-semibold text-black opacity-50">
Welcome to
</div>
<div className="text-3xl font-semibold text-black">the Dream</div>
</div>
<CapsuleBare />;
</div>
</main>
);
}
Loading

0 comments on commit e90af96

Please sign in to comment.