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-3859 feat(portal): better navigation between list details list identity and tag claim #822

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
133 changes: 133 additions & 0 deletions apps/portal/app/components/detail-info-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import {
Button,
ButtonVariant,
cn,
HoverCard,
HoverCardContent,
HoverCardTrigger,
Icon,
Identity,
IdentityTag,
IdentityType,
ProfileCard,
Text,
TextVariant,
Trunctacular,
} from '@0xintuition/1ui'
import { ClaimPresenter } from '@0xintuition/api'

import { PATHS } from '@consts/paths'

export interface DetailInfoCardProps
extends React.HTMLAttributes<HTMLDivElement> {
variant: IdentityType
list?: ClaimPresenter
username: string
avatarImgSrc: string
id: string
description: string
link: string
ipfsLink: string
timestamp: string
}

const DetailInfoCard = ({
variant = Identity.user,
list,
username,
avatarImgSrc,
id,
description,
link,
ipfsLink,
timestamp,
className,
...props
}: DetailInfoCardProps) => {
const formattedDate = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
}).format(new Date(timestamp))

return (
<div
className={cn(
`flex flex-col gap-5 theme-border p-5 rounded-lg max-sm:items-center`,
className,
)}
{...props}
>
{list && (
<div>
<Text variant={TextVariant.caption} className="text-muted-foreground">
List
</Text>
<div className="flex justify-start items-center gap-1">
<a href={`${PATHS.LIST}/${list.claim_id}`}>
<IdentityTag
variant={list.object?.user ? Identity.user : Identity.nonUser}
imgSrc={list.object?.image ?? ''}
>
<Trunctacular
value={
list.object?.user_display_name ??
list.object?.display_name ??
'Unknown'
}
maxStringLength={32}
/>
</IdentityTag>
</a>
</div>
</div>
)}
<div>
<Text variant={TextVariant.caption} className="text-muted-foreground">
Creator
</Text>
<div className="flex justify-start items-center gap-1">
<HoverCard openDelay={150} closeDelay={150}>
<HoverCardTrigger>
<a href={link}>
<IdentityTag variant={variant} imgSrc={avatarImgSrc}>
<Trunctacular value={username} maxStringLength={18} />
</IdentityTag>
</a>
</HoverCardTrigger>
<HoverCardContent side="right" className="w-max">
<div className="flex flex-col gap-4 w-80 max-md:w-[80%]">
<ProfileCard
variant={variant}
avatarSrc={avatarImgSrc ?? ''}
name={username}
id={id ?? ''}
bio={description ?? ''}
ipfsLink={ipfsLink}
className="profile-card"
/>
{link && (
<a href={link}>
<Button
variant={ButtonVariant.secondary}
className="w-full"
>
View Identity{' '}
<Icon name={'arrow-up-right'} className="h-3 w-3" />
</Button>
</a>
)}
</div>
</HoverCardContent>
</HoverCard>
<span className="bg-muted-foreground h-[2px] w-[2px] block rounded-full" />
<Text variant={TextVariant.body} className="text-muted-foreground">
{formattedDate}
</Text>
</div>
</div>
</div>
)
}

export { DetailInfoCard }
27 changes: 17 additions & 10 deletions apps/portal/app/routes/app+/claim+/$id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
ClaimStakeCard,
Icon,
Identity,
InfoCard,
PieChartVariant,
PositionCard,
PositionCardLastUpdated,
Expand All @@ -21,13 +20,15 @@ import {
SortDirection,
} from '@0xintuition/api'

import { DetailInfoCard } from '@components/detail-info-card'
import { ErrorPage } from '@components/error-page'
import NavigationButton from '@components/navigation-link'
import StakeModal from '@components/stake/stake-modal'
import { useGoBack } from '@lib/hooks/useGoBack'
import { useLiveLoader } from '@lib/hooks/useLiveLoader'
import { getClaimOrPending } from '@lib/services/claims'
import { stakeModalAtom } from '@lib/state/store'
import { getSpecialPredicate } from '@lib/utils/app'
import {
calculatePercentageOfTvl,
formatBalance,
Expand All @@ -39,10 +40,15 @@ import {
invariant,
} from '@lib/utils/misc'
import { json, LoaderFunctionArgs } from '@remix-run/node'
import { Outlet, useNavigate } from '@remix-run/react'
import { Outlet } from '@remix-run/react'
import { requireUserWallet } from '@server/auth'
import { getVaultDetails } from '@server/multivault'
import { BLOCK_EXPLORER_URL, NO_WALLET_ERROR, PATHS } from 'app/consts'
import {
BLOCK_EXPLORER_URL,
CURRENT_ENV,
NO_WALLET_ERROR,
PATHS,
} from 'app/consts'
import TwoPanelLayout from 'app/layouts/two-panel-layout'
import { VaultDetailsType } from 'app/types/vault'
import { useAtom } from 'jotai'
Expand Down Expand Up @@ -108,8 +114,6 @@ export default function ClaimDetails() {
vaultDetails: VaultDetailsType
isPending: boolean
}>(['create', 'attest'])
const navigate = useNavigate()

const [stakeModalActive, setStakeModalActive] = useAtom(stakeModalAtom)

const direction: 'for' | 'against' = isPending
Expand Down Expand Up @@ -285,8 +289,14 @@ export default function ClaimDetails() {
}
/>
)}
<InfoCard
<DetailInfoCard
variant={Identity.user}
list={
claim?.predicate?.id ===
getSpecialPredicate(CURRENT_ENV).tagPredicate.id
? claim
: undefined
}
username={claim.creator?.display_name ?? '?'}
avatarImgSrc={claim.creator?.image ?? ''}
id={claim.creator?.wallet ?? ''}
Expand All @@ -296,10 +306,7 @@ export default function ClaimDetails() {
}
ipfsLink={`${BLOCK_EXPLORER_URL}/address/${claim.creator?.wallet}`}
timestamp={claim.created_at}
onClick={() => {
navigate(`/app/profile/${claim.creator?.wallet}`)
}}
className="hover:cursor-pointer w-full"
className="w-full"
/>
</div>
)
Expand Down
40 changes: 30 additions & 10 deletions apps/portal/app/routes/app+/identity+/$id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
Banner,
Icon,
Identity,
InfoCard,
PieChartVariant,
PositionCard,
PositionCardLastUpdated,
Expand All @@ -18,8 +17,14 @@ import {
TagsContent,
TagWithValue,
} from '@0xintuition/1ui'
import { IdentityPresenter, TagEmbeddedPresenter } from '@0xintuition/api'
import {
ClaimPresenter,
ClaimsService,
IdentityPresenter,
TagEmbeddedPresenter,
} from '@0xintuition/api'

