From 91e3cca4528363a246aba47a998fab87cc01112e Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 17 Mar 2026 11:41:11 +0100 Subject: [PATCH] bug-fixes --- src/PageManager.tsx | 36 ++++-- src/components/Favicon/index.tsx | 7 +- src/components/PostEditor/PostContent.tsx | 87 +------------- .../PostEditor/PostTextarea/index.tsx | 5 +- .../CalendarEventPreview.tsx | 6 +- .../ScheduleInPersonMeetingDialog.tsx | 12 +- .../ScheduleInPersonMeetingSingleDialog.tsx | 12 +- .../ScheduleVideoCallDialog.tsx | 12 +- .../ScheduleVideoCallSingleDialog.tsx | 12 +- src/components/ui/TimePicker.tsx | 107 ++++++++---------- 10 files changed, 115 insertions(+), 181 deletions(-) diff --git a/src/PageManager.tsx b/src/PageManager.tsx index 978298d9..1ecc62d0 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -109,6 +109,8 @@ const PrimaryNoteViewContext = createContext<{ setPrimaryNoteView: (view: ReactNode | null, type?: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings') => void primaryViewType: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings' | null getNavigationCounter: () => number + /** Top URL in the secondary stack (right panel), or undefined if empty. Used so settings sub-pages open in the panel instead of behind it. */ + getTopSecondaryUrl: () => string | undefined } | undefined>(undefined) const NoteDrawerContext = createContext<{ @@ -398,12 +400,22 @@ export function useSmartOthersRelaySettingsNavigation() { return { navigateToOthersRelaySettings } } -// Fixed: Settings navigation now uses primary note view since secondary panel is disabled +// Fixed: Settings navigation uses primary note view when settings is in main area; when settings list is in the right panel (Sheet), push sub-pages so they open in the panel instead of behind it. export function useSmartSettingsNavigation() { - const { setPrimaryNoteView } = usePrimaryNoteView() - + const { setPrimaryNoteView, getTopSecondaryUrl } = usePrimaryNoteView() + const { push: pushSecondaryPage } = useSecondaryPage() + const navigateToSettings = (url: string) => { - // Use primary note view to show settings since secondary panel is disabled + const topUrl = getTopSecondaryUrl?.() + const settingsInRightPanel = topUrl === '/settings' + + // When the right panel is showing the settings list, push the sub-page so it opens in the panel instead of in the main area (behind the panel). + if (settingsInRightPanel && url !== '/settings') { + pushSecondaryPage(url) + return + } + + // Otherwise use primary note view (main content area) if (url === '/settings') { window.history.pushState(null, '', url) setPrimaryNoteView(, 'settings') @@ -427,7 +439,7 @@ export function useSmartSettingsNavigation() { setPrimaryNoteView(, 'settings-sub') } } - + return { navigateToSettings } } @@ -1374,6 +1386,16 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { })) currentTabStateRef.current.set('search', tab) } + } else if (secondaryStack.length > 1) { + // Pop to previous page (e.g. from /settings/general back to /settings) so Back/Close return to the list instead of closing the panel + setSecondaryStack((prevStack) => { + const newStack = prevStack.slice(0, -1) + const topItem = newStack[newStack.length - 1] + if (topItem) { + window.history.replaceState({ index: topItem.index, url: topItem.url }, '', topItem.url) + } + return newStack + }) } else { window.history.go(-1) } @@ -1410,7 +1432,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { > - navigationCounterRef.current }}> + navigationCounterRef.current, getTopSecondaryUrl: () => secondaryStack.length > 0 ? secondaryStack[secondaryStack.length - 1].url : undefined }}> {primaryNoteView ? ( // Show primary note view with back button on mobile @@ -1527,7 +1549,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { > - navigationCounterRef.current }}> + navigationCounterRef.current, getTopSecondaryUrl: () => secondaryStack.length > 0 ? secondaryStack[secondaryStack.length - 1].url : undefined }}>
{loading &&
{fallback}
} {domain} setError(true)} onLoad={() => setLoading(false)} diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx index bde3c5d1..0d0ac897 100644 --- a/src/components/PostEditor/PostContent.tsx +++ b/src/components/PostEditor/PostContent.tsx @@ -324,15 +324,7 @@ export default function PostContent({ } // For voice comments in replies, check mediaNoteKind even if mediaUrl is not set yet (for preview) - // Debug logging - console.log('🔍 getDeterminedKind: checking', { - parentEvent: !!parentEvent, - mediaNoteKind, - VOICE_COMMENT: ExtendedKind.VOICE_COMMENT, - match: parentEvent && mediaNoteKind === ExtendedKind.VOICE_COMMENT - }) if (parentEvent && mediaNoteKind === ExtendedKind.VOICE_COMMENT) { - console.log('✅ getDeterminedKind: returning VOICE_COMMENT') return ExtendedKind.VOICE_COMMENT } else if (mediaNoteKind !== null && mediaUrl) { return mediaNoteKind @@ -357,12 +349,6 @@ export default function PostContent({ } else if (isPoll) { return ExtendedKind.POLL } else if (parentEvent && parentEvent.kind !== kinds.ShortTextNote) { - console.log('⚠️ getDeterminedKind: falling through to COMMENT', { - parentEvent: !!parentEvent, - parentEventKind: parentEvent?.kind, - mediaNoteKind, - mediaUrl - }) return ExtendedKind.COMMENT } else { return kinds.ShortTextNote @@ -623,9 +609,6 @@ export default function PostContent({ summary: citationSummary.trim() || undefined } - // Debug: Log what we're passing to the function - console.log('Creating hardcopy citation with options:', hardcopyOptions) - return createCitationHardcopyDraftEvent(cleanedText, hardcopyOptions) } else if (isCitationPrompt) { return createCitationPromptDraftEvent(cleanedText, { @@ -962,11 +945,6 @@ export default function PostContent({ } const handleUploadStart = (file: File, cancel: () => void) => { - console.log('🔍 handleUploadStart called', { - fileName: file.name, - fileType: file.type, - parentEvent: !!parentEvent - }) setUploadProgresses((prev) => [...prev, { file, progress: 0, cancel }]) // Track file for media upload if (file.type.startsWith('image/') || file.type.startsWith('audio/') || file.type.startsWith('video/')) { @@ -993,56 +971,25 @@ export default function PostContent({ // m4a files are always audio, even if MIME type is wrong const isAudio = isAudioMime || isAudioExt || isM4aFile || isMp4Audio || isWebmFile || isOggFile || isMp3File - console.log('🔍 handleUploadStart: audio detection', { - fileType, - fileName, - isAudioMime, - isAudioExt, - isMp4Audio, - isWebmFile, - isOggFile, - isMp3File, - isAudio - }) - if (isAudio) { // For PM replies, don't set mediaNoteKind - let PM reply handle it with imeta tags if (parentEvent && parentEvent.kind === ExtendedKind.PUBLIC_MESSAGE) { - console.log('✅ handleUploadStart: PM reply with audio - will use imeta tags, not setting mediaNoteKind') // Don't set mediaNoteKind - PM replies stay as kind 24 with imeta tags } else if (parentEvent) { - console.log('✅ handleUploadStart: setting VOICE_COMMENT for reply', { - mediaNoteKind: ExtendedKind.VOICE_COMMENT, - fileType, - fileName - }) setMediaNoteKind(ExtendedKind.VOICE_COMMENT) } else if (isPublicMessage) { - console.log('✅ handleUploadStart: setting VOICE for PM', { - mediaNoteKind: ExtendedKind.VOICE, - fileType, - fileName - }) setMediaNoteKind(ExtendedKind.VOICE) } // Note: URL will be inserted when upload completes in handleMediaUploadSuccess - } else { - console.log('❌ handleUploadStart: file is not audio, not setting media note kind') } } else { // For new posts, detect the kind from the file (async) getMediaKindFromFile(file, false) - .then((kind) => { - console.log('✅ handleUploadStart: detected kind for new post', { kind, fileName: file.name }) - setMediaNoteKind(kind) - }) + .then((kind) => setMediaNoteKind(kind)) .catch((error) => { - console.error('❌ Error detecting media kind in handleUploadStart', { error, file: file.name }) logger.error('Error detecting media kind in handleUploadStart', { error, file: file.name }) }) } - } else { - console.log('❌ handleUploadStart: file is not media type', { fileType: file.type }) } } @@ -1290,37 +1237,16 @@ export default function PostContent({ // m4a files are always audio, even if MIME type is wrong const isAudio = isAudioMime || isAudioExt || isM4aFile || isMp4Audio || isWebmFile || isOggFile || isMp3File - console.log('🔍 handleMediaUploadSuccess: audio detection', { - fileType, - fileName, - isAudioMime, - isAudioExt, - isMp4Audio, - isWebmFile, - isOggFile, - isMp3File, - isAudio - }) - if (isAudio) { // For PM replies, don't set mediaNoteKind - let PM reply handle it with imeta tags if (parentEvent && parentEvent.kind === ExtendedKind.PUBLIC_MESSAGE) { - console.log('✅ handleMediaUploadSuccess: PM reply with audio - will use imeta tags, not setting mediaNoteKind') // Don't set mediaNoteKind - PM replies stay as kind 24 with imeta tags // Just set the URL and imeta tags } else if (parentEvent) { // For regular replies, always create voice comments (kind 1244), regardless of duration - console.log('✅ handleMediaUploadSuccess: setting VOICE_COMMENT for reply', { - mediaNoteKind: ExtendedKind.VOICE_COMMENT, - url - }) setMediaNoteKind(ExtendedKind.VOICE_COMMENT) } else if (isPublicMessage) { // For new PMs, create voice notes (kind 1222) - console.log('✅ handleMediaUploadSuccess: setting VOICE for PM', { - mediaNoteKind: ExtendedKind.VOICE, - url - }) setMediaNoteKind(ExtendedKind.VOICE) } setMediaUrl(url) @@ -1365,11 +1291,6 @@ export default function PostContent({ } else { // Non-audio media in replies/PMs - don't set mediaNoteKind, will be handled as regular comment/PM // Clear any existing media note kind - console.log('❌ handleMediaUploadSuccess: file is not audio, clearing mediaNoteKind', { - fileType, - fileName, - isAudio - }) setMediaNoteKind(null) setMediaUrl('') setMediaImetaTags([]) @@ -2032,11 +1953,7 @@ export default function PostContent({ onUploadStart={handleUploadStart} onUploadProgress={handleUploadProgress} onUploadEnd={handleUploadEnd} - kind={(() => { - const kind = getDeterminedKind - console.log('🔍 PostTextarea kind prop:', { kind, mediaNoteKind, parentEvent: !!parentEvent }) - return kind - })()} + kind={getDeterminedKind} highlightData={isHighlight ? highlightData : undefined} pollCreateData={isPoll ? pollCreateData : undefined} getDraftEventJson={getDraftEventJson} diff --git a/src/components/PostEditor/PostTextarea/index.tsx b/src/components/PostEditor/PostTextarea/index.tsx index bd94df47..502f45aa 100644 --- a/src/components/PostEditor/PostTextarea/index.tsx +++ b/src/components/PostEditor/PostTextarea/index.tsx @@ -87,10 +87,7 @@ const PostTextarea = forwardRef< const [draftEventJson, setDraftEventJson] = useState('') const [isLoadingJson, setIsLoadingJson] = useState(false) - const kindDescription = useMemo(() => { - console.log('🔍 kindDescription: recalculating', { kind }) - return getKindDescription(kind) - }, [kind]) + const kindDescription = useMemo(() => getKindDescription(kind), [kind]) useEffect(() => { if (activeTab === 'json' && getDraftEventJson) { diff --git a/src/components/ScheduleVideoCallDialog/CalendarEventPreview.tsx b/src/components/ScheduleVideoCallDialog/CalendarEventPreview.tsx index afdf1c1e..f8e135ed 100644 --- a/src/components/ScheduleVideoCallDialog/CalendarEventPreview.tsx +++ b/src/components/ScheduleVideoCallDialog/CalendarEventPreview.tsx @@ -36,19 +36,19 @@ export function CalendarEventPreview({ ) return ( -
+
{t('Rendered')} {t('JSON')} -
+
-
+          
             {jsonString}
           
diff --git a/src/components/ScheduleVideoCallDialog/ScheduleInPersonMeetingDialog.tsx b/src/components/ScheduleVideoCallDialog/ScheduleInPersonMeetingDialog.tsx index b6a74172..e329d263 100644 --- a/src/components/ScheduleVideoCallDialog/ScheduleInPersonMeetingDialog.tsx +++ b/src/components/ScheduleVideoCallDialog/ScheduleInPersonMeetingDialog.tsx @@ -234,8 +234,8 @@ export function ScheduleInPersonMeetingDialog({ return ( - - + + {t('Schedule in-person meeting')} @@ -244,7 +244,8 @@ export function ScheduleInPersonMeetingDialog({ {t('Required: start (or start date), invitees. Optional: title, end, location, summary, topics, image.')} -
+ +
{formValid && previewDraft && ( -
+
)} - +
+