diff --git a/js/channelProfile.js b/js/channelProfile.js index dd120ac7..fbdcc161 100644 --- a/js/channelProfile.js +++ b/js/channelProfile.js @@ -4163,11 +4163,28 @@ function renderSubscribeButton(channelHex) { } return; } + + // Optimistic UI update + const wasSubscribed = toggleBtn.dataset.state === "subscribed"; + const nextState = wasSubscribed ? "unsubscribed" : "subscribed"; + const label = toggleBtn.querySelector("span"); + + toggleBtn.dataset.state = nextState; + if (label) { + label.textContent = nextState === "subscribed" ? "Unsubscribe" : "Subscribe"; + } + try { await subscriptions.toggleChannel(channelHex, currentApp.pubkey); - // Re-render the button so it toggles state + // Re-render to ensure state is perfectly synced with the service renderSubscribeButton(channelHex); } catch (err) { + // Revert UI on failure + toggleBtn.dataset.state = wasSubscribed ? "subscribed" : "unsubscribed"; + if (label) { + label.textContent = wasSubscribed ? "Unsubscribe" : "Subscribe"; + } + userLogger.error("Failed to update subscription:", err); const permissionErrorCodes = new Set([ "extension-permission-denied", diff --git a/js/services/hashtagPreferencesService.js b/js/services/hashtagPreferencesService.js index b4788b5b..4eba4f25 100644 --- a/js/services/hashtagPreferencesService.js +++ b/js/services/hashtagPreferencesService.js @@ -285,7 +285,7 @@ class HashtagPreferencesService { loadFromCache(pubkey) { // profileCache internally uses activePubkey, but we should verify if it matches try { - let cached = profileCache.get("interests"); + let cached = profileCache.getProfileData(pubkey, "interests"); // Legacy fallback migration if (!cached && typeof localStorage !== "undefined") { diff --git a/js/subscriptions.js b/js/subscriptions.js index 4a44bc12..246fdb21 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -310,7 +310,7 @@ class SubscriptionsManager { const normalizedUserPubkey = normalizeHexPubkey(userPubkey) || userPubkey; // 1. Attempt to load from cache first - const cached = profileCache.get("subscriptions"); + const cached = profileCache.getProfileData(normalizedUserPubkey, "subscriptions"); if (Array.isArray(cached)) { devLogger.log("[SubscriptionsManager] Loaded subscriptions from cache."); this.subscribedPubkeys = new Set(cached); diff --git a/verify_fix.mjs b/verify_fix.mjs new file mode 100644 index 00000000..9a219438 --- /dev/null +++ b/verify_fix.mjs @@ -0,0 +1,61 @@ + +import { subscriptions } from './js/subscriptions.js'; +import { hashtagPreferences } from './js/services/hashtagPreferencesService.js'; +import { profileCache } from './js/state/profileCache.js'; + +// Mock profileCache.getProfileData +const originalGetProfileData = profileCache.getProfileData; +const originalGet = profileCache.get; + +let calls = []; + +profileCache.getProfileData = (pubkey, section) => { + calls.push({ method: 'getProfileData', pubkey, section }); + return null; +}; + +profileCache.get = (section) => { + calls.push({ method: 'get', section }); + return null; +}; + +async function runVerify() { + console.log("Verifying fix..."); + + // Test SubscriptionsManager + const subPubkey = "0000000000000000000000000000000000000000000000000000000000000001"; + // We need to mock updateFromRelays to avoid network calls, or just catch error + subscriptions.updateFromRelays = async () => {}; + + await subscriptions.loadSubscriptions(subPubkey); + + const subCall = calls.find(c => c.section === "subscriptions"); + if (subCall && subCall.method === "getProfileData" && subCall.pubkey === subPubkey) { + console.log("PASS: subscriptions.loadSubscriptions used getProfileData with correct pubkey."); + } else { + console.error("FAIL: subscriptions.loadSubscriptions did not use getProfileData correctly.", calls); + process.exit(1); + } + + calls = []; // Reset + + // Test HashtagPreferencesService + const tagPubkey = "0000000000000000000000000000000000000000000000000000000000000002"; + // Mock load logic to avoid network + hashtagPreferences.loadFromCache(tagPubkey); + + const tagCall = calls.find(c => c.section === "interests"); + if (tagCall && tagCall.method === "getProfileData" && tagCall.pubkey === tagPubkey) { + console.log("PASS: hashtagPreferences.loadFromCache used getProfileData with correct pubkey."); + } else { + console.error("FAIL: hashtagPreferences.loadFromCache did not use getProfileData correctly.", calls); + process.exit(1); + } + + console.log("All verifications passed."); +} + +runVerify().catch(err => { + console.error(err); + process.exit(1); +});