Prevent local admin profile media from blurring during NSFW node updates
Hop-State: A_06FPE5MS0ZXE3ESZJJ27C98 Hop-Proposal: R_06FPE5KR2QGEVQD0MW8DSZR Hop-Task: T_06FPE564WJTQYM53WG3W8P8 Hop-Attempt: AT_06FPE564WKTFF688KW6DM80
This commit is contained in:
@@ -8,10 +8,12 @@ import { useToast } from '@/lib/contexts/ToastContext';
|
||||
import { useAccentColor } from '@/lib/contexts/AccentColorContext';
|
||||
import { getStorageProvider, MediaUploadError, uploadMediaFile } from '@/lib/stuffbox/browser-upload';
|
||||
import { hasUnsavedChanges } from '@/lib/forms/dirty-state';
|
||||
import { useRuntimeConfig } from '@/lib/contexts/ConfigContext';
|
||||
|
||||
export default function AdminPage() {
|
||||
const { showToast } = useToast();
|
||||
const { refreshAccentColor } = useAccentColor();
|
||||
const { setNodeNsfw } = useRuntimeConfig();
|
||||
const [isAdmin, setIsAdmin] = useState<boolean | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [nodeSettings, setNodeSettings] = useState({
|
||||
@@ -93,6 +95,11 @@ export default function AdminPage() {
|
||||
savedNodeSettingsRef.current = payload;
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (data.node) {
|
||||
// Keep the global local-node classification and the sidebar's
|
||||
// node payload in the same React batch. Otherwise profile
|
||||
// media briefly sees "remote NSFW node on a safe local node"
|
||||
// and applies a blur until the next full config refresh.
|
||||
setNodeNsfw(data.node.isNsfw === true);
|
||||
window.dispatchEvent(new CustomEvent('synapsis:node-updated', { detail: data.node }));
|
||||
}
|
||||
showToast('Settings saved!', 'success');
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { AvatarImage } from './AvatarImage';
|
||||
import { ProfileBanner } from './ProfileBanner';
|
||||
import { useRuntimeConfig } from '@/lib/contexts/ConfigContext';
|
||||
|
||||
interface Admin {
|
||||
handle: string;
|
||||
@@ -34,6 +35,8 @@ function formatNetworkTotal(value: number | undefined): string {
|
||||
}
|
||||
|
||||
export function RightSidebar() {
|
||||
const { config } = useRuntimeConfig();
|
||||
const localNodeIsNsfw = config?.isNsfw ?? false;
|
||||
const fallbackDescription = process.env.NEXT_PUBLIC_NODE_DESCRIPTION || 'A swarm social network node.';
|
||||
const [nodeInfo, setNodeInfo] = useState<NodeInfo>({
|
||||
name: process.env.NEXT_PUBLIC_NODE_NAME || 'Synapsis Node',
|
||||
@@ -138,7 +141,7 @@ export function RightSidebar() {
|
||||
{nodeInfo.bannerUrl && (
|
||||
<ProfileBanner
|
||||
url={nodeInfo.bannerUrl}
|
||||
nodeIsNsfw={nodeInfo.isNsfw}
|
||||
nodeIsNsfw={localNodeIsNsfw}
|
||||
height={140}
|
||||
borderBottom="1px solid var(--border)"
|
||||
/>
|
||||
@@ -187,7 +190,7 @@ export function RightSidebar() {
|
||||
style={{ display: 'flex', alignItems: 'center', gap: '10px', textDecoration: 'none', color: 'inherit' }}
|
||||
>
|
||||
<div className="avatar avatar-sm" style={{ flexShrink: 0 }}>
|
||||
<AvatarImage avatarUrl={admin.avatarUrl} seed={admin.handle} isNsfw={admin.isNsfw} nodeIsNsfw={nodeInfo.isNsfw} alt={admin.displayName || admin.handle} />
|
||||
<AvatarImage avatarUrl={admin.avatarUrl} seed={admin.handle} isNsfw={admin.isNsfw} nodeIsNsfw={localNodeIsNsfw} alt={admin.displayName || admin.handle} />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontWeight: 500, fontSize: '14px' }}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
||||
import { createContext, useCallback, useContext, useEffect, useState, ReactNode } from 'react';
|
||||
|
||||
interface RuntimeConfig {
|
||||
domain: string;
|
||||
@@ -10,17 +10,23 @@ interface RuntimeConfig {
|
||||
interface ConfigContextType {
|
||||
config: RuntimeConfig | null;
|
||||
isLoading: boolean;
|
||||
setNodeNsfw: (isNsfw: boolean) => void;
|
||||
}
|
||||
|
||||
const ConfigContext = createContext<ConfigContextType>({
|
||||
config: null,
|
||||
isLoading: true,
|
||||
setNodeNsfw: () => { },
|
||||
});
|
||||
|
||||
export function ConfigProvider({ children }: { children: ReactNode }) {
|
||||
const [config, setConfig] = useState<RuntimeConfig | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const setNodeNsfw = useCallback((isNsfw: boolean) => {
|
||||
setConfig((current) => current ? { ...current, isNsfw } : current);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Fetch runtime config on mount
|
||||
fetch('/api/config')
|
||||
@@ -44,7 +50,7 @@ export function ConfigProvider({ children }: { children: ReactNode }) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ConfigContext.Provider value={{ config, isLoading }}>
|
||||
<ConfigContext.Provider value={{ config, isLoading, setNodeNsfw }}>
|
||||
{children}
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user