import { DetailInfoCard } from '@components/detail-info-card'
import { ErrorPage } from '@components/error-page'
import NavigationButton from '@components/navigation-link'
import ImageModal from '@components/profile/image-modal'
Expand All @@ -34,6 +39,7 @@ import {
stakeModalAtom,
tagsModalAtom,
} from '@lib/state/store'
import { getSpecialPredicate } from '@lib/utils/app'
import logger from '@lib/utils/logger'
import {
calculatePercentageOfTvl,
Expand All @@ -51,12 +57,12 @@ import { requireUser, requireUserWallet } from '@server/auth'
import { getVaultDetails } from '@server/multivault'
import {
BLOCK_EXPLORER_URL,
CURRENT_ENV,
MULTIVAULT_CONTRACT_ADDRESS,
NO_WALLET_ERROR,
PATHS,
} from 'app/consts'
import TwoPanelLayout from 'app/layouts/two-panel-layout'
import { ExtendedIdentityPresenter } from 'app/types/identity'
import { VaultDetailsType } from 'app/types/vault'
import { useAtom } from 'jotai'

Expand All @@ -79,6 +85,21 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
throw new Response('Not Found', { status: 404 })
}

let list: ClaimPresenter | null = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to start moving away from using let we could try something like this --

const list = await ClaimsService.searchClaims({
  predicate: getSpecialPredicate(CURRENT_ENV).tagPredicate.id,
  object: identity.id,
})
  .then(listResult => listResult?.data[0] ?? null)
  .catch(error => {
    logger('Failed to fetch list:', error);
    return null;
  });

what do you think? i know we're mixing these patterns in our loaders so likely a bigger question but wondering what you think.

not blocking just a question

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way works for me, I don't really have a preference. We should just have a quick chat and land on one or the other.


try {
const listResult = await ClaimsService.searchClaims({
predicate: getSpecialPredicate(CURRENT_ENV).tagPredicate.id,
object: identity.id,
})

if (listResult && listResult.data.length > 0) {
list = listResult.data[0]
}
} catch (error) {
logger('Failed to fetch list:', error)
}

let vaultDetails: VaultDetailsType | null = null

if (!!identity && identity.vault_id) {
Expand All @@ -97,6 +118,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
logger('[$ID] -- END')
return json({
identity,
list,
isPending,
vaultDetails,
userWallet,
Expand All @@ -105,18 +127,15 @@ export async function loader({ request, params }: LoaderFunctionArgs) {

export interface IdentityLoaderData {
identity: IdentityPresenter
list: ClaimPresenter
vaultDetails: VaultDetailsType
userWallet: string
isPending: boolean
}

export default function IdentityDetails() {
const { identity, vaultDetails, userWallet, isPending } = useLiveLoader<{
identity: ExtendedIdentityPresenter
vaultDetails: VaultDetailsType
userWallet: string
isPending: boolean
}>(['attest', 'create'])
const { identity, list, vaultDetails, userWallet, isPending } =
useLiveLoader<IdentityLoaderData>(['attest', 'create'])
const navigate = useNavigate()

const { user_assets, assets_sum } = vaultDetails ? vaultDetails : identity
Expand Down Expand Up @@ -236,8 +255,9 @@ export default function IdentityDetails() {
/>
</>
)}
<InfoCard
<DetailInfoCard
variant={Identity.user}
list={list}
username={identity.creator?.display_name ?? '?'}
avatarImgSrc={identity.creator?.image ?? ''}
id={identity.creator?.wallet ?? ''}
Expand Down
Loading