refactor: add repost tag if missing

This commit is contained in:
enes 2024-11-27 19:56:19 +01:00
parent 35cedba3db
commit 376164cbf4
7 changed files with 132 additions and 19 deletions

View File

@ -0,0 +1,15 @@
import { useState } from 'react'
import { useNDKContext } from './useNDKContext'
import { useDidMount } from './useDidMount'
import { CurationSetIdentifiers, getReportingSet } from 'utils'
export const useCuratedSet = (type: CurationSetIdentifiers) => {
const ndkContext = useNDKContext()
const [curatedSet, setCuratedSet] = useState<string[]>([])
useDidMount(async () => {
setCuratedSet(await getReportingSet(type, ndkContext))
})
return curatedSet
}

View File

@ -514,9 +514,12 @@ const Body = ({
{repost && ( {repost && (
<div className='IBMSMSMBSSTagsTag IBMSMSMBSSTagsTagRepost'> <div className='IBMSMSMBSSTagsTag IBMSMSMBSSTagsTagRepost'>
<p> <p>
REPOST. Original Author:{' '} REPOST
{!!originalAuthor && ( {originalAuthor && originalAuthor !== '' && (
<OriginalAuthor value={originalAuthor} fallback={true} /> <>
. Original Author:{' '}
<OriginalAuthor value={originalAuthor} fallback={true} />
</>
)} )}
</p> </p>
</div> </div>

View File

@ -12,10 +12,12 @@ import {
NSFWFilter NSFWFilter
} from 'types' } from 'types'
import { import {
CurationSetIdentifiers,
DEFAULT_FILTER_OPTIONS, DEFAULT_FILTER_OPTIONS,
extractBlogCardDetails, extractBlogCardDetails,
extractModData, extractModData,
getLocalStorageItem, getLocalStorageItem,
getReportingSet,
log, log,
LogType LogType
} from 'utils' } from 'utils'
@ -83,7 +85,8 @@ export const modRouteLoader =
ndkContext.fetchEvent(modFilter), ndkContext.fetchEvent(modFilter),
ndkContext.fetchEvents(latestFilter), ndkContext.fetchEvents(latestFilter),
ndkContext.getMuteLists(loggedInUserPubkey), // Pass pubkey for logged-in users ndkContext.getMuteLists(loggedInUserPubkey), // Pass pubkey for logged-in users
ndkContext.getNSFWList() getReportingSet(CurationSetIdentifiers.NSFW, ndkContext),
getReportingSet(CurationSetIdentifiers.Repost, ndkContext)
]) ])
const result: ModPageLoaderResult = { const result: ModPageLoaderResult = {
@ -205,6 +208,28 @@ export const modRouteLoader =
log(true, LogType.Error, 'Issue fetching nsfw list', nsfwList.reason) log(true, LogType.Error, 'Issue fetching nsfw list', nsfwList.reason)
} }
const repostList = settled[4]
if (repostList.status === 'fulfilled' && repostList.value) {
// Check if the mod is marked as Repost
// Mark it as Repost only if it's missing the tag
if (result.mod) {
const isMissingRepostTag =
!result.mod.repost &&
result.mod.aTag &&
repostList.value.includes(result.mod.aTag)
if (isMissingRepostTag) {
result.mod.repost = true
}
if (result.mod.aTag && repostList.value.includes(result.mod.aTag)) {
result.isRepost = true
}
}
} else if (repostList.status === 'rejected') {
log(true, LogType.Error, 'Issue fetching nsfw list', repostList.reason)
}
// Filter latest, sort and take only three // Filter latest, sort and take only three
result.latest = result.latest result.latest = result.latest
.filter( .filter(

View File

@ -19,8 +19,13 @@ import '../styles/pagination.css'
import '../styles/search.css' import '../styles/search.css'
import '../styles/styles.css' import '../styles/styles.css'
import { FilterOptions, ModDetails } from '../types' import { FilterOptions, ModDetails } from '../types'
import { DEFAULT_FILTER_OPTIONS, scrollIntoView } from 'utils' import {
CurationSetIdentifiers,
DEFAULT_FILTER_OPTIONS,
scrollIntoView
} from 'utils'
import { SearchInput } from 'components/SearchInput' import { SearchInput } from 'components/SearchInput'
import { useCuratedSet } from 'hooks/useCuratedSet'
export const ModsPage = () => { export const ModsPage = () => {
const scrollTargetRef = useRef<HTMLDivElement>(null) const scrollTargetRef = useRef<HTMLDivElement>(null)
@ -97,6 +102,14 @@ export const ModsPage = () => {
muteLists muteLists
) )
// Add repost tag to mods included in repostList
const repostList = useCuratedSet(CurationSetIdentifiers.Repost)
const filteredModListRepost = filteredModList.map((mod) => {
return !mod.repost && repostList.includes(mod.aTag)
? { ...mod, repost: true }
: mod
})
return ( return (
<> <>
{isFetching && <LoadingSpinner desc='Fetching mod details from relays' />} {isFetching && <LoadingSpinner desc='Fetching mod details from relays' />}
@ -111,7 +124,7 @@ export const ModsPage = () => {
<div className='IBMSecMain IBMSMListWrapper'> <div className='IBMSecMain IBMSMListWrapper'>
<div className='IBMSMList'> <div className='IBMSMList'>
{filteredModList.map((mod) => ( {filteredModListRepost.map((mod) => (
<ModCard key={mod.id} {...mod} /> <ModCard key={mod.id} {...mod} />
))} ))}
</div> </div>

View File

@ -10,9 +10,7 @@ import {
useAppSelector, useAppSelector,
useFilteredMods, useFilteredMods,
useLocalStorage, useLocalStorage,
useMuteLists, useNDKContext
useNDKContext,
useNSFWList
} from 'hooks' } from 'hooks'
import { kinds, UnsignedEvent } from 'nostr-tools' import { kinds, UnsignedEvent } from 'nostr-tools'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
@ -47,7 +45,10 @@ export const ProfilePage = () => {
profilePubkey, profilePubkey,
profile, profile,
isBlocked: _isBlocked, isBlocked: _isBlocked,
isOwnProfile isOwnProfile,
repostList,
muteLists,
nsfwList
} = useLoaderData() as ProfilePageLoaderResult } = useLoaderData() as ProfilePageLoaderResult
const scrollTargetRef = useRef<HTMLDivElement>(null) const scrollTargetRef = useRef<HTMLDivElement>(null)
const { ndk, publish, fetchEventFromUserRelays, fetchMods } = useNDKContext() const { ndk, publish, fetchEventFromUserRelays, fetchMods } = useNDKContext()
@ -200,8 +201,6 @@ export const ProfilePage = () => {
const [filterOptions] = useLocalStorage<FilterOptions>(filterKey, { const [filterOptions] = useLocalStorage<FilterOptions>(filterKey, {
...DEFAULT_FILTER_OPTIONS ...DEFAULT_FILTER_OPTIONS
}) })
const muteLists = useMuteLists()
const nsfwList = useNSFWList()
const handleNext = useCallback(() => { const handleNext = useCallback(() => {
setIsLoading(true) setIsLoading(true)
@ -263,6 +262,7 @@ export const ProfilePage = () => {
break break
} }
}, [filterOptions.source, tab, fetchMods, profilePubkey]) }, [filterOptions.source, tab, fetchMods, profilePubkey])
const filteredModList = useFilteredMods( const filteredModList = useFilteredMods(
mods, mods,
userState, userState,
@ -272,6 +272,13 @@ export const ProfilePage = () => {
profilePubkey profilePubkey
) )
// Add repost tag to mods included in repostList
const filteredModListRepost = filteredModList.map((mod) => {
return !mod.repost && repostList.includes(mod.aTag)
? { ...mod, repost: true }
: mod
})
return ( return (
<div className='InnerBodyMain'> <div className='InnerBodyMain'>
<div className='ContainerMain'> <div className='ContainerMain'>
@ -422,7 +429,7 @@ export const ProfilePage = () => {
<ModFilter filterKey={filterKey} author={profilePubkey} /> <ModFilter filterKey={filterKey} author={profilePubkey} />
<div className='IBMSMList IBMSMListAlt'> <div className='IBMSMList IBMSMListAlt'>
{filteredModList.map((mod) => ( {filteredModListRepost.map((mod) => (
<ModCard key={mod.id} {...mod} /> <ModCard key={mod.id} {...mod} />
))} ))}
</div> </div>

View File

@ -4,7 +4,13 @@ import { LoaderFunctionArgs, redirect } from 'react-router-dom'
import { appRoutes, getProfilePageRoute } from 'routes' import { appRoutes, getProfilePageRoute } from 'routes'
import { store } from 'store' import { store } from 'store'
import { MuteLists, UserProfile } from 'types' import { MuteLists, UserProfile } from 'types'
import { log, LogType, npubToHex } from 'utils' import {
CurationSetIdentifiers,
getReportingSet,
log,
LogType,
npubToHex
} from 'utils'
export interface ProfilePageLoaderResult { export interface ProfilePageLoaderResult {
profilePubkey: string profilePubkey: string
@ -16,6 +22,7 @@ export interface ProfilePageLoaderResult {
user: MuteLists user: MuteLists
} }
nsfwList: string[] nsfwList: string[]
repostList: string[]
} }
export const profileRouteLoader = export const profileRouteLoader =
@ -87,7 +94,8 @@ export const profileRouteLoader =
replaceableEvents: [] replaceableEvents: []
} }
}, },
nsfwList: [] nsfwList: [],
repostList: []
} }
// Check if user the user is logged in // Check if user the user is logged in
@ -98,7 +106,8 @@ export const profileRouteLoader =
const settled = await Promise.allSettled([ const settled = await Promise.allSettled([
ndkContext.findMetadata(profilePubkey), ndkContext.findMetadata(profilePubkey),
ndkContext.getMuteLists(userPubkey), ndkContext.getMuteLists(userPubkey),
ndkContext.getNSFWList() getReportingSet(CurationSetIdentifiers.NSFW, ndkContext),
getReportingSet(CurationSetIdentifiers.Repost, ndkContext)
]) ])
// Check the profile event result // Check the profile event result
@ -138,10 +147,23 @@ export const profileRouteLoader =
log( log(
true, true,
LogType.Error, LogType.Error,
'Failed to fetch mutelist.', 'Failed to fetch nsfwlist.',
nsfwListResult.reason nsfwListResult.reason
) )
} }
// Check the profile 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 return result
} }

