mirror of
https://github.com/dergigi/boris.git
synced 2025-12-24 01:54:19 +01:00
refactor: extract settings logic into custom hook
- Create useSettings hook to handle settings loading, saving, and watching - Move settings-related logic out of Bookmarks component - Move font loading logic into the hook - Reduce Bookmarks.tsx from 221 to 167 lines (under 210 limit) - Keep code DRY by centralizing settings management - All lint and type checks pass
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Hooks } from 'applesauce-react'
|
||||
import { useEventStore } from 'applesauce-react/hooks'
|
||||
import { RelayPool } from 'applesauce-relay'
|
||||
import { EventFactory } from 'applesauce-factory'
|
||||
import { Bookmark } from '../types/bookmarks'
|
||||
import { Highlight } from '../types/highlights'
|
||||
import { BookmarkList } from './BookmarkList'
|
||||
@@ -12,9 +11,8 @@ import ContentPanel from './ContentPanel'
|
||||
import { HighlightsPanel } from './HighlightsPanel'
|
||||
import { fetchReadableContent, ReadableContent } from '../services/readerService'
|
||||
import Settings from './Settings'
|
||||
import { UserSettings, loadSettings, saveSettings, watchSettings } from '../services/settingsService'
|
||||
import { loadFont, getFontFamily } from '../utils/fontLoader'
|
||||
import Toast from './Toast'
|
||||
import { useSettings } from '../hooks/useSettings'
|
||||
export type ViewMode = 'compact' | 'cards' | 'large'
|
||||
|
||||
interface BookmarksProps {
|
||||
@@ -22,11 +20,6 @@ interface BookmarksProps {
|
||||
onLogout: () => void
|
||||
}
|
||||
|
||||
const RELAY_URLS = [
|
||||
'wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.nostr.band',
|
||||
'wss://relay.dergigi.com', 'wss://wot.dergigi.com'
|
||||
]
|
||||
|
||||
const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
const [bookmarks, setBookmarks] = useState<Bookmark[]>([])
|
||||
const [highlights, setHighlights] = useState<Highlight[]>([])
|
||||
@@ -40,47 +33,30 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
const [showUnderlines, setShowUnderlines] = useState(true)
|
||||
const [selectedHighlightId, setSelectedHighlightId] = useState<string | undefined>(undefined)
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [settings, setSettings] = useState<UserSettings>({})
|
||||
const [toastMessage, setToastMessage] = useState<string | null>(null)
|
||||
const [toastType, setToastType] = useState<'success' | 'error'>('success')
|
||||
const activeAccount = Hooks.useActiveAccount()
|
||||
const accountManager = Hooks.useAccountManager()
|
||||
const eventStore = useEventStore()
|
||||
|
||||
const { settings, saveSettings, toastMessage, toastType, clearToast } = useSettings({
|
||||
relayPool,
|
||||
eventStore,
|
||||
pubkey: activeAccount?.pubkey,
|
||||
accountManager
|
||||
})
|
||||
|
||||
// Load initial data and set up settings subscription on login
|
||||
// Load initial data on login
|
||||
useEffect(() => {
|
||||
if (!relayPool || !activeAccount || !eventStore) return
|
||||
|
||||
// Fetch bookmarks and highlights
|
||||
if (!relayPool || !activeAccount) return
|
||||
handleFetchBookmarks()
|
||||
handleFetchHighlights()
|
||||
}, [relayPool, activeAccount?.pubkey])
|
||||
|
||||
// Load settings from Nostr and set up live subscription
|
||||
handleLoadSettings()
|
||||
|
||||
const subscription = watchSettings(eventStore, activeAccount.pubkey, (loadedSettings) => {
|
||||
if (loadedSettings) {
|
||||
setSettings(loadedSettings)
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe()
|
||||
}
|
||||
}, [relayPool, activeAccount?.pubkey, eventStore])
|
||||
|
||||
// Apply UI settings
|
||||
useEffect(() => {
|
||||
const root = document.documentElement.style
|
||||
if (settings.defaultViewMode) setViewMode(settings.defaultViewMode)
|
||||
if (settings.showUnderlines !== undefined) setShowUnderlines(settings.showUnderlines)
|
||||
if (settings.sidebarCollapsed !== undefined) setIsCollapsed(settings.sidebarCollapsed)
|
||||
if (settings.highlightsCollapsed !== undefined) setIsHighlightsCollapsed(settings.highlightsCollapsed)
|
||||
|
||||
// Always set font variables (use defaults if not specified)
|
||||
const fontKey = settings.readingFont || 'system'
|
||||
if (fontKey !== 'system') loadFont(fontKey)
|
||||
root.setProperty('--reading-font', getFontFamily(fontKey))
|
||||
root.setProperty('--reading-font-size', `${settings.fontSize || 16}px`)
|
||||
}, [settings])
|
||||
|
||||
const handleFetchBookmarks = async () => {
|
||||
@@ -102,35 +78,6 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleLoadSettings = async () => {
|
||||
if (!relayPool || !activeAccount) return
|
||||
try {
|
||||
const loadedSettings = await loadSettings(relayPool, eventStore, activeAccount.pubkey, RELAY_URLS)
|
||||
if (loadedSettings) {
|
||||
setSettings(loadedSettings)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to load settings:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveSettings = useCallback(async (newSettings: UserSettings) => {
|
||||
if (!relayPool || !activeAccount) return
|
||||
try {
|
||||
const fullAccount = accountManager.getActive()
|
||||
if (!fullAccount) throw new Error('No active account')
|
||||
const factory = new EventFactory({ signer: fullAccount })
|
||||
await saveSettings(relayPool, eventStore, factory, newSettings, RELAY_URLS)
|
||||
setSettings(newSettings)
|
||||
setToastType('success')
|
||||
setToastMessage('Settings saved')
|
||||
} catch (err) {
|
||||
console.error('Failed to save settings:', err)
|
||||
setToastType('error')
|
||||
setToastMessage('Failed to save settings')
|
||||
}
|
||||
}, [relayPool, activeAccount, accountManager, eventStore])
|
||||
|
||||
const handleSelectUrl = async (url: string) => {
|
||||
setSelectedUrl(url)
|
||||
setReaderLoading(true)
|
||||
@@ -171,7 +118,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
{showSettings ? (
|
||||
<Settings
|
||||
settings={settings}
|
||||
onSave={handleSaveSettings}
|
||||
onSave={saveSettings}
|
||||
onClose={() => setShowSettings(false)}
|
||||
/>
|
||||
) : (
|
||||
@@ -210,7 +157,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
<Toast
|
||||
message={toastMessage}
|
||||
type={toastType}
|
||||
onClose={() => setToastMessage(null)}
|
||||
onClose={clearToast}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
81
src/hooks/useSettings.ts
Normal file
81
src/hooks/useSettings.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { IEventStore } from 'applesauce-core'
|
||||
import { RelayPool } from 'applesauce-relay'
|
||||
import { EventFactory } from 'applesauce-factory'
|
||||
import { AccountManager } from 'applesauce-accounts'
|
||||
import { UserSettings, loadSettings, saveSettings, watchSettings } from '../services/settingsService'
|
||||
import { loadFont, getFontFamily } from '../utils/fontLoader'
|
||||
|
||||
const RELAY_URLS = [
|
||||
'wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.nostr.band',
|
||||
'wss://relay.dergigi.com', 'wss://wot.dergigi.com'
|
||||
]
|
||||
|
||||
interface UseSettingsParams {
|
||||
relayPool: RelayPool | null
|
||||
eventStore: IEventStore
|
||||
pubkey: string | undefined
|
||||
accountManager: AccountManager
|
||||
}
|
||||
|
||||
export function useSettings({ relayPool, eventStore, pubkey, accountManager }: UseSettingsParams) {
|
||||
const [settings, setSettings] = useState<UserSettings>({})
|
||||
const [toastMessage, setToastMessage] = useState<string | null>(null)
|
||||
const [toastType, setToastType] = useState<'success' | 'error'>('success')
|
||||
|
||||
// Load settings and set up subscription
|
||||
useEffect(() => {
|
||||
if (!relayPool || !pubkey || !eventStore) return
|
||||
|
||||
const loadAndWatch = async () => {
|
||||
try {
|
||||
const loadedSettings = await loadSettings(relayPool, eventStore, pubkey, RELAY_URLS)
|
||||
if (loadedSettings) setSettings(loadedSettings)
|
||||
} catch (err) {
|
||||
console.error('Failed to load settings:', err)
|
||||
}
|
||||
}
|
||||
|
||||
loadAndWatch()
|
||||
|
||||
const subscription = watchSettings(eventStore, pubkey, (loadedSettings) => {
|
||||
if (loadedSettings) setSettings(loadedSettings)
|
||||
})
|
||||
|
||||
return () => subscription.unsubscribe()
|
||||
}, [relayPool, pubkey, eventStore])
|
||||
|
||||
// Apply settings to document
|
||||
useEffect(() => {
|
||||
const root = document.documentElement.style
|
||||
const fontKey = settings.readingFont || 'system'
|
||||
if (fontKey !== 'system') loadFont(fontKey)
|
||||
root.setProperty('--reading-font', getFontFamily(fontKey))
|
||||
root.setProperty('--reading-font-size', `${settings.fontSize || 16}px`)
|
||||
}, [settings])
|
||||
|
||||
const saveSettingsWithToast = useCallback(async (newSettings: UserSettings) => {
|
||||
if (!relayPool || !pubkey) return
|
||||
try {
|
||||
const fullAccount = accountManager.getActive()
|
||||
if (!fullAccount) throw new Error('No active account')
|
||||
const factory = new EventFactory({ signer: fullAccount })
|
||||
await saveSettings(relayPool, eventStore, factory, newSettings, RELAY_URLS)
|
||||
setSettings(newSettings)
|
||||
setToastType('success')
|
||||
setToastMessage('Settings saved')
|
||||
} catch (err) {
|
||||
console.error('Failed to save settings:', err)
|
||||
setToastType('error')
|
||||
setToastMessage('Failed to save settings')
|
||||
}
|
||||
}, [relayPool, pubkey, accountManager, eventStore])
|
||||
|
||||
return {
|
||||
settings,
|
||||
saveSettings: saveSettingsWithToast,
|
||||
toastMessage,
|
||||
toastType,
|
||||
clearToast: () => setToastMessage(null)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user