diff --git a/docs/index.html b/docs/index.html
index 74260a3fe..6c5b2a526 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1630,77 +1630,36 @@
Configuration
state.user = session.user;
await startApp();
} else {
- // No session - show public feed without personal state sync
- await startPublicApp();
+ // Redirect to login - archive features require authentication
+ window.location.href = './login.html';
}
// Listen for auth state changes
supabase.auth.onAuthStateChange(async (event, session) => {
if (event === 'SIGNED_IN' && session) {
state.user = session.user;
- // Migrate localStorage archived items to Supabase if any
+ // Clean up any old localStorage data
await migrateLocalStorageToSupabase();
await startApp();
} else if (event === 'SIGNED_OUT') {
- state.user = null;
- state.supabaseReady = false;
- updateAuthUI();
- // Keep viewing the feed but use localStorage
- loadLocalArchivedState();
- render();
+ // Redirect to login on sign out
+ window.location.href = './login.html';
}
});
}
- // Start app in public mode (no login)
- async function startPublicApp() {
- updateAuthUI();
- loadLocalArchivedState();
- await fetchFeed();
- if (feedIntervalId) clearInterval(feedIntervalId);
- feedIntervalId = setInterval(fetchFeed, 60000);
- }
-
- // Load archived state from localStorage for anonymous users
- function loadLocalArchivedState() {
- try {
- const archived = JSON.parse(localStorage.getItem('archivedIds') || '[]');
- state.archivedIds = new Set(archived);
- } catch {
- state.archivedIds = new Set();
- }
- }
-
- // Save archived state to localStorage for anonymous users
- function saveLocalArchivedState() {
- localStorage.setItem('archivedIds', JSON.stringify([...state.archivedIds]));
- }
-
- // Migrate localStorage archived items to Supabase when user logs in
+ // Migrate localStorage archived items to Supabase when user logs in (cleanup old data)
async function migrateLocalStorageToSupabase() {
- if (!state.user) return;
-
+ // Clean up any old localStorage archive data (no longer used)
+ // All archive state now lives in Supabase only
try {
- const localArchived = JSON.parse(localStorage.getItem('archivedIds') || '[]');
- if (localArchived.length > 0) {
- console.log('[Migration] Migrating', localArchived.length, 'archived items to Supabase');
- const results = await Promise.all(
- localArchived.map(id => updatePostState(id, { is_archived: true }))
- );
-
- // Only clear localStorage if all items migrated successfully
- const allSucceeded = results.every(r => r);
- if (allSucceeded) {
- localStorage.removeItem('archivedIds');
- } else {
- // Keep only failed items in localStorage for retry
- const failedIds = localArchived.filter((id, i) => !results[i]);
- localStorage.setItem('archivedIds', JSON.stringify(failedIds));
- console.warn('[Migration] Some items failed, kept in localStorage:', failedIds.length);
- }
+ const oldArchived = localStorage.getItem('archivedIds');
+ if (oldArchived) {
+ console.log('[Cleanup] Removing old localStorage archive data');
+ localStorage.removeItem('archivedIds');
}
} catch (e) {
- console.error('[Migration] Error migrating localStorage to Supabase:', e);
+ console.error('[Cleanup] Error removing old localStorage:', e);
}
}
@@ -1747,20 +1706,30 @@ Configuration
if (error) {
console.error('[Supabase] Error loading post states:', error);
+ showToast('Failed to load archive state', 'error');
+ // Don't clear existing state - keep whatever we have
return;
}
- state.archivedIds.clear();
- state.bookmarkedIds.clear();
+ // Build new state in temp sets (atomic update)
+ const newArchivedIds = new Set();
+ const newBookmarkedIds = new Set();
data?.forEach(row => {
- if (row.is_archived) state.archivedIds.add(row.post_id);
- if (row.is_bookmarked) state.bookmarkedIds.add(row.post_id);
+ if (row.is_archived) newArchivedIds.add(row.post_id);
+ if (row.is_bookmarked) newBookmarkedIds.add(row.post_id);
});
+ // Only update state if query succeeded
+ state.archivedIds = newArchivedIds;
+ state.bookmarkedIds = newBookmarkedIds;
state.supabaseReady = true;
+
+ console.log(`[Supabase] Loaded ${newArchivedIds.size} archived, ${newBookmarkedIds.size} bookmarked posts`);
} catch (e) {
console.error('[Supabase] Exception loading post states:', e);
+ showToast('Failed to load archive state', 'error');
+ // Don't clear existing state on exception
}
}
@@ -2024,7 +1993,15 @@ Configuration
updateAuthUI();
+ // Load archive state FIRST before fetching feed
await loadPostStates();
+
+ // Warn user if archive state failed to load
+ if (!state.supabaseReady) {
+ console.warn('[App] Failed to load archive state, continuing anyway');
+ showToast('Unable to load archive state. Posts may not display correctly.', 'warning');
+ }
+
await migrateLocalStorageArchives();
await loadUserSettings();
subscribeToPostStates();
@@ -2078,6 +2055,12 @@ Configuration
// --- Rendering ---
function render() {
+ // Wait for archive state to load for logged-in users
+ if (state.user && !state.supabaseReady && state.items.length > 0) {
+ elements.feedList.innerHTML = 'Loading your archive state...
';
+ return;
+ }
+
const query = (state.searchQuery || '').trim().toLowerCase();
const isSearchActive = query.length > 0;
@@ -2360,6 +2343,11 @@ Configuration
const count = state.selectedIds.size;
if (count === 0) return;
+ if (!state.user) {
+ showToast('Sign in to archive posts', 'warning');
+ return;
+ }
+
const idsToArchive = [...state.selectedIds];
// Optimistic update
@@ -2367,31 +2355,30 @@ Configuration
state.selectedIds.clear();
render();
- // If logged in, sync to Supabase; otherwise use localStorage
- if (state.user) {
- const results = await Promise.all(
- idsToArchive.map(id => updatePostState(id, { is_archived: true }))
- );
-
- const successCount = results.filter(r => r).length;
- if (successCount === count) {
- showToast(`Archived ${count} items`);
- } else {
- // Revert failed items
- idsToArchive.forEach((id, i) => {
- if (!results[i]) state.archivedIds.delete(id);
- });
- render();
- showToast(`Archived ${successCount}/${count} items`, 'warning');
- }
- } else {
- // Anonymous user - save to localStorage
- saveLocalArchivedState();
+ // Sync to Supabase
+ const results = await Promise.all(
+ idsToArchive.map(id => updatePostState(id, { is_archived: true }))
+ );
+
+ const successCount = results.filter(r => r).length;
+ if (successCount === count) {
showToast(`Archived ${count} items`);
+ } else {
+ // Revert failed items
+ idsToArchive.forEach((id, i) => {
+ if (!results[i]) state.archivedIds.delete(id);
+ });
+ render();
+ showToast(`Archived ${successCount}/${count} items`, 'warning');
}
}
async function toggleArchive(id) {
+ if (!state.user) {
+ showToast('Sign in to archive posts', 'warning');
+ return;
+ }
+
const wasArchived = state.archivedIds.has(id);
// Optimistic update
@@ -2403,26 +2390,20 @@ Configuration
}
render();
- // If logged in, sync to Supabase; otherwise use localStorage
- if (state.user) {
- const success = await updatePostState(id, { is_archived: !wasArchived });
-
- if (success) {
- showToast(wasArchived ? 'Post unarchived' : 'Post archived');
+ // Sync to Supabase
+ const success = await updatePostState(id, { is_archived: !wasArchived });
+
+ if (success) {
+ showToast(wasArchived ? 'Post unarchived' : 'Post archived');
+ } else {
+ // Revert on failure
+ if (wasArchived) {
+ state.archivedIds.add(id);
} else {
- // Revert on failure
- if (wasArchived) {
- state.archivedIds.add(id);
- } else {
- state.archivedIds.delete(id);
- }
- render();
- showToast('Failed to update - try again', 'error');
+ state.archivedIds.delete(id);
}
- } else {
- // Anonymous user - save to localStorage
- saveLocalArchivedState();
- showToast(wasArchived ? 'Post unarchived' : 'Post archived');
+ render();
+ showToast('Failed to update - try again', 'error');
}
}