Add post warnings to blog/mod #197

Merged
enes merged 3 commits from extra/154-blocked-warning into staging 2025-01-16 12:07:46 +00:00
8 changed files with 77 additions and 9 deletions

View File

@ -0,0 +1,22 @@
interface PostWarningsProps {
type: 'user' | 'admin'
}
export const PostWarnings = ({ type }: PostWarningsProps) => (
<div className='IBMSMSMBSSWarning'>
<p>
{type === 'admin' ? (
<>
Warning: This post has been blocked/hidden by the site for one of the
following reasons:
<br />
Malware, Not a Mod, Illegal, Spam, Verified Report of Unauthorized
Repost.
<br />
</>
) : (
<>Notice: You have blocked this post</>
)}
</p>
</div>
)

View File

@ -3,7 +3,7 @@ import {
launch as launchNostrLoginDialog
} from 'nostr-login'
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { Link, useRevalidator } from 'react-router-dom'
import { Banner } from '../components/Banner'
import { ZapPopUp } from '../components/Zap'
import {
@ -27,7 +27,7 @@ export const Header = () => {
const dispatch = useAppDispatch()
const { findMetadata } = useNDKContext()
const userState = useAppSelector((state) => state.user)
const revalidator = useRevalidator()
// Track nostr-login extension modal open state
const [isOpen, setIsOpen] = useState(false)
const handleOpen = () => setIsOpen(true)
@ -75,8 +75,12 @@ export const Header = () => {
}
})
}
// React router - revalidate loader states on auth changes
revalidator.revalidate()
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch, findMetadata])
const handleLogin = () => {
@ -447,7 +451,9 @@ const RegisterButtonWithDialog = () => {
color: '#ffffffbf'
}}
>
Warning:&nbsp;Make sure you backup your private key somewhere safe. If you lose it or it gets leaked, we actually can't help you.
Warning:&nbsp;Make sure you backup your private key
somewhere safe. If you lose it or it gets leaked, we
actually can't help you.
</p>
<p
className='labelDescriptionMain'

View File

