mirror of
https://github.com/dergigi/boris.git
synced 2026-01-18 22:34:34 +01:00
refactor: create centralized reading progress controller
- Add readingProgressController following the same pattern as highlightsController and writingsController - Controller manages reading progress (kind:39802) centrally with subscriptions - Remove duplicated reading progress loading logic from Explore, Profile, and Me components - Components now subscribe to controller updates instead of loading data individually - Supports incremental sync and force reload - Improves efficiency and maintainability
This commit is contained in:
@@ -30,10 +30,7 @@ import { useStoreTimeline } from '../hooks/useStoreTimeline'
|
||||
import { dedupeHighlightsById, dedupeWritingsByReplaceable } from '../utils/dedupe'
|
||||
import { writingsController } from '../services/writingsController'
|
||||
import { nostrverseWritingsController } from '../services/nostrverseWritingsController'
|
||||
import { queryEvents } from '../services/dataFetch'
|
||||
import { processReadingProgress } from '../services/readingDataProcessor'
|
||||
import { ReadItem } from '../services/readsService'
|
||||
import { RELAYS } from '../config/relays'
|
||||
import { readingProgressController } from '../services/readingProgressController'
|
||||
|
||||
const { getArticleTitle, getArticleImage, getArticlePublished, getArticleSummary } = Helpers
|
||||
|
||||
@@ -177,40 +174,32 @@ const Explore: React.FC<ExploreProps> = ({ relayPool, eventStore, settings, acti
|
||||
return () => unsub()
|
||||
}, [])
|
||||
|
||||
// Load reading progress data
|
||||
// Subscribe to reading progress controller
|
||||
useEffect(() => {
|
||||
// Get initial state immediately
|
||||
setReadingProgressMap(readingProgressController.getProgressMap())
|
||||
|
||||
// Subscribe to updates
|
||||
const unsubProgress = readingProgressController.onProgress(setReadingProgressMap)
|
||||
|
||||
return () => {
|
||||
unsubProgress()
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Load reading progress data when logged in
|
||||
useEffect(() => {
|
||||
if (!activeAccount?.pubkey) {
|
||||
setReadingProgressMap(new Map())
|
||||
return
|
||||
}
|
||||
|
||||
const loadReadingProgress = async () => {
|
||||
try {
|
||||
const progressEvents = await queryEvents(
|
||||
relayPool,
|
||||
{ kinds: [KINDS.ReadingProgress], authors: [activeAccount.pubkey] },
|
||||
{ relayUrls: RELAYS }
|
||||
)
|
||||
|
||||
const readsMap = new Map<string, ReadItem>()
|
||||
processReadingProgress(progressEvents, readsMap)
|
||||
|
||||
// Convert to naddr -> progress map
|
||||
const progressMap = new Map<string, number>()
|
||||
for (const [id, item] of readsMap.entries()) {
|
||||
if (item.readingProgress !== undefined && item.type === 'article') {
|
||||
progressMap.set(id, item.readingProgress)
|
||||
}
|
||||
}
|
||||
|
||||
setReadingProgressMap(progressMap)
|
||||
} catch (err) {
|
||||
console.error('Failed to load reading progress:', err)
|
||||
}
|
||||
}
|
||||
|
||||
loadReadingProgress()
|
||||
}, [activeAccount?.pubkey, relayPool, refreshTrigger])
|
||||
readingProgressController.start({
|
||||
relayPool,
|
||||
eventStore,
|
||||
pubkey: activeAccount.pubkey,
|
||||
force: refreshTrigger > 0
|
||||
})
|
||||
}, [activeAccount?.pubkey, relayPool, eventStore, refreshTrigger])
|
||||
|
||||
// Update visibility when settings/login state changes
|
||||
useEffect(() => {
|
||||
|
||||
@@ -31,10 +31,7 @@ import { filterByReadingProgress } from '../utils/readingProgressUtils'
|
||||
import { deriveReadsFromBookmarks } from '../utils/readsFromBookmarks'
|
||||
import { deriveLinksFromBookmarks } from '../utils/linksFromBookmarks'
|
||||
import { mergeReadItem } from '../utils/readItemMerge'
|
||||
import { queryEvents } from '../services/dataFetch'
|
||||
import { processReadingProgress } from '../services/readingDataProcessor'
|
||||
import { RELAYS } from '../config/relays'
|
||||
import { KINDS } from '../config/kinds'
|
||||
import { readingProgressController } from '../services/readingProgressController'
|
||||
|
||||
interface MeProps {
|
||||
relayPool: RelayPool
|
||||
@@ -156,40 +153,32 @@ const Me: React.FC<MeProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe to reading progress controller
|
||||
useEffect(() => {
|
||||
// Get initial state immediately
|
||||
setReadingProgressMap(readingProgressController.getProgressMap())
|
||||
|
||||
// Subscribe to updates
|
||||
const unsubProgress = readingProgressController.onProgress(setReadingProgressMap)
|
||||
|
||||
return () => {
|
||||
unsubProgress()
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Load reading progress data for writings tab
|
||||
useEffect(() => {
|
||||
if (!viewingPubkey) {
|
||||
setReadingProgressMap(new Map())
|
||||
return
|
||||
}
|
||||
|
||||
const loadReadingProgress = async () => {
|
||||
try {
|
||||
const progressEvents = await queryEvents(
|
||||
relayPool,
|
||||
{ kinds: [KINDS.ReadingProgress], authors: [viewingPubkey] },
|
||||
{ relayUrls: RELAYS }
|
||||
)
|
||||
|
||||
const readsMap = new Map<string, ReadItem>()
|
||||
processReadingProgress(progressEvents, readsMap)
|
||||
|
||||
// Convert to naddr -> progress map
|
||||
const progressMap = new Map<string, number>()
|
||||
for (const [id, item] of readsMap.entries()) {
|
||||
if (item.readingProgress !== undefined && item.type === 'article') {
|
||||
progressMap.set(id, item.readingProgress)
|
||||
}
|
||||
}
|
||||
|
||||
setReadingProgressMap(progressMap)
|
||||
} catch (err) {
|
||||
console.error('Failed to load reading progress:', err)
|
||||
}
|
||||
}
|
||||
|
||||
loadReadingProgress()
|
||||
}, [viewingPubkey, relayPool, refreshTrigger])
|
||||
readingProgressController.start({
|
||||
relayPool,
|
||||
eventStore,
|
||||
pubkey: viewingPubkey,
|
||||
force: refreshTrigger > 0
|
||||
})
|
||||
}, [viewingPubkey, relayPool, eventStore, refreshTrigger])
|
||||
|
||||
// Tab-specific loading functions
|
||||
const loadHighlightsTab = async () => {
|
||||
|
||||
@@ -19,9 +19,7 @@ import { toBlogPostPreview } from '../utils/toBlogPostPreview'
|
||||
import { usePullToRefresh } from 'use-pull-to-refresh'
|
||||
import RefreshIndicator from './RefreshIndicator'
|
||||
import { Hooks } from 'applesauce-react'
|
||||
import { queryEvents } from '../services/dataFetch'
|
||||
import { processReadingProgress } from '../services/readingDataProcessor'
|
||||
import { ReadItem } from '../services/readsService'
|
||||
import { readingProgressController } from '../services/readingProgressController'
|
||||
|
||||
interface ProfileProps {
|
||||
relayPool: RelayPool
|
||||
@@ -66,40 +64,32 @@ const Profile: React.FC<ProfileProps> = ({
|
||||
}
|
||||
}, [propActiveTab])
|
||||
|
||||
// Load reading progress data for logged-in user
|
||||
// Subscribe to reading progress controller
|
||||
useEffect(() => {
|
||||
// Get initial state immediately
|
||||
setReadingProgressMap(readingProgressController.getProgressMap())
|
||||
|
||||
// Subscribe to updates
|
||||
const unsubProgress = readingProgressController.onProgress(setReadingProgressMap)
|
||||
|
||||
return () => {
|
||||
unsubProgress()
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Load reading progress data when logged in
|
||||
useEffect(() => {
|
||||
if (!activeAccount?.pubkey) {
|
||||
setReadingProgressMap(new Map())
|
||||
return
|
||||
}
|
||||
|
||||
const loadReadingProgress = async () => {
|
||||
try {
|
||||
const progressEvents = await queryEvents(
|
||||
relayPool,
|
||||
{ kinds: [KINDS.ReadingProgress], authors: [activeAccount.pubkey] },
|
||||
{ relayUrls: RELAYS }
|
||||
)
|
||||
|
||||
const readsMap = new Map<string, ReadItem>()
|
||||
processReadingProgress(progressEvents, readsMap)
|
||||
|
||||
// Convert to naddr -> progress map
|
||||
const progressMap = new Map<string, number>()
|
||||
for (const [id, item] of readsMap.entries()) {
|
||||
if (item.readingProgress !== undefined && item.type === 'article') {
|
||||
progressMap.set(id, item.readingProgress)
|
||||
}
|
||||
}
|
||||
|
||||
setReadingProgressMap(progressMap)
|
||||
} catch (err) {
|
||||
console.error('Failed to load reading progress:', err)
|
||||
}
|
||||
}
|
||||
|
||||
loadReadingProgress()
|
||||
}, [activeAccount?.pubkey, relayPool, refreshTrigger])
|
||||
readingProgressController.start({
|
||||
relayPool,
|
||||
eventStore,
|
||||
pubkey: activeAccount.pubkey,
|
||||
force: refreshTrigger > 0
|
||||
})
|
||||
}, [activeAccount?.pubkey, relayPool, eventStore, refreshTrigger])
|
||||
|
||||
// Background fetch to populate event store (non-blocking)
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user