fix(topbar): sync subscription visibility with account subscriptions

Replace per-address visibility tracking with a boolean flag so newly subscribed boards appear immediately in the topbar without requiring a modal reopen.
This commit is contained in:
plebeius
2026-02-13 14:01:49 +08:00
parent 3d2dbbf75c
commit 61eb1e80f5
3 changed files with 40 additions and 49 deletions
@@ -8,7 +8,7 @@ import styles from './topbar-edit-modal.module.css';
const TopbarEditModal = () => { const TopbarEditModal = () => {
const { showModal, closeTopbarEditModal } = useTopbarEditModalStore(); const { showModal, closeTopbarEditModal } = useTopbarEditModalStore();
const { visibleDirectories, visibleSubscriptions, setDirectoryVisibility, setSubscriptionVisibility } = useTopbarVisibilityStore(); const { visibleDirectories, showSubscriptionsInTopbar, setDirectoryVisibility, setShowSubscriptionsInTopbar } = useTopbarVisibilityStore();
const account = useAccount(); const account = useAccount();
const subscriptions = useMemo(() => account?.subscriptions || [], [account?.subscriptions]); const subscriptions = useMemo(() => account?.subscriptions || [], [account?.subscriptions]);
const location = useLocation(); const location = useLocation();
@@ -37,17 +37,16 @@ const TopbarEditModal = () => {
// Local state for text input (will be saved on Save click) // Local state for text input (will be saved on Save click)
// Empty string means all directories visible (default), otherwise show only the specified codes // Empty string means all directories visible (default), otherwise show only the specified codes
const [localDirectoryInput, setLocalDirectoryInput] = useState<string>(allDirectoriesVisible ? '' : directoriesToString(visibleDirectories)); const [localDirectoryInput, setLocalDirectoryInput] = useState<string>(allDirectoriesVisible ? '' : directoriesToString(visibleDirectories));
// Check if all subscriptions are visible (if any subscription is visible, show subscriptions is checked) const [showSubscriptions, setShowSubscriptions] = useState<boolean>(showSubscriptionsInTopbar);
const [showSubscriptions, setShowSubscriptions] = useState<boolean>(subscriptions.length > 0 && subscriptions.some((addr: string) => visibleSubscriptions.has(addr)));
// Update local state when modal opens or store changes // Sync local state when modal opens or store changes
useEffect(() => { useEffect(() => {
if (showModal) { if (showModal) {
const allVisible = allBoardCodes.every((code) => visibleDirectories.has(code)); const allVisible = allBoardCodes.every((code) => visibleDirectories.has(code));
setLocalDirectoryInput(allVisible ? '' : directoriesToString(visibleDirectories)); setLocalDirectoryInput(allVisible ? '' : directoriesToString(visibleDirectories));
setShowSubscriptions(subscriptions.length > 0 && subscriptions.some((addr: string) => visibleSubscriptions.has(addr))); setShowSubscriptions(showSubscriptionsInTopbar);
} }
}, [showModal, visibleDirectories, visibleSubscriptions, allBoardCodes, subscriptions]); }, [showModal, visibleDirectories, showSubscriptionsInTopbar, allBoardCodes]);
if (!showModal) { if (!showModal) {
return null; return null;
@@ -75,13 +74,7 @@ const TopbarEditModal = () => {
}); });
} }
// Apply subscription visibility changes setShowSubscriptionsInTopbar(showSubscriptions);
// If showSubscriptions is checked, make all subscriptions visible
// Otherwise, hide all subscriptions
subscriptions.forEach((address: string) => {
setSubscriptionVisibility(address, showSubscriptions);
});
closeTopbarEditModal(); closeTopbarEditModal();
}; };
+3 -3
View File
@@ -96,7 +96,7 @@ const TopBarDesktop = () => {
const { openCreateBoardModal } = useCreateBoardModalStore(); const { openCreateBoardModal } = useCreateBoardModalStore();
const { openTopbarEditModal } = useTopbarEditModalStore(); const { openTopbarEditModal } = useTopbarEditModalStore();
const { openDirectoryModal } = useDirectoryModalStore(); const { openDirectoryModal } = useDirectoryModalStore();
const { visibleDirectories, visibleSubscriptions } = useTopbarVisibilityStore(); const { visibleDirectories, showSubscriptionsInTopbar } = useTopbarVisibilityStore();
const directories = useDirectories(); const directories = useDirectories();
// Memoize allBoardCodes since it's derived from a constant // Memoize allBoardCodes since it's derived from a constant
@@ -127,8 +127,8 @@ const TopBarDesktop = () => {
}, },
); );
// Filter subscriptions to only show visible ones // Show all subscriptions when enabled; no separate per-address tracking (avoids drift when subscribing from board-buttons)
const visibleSubscriptionAddresses = subscriptions.filter((address: string) => visibleSubscriptions.has(address)); const visibleSubscriptionAddresses = showSubscriptionsInTopbar ? subscriptions : [];
// Check if any directories are hidden // Check if any directories are hidden
const hasHiddenDirectories = useMemo(() => { const hasHiddenDirectories = useMemo(() => {
+31 -33
View File
@@ -7,13 +7,12 @@ const LOCALSTORAGE_KEY_SUBSCRIPTIONS = '5chan-topbar-subscriptions-visible';
interface TopbarVisibilityState { interface TopbarVisibilityState {
// Directory codes that are visible (all visible by default) // Directory codes that are visible (all visible by default)
visibleDirectories: Set<string>; visibleDirectories: Set<string>;
// Subscription addresses that are visible in topbar (all hidden by default) // If true, show all account subscriptions in topbar (default: false)
visibleSubscriptions: Set<string>; showSubscriptionsInTopbar: boolean;
// Actions // Actions
toggleDirectory: (code: string) => void; toggleDirectory: (code: string) => void;
toggleSubscription: (address: string) => void;
setDirectoryVisibility: (code: string, visible: boolean) => void; setDirectoryVisibility: (code: string, visible: boolean) => void;
setSubscriptionVisibility: (address: string, visible: boolean) => void; setShowSubscriptionsInTopbar: (show: boolean) => void;
// Initialize from localStorage // Initialize from localStorage
initialize: () => void; initialize: () => void;
} }
@@ -40,15 +39,36 @@ const saveToLocalStorage = (key: string, set: Set<string>) => {
} }
}; };
const loadShowSubscriptionsFromStorage = (): boolean => {
try {
const stored = localStorage.getItem(LOCALSTORAGE_KEY_SUBSCRIPTIONS);
if (!stored) return false;
const parsed = JSON.parse(stored);
// Migrate from old format (array of addresses)
if (Array.isArray(parsed)) return parsed.length > 0;
if (typeof parsed === 'boolean') return parsed;
} catch (e) {
console.warn('Failed to load subscriptions visibility from localStorage:', e);
}
return false;
};
const saveShowSubscriptionsToStorage = (show: boolean) => {
try {
localStorage.setItem(LOCALSTORAGE_KEY_SUBSCRIPTIONS, JSON.stringify(show));
} catch (e) {
console.warn('Failed to save subscriptions visibility to localStorage:', e);
}
};
const useTopbarVisibilityStore = create<TopbarVisibilityState>((set, _get) => { const useTopbarVisibilityStore = create<TopbarVisibilityState>((set, _get) => {
// Initialize with all directories visible by default // Initialize with all directories visible by default
const allBoardCodes = getAllBoardCodes(); const allBoardCodes = getAllBoardCodes();
const defaultVisibleDirectories = new Set(allBoardCodes); const defaultVisibleDirectories = new Set(allBoardCodes);
const defaultVisibleSubscriptions = new Set<string>();
return { return {
visibleDirectories: loadFromLocalStorage(LOCALSTORAGE_KEY_DIRECTORIES, defaultVisibleDirectories), visibleDirectories: loadFromLocalStorage(LOCALSTORAGE_KEY_DIRECTORIES, defaultVisibleDirectories),
visibleSubscriptions: loadFromLocalStorage(LOCALSTORAGE_KEY_SUBSCRIPTIONS, defaultVisibleSubscriptions), showSubscriptionsInTopbar: loadShowSubscriptionsFromStorage(),
toggleDirectory: (code: string) => { toggleDirectory: (code: string) => {
set((state) => { set((state) => {
@@ -63,19 +83,6 @@ const useTopbarVisibilityStore = create<TopbarVisibilityState>((set, _get) => {
}); });
}, },
toggleSubscription: (address: string) => {
set((state) => {
const newSet = new Set(state.visibleSubscriptions);
if (newSet.has(address)) {
newSet.delete(address);
} else {
newSet.add(address);
}
saveToLocalStorage(LOCALSTORAGE_KEY_SUBSCRIPTIONS, newSet);
return { visibleSubscriptions: newSet };
});
},
setDirectoryVisibility: (code: string, visible: boolean) => { setDirectoryVisibility: (code: string, visible: boolean) => {
set((state) => { set((state) => {
const newSet = new Set(state.visibleDirectories); const newSet = new Set(state.visibleDirectories);
@@ -89,26 +96,17 @@ const useTopbarVisibilityStore = create<TopbarVisibilityState>((set, _get) => {
}); });
}, },
setSubscriptionVisibility: (address: string, visible: boolean) => { setShowSubscriptionsInTopbar: (show: boolean) => {
set((state) => { saveShowSubscriptionsToStorage(show);
const newSet = new Set(state.visibleSubscriptions); set({ showSubscriptionsInTopbar: show });
if (visible) {
newSet.add(address);
} else {
newSet.delete(address);
}
saveToLocalStorage(LOCALSTORAGE_KEY_SUBSCRIPTIONS, newSet);
return { visibleSubscriptions: newSet };
});
}, },
initialize: () => { initialize: () => {
// Load from localStorage on initialization
const directories = loadFromLocalStorage(LOCALSTORAGE_KEY_DIRECTORIES, defaultVisibleDirectories); const directories = loadFromLocalStorage(LOCALSTORAGE_KEY_DIRECTORIES, defaultVisibleDirectories);
const subscriptions = loadFromLocalStorage(LOCALSTORAGE_KEY_SUBSCRIPTIONS, defaultVisibleSubscriptions); const showSubscriptions = loadShowSubscriptionsFromStorage();
set({ set({
visibleDirectories: directories, visibleDirectories: directories,
visibleSubscriptions: subscriptions, showSubscriptionsInTopbar: showSubscriptions,
}); });
}, },
}; };