From e85240b13a6581d40de1f09ba7ede0e1b653acba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Mon, 12 May 2025 11:45:24 -0300 Subject: [PATCH 1/4] fix: correct deposit link --- src/app/(mobile-ui)/layout.tsx | 2 +- src/components/AddFunds/index.tsx | 4 ++-- src/constants/general.consts.ts | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/(mobile-ui)/layout.tsx b/src/app/(mobile-ui)/layout.tsx index ff3322e4c..78f6b3304 100644 --- a/src/app/(mobile-ui)/layout.tsx +++ b/src/app/(mobile-ui)/layout.tsx @@ -16,7 +16,7 @@ import { useEffect, useMemo, useState } from 'react' import { twMerge } from 'tailwind-merge' import '../../styles/globals.css' -const publicPathRegex = /^\/(request\/pay|claim)/ +const publicPathRegex = /^\/(request\/pay|claim|pay\/.+$)/ const Layout = ({ children }: { children: React.ReactNode }) => { const pathName = usePathname() diff --git a/src/components/AddFunds/index.tsx b/src/components/AddFunds/index.tsx index 053055cdb..38a021bac 100644 --- a/src/components/AddFunds/index.tsx +++ b/src/components/AddFunds/index.tsx @@ -10,7 +10,7 @@ import { Button, NavIcons } from '../0_Bruddle' import Icon from '../Global/Icon' import Modal from '../Global/Modal' import QRCodeWrapper from '../Global/QRCodeWrapper' - +import { BASE_URL } from '@/constants' type FundingMethod = 'exchange' | 'request_link' | null type Wallet = { name: string; logo: string } @@ -211,7 +211,7 @@ const UsingExchange = () => { const UsingRequestLink = () => { const { user } = useUserStore() - const depositLink = `https://peanut.me/${user?.user?.username}?action=deposit` + const depositLink = `${BASE_URL}/pay/${user?.user?.username}` const wallets: Wallet[] = useMemo( () => [ diff --git a/src/constants/general.consts.ts b/src/constants/general.consts.ts index 3b5b43a4f..46d48d8d1 100644 --- a/src/constants/general.consts.ts +++ b/src/constants/general.consts.ts @@ -32,6 +32,8 @@ export const PEANUT_API_URL = ( process.env.NEXT_PUBLIC_PEANUT_API_URL || 'https://api.peanut.to' ).replace(/\/$/, '') // remove any accidental trailing slash + +export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me' export const next_proxy_url = '/api/proxy' export const supportedMobulaChains = <{ name: string; chainId: string }[]>[ From 35d903b27a3eddf276152dbe1548b3382c1cebe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Mon, 12 May 2025 12:51:41 -0300 Subject: [PATCH 2/4] fix: recover from error adding account --- src/app/(mobile-ui)/home/page.tsx | 18 +++- src/context/authContext.tsx | 134 ++---------------------------- 2 files changed, 21 insertions(+), 131 deletions(-) diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index 6b8fc70b2..39579c9a3 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -18,11 +18,11 @@ import { useWalletStore } from '@/redux/hooks' import { formatExtendedNumber, getUserPreferences, printableUsdc, updateUserPreferences } from '@/utils' import Image from 'next/image' import Link from 'next/link' -import { useMemo, useState } from 'react' +import { useMemo, useState, useEffect } from 'react' import { twMerge } from 'tailwind-merge' export default function Home() { - const { balance } = useWallet() + const { balance, address } = useWallet() const { rewardWalletBalance } = useWalletStore() const [isRewardsModalOpen, setIsRewardsModalOpen] = useState(false) @@ -31,7 +31,7 @@ export default function Home() { return prefs?.balanceHidden ?? false }) - const { username, isFetchingUser, user } = useAuth() + const { username, isFetchingUser, user, addAccount } = useAuth() const userFullName = useMemo(() => { if (!user) return @@ -49,6 +49,18 @@ export default function Home() { const isLoading = isFetchingUser && !username + useEffect(() => { + // We have some users that didn't have the peanut wallet created + // correctly, so we need to create it + if (address && user && !user.accounts.some((a) => a.account_type === 'peanut-wallet')) { + addAccount({ + accountIdentifier: address, + accountType: 'peanut-wallet', + userId: user.user.userId, + }) + } + }, [user, address]) + if (isLoading) { return } diff --git a/src/context/authContext.tsx b/src/context/authContext.tsx index 4d1bd74aa..9753fa9d2 100644 --- a/src/context/authContext.tsx +++ b/src/context/authContext.tsx @@ -4,18 +4,16 @@ import * as interfaces from '@/interfaces' import { useAppDispatch, useUserStore } from '@/redux/hooks' import { setupActions } from '@/redux/slices/setup-slice' import { type GetUserLinksResponse, fetchWithSentry } from '@/utils' -import { ToastId, useToast } from '@chakra-ui/react' // TODO: use normmal toasts we use throughout the app, not chakra toasts! import { useAppKit } from '@reown/appkit/react' import { useRouter } from 'next/navigation' -import { createContext, ReactNode, useContext, useRef, useState } from 'react' +import { createContext, ReactNode, useContext, useState } from 'react' +import { useToast } from '@/components/0_Bruddle/Toast' interface AuthContextType { user: interfaces.IUserProfile | null userId: string | undefined username: string | undefined fetchUser: () => Promise - updateUserName: (username: string) => Promise - submitProfilePhoto: (file: File) => Promise updateBridgeCustomerData: (customer: GetUserLinksResponse) => Promise addBYOW: () => Promise addAccount: ({ @@ -48,6 +46,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { const { open: web3modalOpen } = useAppKit() const dispatch = useAppDispatch() const { user: authUser } = useUserStore() + const toast = useToast() const { data: user, isFetching: isFetchingUser, refetch: fetchUser } = useUserQuery(!authUser?.user.userId) @@ -56,69 +55,8 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { return fetchedUser ?? null } - const toast = useToast({ - position: 'bottom-right', - duration: 5000, - isClosable: true, - icon: '🥜', - }) - - const toastIdRef = useRef(undefined) const [isLoggingOut, setIsLoggingOut] = useState(false) - const updateUserName = async (username: string) => { - if (!user) return - - try { - if (toastIdRef.current) { - toast.close(toastIdRef.current) - } - toastIdRef.current = toast({ - status: 'loading', - title: 'Updating username...', - }) as ToastId - const response = await fetchWithSentry('/api/peanut/user/update-user', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - username: username, - userId: user.user.userId, - }), - }) - - if (response.status === 409) { - const data = await response.json() - toast.close(toastIdRef.current) - toastIdRef.current = toast({ - status: 'error', - title: data, - }) as ToastId - - return - } - - if (!response.ok) { - throw new Error(response.statusText) - } - toast.close(toastIdRef.current) - toastIdRef.current = toast({ - status: 'success', - title: 'Username updated successfully', - }) as ToastId - } catch (error) { - console.error('Error updating user', error) - toast.close(toastIdRef.current ?? '') - toastIdRef.current = toast({ - status: 'error', - title: 'Failed to update username', - description: 'Please try again later', - }) as ToastId - } finally { - fetchUser() - } - } const updateBridgeCustomerData = async (customer: GetUserLinksResponse) => { if (!user) return @@ -148,50 +86,6 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { } } - const submitProfilePhoto = async (file: File) => { - if (!user) return - - try { - if (toastIdRef.current) { - toast.close(toastIdRef.current) - } - toastIdRef.current = toast({ - status: 'loading', - title: 'Updating profile photo...', - }) as ToastId - const formData = new FormData() - formData.append('file', file) - - const response = await fetchWithSentry('/api/peanut/user/submit-profile-photo', { - method: 'POST', - headers: { - Authorization: `Bearer your-auth-token`, - 'api-key': 'your-api-key', - }, - body: formData, - }) - - if (response.ok) { - fetchUser() - } else { - throw new Error(response.statusText) - } - toast.close(toastIdRef.current) - toastIdRef.current = toast({ - status: 'success', - title: 'Profile photo updated successfully', - }) as ToastId - } catch (error) { - console.error('Error submitting profile photo', error) - toast.close(toastIdRef.current ?? '') - toastIdRef.current = toast({ - status: 'error', - title: 'Failed to update profile photo', - description: 'Please try again later', - }) as ToastId - } - } - const addBYOW = async () => { // we open the web3modal, so the user can disconnect the previous wallet, // connect a new wallet and allow the useEffect(..., [wagmiAddress]) in walletContext take over @@ -263,28 +157,14 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { dispatch(setupActions.resetSetup()) router.replace('/setup') - toast({ - status: 'success', - title: 'Logged out successfully', - duration: 3000, - }) + toast.success('Logged out successfully') } else { console.error('Failed to log out user') - toast({ - status: 'error', - title: 'Failed to log out', - description: 'Please try again', - duration: 5000, - }) + toast.error('Failed to log out') } } catch (error) { console.error('Error logging out user', error) - toast({ - status: 'error', - title: 'Error logging out', - description: 'Please try again', - duration: 5000, - }) + toast.error('Error logging out') } finally { setIsLoggingOut(false) } @@ -300,8 +180,6 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { username: user?.user?.username ?? undefined, updateBridgeCustomerData, fetchUser: legacy_fetchUser, - updateUserName, - submitProfilePhoto, addBYOW, addAccount, isFetchingUser, From ebcb1ede94865264caf3483892b017bba0ffd094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Mon, 12 May 2025 15:26:54 -0300 Subject: [PATCH 3/4] refactor: use BASE_URL constant --- src/app/(mobile-ui)/claim/page.tsx | 3 ++- src/app/(mobile-ui)/link-account/page.tsx | 3 ++- src/app/(mobile-ui)/profile/page.tsx | 3 ++- src/app/(mobile-ui)/refund/page.tsx | 3 ++- src/app/[...recipient]/layout.tsx | 3 ++- src/app/metadata.ts | 5 +++-- src/app/robots.ts | 3 ++- 7 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/app/(mobile-ui)/claim/page.tsx b/src/app/(mobile-ui)/claim/page.tsx index 5d44a3367..ef1ebb5c2 100644 --- a/src/app/(mobile-ui)/claim/page.tsx +++ b/src/app/(mobile-ui)/claim/page.tsx @@ -2,6 +2,7 @@ import { getLinkDetails } from '@/app/actions/claimLinks' import { Claim } from '@/components' import { formatAmount } from '@/utils' import { Metadata } from 'next' +import { BASE_URL } from '@/constants' export const dynamic = 'force-dynamic' @@ -15,7 +16,7 @@ export async function generateMetadata({ const resolvedSearchParams = await searchParams let title = 'Claim your tokens!' - const host = process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me' + const host = BASE_URL let linkDetails = undefined if (resolvedSearchParams.i && resolvedSearchParams.c) { diff --git a/src/app/(mobile-ui)/link-account/page.tsx b/src/app/(mobile-ui)/link-account/page.tsx index ba7cea5c5..9547344d3 100644 --- a/src/app/(mobile-ui)/link-account/page.tsx +++ b/src/app/(mobile-ui)/link-account/page.tsx @@ -1,11 +1,12 @@ import { LinkAccountComponent } from '@/components' +import { BASE_URL } from '@/constants' import { Metadata } from 'next' export const metadata: Metadata = { title: 'Peanut Protocol', description: 'Send crypto via link', - metadataBase: new URL('https://peanut.me'), + metadataBase: new URL(BASE_URL), icons: { icon: '/favicon.ico', diff --git a/src/app/(mobile-ui)/profile/page.tsx b/src/app/(mobile-ui)/profile/page.tsx index e366814a9..4c458b005 100644 --- a/src/app/(mobile-ui)/profile/page.tsx +++ b/src/app/(mobile-ui)/profile/page.tsx @@ -1,11 +1,12 @@ import { Profile } from '@/components' import PageContainer from '@/components/0_Bruddle/PageContainer' import { Metadata } from 'next' +import { BASE_URL } from '@/constants' export const metadata: Metadata = { title: 'Profile | Peanut Protocol', description: 'Manage your Peanut profile', - metadataBase: new URL('https://peanut.me'), + metadataBase: new URL(BASE_URL), icons: { icon: '/favicon.ico', diff --git a/src/app/(mobile-ui)/refund/page.tsx b/src/app/(mobile-ui)/refund/page.tsx index abf5c9832..f87506fa9 100644 --- a/src/app/(mobile-ui)/refund/page.tsx +++ b/src/app/(mobile-ui)/refund/page.tsx @@ -1,10 +1,11 @@ import { Metadata } from 'next' import { Refund } from '@/components' +import { BASE_URL } from '@/constants' export const metadata: Metadata = { title: 'Peanut Protocol', description: 'Send to Anyone', - metadataBase: new URL('https://peanut.me'), + metadataBase: new URL(BASE_URL), icons: { icon: '/favicon.ico', diff --git a/src/app/[...recipient]/layout.tsx b/src/app/[...recipient]/layout.tsx index 516ce318c..5550c33a4 100644 --- a/src/app/[...recipient]/layout.tsx +++ b/src/app/[...recipient]/layout.tsx @@ -1,6 +1,7 @@ import PaymentLayoutWrapper from './payment-layout-wrapper' import { printableAddress } from '@/utils' import { isAddress } from 'viem' +import { BASE_URL } from '@/constants' function getPreviewUrl( host: string, @@ -29,7 +30,7 @@ function getPreviewUrl( export async function generateMetadata({ params }: any) { let title = 'Request Payment | Peanut' let previewUrl = '/metadata-img.jpg' - const host = process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me' + const host = BASE_URL if (!host) { console.error('Error: NEXT_PUBLIC_BASE_URL is not defined') diff --git a/src/app/metadata.ts b/src/app/metadata.ts index 050dcb2bb..6500a5cc3 100644 --- a/src/app/metadata.ts +++ b/src/app/metadata.ts @@ -1,4 +1,5 @@ import { Metadata } from 'next' +import { BASE_URL } from '@/constants' export function generateMetadata({ title, @@ -14,14 +15,14 @@ export function generateMetadata({ return { title, description, - metadataBase: new URL(process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me'), + metadataBase: new URL(BASE_URL), icons: { icon: '/favicon.ico' }, keywords, openGraph: { type: 'website', title, description, - url: 'https://peanut.me', + url: BASE_URL, siteName: 'Peanut Protocol', images: [{ url: image, width: 1200, height: 630, alt: title }], }, diff --git a/src/app/robots.ts b/src/app/robots.ts index a64378c7c..7de4250ee 100644 --- a/src/app/robots.ts +++ b/src/app/robots.ts @@ -1,4 +1,5 @@ import type { MetadataRoute } from 'next' +import { BASE_URL } from '@/constants' export default function robots(): MetadataRoute.Robots { return { @@ -17,6 +18,6 @@ export default function robots(): MetadataRoute.Robots { crawlDelay: 10, }, ], - sitemap: `${process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me'}/sitemap.xml`, + sitemap: `${BASE_URL}/sitemap.xml`, } } From 8fe9773b37b29314a5da16ef6a37935d80139292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Mon, 12 May 2025 15:33:54 -0300 Subject: [PATCH 4/4] fix: handle sendlinks without user sender --- src/components/Claim/Claim.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Claim/Claim.tsx b/src/components/Claim/Claim.tsx index b4d6f3d20..cd218d701 100644 --- a/src/components/Claim/Claim.tsx +++ b/src/components/Claim/Claim.tsx @@ -126,7 +126,7 @@ export const Claim = ({}) => { } if (0 < price) setTokenPrice(price) - if (user && user.user.userId === sendLink.sender.userId) { + if (user && user.user.userId === sendLink.sender?.userId) { setLinkState(_consts.claimLinkStateType.CLAIM_SENDER) } else { setLinkState(_consts.claimLinkStateType.CLAIM)