Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENG-5587 feat(launchpad): logout privy if no wallet connected #1060

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions apps/launchpad/app/.client/privy-logout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useEffect, useRef } from 'react'

import { usePrivy } from '@privy-io/react-auth'
import { useSubmit } from '@remix-run/react'
import { useAccount, useDisconnect } from 'wagmi'

export default function PrivyLogout({ wallet }: { wallet: string }) {
const { address, isConnected } = useAccount()
const submit = useSubmit()
const { logout, ready, authenticated } = usePrivy()
const { disconnect } = useDisconnect()
const logoutTimeoutRef = useRef<NodeJS.Timeout | null>(null)
const hasInitialized = useRef(false)

useEffect(() => {
let mounted = true
const handleLogout = async () => {
// Only proceed if Privy is ready and authenticated
if (mounted && ready && authenticated) {
// Only proceed if we have initialized and either:
// 1. The wallet is connected but the address doesn't match
// 2. The wallet is explicitly disconnected
if (
hasInitialized.current &&
((isConnected && address?.toLowerCase() !== wallet?.toLowerCase()) ||
!isConnected)
) {
// Clear any existing timeout
if (logoutTimeoutRef.current) {
clearTimeout(logoutTimeoutRef.current)
}

// Set a new timeout
logoutTimeoutRef.current = setTimeout(async () => {
// Double-check all conditions before logging out
if (
(isConnected &&
address?.toLowerCase() !== wallet?.toLowerCase()) ||
!isConnected
) {
await logout()
disconnect()
submit(null, {
action: '/actions/logout',
method: 'post',
})
}
}, 1500) // 1500ms delay
}
}
}

// Mark as initialized after the first render where we're ready and authenticated
if (!hasInitialized.current && ready && authenticated) {
hasInitialized.current = true
}

handleLogout()

return () => {
mounted = false
if (logoutTimeoutRef.current) {
clearTimeout(logoutTimeoutRef.current)
}
}
}, [
address,
wallet,
submit,
logout,
disconnect,
isConnected,
ready,
authenticated,
])

return null
}
16 changes: 15 additions & 1 deletion apps/launchpad/app/.server/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { OpenAPI } from '@0xintuition/api'

import logger from '@lib/utils/logger'
import { getAuthHeaders } from '@lib/utils/misc'
import { combineHeaders, getAuthHeaders } from '@lib/utils/misc'
import { User } from '@privy-io/server-auth'
import { redirect } from '@remix-run/node'

Expand Down Expand Up @@ -96,3 +96,17 @@ export async function handlePrivyRedirect({
throw redirect(redirectTo)
}
}

export async function logout(
{
redirectTo = '/',
}: {
redirectTo?: string
},
responseInit?: ResponseInit,
) {
throw redirect(redirectTo, {
...responseInit,
headers: combineHeaders(responseInit?.headers),
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,7 @@ export function SignalStep({
errors.push(`Minimum stake is ${min_deposit} ETH`)
}
if (+val > +walletBalance) {
errors.push(
`Insufficient balance. You have ${(+walletBalance).toFixed(2)} ETH`,
)
errors.push(`Insufficient balance`)
}

if (errors.length > 0) {
Expand Down
15 changes: 15 additions & 0 deletions apps/launchpad/app/lib/utils/misc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,18 @@ export const renderTooltipIcon = (icon: React.ReactNode | string) => {
}
return icon
}

export function combineHeaders(
...headers: Array<ResponseInit['headers'] | null | undefined>
) {
const combined = new Headers()
for (const header of headers) {
if (!header) {
continue
}
for (const [key, value] of new Headers(header).entries()) {
combined.append(key, value)
}
}
return combined
}
15 changes: 12 additions & 3 deletions apps/launchpad/app/routes/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { MULTIVAULT_CONTRACT_ADDRESS } from '@consts/general'
import { json } from '@remix-run/node'
import { Outlet } from '@remix-run/react'
import { json, LoaderFunctionArgs } from '@remix-run/node'
import { Outlet, useLoaderData } from '@remix-run/react'
import { getUser } from '@server/auth'
import { getMultiVaultConfig } from '@server/multivault'
import { dehydrate, QueryClient } from '@tanstack/react-query'

import PrivyLogout from '../.client/privy-logout'
import { AppShell } from '../components/layouts/app-shell'

export async function loader() {
export async function loader({ request }: LoaderFunctionArgs) {
const queryClient = new QueryClient()
const user = await getUser(request)

console.log('user', user)

try {
// await queryClient.prefetchQuery({
Expand All @@ -26,12 +31,16 @@ export async function loader() {

return json({
dehydratedState: dehydrate(queryClient),
wallet: user?.wallet?.address.toLowerCase(),
})
}

export default function AppLayout() {
const { wallet } = useLoaderData<typeof loader>()

return (
<AppShell>
{wallet && <PrivyLogout wallet={wallet} />}
<Outlet />
</AppShell>
)
Expand Down
10 changes: 10 additions & 0 deletions apps/launchpad/app/routes/actions+/logout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { redirect } from '@remix-run/node'
import { logout } from '@server/auth'

export async function loader() {
return redirect('/')
}

export async function action() {
return logout({ redirectTo: '/' })
}
Loading