Browse Source

fix relay seelection in discussions

imwald
Silberengel 5 months ago
parent
commit
19ae0e5ad6
  1. 128
      src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx
  2. 1
      src/pages/primary/DiscussionsPage/index.tsx

128
src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx

@ -2,23 +2,26 @@ import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea' import { Textarea } from '@/components/ui/textarea'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { Switch } from '@/components/ui/switch' import { Switch } from '@/components/ui/switch'
import { Slider } from '@/components/ui/slider' import { Slider } from '@/components/ui/slider'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Checkbox } from '@/components/ui/checkbox'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Hash, X, Users, Code, Coins, Newspaper, BookOpen, Scroll, Cpu, Trophy, Film, Heart, TrendingUp, Utensils, MapPin, Home, PawPrint, Shirt, Image, Zap, Settings, Book, Network, Car, Eye, Edit3 } from 'lucide-react' import { Hash, X, Users, Code, Coins, Newspaper, BookOpen, Scroll, Cpu, Trophy, Film, Heart, TrendingUp, Utensils, MapPin, Home, PawPrint, Shirt, Image, Zap, Settings, Book, Network, Car, Eye, Edit3 } from 'lucide-react'
import { useState } from 'react' import { useState, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { TDraftEvent } from '@/types' import { TDraftEvent, TRelaySet } from '@/types'
import { NostrEvent } from 'nostr-tools' import { NostrEvent } from 'nostr-tools'
import { prefixNostrAddresses } from '@/lib/nostr-address' import { prefixNostrAddresses } from '@/lib/nostr-address'
import { showPublishingError } from '@/lib/publishing-feedback' import { showPublishingError } from '@/lib/publishing-feedback'
import { simplifyUrl } from '@/lib/url'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { extractHashtagsFromContent, normalizeTopic } from '@/lib/discussion-topics' import { extractHashtagsFromContent, normalizeTopic } from '@/lib/discussion-topics'
import DiscussionContent from '@/components/Note/DiscussionContent' import DiscussionContent from '@/components/Note/DiscussionContent'
import RelayIcon from '@/components/RelayIcon'
// Utility functions for thread creation // Utility functions for thread creation
function extractImagesFromContent(content: string): string[] { function extractImagesFromContent(content: string): string[] {
@ -42,7 +45,8 @@ function buildClientTag(): string[] {
interface CreateThreadDialogProps { interface CreateThreadDialogProps {
topic: string topic: string
availableRelays: string[] availableRelays: string[]
selectedRelay?: string | null relaySets: TRelaySet[]
selectedRelay?: string | null // null = "All relays", relay set ID, or single relay URL
onClose: () => void onClose: () => void
onThreadCreated: (publishedEvent?: NostrEvent) => void onThreadCreated: (publishedEvent?: NostrEvent) => void
} }
@ -72,6 +76,7 @@ export const DISCUSSION_TOPICS = [
export default function CreateThreadDialog({ export default function CreateThreadDialog({
topic: initialTopic, topic: initialTopic,
availableRelays, availableRelays,
relaySets,
selectedRelay: initialRelay, selectedRelay: initialRelay,
onClose, onClose,
onThreadCreated onThreadCreated
@ -81,7 +86,7 @@ export default function CreateThreadDialog({
const [title, setTitle] = useState('') const [title, setTitle] = useState('')
const [content, setContent] = useState('') const [content, setContent] = useState('')
const [selectedTopic] = useState(initialTopic) const [selectedTopic] = useState(initialTopic)
const [selectedRelay, setSelectedRelay] = useState<string>(initialRelay || '') const [selectedRelayUrls, setSelectedRelayUrls] = useState<string[]>([])
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [errors, setErrors] = useState<{ title?: string; content?: string; relay?: string; author?: string; subject?: string }>({}) const [errors, setErrors] = useState<{ title?: string; content?: string; relay?: string; author?: string; subject?: string }>({})
const [isNsfw, setIsNsfw] = useState(false) const [isNsfw, setIsNsfw] = useState(false)
@ -95,6 +100,34 @@ export default function CreateThreadDialog({
const [subject, setSubject] = useState('') const [subject, setSubject] = useState('')
const [showReadingsPanel, setShowReadingsPanel] = useState(false) const [showReadingsPanel, setShowReadingsPanel] = useState(false)
// Get all selectable relays (includes relays from selected relay set if applicable)
const selectableRelays = useMemo(() => {
const relaySet = initialRelay ? relaySets.find(set => set.id === initialRelay) : null
if (relaySet) {
// Include relays from the selected set along with available relays
return Array.from(new Set([...availableRelays, ...relaySet.relayUrls]))
}
return availableRelays
}, [availableRelays, relaySets, initialRelay])
// Initialize selected relays based on the originating view state
useEffect(() => {
if (initialRelay === null || initialRelay === undefined) {
// "All relays" selected - check all available relays
setSelectedRelayUrls(availableRelays)
} else {
// Check if it's a relay set ID
const relaySet = relaySets.find(set => set.id === initialRelay)
if (relaySet) {
// It's a relay set - check all relays in that set
setSelectedRelayUrls(relaySet.relayUrls)
} else {
// It's a specific relay - check just that relay
setSelectedRelayUrls([initialRelay])
}
}
}, [initialRelay, availableRelays, relaySets])
const validateForm = () => { const validateForm = () => {
const newErrors: { title?: string; content?: string; relay?: string; author?: string; subject?: string } = {} const newErrors: { title?: string; content?: string; relay?: string; author?: string; subject?: string } = {}
@ -110,8 +143,8 @@ export default function CreateThreadDialog({
newErrors.content = t('Content must be 5000 characters or less') newErrors.content = t('Content must be 5000 characters or less')
} }
if (!selectedRelay) { if (selectedRelayUrls.length === 0) {
newErrors.relay = t('Please select a relay') newErrors.relay = t('Please select at least one relay')
} }
// Validate readings fields if reading group is enabled // Validate readings fields if reading group is enabled
@ -201,9 +234,9 @@ export default function CreateThreadDialog({
} }
// Publish to the selected relay only // Publish to all selected relays
const publishedEvent = await publish(threadEvent, { const publishedEvent = await publish(threadEvent, {
specifiedRelayUrls: [selectedRelay], specifiedRelayUrls: selectedRelayUrls,
minPow minPow
}) })
@ -474,25 +507,70 @@ export default function CreateThreadDialog({
{/* Relay Selection */} {/* Relay Selection */}
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="relay">{t('Publish to Relay')}</Label> <Label>{t('Publish to Relays')}</Label>
<Select value={selectedRelay} onValueChange={setSelectedRelay}> <ScrollArea className={`max-h-64 rounded-md border p-4 ${errors.relay ? 'border-destructive' : ''}`}>
<SelectTrigger className={errors.relay ? 'border-destructive' : ''}> {selectableRelays.length === 0 ? (
<SelectValue placeholder={t('Select a relay to publish to')} /> <div className="text-sm text-muted-foreground text-center py-4">
</SelectTrigger> {t('No relays available. Please configure relays in settings.')}
<SelectContent> </div>
{availableRelays.map(relay => ( ) : (
<SelectItem key={relay} value={relay}> <div className="space-y-3">
{relay.replace('wss://', '').replace('ws://', '')} {selectableRelays.map(relay => {
</SelectItem> const isChecked = selectedRelayUrls.includes(relay)
))} return (
</SelectContent> <div key={relay} className="flex items-center space-x-3">
</Select> <Checkbox
id={`relay-${relay}`}
checked={isChecked}
onCheckedChange={(checked) => {
if (checked) {
setSelectedRelayUrls(prev => [...prev, relay])
} else {
setSelectedRelayUrls(prev => prev.filter(url => url !== relay))
}
}}
/>
<label
htmlFor={`relay-${relay}`}
className="flex items-center gap-2 text-sm font-medium leading-none cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:opacity-70 flex-1"
>
<RelayIcon url={relay} className="w-4 h-4" />
<span className="truncate">{simplifyUrl(relay)}</span>
</label>
</div>
)
})}
</div>
)}
</ScrollArea>
{errors.relay && ( {errors.relay && (
<p className="text-sm text-destructive">{errors.relay}</p> <p className="text-sm text-destructive">{errors.relay}</p>
)} )}
<p className="text-sm text-muted-foreground"> <div className="flex items-center justify-between">
{t('Choose the relay where this discussion will be hosted.')} <p className="text-sm text-muted-foreground">
</p> {selectedRelayUrls.length === 0
? t('No relays selected')
: t('{{count}} relay(s) selected', { count: selectedRelayUrls.length })}
</p>
<div className="flex gap-2">
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => setSelectedRelayUrls(selectableRelays)}
>
{t('Select All')}
</Button>
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => setSelectedRelayUrls([])}
>
{t('Clear All')}
</Button>
</div>
</div>
</div> </div>
{/* Advanced Options Toggle */} {/* Advanced Options Toggle */}

1
src/pages/primary/DiscussionsPage/index.tsx

@ -893,6 +893,7 @@ const DiscussionsPage = forwardRef((_, ref) => {
<CreateThreadDialog <CreateThreadDialog
topic={selectedTopic} topic={selectedTopic}
availableRelays={availableRelays} availableRelays={availableRelays}
relaySets={relaySets}
selectedRelay={selectedRelay} selectedRelay={selectedRelay}
onClose={() => setShowCreateThread(false)} onClose={() => setShowCreateThread(false)}
onThreadCreated={handleThreadCreated} onThreadCreated={handleThreadCreated}

Loading…
Cancel
Save