From a813a36cea7906640bf360681c1ce5261c83f40a Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 2 Oct 2025 11:17:55 +0000 Subject: [PATCH] Fix voice command status transitions and UI bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed multiple issues with voice command workflow: **Status Transition Fixes:** - Fixed infinite loop in status update useEffect by checking if status actually needs to change - Status now properly transitions: listening → understanding → review/close - Added debug logging to track status changes **UI Bug Fixes:** - Fixed crash in diaper tracker when conditions field is undefined (voice-created activities) - Auto-close dialog when classification returns "unknown" type - Added optional chaining for conditions.join() in getDiaperDetails **Changes:** - VoiceFloatingButton: Prevent setting same status repeatedly - VoiceFloatingButton: Close dialog on unknown classification - Diaper page: Handle missing conditions field gracefully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- maternal-web/app/track/diaper/page.tsx | 7 +++++-- .../components/voice/VoiceFloatingButton.tsx | 15 ++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/maternal-web/app/track/diaper/page.tsx b/maternal-web/app/track/diaper/page.tsx index b6c7b2d..4d0e20d 100644 --- a/maternal-web/app/track/diaper/page.tsx +++ b/maternal-web/app/track/diaper/page.tsx @@ -331,9 +331,12 @@ export default function DiaperTrackPage() { const getDiaperDetails = (activity: Activity) => { const data = activity.data as DiaperData; const typeLabel = data.diaperType.charAt(0).toUpperCase() + data.diaperType.slice(1); - const conditionsLabel = data.conditions.join(', '); + const conditionsLabel = data.conditions?.join(', ') || ''; - let details = `${typeLabel} - ${conditionsLabel}`; + let details = typeLabel; + if (conditionsLabel) { + details += ` - ${conditionsLabel}`; + } if (data.hasRash) { details += ` - Rash (${data.rashSeverity})`; diff --git a/maternal-web/components/voice/VoiceFloatingButton.tsx b/maternal-web/components/voice/VoiceFloatingButton.tsx index e04b6ad..3b5821d 100644 --- a/maternal-web/components/voice/VoiceFloatingButton.tsx +++ b/maternal-web/components/voice/VoiceFloatingButton.tsx @@ -60,13 +60,17 @@ export function VoiceFloatingButton() { // Set status when listening starts/stops React.useEffect(() => { - if (isListening) { + console.log('[VoiceFloatingButton] isListening changed:', isListening, 'processingStatus:', processingStatus); + + if (isListening && processingStatus !== 'listening') { + console.log('[VoiceFloatingButton] Setting status to listening'); setProcessingStatus('listening'); - } else if (processingStatus === 'listening' && transcript) { - // Transition from listening to understanding when we have a transcript + } else if (!isListening && processingStatus === 'listening') { + // When listening stops, transition to understanding + console.log('[VoiceFloatingButton] Setting status to understanding'); setProcessingStatus('understanding'); } - }, [isListening, transcript]); + }, [isListening, processingStatus]); // Auto-use classification from backend when transcription completes // MediaRecorder sends audio to backend, which transcribes + classifies in one call @@ -87,8 +91,9 @@ export function VoiceFloatingButton() { setProcessingStatus(null); setShowReview(true); } else { - // For unknown or low confidence, show error + // For unknown or low confidence, show error and close dialog setProcessingStatus(null); + setOpen(false); setSnackbar({ open: true, message: 'Could not understand the command. Please try again or use manual entry.',