View File

@ -1,9 +1,9 @@
import { NDKFilter } from '@nostr-dev-kit/ndk' import { NDKFilter, NDKList } from '@nostr-dev-kit/ndk'
import { NDKContextType } from 'contexts/NDKContext' import { NDKContextType } from 'contexts/NDKContext'
import { UnsignedEvent, kinds } from 'nostr-tools' import { UnsignedEvent, kinds } from 'nostr-tools'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { UserRelaysType } from 'types' import { UserRelaysType } from 'types'
import { now, signAndPublish } from './nostr' import { now, npubToHex, signAndPublish } from './nostr'
interface CurationSetArgs { interface CurationSetArgs {
dTag: CurationSetIdentifiers dTag: CurationSetIdentifiers
@ -54,6 +54,34 @@ export async function createCurationSet(
return isUpdated return isUpdated
} }
export async function getReportingSet(
dTag: CurationSetIdentifiers,
ndkContext: NDKContextType
) {
const result: string[] = []
const reportingNpub = import.meta.env.VITE_REPORTING_NPUB
const hexKey = npubToHex(reportingNpub)
if (hexKey) {
const event = await ndkContext.fetchEvent({
kinds: [kinds.Curationsets],
authors: [hexKey],
'#d': [dTag]
})
if (event) {
const list = NDKList.from(event)
list.items.forEach((item) => {
if (item[0] === 'a') {
result.push(item[1])
}
})
}
}
return result
}
export async function getCurationSet({ export async function getCurationSet({
dTag, dTag,
pubkey, pubkey,