feat: Remove Debug (Voice) tab from navigation
- Delete voice.tsx debug screen file - Remove voice tab configuration from tabs layout 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b851e40f33
commit
06ab4722e5
@ -65,13 +65,6 @@ export default function TabLayout() {
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* Voice tab - HIDDEN (calls go through Julia tab chat screen) */}
|
|
||||||
<Tabs.Screen
|
|
||||||
name="voice"
|
|
||||||
options={{
|
|
||||||
href: null,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="profile"
|
name="profile"
|
||||||
options={{
|
options={{
|
||||||
|
|||||||
@ -1,350 +0,0 @@
|
|||||||
/**
|
|
||||||
* Voice Debug Screen
|
|
||||||
* Shows transcript logs from voice calls for debugging
|
|
||||||
* Allows easy copying of logs
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
import {
|
|
||||||
View,
|
|
||||||
Text,
|
|
||||||
StyleSheet,
|
|
||||||
TouchableOpacity,
|
|
||||||
ScrollView,
|
|
||||||
Alert,
|
|
||||||
} from 'react-native';
|
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
||||||
import { Ionicons, Feather } from '@expo/vector-icons';
|
|
||||||
import * as Clipboard from 'expo-clipboard';
|
|
||||||
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
|
||||||
import { useVoiceTranscript } from '@/contexts/VoiceTranscriptContext';
|
|
||||||
|
|
||||||
export default function VoiceDebugScreen() {
|
|
||||||
const { transcript, clearTranscript, hasNewTranscript, markTranscriptAsShown, addTranscriptEntry } = useVoiceTranscript();
|
|
||||||
|
|
||||||
// Mark as shown when viewed
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (hasNewTranscript) {
|
|
||||||
markTranscriptAsShown();
|
|
||||||
}
|
|
||||||
}, [hasNewTranscript, markTranscriptAsShown]);
|
|
||||||
|
|
||||||
// Copy all logs to clipboard
|
|
||||||
const copyAllLogs = useCallback(async () => {
|
|
||||||
if (transcript.length === 0) {
|
|
||||||
Alert.alert('No logs', 'There are no voice call logs to copy.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const logsText = transcript
|
|
||||||
.map((entry) => {
|
|
||||||
const time = entry.timestamp.toLocaleTimeString();
|
|
||||||
const speaker = entry.role === 'user' ? 'USER' : 'JULIA';
|
|
||||||
return `[${time}] ${speaker}: ${entry.text}`;
|
|
||||||
})
|
|
||||||
.join('\n\n');
|
|
||||||
|
|
||||||
const header = `=== Voice Call Transcript ===\n${new Date().toLocaleString()}\nTotal entries: ${transcript.length}\n\n`;
|
|
||||||
|
|
||||||
await Clipboard.setStringAsync(header + logsText);
|
|
||||||
Alert.alert('Copied!', 'Voice call logs copied to clipboard.');
|
|
||||||
}, [transcript]);
|
|
||||||
|
|
||||||
// Copy single entry
|
|
||||||
const copySingleEntry = useCallback(async (text: string) => {
|
|
||||||
await Clipboard.setStringAsync(text);
|
|
||||||
Alert.alert('Copied!', 'Message copied to clipboard.');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Clear all logs
|
|
||||||
const handleClearLogs = useCallback(() => {
|
|
||||||
Alert.alert(
|
|
||||||
'Clear Logs',
|
|
||||||
'Are you sure you want to clear all voice call logs?',
|
|
||||||
[
|
|
||||||
{ text: 'Cancel', style: 'cancel' },
|
|
||||||
{
|
|
||||||
text: 'Clear',
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: clearTranscript,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}, [clearTranscript]);
|
|
||||||
|
|
||||||
|
|
||||||
// Add mock data for testing (simulator has no microphone)
|
|
||||||
const addMockData = useCallback(() => {
|
|
||||||
const mockConversation = [
|
|
||||||
{ role: 'assistant' as const, text: "Hi! I have some concerns about Ferdinand today - there was an incident this morning. Want me to tell you more?" },
|
|
||||||
{ role: 'user' as const, text: "Yes, what happened?" },
|
|
||||||
{ role: 'assistant' as const, text: "Ferdinand had a fall at 6:32 AM in the bathroom. He was able to get up on his own, but I recommend checking in with him. His sleep was also shorter than usual - only 5 hours last night." },
|
|
||||||
{ role: 'user' as const, text: "Did he take his medications?" },
|
|
||||||
{ role: 'assistant' as const, text: "Yes, he took his morning medications at 8:15 AM. All on schedule. Would you like me to show you the dashboard with more details?" },
|
|
||||||
{ role: 'user' as const, text: "Show me the dashboard" },
|
|
||||||
{ role: 'assistant' as const, text: "Navigating to Dashboard now. You can see the 7-day overview there." },
|
|
||||||
];
|
|
||||||
|
|
||||||
mockConversation.forEach((entry, index) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
addTranscriptEntry(entry.role, entry.text);
|
|
||||||
}, index * 100);
|
|
||||||
});
|
|
||||||
|
|
||||||
Alert.alert('Mock Data Added', 'Sample voice conversation added for testing.');
|
|
||||||
}, [addTranscriptEntry]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={styles.container} edges={['top']}>
|
|
||||||
{/* Header */}
|
|
||||||
<View style={styles.header}>
|
|
||||||
<View style={styles.headerLeft}>
|
|
||||||
<Feather name="terminal" size={24} color={AppColors.primary} />
|
|
||||||
<Text style={styles.headerTitle}>Voice Debug</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.headerButtons}>
|
|
||||||
{transcript.length > 0 && (
|
|
||||||
<>
|
|
||||||
<TouchableOpacity style={styles.headerButton} onPress={copyAllLogs}>
|
|
||||||
<Ionicons name="copy-outline" size={22} color={AppColors.primary} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity style={styles.headerButton} onPress={handleClearLogs}>
|
|
||||||
<Ionicons name="trash-outline" size={22} color={AppColors.error} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Mock Data Button for simulator testing */}
|
|
||||||
<View style={styles.callButtonContainer}>
|
|
||||||
<TouchableOpacity style={styles.mockDataButton} onPress={addMockData}>
|
|
||||||
<Feather name="plus-circle" size={20} color={AppColors.primary} />
|
|
||||||
<Text style={styles.mockDataButtonText}>Add Mock Data</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Logs Section */}
|
|
||||||
<View style={styles.logsHeader}>
|
|
||||||
<Text style={styles.logsTitle}>Call Transcript</Text>
|
|
||||||
<Text style={styles.logsCount}>
|
|
||||||
{transcript.length} {transcript.length === 1 ? 'entry' : 'entries'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Transcript List */}
|
|
||||||
<ScrollView style={styles.logsList} contentContainerStyle={styles.logsContent}>
|
|
||||||
{transcript.length === 0 ? (
|
|
||||||
<View style={styles.emptyState}>
|
|
||||||
<Feather name="mic-off" size={48} color={AppColors.textMuted} />
|
|
||||||
<Text style={styles.emptyTitle}>No voice logs yet</Text>
|
|
||||||
<Text style={styles.emptySubtitle}>
|
|
||||||
Start a voice call with Julia AI to see the transcript here.
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
transcript.map((entry) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={entry.id}
|
|
||||||
style={[
|
|
||||||
styles.logEntry,
|
|
||||||
entry.role === 'user' ? styles.logEntryUser : styles.logEntryAssistant,
|
|
||||||
]}
|
|
||||||
onLongPress={() => copySingleEntry(entry.text)}
|
|
||||||
activeOpacity={0.7}
|
|
||||||
>
|
|
||||||
<View style={styles.logEntryHeader}>
|
|
||||||
<View style={styles.logEntrySpeaker}>
|
|
||||||
<Ionicons
|
|
||||||
name={entry.role === 'user' ? 'person' : 'sparkles'}
|
|
||||||
size={14}
|
|
||||||
color={entry.role === 'user' ? AppColors.primary : AppColors.success}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.logEntrySpeakerText,
|
|
||||||
{ color: entry.role === 'user' ? AppColors.primary : AppColors.success },
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{entry.role === 'user' ? 'You' : 'Julia'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Text style={styles.logEntryTime}>
|
|
||||||
{entry.timestamp.toLocaleTimeString()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Text style={styles.logEntryText} selectable>
|
|
||||||
{entry.text}
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.logEntryHint}>Long press to copy</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
{/* Footer hint */}
|
|
||||||
{transcript.length > 0 && (
|
|
||||||
<View style={styles.footer}>
|
|
||||||
<Text style={styles.footerText}>
|
|
||||||
Tap the copy icon to copy all logs
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: AppColors.background,
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
paddingHorizontal: Spacing.md,
|
|
||||||
paddingVertical: Spacing.sm,
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: AppColors.border,
|
|
||||||
},
|
|
||||||
headerLeft: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: Spacing.sm,
|
|
||||||
},
|
|
||||||
headerTitle: {
|
|
||||||
fontSize: FontSizes.xl,
|
|
||||||
fontWeight: '700',
|
|
||||||
color: AppColors.textPrimary,
|
|
||||||
},
|
|
||||||
headerButtons: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
gap: Spacing.sm,
|
|
||||||
},
|
|
||||||
headerButton: {
|
|
||||||
padding: Spacing.xs,
|
|
||||||
borderRadius: BorderRadius.md,
|
|
||||||
backgroundColor: AppColors.surface,
|
|
||||||
},
|
|
||||||
callButtonContainer: {
|
|
||||||
paddingHorizontal: Spacing.md,
|
|
||||||
paddingVertical: Spacing.md,
|
|
||||||
},
|
|
||||||
mockDataButton: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
gap: Spacing.xs,
|
|
||||||
marginTop: Spacing.sm,
|
|
||||||
paddingVertical: Spacing.sm,
|
|
||||||
borderRadius: BorderRadius.md,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: AppColors.primary,
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
},
|
|
||||||
mockDataButtonText: {
|
|
||||||
fontSize: FontSizes.sm,
|
|
||||||
fontWeight: '500',
|
|
||||||
color: AppColors.primary,
|
|
||||||
},
|
|
||||||
logsHeader: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
paddingHorizontal: Spacing.md,
|
|
||||||
paddingVertical: Spacing.sm,
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: AppColors.border,
|
|
||||||
},
|
|
||||||
logsTitle: {
|
|
||||||
fontSize: FontSizes.base,
|
|
||||||
fontWeight: '600',
|
|
||||||
color: AppColors.textPrimary,
|
|
||||||
},
|
|
||||||
logsCount: {
|
|
||||||
fontSize: FontSizes.sm,
|
|
||||||
color: AppColors.textMuted,
|
|
||||||
},
|
|
||||||
logsList: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
logsContent: {
|
|
||||||
padding: Spacing.md,
|
|
||||||
gap: Spacing.sm,
|
|
||||||
},
|
|
||||||
emptyState: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingVertical: Spacing.xxl * 2,
|
|
||||||
},
|
|
||||||
emptyTitle: {
|
|
||||||
fontSize: FontSizes.lg,
|
|
||||||
fontWeight: '600',
|
|
||||||
color: AppColors.textPrimary,
|
|
||||||
marginTop: Spacing.md,
|
|
||||||
},
|
|
||||||
emptySubtitle: {
|
|
||||||
fontSize: FontSizes.sm,
|
|
||||||
color: AppColors.textMuted,
|
|
||||||
textAlign: 'center',
|
|
||||||
marginTop: Spacing.xs,
|
|
||||||
paddingHorizontal: Spacing.xl,
|
|
||||||
},
|
|
||||||
logEntry: {
|
|
||||||
padding: Spacing.md,
|
|
||||||
borderRadius: BorderRadius.lg,
|
|
||||||
marginBottom: Spacing.sm,
|
|
||||||
},
|
|
||||||
logEntryUser: {
|
|
||||||
backgroundColor: 'rgba(33, 150, 243, 0.1)',
|
|
||||||
borderLeftWidth: 3,
|
|
||||||
borderLeftColor: AppColors.primary,
|
|
||||||
},
|
|
||||||
logEntryAssistant: {
|
|
||||||
backgroundColor: 'rgba(76, 175, 80, 0.1)',
|
|
||||||
borderLeftWidth: 3,
|
|
||||||
borderLeftColor: AppColors.success,
|
|
||||||
},
|
|
||||||
logEntryHeader: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
marginBottom: Spacing.xs,
|
|
||||||
},
|
|
||||||
logEntrySpeaker: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 4,
|
|
||||||
},
|
|
||||||
logEntrySpeakerText: {
|
|
||||||
fontSize: FontSizes.sm,
|
|
||||||
fontWeight: '600',
|
|
||||||
},
|
|
||||||
logEntryTime: {
|
|
||||||
fontSize: FontSizes.xs,
|
|
||||||
color: AppColors.textMuted,
|
|
||||||
},
|
|
||||||
logEntryText: {
|
|
||||||
fontSize: FontSizes.base,
|
|
||||||
color: AppColors.textPrimary,
|
|
||||||
lineHeight: 22,
|
|
||||||
},
|
|
||||||
logEntryHint: {
|
|
||||||
fontSize: FontSizes.xs,
|
|
||||||
color: AppColors.textMuted,
|
|
||||||
marginTop: Spacing.xs,
|
|
||||||
fontStyle: 'italic',
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
padding: Spacing.md,
|
|
||||||
alignItems: 'center',
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: AppColors.border,
|
|
||||||
},
|
|
||||||
footerText: {
|
|
||||||
fontSize: FontSizes.sm,
|
|
||||||
color: AppColors.textMuted,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Loading…
x
Reference in New Issue
Block a user