Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export function FollowLensDialog({ handle, onClose }: Props) {

const { showSnackbar } = useCustomSnackbar()
const lensClient = useLensClient()
const myLensAccount = useMyLensAccountAddress()
const myLensAccount = useMyLensAccountAddress(true)

const { data: lensAccount, isLoading } = useQuery({
enabled: !!handle && !!open,
Expand All @@ -134,17 +134,14 @@ export function FollowLensDialog({ handle, onClose }: Props) {
const isSelf = isSameAddress(lensAccount?.username?.ownedBy as string, walletAccount)

const currentAccount = accounts?.find((p) => isSameAddress(p.account.address, myLensAccount)) || first(accounts)
const currentAccountAddress: EvmAddress | undefined = currentAccount?.account.address
const targetAccountAddress: EvmAddress | undefined = lensAccount?.address
const { isPending, data: isFollowing } = useQuery({
queryKey: ['lens', 'following-status', currentAccountAddress, targetAccountAddress, !lensClient],
queryKey: ['lens', 'following-status', myLensAccount, targetAccountAddress, !lensClient],
queryFn: async () => {
if (!targetAccountAddress || !currentAccountAddress || !lensClient) return false
const res = await lensClient.getFollowStatus([
{ account: targetAccountAddress, follower: currentAccountAddress },
])
if (!targetAccountAddress || !myLensAccount || !lensClient) return false
const res = await lensClient.getFollowStatus([{ account: targetAccountAddress, follower: myLensAccount }])
const status = res[0].isFollowing
return status.onChain || status.optimistic
return status.onChain
},
refetchOnWindowFocus: false,
staleTime: 0,
Expand All @@ -157,31 +154,34 @@ export function FollowLensDialog({ handle, onClose }: Props) {
accountAddress: lensAccount?.address,
onSuccess: (width: number, height: number) => {
showConfettiExplosion(width, height)
updateFollowingStatus(currentAccountAddress, targetAccountAddress, true)
updateFollowingStatus(myLensAccount, targetAccountAddress, true)
},
onFailed: () => updateFollowingStatus(currentAccountAddress, handle, false),
onFailed: () => updateFollowingStatus(myLensAccount, targetAccountAddress, false),
})
const { loading: unfollowLoading, handleUnfollow } = useUnfollow({
accountAddress: lensAccount?.address as string,
onSuccess: () => updateFollowingStatus(currentAccountAddress, targetAccountAddress, false),
onFailed: () => updateFollowingStatus(currentAccountAddress, targetAccountAddress, true),
onSuccess: () => updateFollowingStatus(myLensAccount, targetAccountAddress, false),
onFailed: () => updateFollowingStatus(myLensAccount, targetAccountAddress, true),
})
// #endregion

const handleClick = useCallback(() => {
if (task) {
showSnackbar(isFollowing ? <Trans>Lens Unfollow</Trans> : <Trans>Lens Follow</Trans>, {
processing: true,
message:
isFollowing ?
<Trans>Previous unfollow transaction is in processing, please wait and try again.</Trans>
: <Trans>Previous follow transaction is in processing, please wait and try again.</Trans>,
autoHideDuration: 2000,
})
return
}
task = (isFollowing ? handleUnfollow() : handleFollow()).finally(() => (task = undefined))
}, [handleFollow, handleUnfollow, isFollowing, showSnackbar])
const handleClick = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
if (task) {
showSnackbar(isFollowing ? <Trans>Lens Unfollow</Trans> : <Trans>Lens Follow</Trans>, {
processing: true,
message:
isFollowing ?
<Trans>Previous unfollow transaction is in processing, please wait and try again.</Trans>
: <Trans>Previous follow transaction is in processing, please wait and try again.</Trans>,
autoHideDuration: 2000,
})
return
}
task = (isFollowing ? handleUnfollow() : handleFollow(event)).finally(() => (task = undefined))
},
[handleFollow, handleUnfollow, isFollowing, showSnackbar],
)

const accountConditions =
!walletAccount || !currentAccount || !!wallet?.owner || pluginID !== NetworkPluginID.PLUGIN_EVM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const LensList = memo(function LensList({ accounts }: Props) {
if (!target) return
return {
...target,
address: nativeAccount.address,
ownedBy: nativeAccount.username?.ownedBy as string,
}
}),
Expand All @@ -107,7 +108,7 @@ export const LensList = memo(function LensList({ accounts }: Props) {
const followStatus = await lensV3.getFollowStatus(
(myLensAccount ? nativeAccounts || [] : []).map((x) => ({
follower: evmAddress(myLensAccount!),
account: evmAddress(x.username?.ownedBy),
account: evmAddress(x.address),
})),
)
return compact(
Expand All @@ -121,8 +122,9 @@ export const LensList = memo(function LensList({ accounts }: Props) {
)?.isFollowing
return {
...target,
address: nativeAccount.address,
ownedBy: nativeAccount.username?.ownedBy as string,
isFollowing: status?.onChain || status?.optimistic,
isFollowing: status?.optimistic || status?.onChain,
}
}),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type FollowOptions = {
onFailed?: () => void
}

export function useFollow({ accountAddress, onFailed }: FollowOptions) {
export function useFollow({ accountAddress, onSuccess, onFailed }: FollowOptions) {
const { t } = useLingui()
const [loading, setLoading] = useState(false)
const { chainId } = useChainContext<NetworkPluginID.PLUGIN_EVM>()
Expand All @@ -35,43 +35,48 @@ export function useFollow({ accountAddress, onFailed }: FollowOptions) {
const myLensAccount = useMyLensAccountAddress()
const lensClient = useLensClient()

const handleFollow = useCallback<() => Promise<void>>(async () => {
try {
setLoading(true)
if (!accountAddress || chainId !== ChainId.Polygon) return
if (!lensClient || !myLensAccount) return
await lensClient.login(myLensAccount)
const res = await lensClient.follow(accountAddress)
if (res.isErr()) {
throw res.error
const handleFollow = useCallback(
async (event: React.MouseEvent<HTMLButtonElement>) => {
try {
setLoading(true)
if (!accountAddress || chainId !== ChainId.Polygon) return
if (!lensClient || !myLensAccount) return
await lensClient.login(myLensAccount)
const res = await lensClient.follow(accountAddress)
if (res.isErr()) {
throw res.error
}
const target = event.target as HTMLButtonElement
onSuccess?.(target.offsetWidth, target.offsetHeight)
} catch (error) {
if (!(error instanceof Error)) return
const message = error.message
if (message.match(/Bad user input .* is already following/)) {
showSingletonSnackbar(t`Follow Lens handle`, {
processing: false,
variant: 'warning',
message: <Trans>Already following</Trans>,
})
} else if (
!message.includes('Transaction was rejected') &&
!message.includes('Signature canceled') &&
!message.includes('User rejected the request') &&
!message.includes('User rejected transaction') &&
!message.includes('RPC Error')
) {
onFailed?.()
showSingletonSnackbar(t`Follow Lens handle`, {
processing: false,
variant: 'error',
message: <Trans>Network error, try again: {error.message}</Trans>,
})
}
} finally {
setLoading(false)
}
} catch (error) {
if (!(error instanceof Error)) return
const message = error.message
if (message.match(/Bad user input .* is already following/)) {
showSingletonSnackbar(t`Follow Lens handle`, {
processing: false,
variant: 'warning',
message: <Trans>Already following</Trans>,
})
} else if (
!message.includes('Transaction was rejected') &&
!message.includes('Signature canceled') &&
!message.includes('User rejected the request') &&
!message.includes('User rejected transaction') &&
!message.includes('RPC Error')
) {
onFailed?.()
showSingletonSnackbar(t`Follow Lens handle`, {
processing: false,
variant: 'error',
message: <Trans>Network error, try again: {error.message}</Trans>,
})
}
} finally {
setLoading(false)
}
}, [accountAddress, chainId, lensClient, myLensAccount, onFailed, showSingletonSnackbar, t])
},
[accountAddress, chainId, lensClient, myLensAccount, onFailed, showSingletonSnackbar, t],
)

return { loading, handleFollow }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FireflyConfigAPI } from '@masknet/web3-providers/types'
import { isSameAddress } from '@masknet/web3-shared-base'
import { useQueryClient } from '@tanstack/react-query'
import { useCallback } from 'react'

Expand All @@ -12,7 +13,7 @@ export function useUpdateFollowingStatus() {
(data) => {
if (!data) return data
return data.map((x) => {
return x.handle === targetLensAccount ? { ...x, isFollowing } : x
return isSameAddress(x.address, targetLensAccount) ? { ...x, isFollowing } : x
})
},
)
Expand Down
8 changes: 7 additions & 1 deletion packages/shared/src/hooks/useAvailableLensAccounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useChainContext } from '@masknet/web3-hooks-base'
import { useQuery } from '@tanstack/react-query'
import { useLensClient } from './useLensClient.js'

export function useAvailableLensAccounts() {
export function useAvailableLensAccounts(isManaged?: boolean) {
const { account: walletAccount } = useChainContext<NetworkPluginID.PLUGIN_EVM>()
const lensClient = useLensClient()

Expand All @@ -15,5 +15,11 @@ export function useAvailableLensAccounts() {
const accounts = await lensClient.getAvailableAccounts(evmAddress(walletAccount))
return accounts
},
select(data) {
if (isManaged === undefined || !data) return data
return data.filter((account) =>
isManaged ? account.__typename === 'AccountManaged' : account.__typename === 'AccountOwned',
)
},
})
}
19 changes: 11 additions & 8 deletions packages/shared/src/hooks/useMyLensAccountAddress.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import type { EvmAddress } from '@lens-protocol/client'
import { PersistentStorages, type NetworkPluginID } from '@masknet/shared-base'
import { useChainContext } from '@masknet/web3-hooks-base'
import { PersistentStorages } from '@masknet/shared-base'
import { isSameAddress } from '@masknet/web3-shared-base'
import { useMemo } from 'react'
import { useSubscription } from 'use-subscription'
import { useAvailableLensAccounts } from './useAvailableLensAccounts.js'
import { first } from 'lodash-es'

export function useMyLensAccountAddress(): EvmAddress | undefined {
const { account: walletAccount } = useChainContext<NetworkPluginID.PLUGIN_EVM>()
export function useMyLensAccountAddress(isManaged?: boolean): EvmAddress | undefined {
const lastLensAccount = useSubscription(PersistentStorages.Settings.storage.lastLensAccount.subscription)
const { data: lensAccounts } = useAvailableLensAccounts()
const { data: lensAccounts } = useAvailableLensAccounts(isManaged)

return useMemo(() => {
if (!walletAccount) return
if (!lensAccounts?.length) return
// Make sure lastLensAccount is in lensAccounts
return lensAccounts?.find((x) => isSameAddress(x.account.address, lastLensAccount))?.account.address
}, [walletAccount, lastLensAccount, lensAccounts])
const lensAccount =
lastLensAccount ?
lensAccounts.find((x) => isSameAddress(x.account.address, lastLensAccount))
: first(lensAccounts)
return lensAccount?.account.address
}, [lastLensAccount, lensAccounts])
}

export function setMyLensAccountAddress(address: string) {
Expand Down
16 changes: 8 additions & 8 deletions packages/web3-providers/src/LensV3/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function formatLensPost(result: AnyPost): Social.Post {
canMirror: result.repostOf.operations?.canRepost.__typename === 'PostOperationValidationPassed',
hasMirrored: result.repostOf.operations?.hasReported,
hasQuoted:
result.repostOf.operations?.hasQuoted.onChain || result.repostOf.operations?.hasQuoted.optimistic,
result.repostOf.operations?.hasQuoted.optimistic || result.repostOf.operations?.hasQuoted.onChain,
hasLiked: result.repostOf.operations?.hasUpvoted,
hasBookmarked: result.repostOf.operations?.hasBookmarked,
mentions: result.repostOf.mentions.map((x) => {
Expand Down Expand Up @@ -159,7 +159,7 @@ export function formatLensPost(result: AnyPost): Social.Post {
canComment: result.operations?.canComment.__typename === 'PostOperationValidationPassed',
canMirror: result.operations?.canRepost.__typename === 'PostOperationValidationPassed',
hasMirrored: result.operations?.hasReported,
hasQuoted: result.operations?.hasQuoted.onChain || result.operations?.hasQuoted.optimistic,
hasQuoted: result.operations?.hasQuoted.optimistic || result.operations?.hasQuoted.onChain,
hasLiked: result.operations?.hasUpvoted,
hasBookmarked: result.operations?.hasBookmarked,
quoteOn: formatLensQuoteOrComment(result.quoteOf),
Expand Down Expand Up @@ -199,8 +199,8 @@ export function formatLensPost(result: AnyPost): Social.Post {
commentOn: formatLensQuoteOrComment(result.commentOn),
canComment: result.operations?.canComment.__typename === 'PostOperationValidationPassed',
canMirror: result.operations?.canRepost.__typename === 'PostOperationValidationPassed',
hasMirrored: result.operations?.hasReposted.onChain || result.operations?.hasReposted.optimistic,
hasQuoted: result.operations?.hasQuoted.onChain || result.operations?.hasQuoted.optimistic,
hasMirrored: result.operations?.hasReposted.optimistic || result.operations?.hasReposted.onChain,
hasQuoted: result.operations?.hasQuoted.optimistic || result.operations?.hasQuoted.onChain,
hasLiked: result.operations?.hasUpvoted,
hasBookmarked: result.operations?.hasBookmarked,
mentions: result.mentions.map((x) => {
Expand Down Expand Up @@ -237,8 +237,8 @@ export function formatLensPost(result: AnyPost): Social.Post {
},
canComment: result.operations?.canComment.__typename === 'PostOperationValidationPassed',
canMirror: result.operations?.canRepost.__typename === 'PostOperationValidationPassed',
hasMirrored: result.operations?.hasReposted.onChain || result.operations?.hasReposted.optimistic,
hasQuoted: result.operations?.hasQuoted.onChain || result.operations?.hasQuoted.optimistic,
hasMirrored: result.operations?.hasReposted.optimistic || result.operations?.hasReposted.onChain,
hasQuoted: result.operations?.hasQuoted.optimistic || result.operations?.hasQuoted.onChain,
hasLiked: result.operations?.hasUpvoted,
hasBookmarked: result.operations?.hasBookmarked,
mentions: result.mentions.map((x) => {
Expand Down Expand Up @@ -356,8 +356,8 @@ function formatLensQuoteOrComment(result: ReferencedPost): Social.Post {
},
canComment: result.operations?.canComment.__typename === 'PostOperationValidationPassed',
canMirror: result.operations?.canRepost.__typename === 'PostOperationValidationPassed',
hasMirrored: result.operations?.hasReposted.onChain || result.operations?.hasReposted.optimistic,
hasQuoted: result.operations?.hasQuoted.onChain || result.operations?.hasQuoted.optimistic,
hasMirrored: result.operations?.hasReposted.optimistic || result.operations?.hasReposted.onChain,
hasQuoted: result.operations?.hasQuoted.optimistic || result.operations?.hasQuoted.onChain,
hasLiked: result.operations?.hasUpvoted,
hasBookmarked: result.operations?.hasBookmarked,
stats,
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-providers/src/LensV3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class LensV3 {
})
if (result.isErr()) return []
const list = uniqBy(
sortBy(result.value.items, (x) => (x.__typename === 'AccountOwned' ? -1 : 0)),
sortBy(result.value.items, (x) => (x.__typename === 'AccountManaged' ? -1 : 0)),
(x) => x.account.address,
)
return list as AccountAvailable[]
Expand Down
8 changes: 6 additions & 2 deletions packages/web3-providers/src/NextID/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class NextIDProof {
const nextIDPersonaBindings: NextIDPersonaBindings[] = []
let page = 1
do {
const bindings = await fetchFromProofService<NextIDBindings>(
const bindings = await fetchFromProofService<NextIDBindings | { message: string }>(
urlcat(BASE_URL, '/v1/proof', {
platform,
identity,
Expand All @@ -170,8 +170,12 @@ export class NextIDProof {
order: 'desc',
}),
)
if ('message' in bindings) {
console.error('NextIDProof.queryAllExistedBindingsByPlatform', bindings.message)
return nextIDPersonaBindings
}
const personaBindings = bindings.ids
if (personaBindings.length === 0) return nextIDPersonaBindings
if (!personaBindings?.length) return nextIDPersonaBindings
nextIDPersonaBindings.push(...personaBindings)

// next is `0` if current page is the last one.
Expand Down