160 lines
4.5 KiB
TypeScript
160 lines
4.5 KiB
TypeScript
import { NDKContextType } from 'contexts/NDKContext'
|
|
import { nip19 } from 'nostr-tools'
|
|
import { LoaderFunctionArgs, redirect } from 'react-router-dom'
|
|
import { appRoutes, getProfilePageRoute } from 'routes'
|
|
import { store } from 'store'
|
|
import { MuteLists, UserProfile } from 'types'
|
|
import {
|
|
CurationSetIdentifiers,
|
|
getFallbackPubkey,
|
|
getReportingSet,
|
|
log,
|
|
LogType,
|
|
npubToHex
|
|
} from 'utils'
|
|
|
|
export interface ProfilePageLoaderResult {
|
|
profilePubkey: string
|
|
profile: UserProfile
|
|
isBlocked: boolean
|
|
muteLists: {
|
|
admin: MuteLists
|
|
user: MuteLists
|
|
}
|
|
nsfwList: string[]
|
|
repostList: string[]
|
|
}
|
|
|
|
export const profileRouteLoader =
|
|
(ndkContext: NDKContextType) =>
|
|
async ({ params }: LoaderFunctionArgs) => {
|
|
// Try to decode nprofile parameter
|
|
const { nprofile } = params
|
|
let profilePubkey: string | undefined
|
|
try {
|
|
// Decode if it starts with nprofile1
|
|
if (nprofile?.startsWith('nprofile1')) {
|
|
const value = nprofile
|
|
? nip19.decode(nprofile as `nprofile1${string}`)
|
|
: undefined
|
|
profilePubkey = value?.data.pubkey
|
|
} else if (nprofile?.startsWith('npub1')) {
|
|
// Try to get hex from the npub and encode it to nprofile
|
|
const value = npubToHex(nprofile)
|
|
if (value) {
|
|
return redirect(
|
|
getProfilePageRoute(
|
|
nip19.nprofileEncode({
|
|
pubkey: value
|
|
})
|
|
)
|
|
)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// Silently ignore and redirect to home or logged in user
|
|
log(true, LogType.Error, 'Failed to decode nprofile.', error)
|
|
}
|
|
|
|
// Get the current state
|
|
const userState = store.getState().user
|
|
const loggedInUserPubkey =
|
|
(userState?.user?.pubkey as string | undefined) || getFallbackPubkey()
|
|
|
|
// Redirect if profile naddr is missing
|
|
// - home if user is not logged
|
|
let profileRoute = appRoutes.home
|
|
if (!profilePubkey && loggedInUserPubkey) {
|
|
// - own profile
|
|
profileRoute = getProfilePageRoute(
|
|
nip19.nprofileEncode({
|
|
pubkey: loggedInUserPubkey
|
|
})
|
|
)
|
|
}
|
|
if (!profilePubkey) return redirect(profileRoute)
|
|
|
|
// Empty result
|
|
const result: ProfilePageLoaderResult = {
|
|
profilePubkey: profilePubkey,
|
|
profile: {},
|
|
isBlocked: false,
|
|
muteLists: {
|
|
admin: {
|
|
authors: [],
|
|
replaceableEvents: []
|
|
},
|
|
user: {
|
|
authors: [],
|
|
replaceableEvents: []
|
|
}
|
|
},
|
|
nsfwList: [],
|
|
repostList: []
|
|
}
|
|
|
|
const settled = await Promise.allSettled([
|
|
ndkContext.findMetadata(profilePubkey),
|
|
ndkContext.getMuteLists(loggedInUserPubkey),
|
|
getReportingSet(CurationSetIdentifiers.NSFW, ndkContext),
|
|
getReportingSet(CurationSetIdentifiers.Repost, ndkContext)
|
|
])
|
|
|
|
// Check the profile event result
|
|
const profileEventResult = settled[0]
|
|
if (profileEventResult.status === 'fulfilled' && profileEventResult.value) {
|
|
result.profile = profileEventResult.value
|
|
} else if (profileEventResult.status === 'rejected') {
|
|
log(
|
|
true,
|
|
LogType.Error,
|
|
'Failed to fetch profile.',
|
|
profileEventResult.reason
|
|
)
|
|
}
|
|
|
|
// Check the mutelist event result
|
|
const muteListResult = settled[1]
|
|
if (muteListResult.status === 'fulfilled' && muteListResult.value) {
|
|
result.muteLists = muteListResult.value
|
|
|
|
// Check if user has blocked this profile
|
|
result.isBlocked = result.muteLists.user.authors.includes(profilePubkey)
|
|
} else if (muteListResult.status === 'rejected') {
|
|
log(
|
|
true,
|
|
LogType.Error,
|
|
'Failed to fetch mutelist.',
|
|
muteListResult.reason
|
|
)
|
|
}
|
|
|
|
// Check the nsfwlist event result
|
|
const nsfwListResult = settled[2]
|
|
if (nsfwListResult.status === 'fulfilled' && nsfwListResult.value) {
|
|
result.nsfwList = nsfwListResult.value
|
|
} else if (nsfwListResult.status === 'rejected') {
|
|
log(
|
|
true,
|
|
LogType.Error,
|
|
'Failed to fetch nsfwlist.',
|
|
nsfwListResult.reason
|
|
)
|
|
}
|
|
|
|
// Check the repostlist event result
|
|
const repostListResult = settled[3]
|
|
if (repostListResult.status === 'fulfilled' && repostListResult.value) {
|
|
result.repostList = repostListResult.value
|
|
} else if (repostListResult.status === 'rejected') {
|
|
log(
|
|
true,
|
|
LogType.Error,
|
|
'Failed to fetch repost list.',
|
|
repostListResult.reason
|
|
)
|
|
}
|
|
|
|
return result
|
|
}
|