feat: hide untrusted content button
This commit is contained in:
69
src/components/HideUntrustedContentButton/index.tsx
Normal file
69
src/components/HideUntrustedContentButton/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger
|
||||
} from '@/components/ui/alert-dialog'
|
||||
import { Button, buttonVariants } from '@/components/ui/button'
|
||||
import { useUserTrust } from '@/providers/UserTrustProvider'
|
||||
import { VariantProps } from 'class-variance-authority'
|
||||
import { Shield, ShieldCheck } from 'lucide-react'
|
||||
|
||||
export default function HideUntrustedContentButton({
|
||||
type,
|
||||
size = 'icon'
|
||||
}: {
|
||||
type: 'interactions' | 'notifications'
|
||||
size?: VariantProps<typeof buttonVariants>['size']
|
||||
}) {
|
||||
const {
|
||||
hideUntrustedInteractions,
|
||||
hideUntrustedNotifications,
|
||||
updateHideUntrustedInteractions,
|
||||
updateHideUntrustedNotifications
|
||||
} = useUserTrust()
|
||||
|
||||
const enabled = type === 'interactions' ? hideUntrustedInteractions : hideUntrustedNotifications
|
||||
|
||||
const updateEnabled =
|
||||
type === 'interactions' ? updateHideUntrustedInteractions : updateHideUntrustedNotifications
|
||||
|
||||
return (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="ghost" size={size}>
|
||||
{enabled ? (
|
||||
<ShieldCheck className="text-green-400" />
|
||||
) : (
|
||||
<Shield className="text-muted-foreground" />
|
||||
)}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{enabled ? 'Show' : 'Hide'} untrusted {type}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{enabled
|
||||
? `Currently hiding ${type} from untrusted users. `
|
||||
: `Currently showing all ${type}. `}
|
||||
Trusted users include people you follow and people they follow.
|
||||
{enabled
|
||||
? ` Click continue to show all ${type}.`
|
||||
: ` Click continue to hide ${type} from untrusted users.`}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={() => updateEnabled(!enabled)}>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Event } from 'nostr-tools'
|
||||
import { useState } from 'react'
|
||||
import HideUntrustedContentButton from '../HideUntrustedContentButton'
|
||||
import QuoteList from '../QuoteList'
|
||||
import ReplyNoteList from '../ReplyNoteList'
|
||||
import { Tabs, TTabValue } from './Tabs'
|
||||
@@ -16,7 +17,10 @@ export default function NoteInteractions({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs selectedTab={type} onTabChange={setType} />
|
||||
<div className="flex items-center justify-between pr-1">
|
||||
<Tabs selectedTab={type} onTabChange={setType} />
|
||||
<HideUntrustedContentButton type="interactions" />
|
||||
</div>
|
||||
<Separator />
|
||||
{type === 'replies' ? (
|
||||
<ReplyNoteList index={pageIndex} event={event} />
|
||||
|
||||
@@ -12,11 +12,13 @@ export default function ReplyButton({ event }: { event: Event }) {
|
||||
const { t } = useTranslation()
|
||||
const { checkLogin } = useNostr()
|
||||
const { repliesMap } = useReply()
|
||||
const { isUserTrusted } = useUserTrust()
|
||||
const replyCount = useMemo(
|
||||
() => repliesMap.get(event.id)?.events.filter((evt) => isUserTrusted(evt.pubkey)).length || 0,
|
||||
[repliesMap, event.id, isUserTrusted]
|
||||
)
|
||||
const { hideUntrustedInteractions, isUserTrusted } = useUserTrust()
|
||||
const replyCount = useMemo(() => {
|
||||
if (hideUntrustedInteractions) {
|
||||
return repliesMap.get(event.id)?.events.filter((evt) => isUserTrusted(evt.pubkey)).length ?? 0
|
||||
}
|
||||
return repliesMap.get(event.id)?.events.length ?? 0
|
||||
}, [repliesMap, event.id, isUserTrusted])
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
return (
|
||||
|
||||
@@ -23,7 +23,7 @@ const NotificationList = forwardRef((_, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { current } = usePrimaryPage()
|
||||
const { pubkey } = useNostr()
|
||||
const { isUserTrusted } = useUserTrust()
|
||||
const { hideUntrustedNotifications, isUserTrusted } = useUserTrust()
|
||||
const { clearNewNotifications, getNotificationsSeenAt } = useNotification()
|
||||
const { updateNoteStatsByEvents } = useNoteStats()
|
||||
const [notificationType, setNotificationType] = useState<TNotificationType>('all')
|
||||
@@ -124,9 +124,11 @@ const NotificationList = forwardRef((_, ref) => {
|
||||
}, [pubkey, refreshCount, filterKinds, current])
|
||||
|
||||
useEffect(() => {
|
||||
const visibleNotifications = notifications
|
||||
.slice(0, showCount)
|
||||
.filter((event) => isUserTrusted(event.pubkey))
|
||||
let visibleNotifications = notifications.slice(0, showCount)
|
||||
if (hideUntrustedNotifications) {
|
||||
visibleNotifications = visibleNotifications.filter((event) => isUserTrusted(event.pubkey))
|
||||
}
|
||||
|
||||
const index = visibleNotifications.findIndex((event) => event.created_at <= lastReadTime)
|
||||
if (index === -1) {
|
||||
setNewNotifications(visibleNotifications)
|
||||
@@ -135,7 +137,7 @@ const NotificationList = forwardRef((_, ref) => {
|
||||
setNewNotifications(visibleNotifications.slice(0, index))
|
||||
setOldNotifications(visibleNotifications.slice(index))
|
||||
}
|
||||
}, [notifications, lastReadTime, showCount, isUserTrusted])
|
||||
}, [notifications, lastReadTime, showCount, hideUntrustedNotifications, isUserTrusted])
|
||||
|
||||
useEffect(() => {
|
||||
const options = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BIG_RELAY_URLS } from '@/constants'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { useUserTrust } from '@/providers/UserTrustProvider'
|
||||
import client from '@/services/client.service'
|
||||
import dayjs from 'dayjs'
|
||||
import { Event, kinds } from 'nostr-tools'
|
||||
@@ -13,6 +14,7 @@ const SHOW_COUNT = 10
|
||||
export default function QuoteList({ event, className }: { event: Event; className?: string }) {
|
||||
const { t } = useTranslation()
|
||||
const { startLogin } = useNostr()
|
||||
const { hideUntrustedInteractions, isUserTrusted } = useUserTrust()
|
||||
const [timelineKey, setTimelineKey] = useState<string | undefined>(undefined)
|
||||
const [events, setEvents] = useState<Event[]>([])
|
||||
const [showCount, setShowCount] = useState(SHOW_COUNT)
|
||||
@@ -124,9 +126,12 @@ export default function QuoteList({ event, className }: { event: Event; classNam
|
||||
<div className={className}>
|
||||
<div className="min-h-screen">
|
||||
<div>
|
||||
{events.slice(0, showCount).map((event) => (
|
||||
<NoteCard key={event.id} className="w-full" event={event} />
|
||||
))}
|
||||
{events.slice(0, showCount).map((event) => {
|
||||
if (hideUntrustedInteractions && !isUserTrusted(event.pubkey)) {
|
||||
return null
|
||||
}
|
||||
return <NoteCard key={event.id} className="w-full" event={event} />
|
||||
})}
|
||||
</div>
|
||||
{hasMore || loading ? (
|
||||
<div ref={bottomRef}>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function ReplyNoteList({
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const { currentIndex } = useSecondaryPage()
|
||||
const { isUserTrusted } = useUserTrust()
|
||||
const { hideUntrustedInteractions, isUserTrusted } = useUserTrust()
|
||||
const [rootInfo, setRootInfo] = useState<TRootInfo | undefined>(undefined)
|
||||
const { repliesMap, addReplies } = useReply()
|
||||
const replies = useMemo(() => {
|
||||
@@ -250,7 +250,7 @@ export default function ReplyNoteList({
|
||||
)}
|
||||
<div className={className}>
|
||||
{replies.slice(0, showCount).map((reply) => {
|
||||
if (!isUserTrusted(reply.pubkey)) {
|
||||
if (hideUntrustedInteractions && !isUserTrusted(reply.pubkey)) {
|
||||
const repliesForThisReply = repliesMap.get(reply.id)
|
||||
// If the reply is not trusted and there are no trusted replies for this reply, skip rendering
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user