ai_role_update
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Ionicons, Feather, FontAwesome5 } from '@expo/vector-icons';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { AIRole } from '../types';
|
||||
import { colors, typography, spacing, borderRadius, shadows } from '../theme/colors';
|
||||
import { aiService, AIMessage } from '../services/ai.service';
|
||||
import { assetsService } from '../services/assets.service';
|
||||
@@ -63,7 +64,7 @@ interface ChatSession {
|
||||
// =============================================================================
|
||||
|
||||
export default function FlowScreen() {
|
||||
const { token, user, signOut } = useAuth();
|
||||
const { token, user, signOut, aiRoles, refreshAIRoles } = useAuth();
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
|
||||
// Current conversation state
|
||||
@@ -73,8 +74,8 @@ export default function FlowScreen() {
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [selectedImage, setSelectedImage] = useState<string | null>(null);
|
||||
|
||||
// AI Role state
|
||||
const [selectedRole, setSelectedRole] = useState(AI_CONFIG.ROLES[0]);
|
||||
// AI Role state - start with null to detect first load
|
||||
const [selectedRole, setSelectedRole] = useState<AIRole | null>(aiRoles[0] || null);
|
||||
const [showRoleModal, setShowRoleModal] = useState(false);
|
||||
const [expandedRoleId, setExpandedRoleId] = useState<string | null>(null);
|
||||
|
||||
@@ -159,9 +160,9 @@ export default function FlowScreen() {
|
||||
// Load messages whenever role changes
|
||||
useEffect(() => {
|
||||
const loadRoleMessages = async () => {
|
||||
if (!user) return;
|
||||
if (!user || !selectedRole) return;
|
||||
try {
|
||||
const savedMessages = await storageService.getCurrentChat(selectedRole.id, user.id);
|
||||
const savedMessages = await storageService.getCurrentChat(selectedRole?.id || '', user.id);
|
||||
if (savedMessages) {
|
||||
const formattedMessages = savedMessages.map((msg: any) => ({
|
||||
...msg,
|
||||
@@ -172,18 +173,42 @@ export default function FlowScreen() {
|
||||
setMessages([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to load messages for role ${selectedRole.id}:`, error);
|
||||
if (selectedRole) {
|
||||
console.error(`Failed to load messages for role ${selectedRole?.id}:`, error);
|
||||
}
|
||||
setMessages([]);
|
||||
}
|
||||
};
|
||||
|
||||
loadRoleMessages();
|
||||
}, [selectedRole.id, user]);
|
||||
}, [selectedRole?.id, user]);
|
||||
|
||||
// Ensure we have a valid selected role from the dynamic list
|
||||
useEffect(() => {
|
||||
if (aiRoles.length > 0) {
|
||||
if (!selectedRole) {
|
||||
// Initial load or first time roles become available
|
||||
setSelectedRole(aiRoles[0]);
|
||||
} else {
|
||||
// If roles refreshed, make sure current selectedRole is still valid or updated
|
||||
const updatedRole = aiRoles.find(r => r.id === selectedRole?.id);
|
||||
if (updatedRole) {
|
||||
setSelectedRole(updatedRole);
|
||||
} else {
|
||||
// Current role no longer exists in dynamic list, fallback to first
|
||||
setSelectedRole(aiRoles[0]);
|
||||
}
|
||||
}
|
||||
} else if (!selectedRole) {
|
||||
// Fallback if no dynamic roles yet
|
||||
setSelectedRole(AI_CONFIG.ROLES[0]);
|
||||
}
|
||||
}, [aiRoles]);
|
||||
|
||||
// Save current messages for the active role when they change
|
||||
useEffect(() => {
|
||||
if (user && messages.length >= 0) { // Save even if empty to allow clearing
|
||||
storageService.saveCurrentChat(selectedRole.id, messages, user.id);
|
||||
if (user && selectedRole && messages.length >= 0) { // Save even if empty to allow clearing
|
||||
storageService.saveCurrentChat(selectedRole?.id || '', messages, user.id);
|
||||
}
|
||||
|
||||
if (messages.length > 0) {
|
||||
@@ -191,7 +216,7 @@ export default function FlowScreen() {
|
||||
scrollViewRef.current?.scrollToEnd({ animated: true });
|
||||
}, 100);
|
||||
}
|
||||
}, [messages, selectedRole.id, user]);
|
||||
}, [messages, selectedRole?.id, user]);
|
||||
|
||||
// Save history when it changes
|
||||
useEffect(() => {
|
||||
@@ -229,7 +254,7 @@ export default function FlowScreen() {
|
||||
* Handle sending a message to AI
|
||||
*/
|
||||
const handleSendMessage = async () => {
|
||||
if (!newContent.trim() || isSending) return;
|
||||
if (!newContent.trim() || isSending || !selectedRole) return;
|
||||
|
||||
// Check authentication
|
||||
if (!token) {
|
||||
@@ -256,7 +281,7 @@ export default function FlowScreen() {
|
||||
|
||||
try {
|
||||
// Call AI proxy with selected role's system prompt
|
||||
const aiResponse = await aiService.sendMessage(userMessage, token, selectedRole.systemPrompt);
|
||||
const aiResponse = await aiService.sendMessage(userMessage, token, selectedRole?.systemPrompt || '');
|
||||
|
||||
// Add AI response
|
||||
const aiMsg: ChatMessage = {
|
||||
@@ -424,8 +449,8 @@ export default function FlowScreen() {
|
||||
|
||||
// Clear current messages and storage for this role
|
||||
setMessages([]);
|
||||
if (user) {
|
||||
storageService.saveCurrentChat(selectedRole.id, [], user.id);
|
||||
if (user && selectedRole) {
|
||||
storageService.saveCurrentChat(selectedRole?.id || '', [], user.id);
|
||||
}
|
||||
closeHistoryModal();
|
||||
};
|
||||
@@ -647,9 +672,9 @@ export default function FlowScreen() {
|
||||
<View style={styles.emptyIcon}>
|
||||
<Feather name="feather" size={48} color={colors.nautical.seafoam} />
|
||||
</View>
|
||||
<Text style={styles.emptyTitle}>Chatting with {selectedRole.name}</Text>
|
||||
<Text style={styles.emptyTitle}>Chatting with {selectedRole?.name || 'AI'}</Text>
|
||||
<Text style={styles.emptySubtitle}>
|
||||
{selectedRole.description}
|
||||
{selectedRole?.description || 'Loading AI Assistant...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
@@ -707,13 +732,15 @@ export default function FlowScreen() {
|
||||
onPress={() => setShowRoleModal(true)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Ionicons
|
||||
name={selectedRole.icon as any}
|
||||
size={16}
|
||||
color={colors.nautical.teal}
|
||||
/>
|
||||
{selectedRole && (
|
||||
<Ionicons
|
||||
name={(selectedRole?.icon || 'help-outline') as any}
|
||||
size={16}
|
||||
color={colors.nautical.teal}
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.headerRoleText} numberOfLines={1}>
|
||||
{selectedRole.name}
|
||||
{selectedRole?.name || 'Loading...'}
|
||||
</Text>
|
||||
<Ionicons name="chevron-down" size={14} color={colors.flow.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
@@ -911,34 +938,34 @@ export default function FlowScreen() {
|
||||
<Text style={styles.modalTitle}>Choose AI Assistant</Text>
|
||||
|
||||
<ScrollView style={styles.roleList} showsVerticalScrollIndicator={false}>
|
||||
{AI_CONFIG.ROLES.map((role) => (
|
||||
{aiRoles.map((role) => (
|
||||
<View key={role.id} style={styles.roleItemContainer}>
|
||||
<View
|
||||
style={[
|
||||
styles.roleItem,
|
||||
selectedRole.id === role.id && styles.roleItemActive
|
||||
selectedRole?.id === role.id && styles.roleItemActive
|
||||
]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.roleSelectionArea}
|
||||
onPress={() => {
|
||||
setSelectedRole(role as any);
|
||||
setSelectedRole(role);
|
||||
setShowRoleModal(false);
|
||||
}}
|
||||
>
|
||||
<View style={[
|
||||
styles.roleItemIcon,
|
||||
selectedRole.id === role.id && styles.roleItemIconActive
|
||||
selectedRole?.id === role.id && styles.roleItemIconActive
|
||||
]}>
|
||||
<Ionicons
|
||||
name={role.icon as any}
|
||||
size={20}
|
||||
color={selectedRole.id === role.id ? '#fff' : colors.nautical.teal}
|
||||
color={selectedRole?.id === role.id ? '#fff' : colors.nautical.teal}
|
||||
/>
|
||||
</View>
|
||||
<Text style={[
|
||||
styles.roleItemName,
|
||||
selectedRole.id === role.id && styles.roleItemNameActive
|
||||
selectedRole?.id === role.id && styles.roleItemNameActive
|
||||
]}>
|
||||
{role.name}
|
||||
</Text>
|
||||
|
||||
Reference in New Issue
Block a user