@ -18,6 +18,7 @@ import { toast } from 'react-toastify'
import { useAppSelector, useBodyScrollDisable } from 'hooks'
import { ReportPopup } from 'components/ReportPopup'
import { Viewer } from 'components/Markdown/Viewer'
import { PostWarnings } from 'components/PostWarning'
const BLOG_REPORT_REASONS = [
{ label: 'Actually CP', key: 'actuallyCP' },
@ -29,7 +30,7 @@ const BLOG_REPORT_REASONS = [
]
export const BlogPage = () => {
const { blog, latest, isAddedToNSFW, isBlocked } =
const { blog, latest, isAddedToNSFW, isBlocked, postWarning } =
useLoaderData() as BlogPageLoaderResult
const userState = useAppSelector((state) => state.user)
const isAdmin =
@ -84,6 +85,7 @@ export const BlogPage = () => {
<>
<div className='IBMSMSplitMainBigSide'>
<div className='IBMSMSplitMainBigSideSec'>
{postWarning && <PostWarnings type={postWarning} />}
<div className='IBMSMSMBSSPost'>
<div
className='dropdown dropdownMain dropdownMainBlogpost'

View File

@ -44,6 +44,7 @@ export const blogRouteLoader =
const userState = store.getState().user
const loggedInUserPubkey =
(userState?.user?.pubkey as string | undefined) || getFallbackPubkey()
const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
// Check if editing and the user is the original author
// Redirect if NOT
@ -138,10 +139,28 @@ export const blogRouteLoader =
if (muteLists.status === 'fulfilled' && muteLists.value) {
if (muteLists && muteLists.value) {
if (result.blog && result.blog.aTag) {
// Show user or admin post warning if any mute list includes either post or author
if (
muteLists.value.user.replaceableEvents.includes(
result.blog.aTag
) ||
(result.blog.author &&
muteLists.value.user.authors.includes(result.blog.author))
) {
result.postWarning = 'user'
}
if (
muteLists.value.admin.replaceableEvents.includes(
result.blog.aTag
) ||
(result.blog.author &&
muteLists.value.admin.authors.includes(result.blog.author))
) {
result.postWarning = 'admin'
}
if (
muteLists.value.user.replaceableEvents.includes(result.blog.aTag)
) {
result.isBlocked = true
@ -149,8 +168,6 @@ export const blogRouteLoader =
}
// Moderate the latest
const isAdmin =
userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
const isOwner =
userState.user?.pubkey && userState.user.pubkey === pubkey
const isUnmoderatedFully =

View File

@ -38,6 +38,7 @@ import { Spinner } from 'components/Spinner'
import { RouterLoadingSpinner } from 'components/LoadingSpinner'
import { OriginalAuthor } from 'components/OriginalAuthor'
import { Viewer } from 'components/Markdown/Viewer'
import { PostWarnings } from 'components/PostWarning'
const MOD_REPORT_REASONS = [
{ label: 'Actually CP', key: 'actuallyCP' },
@ -51,7 +52,7 @@ const MOD_REPORT_REASONS = [
]
export const ModPage = () => {
const { mod } = useLoaderData() as ModPageLoaderResult
const { mod, postWarning } = useLoaderData() as ModPageLoaderResult
// We can get author right away from naddr, no need to wait for mod data
const { naddr } = useParams()
@ -98,6 +99,7 @@ export const ModPage = () => {
<>
<div className='IBMSMSplitMainBigSideSec'>
<Game />
{postWarning && <PostWarnings type={postWarning} />}
<Body
featuredImageUrl={mod.featuredImageUrl}
title={mod.title}
@ -125,6 +127,7 @@ export const ModPage = () => {
<h4 className='IBMSMSMBSSDownloadsTitle'>
Mod Download
</h4>
{postWarning && <PostWarnings type={postWarning} />}
{mod.downloadUrls.length > 0 && (
<div className='IBMSMSMBSSDownloadsPrime'>
<Download {...mod.downloadUrls[0]} />

View File

@ -50,6 +50,7 @@ export const modRouteLoader =
const userState = store.getState().user
const loggedInUserPubkey =
(userState?.user?.pubkey as string | undefined) || getFallbackPubkey()
const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
// Check if editing and the user is the original author
// Redirect if NOT
@ -146,10 +147,27 @@ export const modRouteLoader =
if (muteLists.status === 'fulfilled' && muteLists.value) {
if (muteLists && muteLists.value) {
if (result.mod && result.mod.aTag) {
// Show user or admin post warning if any mute list includes either post or author
if (
muteLists.value.user.replaceableEvents.includes(
result.mod.aTag
) ||
muteLists.value.user.authors.includes(result.mod.author)
) {
result.postWarning = 'user'
}
if (
muteLists.value.admin.replaceableEvents.includes(
result.mod.aTag
) ||
muteLists.value.admin.authors.includes(result.mod.author)
) {
result.postWarning = 'admin'
}
// Check if user has blocked this profile
if (
muteLists.value.user.replaceableEvents.includes(result.mod.aTag)
) {
result.isBlocked = true
@ -157,8 +175,6 @@ export const modRouteLoader =
}
// Moderate the latest
const isAdmin =
userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
const isOwner =
userState.user?.pubkey && userState.user.pubkey === pubkey
const isUnmoderatedFully =

View File

@ -39,6 +39,7 @@ export interface BlogPageLoaderResult {
latest: Partial<BlogDetails>[]
isAddedToNSFW: boolean
isBlocked: boolean
postWarning?: 'user' | 'admin'
}
export interface BlogsFilterOptions {

View File

@ -66,6 +66,7 @@ export interface ModPageLoaderResult {
isAddedToNSFW: boolean
isBlocked: boolean
isRepost: boolean
postWarning?: 'user' | 'admin'
}
export type SubmitModActionResult =