Skip to content

Commit 30780bd

Browse files
authored
Merge pull request #38 from pheuberger/claude/refactor-code-simplification-cpR3t
Refactor: Extract bookmark and relay logic into custom hooks
2 parents 7f7972b + 4aa0666 commit 30780bd

16 files changed

Lines changed: 2218 additions & 1994 deletions

src/components/bookmarks/BookmarkList.jsx

Lines changed: 91 additions & 291 deletions
Large diffs are not rendered by default.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* AddRelayDialog - Modal for adding a custom Nostr relay.
3+
* Extracted from RelayConfigurationView.jsx.
4+
*/
5+
6+
import { useState, useEffect } from 'react'
7+
import { cn } from '@/utils/cn'
8+
import { validateRelayUrl, testRelayConnection } from '../../utils/relay-utils'
9+
import {
10+
Plus,
11+
RefreshCw,
12+
Check,
13+
AlertCircle,
14+
Zap,
15+
} from 'lucide-react'
16+
import { Button } from './button'
17+
import { Input } from './input'
18+
import {
19+
Dialog,
20+
DialogContent,
21+
DialogHeader,
22+
DialogTitle,
23+
DialogDescription,
24+
DialogFooter,
25+
} from './dialog'
26+
27+
export function AddRelayDialog({ open, onOpenChange, onAdd, existingRelays }) {
28+
const [url, setUrl] = useState('')
29+
const [validation, setValidation] = useState({ valid: true, error: null })
30+
const [testResult, setTestResult] = useState(null)
31+
const [isTesting, setIsTesting] = useState(false)
32+
33+
const resetState = () => {
34+
setUrl('')
35+
setValidation({ valid: true, error: null })
36+
setTestResult(null)
37+
setIsTesting(false)
38+
}
39+
40+
useEffect(() => {
41+
if (!open) {
42+
resetState()
43+
}
44+
}, [open])
45+
46+
const handleUrlChange = (e) => {
47+
const newUrl = e.target.value
48+
setUrl(newUrl)
49+
setTestResult(null)
50+
51+
if (newUrl.trim()) {
52+
const result = validateRelayUrl(newUrl)
53+
setValidation(result)
54+
55+
// Check for duplicates
56+
if (result.valid && existingRelays.includes(newUrl.trim())) {
57+
setValidation({ valid: false, error: 'This relay is already added' })
58+
}
59+
} else {
60+
setValidation({ valid: true, error: null })
61+
}
62+
}
63+
64+
const handleTest = async () => {
65+
if (!validation.valid || !url.trim()) return
66+
67+
setIsTesting(true)
68+
setTestResult(null)
69+
70+
const result = await testRelayConnection(url.trim())
71+
setTestResult(result)
72+
setIsTesting(false)
73+
}
74+
75+
const handleAdd = () => {
76+
if (!validation.valid || !url.trim()) return
77+
onAdd(url.trim())
78+
onOpenChange(false)
79+
}
80+
81+
return (
82+
<Dialog open={open} onOpenChange={onOpenChange}>
83+
<DialogContent className="sm:max-w-md">
84+
<DialogHeader>
85+
<DialogTitle>Add Custom Relay</DialogTitle>
86+
<DialogDescription>
87+
Enter the WebSocket URL of the Nostr relay you want to add.
88+
</DialogDescription>
89+
</DialogHeader>
90+
91+
<div className="space-y-4 py-4">
92+
<div className="space-y-2">
93+
<Input
94+
placeholder="wss://relay.example.com"
95+
value={url}
96+
onChange={handleUrlChange}
97+
className={cn(
98+
"font-mono text-sm",
99+
validation.error && !validation.valid && "border-destructive"
100+
)}
101+
/>
102+
{validation.error && (
103+
<p className={cn(
104+
"text-xs",
105+
validation.valid ? "text-yellow-500" : "text-destructive"
106+
)}>
107+
{validation.error}
108+
</p>
109+
)}
110+
</div>
111+
112+
{testResult && (
113+
<div className={cn(
114+
"flex items-center gap-2 p-3 rounded-md text-sm",
115+
testResult.success ? "bg-green-500/10 text-green-500" : "bg-destructive/10 text-destructive"
116+
)}>
117+
{testResult.success ? (
118+
<>
119+
<Check className="w-4 h-4" />
120+
<span>Connection successful ({testResult.latency}ms)</span>
121+
</>
122+
) : (
123+
<>
124+
<AlertCircle className="w-4 h-4" />
125+
<span>{testResult.error}</span>
126+
</>
127+
)}
128+
</div>
129+
)}
130+
</div>
131+
132+
<DialogFooter className="gap-2">
133+
<Button
134+
variant="outline"
135+
onClick={handleTest}
136+
disabled={!validation.valid || !url.trim() || isTesting}
137+
>
138+
{isTesting ? (
139+
<>
140+
<RefreshCw className="w-4 h-4 animate-spin" />
141+
Testing...
142+
</>
143+
) : (
144+
<>
145+
<Zap className="w-4 h-4" />
146+
Test
147+
</>
148+
)}
149+
</Button>
150+
<Button
151+
onClick={handleAdd}
152+
disabled={!validation.valid || !url.trim()}
153+
>
154+
<Plus className="w-4 h-4" />
155+
Add Relay
156+
</Button>
157+
</DialogFooter>
158+
</DialogContent>
159+
</Dialog>
160+
)
161+
}

0 commit comments

Comments
 (0)