fix: resolve all linting and type errors

- Remove unused React import from nostrUriResolver
- Add block scoping to switch case statements
- Add react-hooks plugin to eslint config
- Fix exhaustive-deps warnings in components
- Fix DecodeResult type to use ReturnType<typeof decode>
- Update dependency arrays to include all used values
- Add eslint-disable comment for intentional dependency omission

All linting warnings resolved. TypeScript type checking passes.
This commit is contained in:
Gigi
2025-10-11 03:23:38 +01:00
parent 3a8203d26e
commit a0e30aa197
6 changed files with 23 additions and 17 deletions

View File

@@ -59,7 +59,8 @@
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"plugins": [ "plugins": [
"@typescript-eslint", "@typescript-eslint",
"react-refresh" "react-refresh",
"react-hooks"
], ],
"rules": { "rules": {
"react-refresh/only-export-components": [ "react-refresh/only-export-components": [
@@ -68,6 +69,7 @@
"allowConstantExport": true "allowConstantExport": true
} }
], ],
"react-hooks/exhaustive-deps": "warn",
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [
"error", "error",
{ {

View File

@@ -139,7 +139,8 @@ const AddBookmarkModal: React.FC<AddBookmarkModalProps> = ({ onClose, onSave })
clearTimeout(fetchTimeoutRef.current) clearTimeout(fetchTimeoutRef.current)
} }
} }
}, [url]) // Only depend on url // eslint-disable-next-line react-hooks/exhaustive-deps
}, [url]) // Only depend on url - title, description, tagsInput are intentionally checked but not dependencies
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()

View File

@@ -52,7 +52,7 @@ export const RelayStatusIndicator: React.FC<RelayStatusIndicatorProps> = ({ rela
hasRemoteRelay, hasRemoteRelay,
isConnecting isConnecting
}) })
}, [offlineMode, localOnlyMode, connectedUrls.length, relayStatuses.length, hasLocalRelay, hasRemoteRelay, isConnecting]) }, [offlineMode, localOnlyMode, connectedUrls, relayStatuses.length, hasLocalRelay, hasRemoteRelay, isConnecting])
// Don't show indicator when fully connected (but show when connecting) // Don't show indicator when fully connected (but show when connecting)
if (!localOnlyMode && !offlineMode && !isConnecting) return null if (!localOnlyMode && !offlineMode && !isConnecting) return null

View File

@@ -113,22 +113,24 @@ const ThreePaneLayout: React.FC<ThreePaneLayoutProps> = (props) => {
// Handle ESC key to close sidebar or highlights // Handle ESC key to close sidebar or highlights
useEffect(() => { useEffect(() => {
const { isSidebarOpen, isHighlightsCollapsed, onToggleSidebar, onToggleHighlightsPanel } = props
if (!isMobile) return if (!isMobile) return
if (!props.isSidebarOpen && props.isHighlightsCollapsed) return if (!isSidebarOpen && isHighlightsCollapsed) return
const handleEscape = (e: KeyboardEvent) => { const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
if (props.isSidebarOpen) { if (isSidebarOpen) {
props.onToggleSidebar() onToggleSidebar()
} else if (!props.isHighlightsCollapsed) { } else if (!isHighlightsCollapsed) {
props.onToggleHighlightsPanel() onToggleHighlightsPanel()
} }
} }
} }
document.addEventListener('keydown', handleEscape) document.addEventListener('keydown', handleEscape)
return () => document.removeEventListener('keydown', handleEscape) return () => document.removeEventListener('keydown', handleEscape)
}, [isMobile, props.isSidebarOpen, props.isHighlightsCollapsed, props.onToggleSidebar, props.onToggleHighlightsPanel]) }, [isMobile, props])
// Trap focus in sidebar when open on mobile // Trap focus in sidebar when open on mobile
useEffect(() => { useEffect(() => {

View File

@@ -110,7 +110,7 @@ export const useBookmarksData = ({
handleFetchHighlights() handleFetchHighlights()
} }
handleFetchContacts() handleFetchContacts()
}, [relayPool, activeAccount?.pubkey, naddr, handleFetchBookmarks, handleFetchHighlights, handleFetchContacts]) }, [relayPool, activeAccount, naddr, handleFetchBookmarks, handleFetchHighlights, handleFetchContacts])
return { return {
bookmarks, bookmarks,

View File

@@ -1,6 +1,4 @@
import React from 'react'
import { decode, npubEncode, noteEncode } from 'nostr-tools/nip19' import { decode, npubEncode, noteEncode } from 'nostr-tools/nip19'
import { DecodeResult } from 'nostr-tools/nip19'
/** /**
* Regular expression to match nostr: URIs and bare NIP-19 identifiers * Regular expression to match nostr: URIs and bare NIP-19 identifiers
@@ -75,15 +73,17 @@ export function getNostrUriLabel(encoded: string): string {
switch (decoded.type) { switch (decoded.type) {
case 'npub': case 'npub':
return `@${encoded.slice(0, 12)}...` return `@${encoded.slice(0, 12)}...`
case 'nprofile': case 'nprofile': {
const npub = npubEncode(decoded.data.pubkey) const npub = npubEncode(decoded.data.pubkey)
return `@${npub.slice(0, 12)}...` return `@${npub.slice(0, 12)}...`
}
case 'note': case 'note':
return `note:${encoded.slice(5, 12)}...` return `note:${encoded.slice(5, 12)}...`
case 'nevent': case 'nevent': {
const note = noteEncode(decoded.data.id) const note = noteEncode(decoded.data.id)
return `note:${note.slice(5, 12)}...` return `note:${note.slice(5, 12)}...`
case 'naddr': }
case 'naddr': {
// For articles, show the identifier if available // For articles, show the identifier if available
const identifier = decoded.data.identifier const identifier = decoded.data.identifier
if (identifier && identifier.length > 0) { if (identifier && identifier.length > 0) {
@@ -91,6 +91,7 @@ export function getNostrUriLabel(encoded: string): string {
return identifier.length > 40 ? `${identifier.slice(0, 37)}...` : identifier return identifier.length > 40 ? `${identifier.slice(0, 37)}...` : identifier
} }
return 'nostr article' return 'nostr article'
}
default: default:
return encoded.slice(0, 16) + '...' return encoded.slice(0, 16) + '...'
} }
@@ -166,11 +167,11 @@ export function replaceNostrUrisInHTML(html: string): string {
*/ */
export function getNostrUriInfo(encoded: string): { export function getNostrUriInfo(encoded: string): {
type: string type: string
decoded: DecodeResult | null decoded: ReturnType<typeof decode> | null
link: string link: string
label: string label: string
} { } {
let decoded: DecodeResult | null = null let decoded: ReturnType<typeof decode> | null = null
try { try {
decoded = decode(encoded) decoded = decode(encoded)
} catch (error) { } catch (error) {