From ed22dc33ae73d7cca967f5d1647612578ca5981c Mon Sep 17 00:00:00 2001 From: Alfredo Bonilla Date: Thu, 20 Feb 2025 07:27:21 -0600 Subject: [PATCH] feat: update wallet connection and session --- .../_components/features/ProfileOptions.tsx | 2 +- .../_components/features/WalletConnect.tsx | 81 ++++++++++---- .../features/WalletConnectFlow.tsx | 100 ++++++++---------- .../features/checkout/OrderReview.tsx | 19 +++- apps/web/src/app/user-profile/page.tsx | 45 ++++---- apps/web/src/providers/starknet.tsx | 2 - 6 files changed, 138 insertions(+), 111 deletions(-) diff --git a/apps/web/src/app/_components/features/ProfileOptions.tsx b/apps/web/src/app/_components/features/ProfileOptions.tsx index db235d8..501aaec 100644 --- a/apps/web/src/app/_components/features/ProfileOptions.tsx +++ b/apps/web/src/app/_components/features/ProfileOptions.tsx @@ -44,7 +44,7 @@ export function ProfileOptions({ address: _ }: ProfileOptionsProps) { // Common options that are always shown const commonOptions: ProfileOption[] = [ - { icon: UserIcon, label: t("user_profile"), href: "/user/user-profile" }, + { icon: UserIcon, label: t("user_profile"), href: "/user-profile" }, { icon: HeartIcon, label: t("favorite_products"), diff --git a/apps/web/src/app/_components/features/WalletConnect.tsx b/apps/web/src/app/_components/features/WalletConnect.tsx index f5dbdde..797996a 100644 --- a/apps/web/src/app/_components/features/WalletConnect.tsx +++ b/apps/web/src/app/_components/features/WalletConnect.tsx @@ -11,6 +11,7 @@ import { import { signIn, signOut } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; +import { toast } from "react-hot-toast"; import { useTranslation } from "react-i18next"; import { connect } from "starknetkit"; import { ARGENT_WEBWALLET_URL, MESSAGE } from "~/constants"; @@ -34,7 +35,8 @@ export default function WalletConnect({ }: WalletConnectProps) { const [isClient, setIsClient] = useState(false); const [isConnecting, setIsConnecting] = useState(false); - const { address } = useAccount(); + const [connectionError, setConnectionError] = useState(null); + const { address, isConnecting: isAutoConnecting } = useAccount(); const { connect: connectWallet, connectors } = useConnect(); const { disconnect } = useDisconnect(); const { signTypedDataAsync } = useSignTypedData(MESSAGE); @@ -42,13 +44,26 @@ export default function WalletConnect({ const router = useRouter(); const utils = api.useUtils(); + // Reset error when modal opens + useEffect(() => { + if (isOpen) { + setConnectionError(null); + } + }, [isOpen]); + const handleConnectWallet = async (connector: Connector): Promise => { if (connector) { try { + setIsConnecting(true); + setConnectionError(null); const result = connectWallet({ connector }); console.log("connector result", result); + router.push("/marketplace"); } catch (error) { console.error("Error connecting wallet:", error); + setConnectionError(t("error_connecting_wallet")); + } finally { + setIsConnecting(false); } } }; @@ -56,6 +71,7 @@ export default function WalletConnect({ const handleConnectArgentMobile = async (): Promise => { try { setIsConnecting(true); + setConnectionError(null); const result = await connect({ webWalletUrl: ARGENT_WEBWALLET_URL, argentMobileOptions: { @@ -65,13 +81,14 @@ export default function WalletConnect({ }); if (result?.connector) { - const connectorResult = connectWallet({ + connectWallet({ connector: result.connector as unknown as Connector, }); - console.log("connectorResult", connectorResult); + router.push("/marketplace"); } } catch (error) { console.error("Error connecting Argent Mobile:", error); + setConnectionError(t("error_connecting_argent")); } finally { setIsConnecting(false); } @@ -79,6 +96,8 @@ export default function WalletConnect({ const handleSignMessage = async (): Promise => { try { + setIsConnecting(true); + setConnectionError(null); const signature = await signTypedDataAsync(); const signInResult = await signIn("credentials", { @@ -90,17 +109,30 @@ export default function WalletConnect({ if (signInResult?.ok) { await utils.user.getMe.prefetch(); + toast.success(t("successfully_signed_in")); onSuccess?.(); + } else { + setConnectionError(t("error_signing_in")); + toast.error(t("error_signing_in")); } } catch (err) { console.error(t("error_signing_message"), err); + setConnectionError(t("error_signing_message")); + toast.error(t("error_signing_message")); + } finally { + setIsConnecting(false); } }; const handleDisconnectWallet = (): void => { - disconnect(); - void signOut(); - router.push("/"); + try { + disconnect(); + router.push("/"); + toast.success(t("successfully_disconnected")); + } catch (error) { + console.error("Error disconnecting:", error); + toast.error(t("error_disconnecting")); + } }; useEffect(() => { @@ -115,25 +147,27 @@ export default function WalletConnect({

CofiBlocks

+ {isAutoConnecting && ( +
+ + {t("connecting_to_wallet")} + +
+ )} + {connectionError && ( +
+ {connectionError} +
+ )}
{address ? ( - <> - - - + ) : ( <> {isClient && ( @@ -158,6 +192,7 @@ export default function WalletConnect({ key={connector.id} onClick={() => void handleConnectWallet(connector)} className="w-full max-w-[15rem]" + disabled={!connector.available() || isConnecting} >
diff --git a/apps/web/src/app/_components/features/WalletConnectFlow.tsx b/apps/web/src/app/_components/features/WalletConnectFlow.tsx index c026e4e..b71566d 100644 --- a/apps/web/src/app/_components/features/WalletConnectFlow.tsx +++ b/apps/web/src/app/_components/features/WalletConnectFlow.tsx @@ -3,12 +3,7 @@ import { ChevronRightIcon } from "@heroicons/react/24/outline"; import Button from "@repo/ui/button"; import { Text } from "@repo/ui/typography"; -import { - type Connector, - useAccount, - useConnect, - useDisconnect, -} from "@starknet-react/core"; +import { type Connector, useAccount, useConnect } from "@starknet-react/core"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -18,9 +13,9 @@ import { ARGENT_WEBWALLET_URL } from "~/constants"; export default function WalletConnectFlow() { const [isClient, setIsClient] = useState(false); const [isConnecting, setIsConnecting] = useState(false); - const { address } = useAccount(); + const [connectionError, setConnectionError] = useState(null); + const { isConnecting: isAutoConnecting } = useAccount(); const { connect: connectWallet, connectors } = useConnect(); - const { disconnect } = useDisconnect(); const { t } = useTranslation(); const router = useRouter(); @@ -28,10 +23,12 @@ export default function WalletConnectFlow() { if (connector) { try { setIsConnecting(true); + setConnectionError(null); connectWallet({ connector }); - router.push("/"); + router.push("/marketplace"); } catch (error) { console.error("Failed to connect wallet:", error); + setConnectionError(t("error_connecting_wallet")); } finally { setIsConnecting(false); } @@ -41,6 +38,7 @@ export default function WalletConnectFlow() { const handleConnectArgentMobile = async (): Promise => { try { setIsConnecting(true); + setConnectionError(null); const result = await connect({ webWalletUrl: ARGENT_WEBWALLET_URL, argentMobileOptions: { @@ -53,27 +51,16 @@ export default function WalletConnectFlow() { connectWallet({ connector: result.connector as unknown as Connector, }); - router.push("/"); + router.push("/marketplace"); } } catch (error) { console.error("Error connecting Argent Mobile:", error); + setConnectionError(t("error_connecting_argent")); } finally { setIsConnecting(false); } }; - const handleDisconnectWallet = (): void => { - disconnect(); - router.push("/"); - }; - - // Redirect to marketplace when address is available - useEffect(() => { - if (address) { - router.push("/marketplace"); - } - }, [address, router]); - useEffect(() => { setIsClient(true); }, []); @@ -85,52 +72,51 @@ export default function WalletConnectFlow() { {t("connect_your_wallet")}
+ {isAutoConnecting && ( +
+ + {t("connecting_to_wallet")} + +
+ )} + {connectionError && ( +
+ {connectionError} +
+ )}
- {address ? ( - - ) : ( + {isClient && ( <> - {isClient && ( - <> + + {Array.isArray(connectors) && + connectors.map((connector) => ( - {Array.isArray(connectors) && - connectors.map((connector) => ( - - ))} - - )} + ))} )}
diff --git a/apps/web/src/app/_components/features/checkout/OrderReview.tsx b/apps/web/src/app/_components/features/checkout/OrderReview.tsx index d255d4f..c9511ae 100644 --- a/apps/web/src/app/_components/features/checkout/OrderReview.tsx +++ b/apps/web/src/app/_components/features/checkout/OrderReview.tsx @@ -19,6 +19,23 @@ import type { CartItem } from "~/store/cartAtom"; import Confirmation from "./Confirmation"; import { CurrencySelector } from "./CurrencySelector"; +const getImageUrl = (src: string) => { + if (src.startsWith("Qm")) { + return `${process.env.NEXT_PUBLIC_GATEWAY_URL}/ipfs/${src}`; + } + if (src.startsWith("ipfs://")) { + return `${process.env.NEXT_PUBLIC_GATEWAY_URL}/ipfs/${src.replace("ipfs://", "")}`; + } + if ( + src.startsWith("http://") || + src.startsWith("https://") || + src.startsWith("/") + ) { + return src; + } + return "/images/cafe1.webp"; // Fallback image +}; + interface OrderReviewProps { readonly onNext: () => void; readonly onCurrencySelect: (currency: string) => void; @@ -116,7 +133,7 @@ export default function OrderReview({
{item.name} { - if (!user && !isLoading && status === "authenticated") { - toast.error(t("error_fetching_profile")); - router.push("/"); - } - }, [user, isLoading, router, t, status]); - - // Handle session status - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); + // Show loading state while checking data + if (isLoading) { + return ( +
+
+
+
+
+
+
+
+ ); + } // Check if user needs to connect wallet - const needsWalletConnection = - !address || user?.walletAddress?.startsWith("placeholder_"); + const needsWalletConnection = !address; // Show wallet connection flow if needed if (needsWalletConnection) { @@ -80,25 +78,18 @@ export default function UserProfile() { ); } - // Show loading state - if (status === "loading" || isLoading) { + // Only show profile if we have user data + if (!user) { return (
-
+
-
-
-
+

{t("error_loading_profile")}

); } - // Return null if no user data - if (!user || status === "unauthenticated") { - return null; - } - const userProfile = { name: user.name ?? t("unnamed_user"), country: "costa_rica", diff --git a/apps/web/src/providers/starknet.tsx b/apps/web/src/providers/starknet.tsx index 7b0b06d..fb2874f 100644 --- a/apps/web/src/providers/starknet.tsx +++ b/apps/web/src/providers/starknet.tsx @@ -12,10 +12,8 @@ export default function StarknetProvider({ children: React.ReactNode; }) { const { connectors } = useInjectedConnectors({ - // Show these connectors if the user has no connector installed. recommended: [argent(), braavos()], includeRecommended: "onlyIfNoConnectors", - // Randomize the order of the connectors. order: "random", });