From 19ae0e5ad614d3c0dc141948de0845d87a8da3c3 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Sun, 12 Oct 2025 08:37:18 +0200 Subject: [PATCH] fix relay seelection in discussions --- .../DiscussionsPage/CreateThreadDialog.tsx | 128 ++++++++++++++---- src/pages/primary/DiscussionsPage/index.tsx | 1 + 2 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx b/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx index bc887d8..12050fb 100644 --- a/src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx +++ b/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 { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Textarea } from '@/components/ui/textarea' import { Badge } from '@/components/ui/badge' import { Switch } from '@/components/ui/switch' import { Slider } from '@/components/ui/slider' 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 { useState } from 'react' +import { useState, useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useNostr } from '@/providers/NostrProvider' -import { TDraftEvent } from '@/types' +import { TDraftEvent, TRelaySet } from '@/types' import { NostrEvent } from 'nostr-tools' import { prefixNostrAddresses } from '@/lib/nostr-address' import { showPublishingError } from '@/lib/publishing-feedback' +import { simplifyUrl } from '@/lib/url' import dayjs from 'dayjs' import { extractHashtagsFromContent, normalizeTopic } from '@/lib/discussion-topics' import DiscussionContent from '@/components/Note/DiscussionContent' +import RelayIcon from '@/components/RelayIcon' // Utility functions for thread creation function extractImagesFromContent(content: string): string[] { @@ -42,7 +45,8 @@ function buildClientTag(): string[] { interface CreateThreadDialogProps { topic: string availableRelays: string[] - selectedRelay?: string | null + relaySets: TRelaySet[] + selectedRelay?: string | null // null = "All relays", relay set ID, or single relay URL onClose: () => void onThreadCreated: (publishedEvent?: NostrEvent) => void } @@ -72,6 +76,7 @@ export const DISCUSSION_TOPICS = [ export default function CreateThreadDialog({ topic: initialTopic, availableRelays, + relaySets, selectedRelay: initialRelay, onClose, onThreadCreated @@ -81,7 +86,7 @@ export default function CreateThreadDialog({ const [title, setTitle] = useState('') const [content, setContent] = useState('') const [selectedTopic] = useState(initialTopic) - const [selectedRelay, setSelectedRelay] = useState(initialRelay || '') + const [selectedRelayUrls, setSelectedRelayUrls] = useState([]) const [isSubmitting, setIsSubmitting] = useState(false) const [errors, setErrors] = useState<{ title?: string; content?: string; relay?: string; author?: string; subject?: string }>({}) const [isNsfw, setIsNsfw] = useState(false) @@ -95,6 +100,34 @@ export default function CreateThreadDialog({ const [subject, setSubject] = useState('') 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 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') } - if (!selectedRelay) { - newErrors.relay = t('Please select a relay') + if (selectedRelayUrls.length === 0) { + newErrors.relay = t('Please select at least one relay') } // 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, { - specifiedRelayUrls: [selectedRelay], + specifiedRelayUrls: selectedRelayUrls, minPow }) @@ -474,25 +507,70 @@ export default function CreateThreadDialog({ {/* Relay Selection */}
- - + + + {selectableRelays.length === 0 ? ( +
+ {t('No relays available. Please configure relays in settings.')} +
+ ) : ( +
+ {selectableRelays.map(relay => { + const isChecked = selectedRelayUrls.includes(relay) + return ( +
+ { + if (checked) { + setSelectedRelayUrls(prev => [...prev, relay]) + } else { + setSelectedRelayUrls(prev => prev.filter(url => url !== relay)) + } + }} + /> + +
+ ) + })} +
+ )} +
{errors.relay && (

{errors.relay}

)} -

- {t('Choose the relay where this discussion will be hosted.')} -

+
+

+ {selectedRelayUrls.length === 0 + ? t('No relays selected') + : t('{{count}} relay(s) selected', { count: selectedRelayUrls.length })} +

+
+ + +
+
{/* Advanced Options Toggle */} diff --git a/src/pages/primary/DiscussionsPage/index.tsx b/src/pages/primary/DiscussionsPage/index.tsx index ceafa3d..96cfd1f 100644 --- a/src/pages/primary/DiscussionsPage/index.tsx +++ b/src/pages/primary/DiscussionsPage/index.tsx @@ -893,6 +893,7 @@ const DiscussionsPage = forwardRef((_, ref) => { setShowCreateThread(false)} onThreadCreated={handleThreadCreated}