f68f257234
- Add useWorldFeed hook combining infinite-scroll pagination with live streaming and 'X new posts' buffer/flush pattern - World feed queries all country-tagged events globally with a diversity cap (max 4 posts per country per page) - Live streaming via persistent relay subscription with scroll-aware buffering and highlight animation on flush - Rename Ditto tab to World across Feed, ContentSettings, and useFeedTab - Migrate localStorage key from ditto:showDittoFeed to agora:showWorldFeed
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
|
|
|
const STORAGE_PREFIX = 'ditto:feed-tab:';
|
|
|
|
/**
|
|
* Manages the active feed tab for a specific feed page, persisting
|
|
* the selection in sessionStorage so it survives navigation within
|
|
* the same browser session.
|
|
*
|
|
* Each feed page should pass a unique `feedId` (e.g. 'home', 'vines', 'videos').
|
|
*
|
|
* @param feedId Unique identifier for this feed page.
|
|
* @param validTabs Optional list of valid tab values for validation. If omitted, any stored value is accepted.
|
|
*/
|
|
export function useFeedTab<T extends string = string>(
|
|
feedId: string,
|
|
validTabs?: readonly T[],
|
|
): [T, (tab: T) => void] {
|
|
const { user } = useCurrentUser();
|
|
const key = STORAGE_PREFIX + feedId;
|
|
|
|
const [activeTab, setActiveTab] = useState<T>(() => {
|
|
const defaultTab = (user ? 'follows' : 'world') as T;
|
|
try {
|
|
const stored = sessionStorage.getItem(key);
|
|
if (stored) {
|
|
if (!validTabs || validTabs.includes(stored as T)) {
|
|
return stored as T;
|
|
}
|
|
}
|
|
} catch { /* sessionStorage unavailable */ }
|
|
// Validate the default tab against validTabs. If it's not in the list,
|
|
// fall back to the last valid tab (typically 'global').
|
|
if (validTabs && !validTabs.includes(defaultTab)) {
|
|
return validTabs[validTabs.length - 1];
|
|
}
|
|
return defaultTab;
|
|
});
|
|
|
|
const setTab = useCallback((tab: T) => {
|
|
setActiveTab(tab);
|
|
try { sessionStorage.setItem(key, tab); } catch { /* ignore */ }
|
|
}, [key]);
|
|
|
|
return [activeTab, setTab];
|
|
}
|