From 08fafedeb94092419b2172e6c70f1b63bf19e88d Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 12:50:35 +0530 Subject: [PATCH 01/10] add 1 second delay in login flow --- src/components/Setup/Views/JoinWaitlist.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Setup/Views/JoinWaitlist.tsx b/src/components/Setup/Views/JoinWaitlist.tsx index 5c6bf5ef2..203097e0a 100644 --- a/src/components/Setup/Views/JoinWaitlist.tsx +++ b/src/components/Setup/Views/JoinWaitlist.tsx @@ -61,6 +61,8 @@ const JoinWaitlist = () => { const onLoginClick = async () => { try { await handleLogin() + // 1 second delay for user context and cookies to be updated + await new Promise((resolve) => setTimeout(resolve, 1000)) const localStorageRedirect = getFromLocalStorage('redirect') const redirect_uri = searchParams.get('redirect_uri') if (redirect_uri) { From 0027be71b451a0839dc939f382424ac7cabbea3a Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 13:10:23 +0530 Subject: [PATCH 02/10] refactor: add readiness check before redirecting in layout and remove unnecessary delay in login flow --- src/app/(mobile-ui)/layout.tsx | 4 ++-- src/components/Setup/Views/JoinWaitlist.tsx | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/(mobile-ui)/layout.tsx b/src/app/(mobile-ui)/layout.tsx index 024c93328..1e4c0f55d 100644 --- a/src/app/(mobile-ui)/layout.tsx +++ b/src/app/(mobile-ui)/layout.tsx @@ -79,10 +79,10 @@ const Layout = ({ children }: { children: React.ReactNode }) => { const isPublicPath = publicPathRegex.test(pathName) useEffect(() => { - if (!isPublicPath && !isFetchingUser && !user) { + if (isReady && !isPublicPath && !isFetchingUser && !user) { router.push('/setup') } - }, [user, isFetchingUser]) + }, [isReady, user, isFetchingUser]) if (!isReady || isFetchingUser || (!hasToken && !isPublicPath) || (!isPublicPath && !user)) { return ( diff --git a/src/components/Setup/Views/JoinWaitlist.tsx b/src/components/Setup/Views/JoinWaitlist.tsx index 203097e0a..5c6bf5ef2 100644 --- a/src/components/Setup/Views/JoinWaitlist.tsx +++ b/src/components/Setup/Views/JoinWaitlist.tsx @@ -61,8 +61,6 @@ const JoinWaitlist = () => { const onLoginClick = async () => { try { await handleLogin() - // 1 second delay for user context and cookies to be updated - await new Promise((resolve) => setTimeout(resolve, 1000)) const localStorageRedirect = getFromLocalStorage('redirect') const redirect_uri = searchParams.get('redirect_uri') if (redirect_uri) { From a4d8c879e473f65a9eb5f6d4afae7a7f7daffb93 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 13:24:36 +0530 Subject: [PATCH 03/10] fix: update isLoading to isFetching in useUserQuery for consistency --- src/app/(mobile-ui)/layout.tsx | 4 ++-- src/context/authContext.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/(mobile-ui)/layout.tsx b/src/app/(mobile-ui)/layout.tsx index 1e4c0f55d..024c93328 100644 --- a/src/app/(mobile-ui)/layout.tsx +++ b/src/app/(mobile-ui)/layout.tsx @@ -79,10 +79,10 @@ const Layout = ({ children }: { children: React.ReactNode }) => { const isPublicPath = publicPathRegex.test(pathName) useEffect(() => { - if (isReady && !isPublicPath && !isFetchingUser && !user) { + if (!isPublicPath && !isFetchingUser && !user) { router.push('/setup') } - }, [isReady, user, isFetchingUser]) + }, [user, isFetchingUser]) if (!isReady || isFetchingUser || (!hasToken && !isPublicPath) || (!isPublicPath && !user)) { return ( diff --git a/src/context/authContext.tsx b/src/context/authContext.tsx index bbdc9c220..dc4472119 100644 --- a/src/context/authContext.tsx +++ b/src/context/authContext.tsx @@ -54,7 +54,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { const queryClient = useQueryClient() const LOCAL_STORAGE_WEB_AUTHN_KEY = 'web-authn-key' - const { data: user, isLoading: isFetchingUser, refetch: fetchUser } = useUserQuery(!authUser?.user.userId) + const { data: user, isFetching: isFetchingUser, refetch: fetchUser } = useUserQuery(!authUser?.user.userId) // Pre-compute a Set of invited usernames for O(1) lookups const invitedUsernamesSet = useMemo(() => { From 5bb8f9c97592f6544a8ac0871b8562ac60889749 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 14:08:10 +0530 Subject: [PATCH 04/10] fix: user has to login twice --- src/components/Setup/Views/JoinWaitlist.tsx | 16 ++++++++++++---- src/context/authContext.tsx | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/Setup/Views/JoinWaitlist.tsx b/src/components/Setup/Views/JoinWaitlist.tsx index 5c6bf5ef2..8a8ed3ccb 100644 --- a/src/components/Setup/Views/JoinWaitlist.tsx +++ b/src/components/Setup/Views/JoinWaitlist.tsx @@ -4,7 +4,7 @@ import { Button } from '@/components/0_Bruddle' import { useToast } from '@/components/0_Bruddle/Toast' import ValidatedInput from '@/components/Global/ValidatedInput' import { useZeroDev } from '@/hooks/useZeroDev' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { twMerge } from 'tailwind-merge' import * as Sentry from '@sentry/nextjs' import { useSetupFlow } from '@/hooks/useSetupFlow' @@ -14,6 +14,7 @@ import { invitesApi } from '@/services/invites' import { useRouter, useSearchParams } from 'next/navigation' import { getFromLocalStorage, sanitizeRedirectURL } from '@/utils' import ErrorAlert from '@/components/Global/ErrorAlert' +import { useAuth } from '@/context/authContext' const JoinWaitlist = () => { const [inviteCode, setInviteCode] = useState('') @@ -28,6 +29,7 @@ const JoinWaitlist = () => { const dispatch = useAppDispatch() const router = useRouter() const searchParams = useSearchParams() + const { user } = useAuth() const validateInviteCode = async (inviteCode: string): Promise => { try { @@ -61,6 +63,14 @@ const JoinWaitlist = () => { const onLoginClick = async () => { try { await handleLogin() + } catch (e) { + handleError(e) + } + } + + // Wait for user to be fetched, then redirect + useEffect(() => { + if (user) { const localStorageRedirect = getFromLocalStorage('redirect') const redirect_uri = searchParams.get('redirect_uri') if (redirect_uri) { @@ -77,10 +87,8 @@ const JoinWaitlist = () => { } else { router.push('/home') } - } catch (e) { - handleError(e) } - } + }, [user, router, searchParams]) return (
diff --git a/src/context/authContext.tsx b/src/context/authContext.tsx index dc4472119..bbdc9c220 100644 --- a/src/context/authContext.tsx +++ b/src/context/authContext.tsx @@ -54,7 +54,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { const queryClient = useQueryClient() const LOCAL_STORAGE_WEB_AUTHN_KEY = 'web-authn-key' - const { data: user, isFetching: isFetchingUser, refetch: fetchUser } = useUserQuery(!authUser?.user.userId) + const { data: user, isLoading: isFetchingUser, refetch: fetchUser } = useUserQuery(!authUser?.user.userId) // Pre-compute a Set of invited usernames for O(1) lookups const invitedUsernamesSet = useMemo(() => { From fa8c6272eb26b70799e867928586944a6b432f62 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 15:35:13 +0530 Subject: [PATCH 05/10] feat: add no more jail modal --- src/app/(mobile-ui)/home/page.tsx | 7 +- .../Global/NoMoreJailModal/index.tsx | 71 +++++++++++++++++++ src/components/Invites/JoinWaitlistPage.tsx | 1 + 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/components/Global/NoMoreJailModal/index.tsx diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index ab611456a..460a82707 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -41,6 +41,7 @@ import { useDeviceType, DeviceType } from '@/hooks/useGetDeviceType' import useKycStatus from '@/hooks/useKycStatus' import HomeBanners from '@/components/Home/HomeBanners' import InvitesIcon from '@/components/Home/InvitesIcon' +import NoMoreJailModal from '@/components/Global/NoMoreJailModal' const BALANCE_WARNING_THRESHOLD = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_THRESHOLD ?? '500') const BALANCE_WARNING_EXPIRY = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_EXPIRY ?? '1814400') // 21 days in seconds @@ -189,6 +190,7 @@ export default function Home() { useEffect(() => { if (typeof window !== 'undefined' && !isFetchingBalance) { const hasSeenAddMoneyPromptThisSession = sessionStorage.getItem('hasSeenAddMoneyPromptThisSession') + const showNoMoreJailModal = sessionStorage.getItem('showNoMoreJailModal') // show if: // 1. balance is zero. @@ -202,7 +204,8 @@ export default function Home() { !hasSeenAddMoneyPromptThisSession && !showIOSPWAInstallModal && !showBalanceWarningModal && - !isPostSignupActionModalVisible + !isPostSignupActionModalVisible && + showNoMoreJailModal !== 'true' // Give No more jail modal precedence, showing two modals together isn't ideal and it messes up their functionality ) { setShowAddMoneyPromptModal(true) sessionStorage.setItem('hasSeenAddMoneyPromptThisSession', 'true') @@ -268,6 +271,8 @@ export default function Home() { {/* Add Money Prompt Modal */} setShowAddMoneyPromptModal(false)} /> + + {/* Balance Warning Modal */} { + const [isOpen, setisOpen] = useState(false) + const showNoMoreJailModal = sessionStorage.getItem('showNoMoreJailModal') + + const onClose = () => { + setisOpen(false) + sessionStorage.removeItem('showNoMoreJailModal') + } + + useEffect(() => { + if (showNoMoreJailModal === 'true') { + setisOpen(true) + } + }, [showNoMoreJailModal]) + + return ( + + {/* Main content container */} +
+
+
+
+

+ No more Peanut jail! +

+ +
+

+ You’re now part of Peanut! +
+ Explore, pay, and invite your friends. +

+
+
+
+ + +
+
+ + {/* Peanutman animation */} +
+
+ Peanut Man +
+
+
+ ) +} + +export default NoMoreJailModal diff --git a/src/components/Invites/JoinWaitlistPage.tsx b/src/components/Invites/JoinWaitlistPage.tsx index 94a1ca8b0..68854660c 100644 --- a/src/components/Invites/JoinWaitlistPage.tsx +++ b/src/components/Invites/JoinWaitlistPage.tsx @@ -43,6 +43,7 @@ const JoinWaitlistPage = () => { try { const res = await invitesApi.acceptInvite(inviteCode, inviteType) if (res.success) { + sessionStorage.setItem('showNoMoreJailModal', 'true') fetchUser() } else { setError('Something went wrong. Please try again or contact support.') From 47a1e18604f420ab69845a7816c5b1b6b940c092 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 7 Oct 2025 17:44:21 +0530 Subject: [PATCH 06/10] update invites icon animation --- src/components/Home/InvitesIcon.tsx | 29 +---------------------------- tailwind.config.js | 7 +++++++ 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/components/Home/InvitesIcon.tsx b/src/components/Home/InvitesIcon.tsx index f0586d213..7706b194e 100644 --- a/src/components/Home/InvitesIcon.tsx +++ b/src/components/Home/InvitesIcon.tsx @@ -1,35 +1,8 @@ import STAR_STRAIGHT_ICON from '@/assets/icons/starStraight.svg' import Image from 'next/image' -import { motion } from 'framer-motion' const InvitesIcon = () => { - return ( - - star - - ) + return star } export default InvitesIcon diff --git a/tailwind.config.js b/tailwind.config.js index 9c52f8e83..d251d8126 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -174,6 +174,12 @@ module.exports = { '50%': { transform: 'scale(1.05)', opacity: '1' }, '100%': { transform: 'scale(0.95)', opacity: '0.8' }, }, + pulsateDeep: { + '0%': { transform: 'scale(1)', opacity: '1' }, + '30%': { transform: 'scale(0.7)', opacity: '1' }, + '60%': { transform: 'scale(1)', opacity: '1' }, + '100%': { transform: 'scale(1)', opacity: '1' }, + }, 'pulse-strong': { '0%': { opacity: '1' }, '50%': { opacity: '0.3' }, @@ -184,6 +190,7 @@ module.exports = { colorPulse: 'colorPulse 2.5s cubic-bezier(0.4, 0, 0.6, 1) infinite', fadeIn: 'fadeIn 0.3s ease-in-out', pulsate: 'pulsate 1.5s ease-in-out infinite', + 'pulsate-slow': 'pulsateDeep 4s ease-in-out infinite', 'pulse-strong': 'pulse-strong 1s ease-in-out infinite', }, opacity: { From 3e1e1e37d9937664809196607f65b30816621e78 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Wed, 8 Oct 2025 13:23:31 +0530 Subject: [PATCH 07/10] feat: add early user modal --- src/app/(mobile-ui)/home/page.tsx | 6 ++- .../Global/EarlyUserModal/index.tsx | 53 +++++++++++++++++++ src/components/Global/Icons/Icon.tsx | 3 ++ src/components/Global/Icons/lock.tsx | 12 +++++ src/interfaces/interfaces.ts | 1 + 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/components/Global/EarlyUserModal/index.tsx create mode 100644 src/components/Global/Icons/lock.tsx diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index 460a82707..97c9f81e9 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -42,6 +42,7 @@ import useKycStatus from '@/hooks/useKycStatus' import HomeBanners from '@/components/Home/HomeBanners' import InvitesIcon from '@/components/Home/InvitesIcon' import NoMoreJailModal from '@/components/Global/NoMoreJailModal' +import EarlyUserModal from '@/components/Global/EarlyUserModal' const BALANCE_WARNING_THRESHOLD = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_THRESHOLD ?? '500') const BALANCE_WARNING_EXPIRY = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_EXPIRY ?? '1814400') // 21 days in seconds @@ -205,7 +206,8 @@ export default function Home() { !showIOSPWAInstallModal && !showBalanceWarningModal && !isPostSignupActionModalVisible && - showNoMoreJailModal !== 'true' // Give No more jail modal precedence, showing two modals together isn't ideal and it messes up their functionality + showNoMoreJailModal !== 'true' && + !user?.showEarlyUserModal // Give Early User and No more jail modal precedence, showing two modals together isn't ideal and it messes up their functionality ) { setShowAddMoneyPromptModal(true) sessionStorage.setItem('hasSeenAddMoneyPromptThisSession', 'true') @@ -273,6 +275,8 @@ export default function Home() { + + {/* Balance Warning Modal */} { + const { user } = useAuth() + const inviteCode = `${user?.user.username?.toUpperCase()}INVITESYOU` + const inviteLink = `${process.env.NEXT_PUBLIC_BASE_URL}/invite?code=${inviteCode}` + const [showModal, setShowModal] = useState(false) + + useEffect(() => { + if (user && user.showEarlyUserModal) { + setShowModal(true) + } + }, [user]) + + const handleCloseModal = () => { + setShowModal(false) + updateUserById({ userId: user?.user.userId, hasSeenEarlyUserModal: true }) + } + + return ( + +

+ Peanut is now invite-only. +
+ As an early user, you keep full access and you get the power to invite friends. +
+ Each invite earns you points and perks. +

+ Promise.resolve(generateInvitesShareText(inviteLink))} + title="Share your invite link" + > + Share Invite link + + + } + /> + ) +} + +export default EarlyUserModal diff --git a/src/components/Global/Icons/Icon.tsx b/src/components/Global/Icons/Icon.tsx index 647e135bd..5da9f3b1f 100644 --- a/src/components/Global/Icons/Icon.tsx +++ b/src/components/Global/Icons/Icon.tsx @@ -61,6 +61,7 @@ import { QuestionMarkIcon } from './question-mark' import { ShieldIcon } from './shield' import { TrophyIcon } from './trophy' import { InviteHeartIcon } from './invite-heart' +import { LockIcon } from './lock' // available icon names export type IconName = @@ -126,6 +127,7 @@ export type IconName = | 'question-mark' | 'trophy' | 'invite-heart' + | 'lock' export interface IconProps extends SVGProps { name: IconName @@ -196,6 +198,7 @@ const iconComponents: Record>> = shield: ShieldIcon, trophy: TrophyIcon, 'invite-heart': InviteHeartIcon, + lock: LockIcon, } export const Icon: FC = ({ name, size = 24, width, height, ...props }) => { diff --git a/src/components/Global/Icons/lock.tsx b/src/components/Global/Icons/lock.tsx new file mode 100644 index 000000000..6eecc9012 --- /dev/null +++ b/src/components/Global/Icons/lock.tsx @@ -0,0 +1,12 @@ +import { FC, SVGProps } from 'react' + +export const LockIcon: FC> = () => { + return ( + + + + ) +} diff --git a/src/interfaces/interfaces.ts b/src/interfaces/interfaces.ts index 2401b49d6..9be06ac66 100644 --- a/src/interfaces/interfaces.ts +++ b/src/interfaces/interfaces.ts @@ -326,6 +326,7 @@ export interface IUserProfile { }> totalReferralPoints: number invitesSent: userInvites[] + showEarlyUserModal: boolean } interface Contact { From d84fed11a6dba8bb0332cef88f3ebf30ef6efd7d Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Wed, 8 Oct 2025 13:28:18 +0530 Subject: [PATCH 08/10] refactor: move sessionStorage check inside useEffect for NoMoreJailModal --- src/components/Global/NoMoreJailModal/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Global/NoMoreJailModal/index.tsx b/src/components/Global/NoMoreJailModal/index.tsx index 86eeac166..70a9cb1f8 100644 --- a/src/components/Global/NoMoreJailModal/index.tsx +++ b/src/components/Global/NoMoreJailModal/index.tsx @@ -8,7 +8,6 @@ import chillPeanutAnim from '@/animations/GIF_ALPHA_BACKGORUND/512X512_ALPHA_GIF const NoMoreJailModal = () => { const [isOpen, setisOpen] = useState(false) - const showNoMoreJailModal = sessionStorage.getItem('showNoMoreJailModal') const onClose = () => { setisOpen(false) @@ -16,10 +15,11 @@ const NoMoreJailModal = () => { } useEffect(() => { + const showNoMoreJailModal = sessionStorage.getItem('showNoMoreJailModal') if (showNoMoreJailModal === 'true') { setisOpen(true) } - }, [showNoMoreJailModal]) + }, []) return ( Date: Wed, 8 Oct 2025 13:37:32 +0530 Subject: [PATCH 09/10] feat: enhance LockIcon component to accept props for better customization --- src/components/Global/Icons/lock.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/Global/Icons/lock.tsx b/src/components/Global/Icons/lock.tsx index 6eecc9012..5467d8b67 100644 --- a/src/components/Global/Icons/lock.tsx +++ b/src/components/Global/Icons/lock.tsx @@ -1,11 +1,18 @@ import { FC, SVGProps } from 'react' -export const LockIcon: FC> = () => { +export const LockIcon: FC> = (props) => { return ( - + ) From 5b33ba835807ce6462ce7cdc5e0a163b15ca9765 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Wed, 8 Oct 2025 16:38:51 +0530 Subject: [PATCH 10/10] fixes and improvements --- src/app/(mobile-ui)/home/page.tsx | 14 ++++++++------ src/components/Global/EarlyUserModal/index.tsx | 5 ++--- src/components/Profile/index.tsx | 11 +++++------ src/utils/general.utils.ts | 6 ++++++ 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index 97c9f81e9..2975e3eaf 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -68,7 +68,7 @@ export default function Home() { const [showAddMoneyPromptModal, setShowAddMoneyPromptModal] = useState(false) const [showBalanceWarningModal, setShowBalanceWarningModal] = useState(false) // const [showReferralCampaignModal, setShowReferralCampaignModal] = useState(false) - const [isPostSignupActionModalVisible, setIsPostSignupActionModalVisible] = useState(false) + const [showPostSignupActionModal, setShowPostSignupActionModal] = useState(false) const userFullName = useMemo(() => { if (!user) return @@ -129,7 +129,7 @@ export default function Home() { !isStandalone && !hasSeenModalThisSession && !user?.hasPwaInstalled && - !isPostSignupActionModalVisible && + !showPostSignupActionModal && !redirectUrl ) { setShowIOSPWAInstallModal(true) @@ -138,7 +138,7 @@ export default function Home() { setShowIOSPWAInstallModal(false) } } - }, [user?.hasPwaInstalled, isPostSignupActionModalVisible, deviceType]) + }, [user?.hasPwaInstalled, showPostSignupActionModal, deviceType]) // effect for showing balance warning modal useEffect(() => { @@ -157,7 +157,7 @@ export default function Home() { !hasSeenBalanceWarning && !showIOSPWAInstallModal && !showAddMoneyPromptModal && - !isPostSignupActionModalVisible + !showPostSignupActionModal ) { setShowBalanceWarningModal(true) } @@ -198,6 +198,8 @@ export default function Home() { // 2. user hasn't seen this prompt in the current session. // 3. the iOS PWA install modal is not currently active. // 4. the balance warning modal is not currently active. + // 5. the early user modal is not currently active. + // 6. the no more jail modal is not currently active. // this allows the modal on any device (iOS/Android) and in any display mode (PWA/browser), // as long as the PWA modal (which is iOS & browser-specific) isn't taking precedence. if ( @@ -205,7 +207,7 @@ export default function Home() { !hasSeenAddMoneyPromptThisSession && !showIOSPWAInstallModal && !showBalanceWarningModal && - !isPostSignupActionModalVisible && + !showPostSignupActionModal && showNoMoreJailModal !== 'true' && !user?.showEarlyUserModal // Give Early User and No more jail modal precedence, showing two modals together isn't ideal and it messes up their functionality ) { @@ -296,7 +298,7 @@ export default function Home() { {/* setShowReferralCampaignModal(true)} /> */} {/* Post Signup Action Modal */} - + ) } diff --git a/src/components/Global/EarlyUserModal/index.tsx b/src/components/Global/EarlyUserModal/index.tsx index 4f7021f07..509692da8 100644 --- a/src/components/Global/EarlyUserModal/index.tsx +++ b/src/components/Global/EarlyUserModal/index.tsx @@ -2,14 +2,13 @@ import { useEffect, useState } from 'react' import ActionModal from '../ActionModal' import ShareButton from '../ShareButton' -import { generateInvitesShareText } from '@/utils' +import { generateInviteCodeLink, generateInvitesShareText } from '@/utils' import { useAuth } from '@/context/authContext' import { updateUserById } from '@/app/actions/users' const EarlyUserModal = () => { const { user } = useAuth() - const inviteCode = `${user?.user.username?.toUpperCase()}INVITESYOU` - const inviteLink = `${process.env.NEXT_PUBLIC_BASE_URL}/invite?code=${inviteCode}` + const inviteLink = generateInviteCodeLink(user?.user.username ?? '').inviteLink const [showModal, setShowModal] = useState(false) useEffect(() => { diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index 9ba045e83..2372ff10a 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -7,7 +7,7 @@ import NavHeader from '../Global/NavHeader' import ProfileHeader from './components/ProfileHeader' import ProfileMenuItem from './components/ProfileMenuItem' import { useRouter } from 'next/navigation' -import { checkIfInternalNavigation, generateInvitesShareText } from '@/utils' +import { checkIfInternalNavigation, generateInviteCodeLink, generateInvitesShareText } from '@/utils' import ActionModal from '../Global/ActionModal' import { useState } from 'react' import useKycStatus from '@/hooks/useKycStatus' @@ -31,8 +31,7 @@ export const Profile = () => { const fullName = user?.user.fullName || user?.user?.username || 'Anonymous User' const username = user?.user.username || 'anonymous' - const inviteCode = `${user?.user.username?.toUpperCase()}INVITESYOU` - const inviteLink = `${process.env.NEXT_PUBLIC_BASE_URL}/invite?code=${inviteCode}` + const inviteData = generateInviteCodeLink(user?.user.username ?? '') return (
@@ -162,13 +161,13 @@ export const Profile = () => { <>
-

{`${inviteCode}`}

+

{`${inviteData.inviteCode}`}

- +
Promise.resolve(generateInvitesShareText(inviteLink))} + generateText={() => Promise.resolve(generateInvitesShareText(inviteData.inviteLink))} title="Share your invite link" > Share Invite link diff --git a/src/utils/general.utils.ts b/src/utils/general.utils.ts index cd3366add..97242166f 100644 --- a/src/utils/general.utils.ts +++ b/src/utils/general.utils.ts @@ -1323,3 +1323,9 @@ export function slugify(text: string): string { export const generateInvitesShareText = (inviteLink: string) => { return `I’m using Peanut, an invite-only app for easy payments. With it you can pay friends, use merchants, and move money in and out of your bank, even cross-border. Here’s my invite: ${inviteLink}` } + +export const generateInviteCodeLink = (username: string) => { + const inviteCode = `${username.toUpperCase()}INVITESYOU` + const inviteLink = `${consts.BASE_URL}/invite?code=${inviteCode}` + return { inviteLink, inviteCode } +}