Skip to content

Commit

Permalink
Merge branch 'main' into eng-4705-rename-template
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanprozzi authored Nov 23, 2024
2 parents e069c68 + a96af14 commit 0ea2a28
Show file tree
Hide file tree
Showing 28 changed files with 461 additions and 270 deletions.
9 changes: 7 additions & 2 deletions apps/portal/app/.client/privy-login-button.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'

import { Button, Icon } from '@0xintuition/1ui'

import logger from '@lib/utils/logger'
import { useLogin, User } from '@privy-io/react-auth'
import { useLogin, useLogout, User } from '@privy-io/react-auth'

interface PrivyLoginButtonProps {
handleLogin: (
Expand All @@ -16,6 +16,7 @@ interface PrivyLoginButtonProps {
export default function PrivyLoginButton({
handleLogin,
}: PrivyLoginButtonProps) {
const { logout } = useLogout()
const [loading, setLoading] = useState(false)
const { login } = useLogin({
onComplete: (user, isNewUser, wasAlreadyAuthenticated) => {
Expand All @@ -31,6 +32,10 @@ export default function PrivyLoginButton({
setLoading(true)
login()
}
useEffect(() => {
// ensure privy knows user is logged out
logout()
}, [])

return (
<Button
Expand Down
62 changes: 51 additions & 11 deletions apps/portal/app/.client/privy-refresh.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,62 @@
import { useEffect } from 'react'
import { useCallback, useEffect, useState } from 'react'

import LoadingLogo from '@components/loading-logo'
import logger from '@lib/utils/logger'
import { usePrivy } from '@privy-io/react-auth'
import { useRevalidator } from '@remix-run/react'

export default function PrivyRefresh() {
export default function PrivyRefresh({
refreshPath,
redirectTo,
}: {
refreshPath: string
redirectTo: string
}) {
const { ready, getAccessToken } = usePrivy()
const { revalidate } = useRevalidator()
const [accessToken, setAccessToken] = useState<string | null>(null)

useEffect(() => {
async function refresh() {
if (ready) {
await getAccessToken()
revalidate()
const refresh = useCallback(async () => {
try {
if (!ready) {
return
}

logger('Getting access token...')
const idToken = await getAccessToken()
logger('Access token:', idToken)
setAccessToken(idToken)
} catch (error) {
console.error('Failed to refresh session:', error)
}
}, [ready])

useEffect(() => {
refresh()
}, [ready, revalidate])
}, [refresh])
useEffect(() => {
if (accessToken) {
// instead of revalidating, redirect to same route and replace true
logger('Redirecting to', `${refreshPath}?redirectTo=${redirectTo}`)
window.location.replace(`${refreshPath}?redirectTo=${redirectTo}`)
}
}, [accessToken])

return <div />
return (
<div className="fixed inset-0 flex items-center justify-center">
<div
role="status"
className="flex flex-col items-center gap-4"
aria-label="Refreshing session"
>
<LoadingLogo size={50} />
<div className="flex flex-col items-center gap-1">
<p className="text-base text-foreground/70 font-medium">
Reconnecting your session...
</p>
<p className="text-sm text-muted-foreground">
This will only take a moment.
</p>
</div>
</div>
</div>
)
}
45 changes: 37 additions & 8 deletions apps/portal/app/.server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { RedirectOptions } from 'app/types'

import {
getPrivyAccessToken,
getPrivyClient,
getPrivySessionToken,
getPrivyUserById,
isOAuthInProgress,
verifyPrivyAccessToken,
} from './privy'
Expand All @@ -21,13 +21,38 @@ export async function getUserId(request: Request): Promise<string | null> {
}

export async function getUser(request: Request): Promise<User | null> {
const userId = await getUserId(request)
return userId ? await getPrivyUserById(userId) : null
const privyIdToken = getPrivyAccessToken(request)
const privyClient = getPrivyClient()

if (!privyIdToken) {
logger('No Privy ID token found')
return null
}

try {
// First verify the token is valid
const verifiedClaims = await verifyPrivyAccessToken(request)
if (!verifiedClaims) {
logger('Invalid Privy token')
return null
}

// Then get the full user object directly using the verified user ID
const user = await privyClient.getUserById(verifiedClaims.userId)
logger('Successfully fetched user by ID', user.wallet?.address)
return user
} catch (error) {
logger('Error fetching user', error)
return null
}
}

export async function getUserWallet(request: Request): Promise<string | null> {
const user = await getUser(request)
return user?.wallet?.address ?? null
if (!user) {
return null
}
return user.wallet?.address ?? null
}

export async function requireUserId(
Expand Down Expand Up @@ -99,15 +124,19 @@ export async function handlePrivyRedirect({
const accessToken = getPrivyAccessToken(request)
const sessionToken = getPrivySessionToken(request)
const isOAuth = await isOAuthInProgress(request.url)

if (isOAuth) {
// Do not redirect or interrupt the flow.
return
} else if (!accessToken || !sessionToken) {
return null
}

if (!accessToken || !sessionToken) {
const redirectUrl = await getRedirectToUrl(request, path, options)
throw redirect(redirectUrl)
}
logger('Hit end of handlePrivyRedirect', accessToken, sessionToken, isOAuth)
return

// Explicitly return null when we reach the end
return null
}

export async function setupAPI(request: Request) {
Expand Down
23 changes: 14 additions & 9 deletions apps/portal/app/.server/privy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,25 @@ export const verifyPrivyAccessToken = async (
const privy = getPrivyClient()
const authToken = getPrivyAccessToken(req)
if (!authToken) {
logger('No privy access token found')
logger('No Privy access token found')
return null
}
try {
const verifiedClaims = await privy.verifyAuthToken(
authToken,
process.env.PRIVY_VERIFICATION_KEY,
)
return verifiedClaims
} catch (error) {
logger('Error verifying Privy access token', error)
return null
}
const verifiedClaims = await privy.verifyAuthToken(
authToken,
process.env.PRIVY_VERIFICATION_KEY,
)
return verifiedClaims
}

// takes user privy DID (e.g. authCheck().userId)
export const getPrivyUserById = async (id: string): Promise<User> => {
export const getPrivyUserById = async (idToken: string): Promise<User> => {
const privy = getPrivyClient()
const user = await privy.getUser(id)
const user = await privy.getUser({ idToken })
logger('Successfully fetched getPrivyUserById')
return user
}

Expand Down
3 changes: 3 additions & 0 deletions apps/portal/app/assets/intuition-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ import {
TransactionSuccessAction,
TransactionSuccessActionType,
} from 'app/types'
import { Address, decodeEventLog, extractChain, parseUnits, toHex } from 'viem'
import {
Address,
decodeEventLog,
extractChain,
getAddress,
parseUnits,
toHex,
} from 'viem'
import { reset } from 'viem/actions'
import * as chains from 'viem/chains'
import { mode } from 'viem/chains'
Expand Down Expand Up @@ -250,10 +257,22 @@ export function CAIP10AccountForm({
},
})

const reviewIdentity = {
imageUrl: IconName.fileText,
displayName: `caip10:eip155:${formState.chainId}:${formState.address}`,
}
const reviewIdentity =
formState.address && formState.chainId
? {
imageUrl: IconName.fileText,
displayName: `caip10:eip155:${formState.chainId}:${getAddress(formState.address, Number(formState.chainId))}`,
description: undefined,
externalReference: undefined,
initialDeposit: undefined,
}
: {
imageUrl: undefined,
displayName: undefined,
description: undefined,
externalReference: undefined,
initialDeposit: undefined,
}

return (
<>
Expand Down Expand Up @@ -446,15 +465,20 @@ export function CAIP10AccountForm({
form={form.id}
type="submit"
variant="primary"
onClick={() =>
onClick={() => {
if (!formState.chainId || !formState.address) {
return
}
handleOnChainCreateIdentity({
atomData: `caip10:eip155:${formState.chainId}:${formState.address}`,
atomData: `caip10:eip155:${formState.chainId}:${getAddress(formState.address, Number(formState.chainId))}`,
})
}
}}
disabled={
!address ||
loading ||
!formTouched ||
!formState.chainId ||
!formState.address ||
['confirm', 'transaction-pending', 'awaiting'].includes(
state.status,
)
Expand Down
4 changes: 2 additions & 2 deletions apps/portal/app/components/list/tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ export function TagsList({
{enableHeader && (
<ListHeader
items={[
{ label: 'Tag', icon: IconName.bookmark },
{ label: 'TVL', icon: IconName.ethereum },
{ label: 'Identity', icon: IconName.fingerprint },
{ label: 'Claim TVL', icon: IconName.ethereum },
]}
/>
)}
Expand Down
31 changes: 31 additions & 0 deletions apps/portal/app/components/loading-logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react'

interface LoadingLogoProps {
size?: number
}

const LoadingLogo: React.FC<LoadingLogoProps> = ({ size = 300 }) => {
return (
<div className="animate-pulse-slow">
<svg
width={size}
height={size}
viewBox="0 0 300 300"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="animate-spin-slow"
>
<g>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M160.133 0.342656C161.316 0.422794 162.196 1.46156 162.099 2.64387L161.591 8.82711C161.494 10.0094 160.457 10.8874 159.273 10.8086C139.849 9.51442 120.36 12.2998 102.063 18.995C83.0936 25.9362 65.8577 36.9143 51.5472 51.1704C37.2366 65.4264 26.1927 82.6202 19.179 101.563C12.4141 119.834 9.55422 139.312 10.7742 158.742C10.8485 159.926 9.96653 160.959 8.78386 161.052L2.59873 161.536C1.41605 161.629 0.380659 160.745 0.305042 159.561C-1.03277 138.616 2.03942 117.614 9.33229 97.9174C16.8739 77.5486 28.749 59.0606 44.1367 43.7316C59.5245 28.4025 78.0577 16.5981 98.4551 9.13438C118.18 1.91679 139.193 -1.07515 160.133 0.342656ZM239.534 32.3403C240.253 31.3963 240.071 30.0472 239.116 29.3424C219.597 14.9257 196.871 5.45943 172.889 1.75665C171.717 1.57563 170.631 2.3965 170.466 3.57137L169.608 9.71569C169.443 10.8906 170.263 11.9744 171.435 12.1567C193.634 15.6087 214.672 24.3715 232.757 37.6992C233.712 38.403 235.059 38.2215 235.777 37.2775L239.534 32.3403ZM282.833 219.68C282.282 220.731 280.976 221.117 279.934 220.551L274.481 217.59C273.439 217.024 273.054 215.721 273.604 214.67C288.233 186.71 292.96 154.593 286.973 123.567C280.985 92.5419 264.648 64.4899 240.665 43.9811C239.764 43.2101 239.636 41.8569 240.393 40.9436L244.352 36.167C245.109 35.2537 246.464 35.1262 247.367 35.8963C273.221 57.9579 290.834 88.1641 297.282 121.578C303.731 154.991 298.622 189.583 282.833 219.68ZM1.27663 169.528C1.12219 168.352 1.96743 167.285 3.14571 167.148L9.30789 166.428C10.4862 166.29 11.5512 167.134 11.7069 168.31C14.0852 186.273 19.9402 203.6 28.9445 219.324C29.534 220.353 29.1992 221.67 28.1789 222.276L22.8433 225.441C21.8231 226.047 20.5039 225.711 19.9132 224.682C10.1588 207.691 3.82726 188.953 1.27663 169.528ZM232.933 272.402C233.598 273.384 233.342 274.721 232.351 275.373C216.191 285.987 198.125 293.381 179.146 297.141C159.465 301.039 139.201 300.95 119.555 296.878C99.9087 292.805 81.279 284.833 64.7687 273.433C48.8478 262.439 35.2097 248.473 24.6004 232.31C23.9495 231.318 24.2461 229.99 25.247 229.353L30.4818 226.023C31.4828 225.387 32.809 225.683 33.461 226.674C43.3158 241.653 55.9698 254.597 70.7349 264.792C86.0895 275.395 103.415 282.809 121.686 286.596C139.957 290.383 158.802 290.467 177.106 286.841C194.707 283.354 211.464 276.506 226.461 266.679C227.453 266.029 228.787 266.284 229.453 267.266L232.933 272.402ZM277.015 229.794C277.646 228.789 277.323 227.467 276.31 226.85L271.01 223.626C269.996 223.009 268.676 223.332 268.044 224.336C259.058 238.605 247.559 251.128 234.105 261.295C233.159 262.01 232.949 263.353 233.65 264.31L237.314 269.317C238.014 270.274 239.359 270.484 240.306 269.769C254.871 258.787 267.311 245.24 277.015 229.794ZM257.757 150C257.757 209.512 209.512 257.757 150 257.757C90.4879 257.757 42.2437 209.512 42.2437 150C42.2437 90.4879 90.4879 42.2437 150 42.2437C209.512 42.2437 257.757 90.4879 257.757 150ZM280.668 150C280.668 222.166 222.166 280.668 150 280.668C77.8342 280.668 19.332 222.166 19.332 150C19.332 77.8342 77.8342 19.332 150 19.332C222.166 19.332 280.668 77.8342 280.668 150Z"
className="fill-foreground/50 "
/>
</g>
</svg>
</div>
)
}

export default LoadingLogo
7 changes: 5 additions & 2 deletions apps/portal/app/components/profile/overview-about-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react'
import {
Button,
ButtonVariant,
formatNumber,
Icon,
IconName,
IdentityTag,
Expand Down Expand Up @@ -77,7 +78,9 @@ export function OverviewAboutHeader({
{variant === 'claims' ? 'Claims' : 'Positions'}
</Text>
<Text variant="bodyLarge" weight="medium" className="items-center">
{variant === 'claims' ? totalClaims ?? 0 : totalPositions ?? 0}
{formatNumber(
variant === 'claims' ? totalClaims ?? 0 : totalPositions ?? 0,
)}
</Text>
</div>
<div className="flex flex-col max-md:items-center">
Expand All @@ -88,7 +91,7 @@ export function OverviewAboutHeader({
>
TVL
</Text>
<MonetaryValue value={totalStake} currency="ETH" />
<MonetaryValue value={+totalStake.toFixed(2)} currency="ETH" />
</div>
</div>
<div className="flex flex-col items-end justify-end ml-auto max-sm:w-full max-sm:items-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react'
import {
Button,
ButtonVariant,
formatNumber,
Icon,
IconName,
Text,
Expand Down Expand Up @@ -51,7 +52,7 @@ export function OverviewCreatedHeader({
weight="medium"
className="items-center max-sm:items-start"
>
{totalCreated ?? 0}
{formatNumber(totalCreated ?? 0)}
</Text>
</div>
<div className="flex flex-col items-end justify-end ml-auto">
Expand Down
Loading

0 comments on commit 0ea2a28

Please sign in to comment.