mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 17:19:40 +02:00
- Restructure chat as apps/mobile, apps/web, apps/landing, backend - Add NestJS backend for secure Azure OpenAI API calls - Remove exposed API key from mobile app (security fix) - Add shared chat-types package - Create SvelteKit web app scaffold - Create Astro landing page scaffold - Update pnpm workspace configuration - Add project-level CLAUDE.md documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
161 lines
5.6 KiB
TypeScript
161 lines
5.6 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { View, Text, TouchableOpacity, Modal, FlatList, StyleSheet } from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { useAppTheme } from '../theme/ThemeProvider';
|
|
import { Model } from '../types';
|
|
import { availableModels } from '../config/azure';
|
|
import { getModels } from '../services/modelService';
|
|
|
|
// Verwende Modelle aus der Konfiguration
|
|
const FALLBACK_MODELS: Model[] = availableModels;
|
|
|
|
type ModelDropdownProps = {
|
|
selectedModelId: string;
|
|
onSelectModel: (id: string) => void;
|
|
};
|
|
|
|
export default function ModelDropdown({ selectedModelId, onSelectModel }: ModelDropdownProps) {
|
|
const { isDarkMode } = useAppTheme();
|
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
const [models, setModels] = useState<Model[]>(FALLBACK_MODELS);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
// Lade die Modelle vom ModelService
|
|
useEffect(() => {
|
|
const fetchModels = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const modelsList = await getModels();
|
|
setModels(modelsList);
|
|
} catch (err) {
|
|
console.error('Fehler beim Laden der Modelle:', err);
|
|
setModels(FALLBACK_MODELS);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchModels();
|
|
}, []);
|
|
|
|
const selectedModel = models.find(model => model.id === selectedModelId) || models[0];
|
|
|
|
return (
|
|
<View>
|
|
<TouchableOpacity
|
|
onPress={() => setIsModalVisible(true)}
|
|
className={`flex-row items-center rounded-lg px-2 py-1 ${isDarkMode ? 'bg-[#2C2C2E]' : 'bg-gray-100'}`}
|
|
>
|
|
<Text className={`text-sm font-medium ${isDarkMode ? 'text-white' : 'text-black'}`}>
|
|
{selectedModel.name}
|
|
</Text>
|
|
<Ionicons
|
|
name="chevron-down"
|
|
size={16}
|
|
color={isDarkMode ? '#FFFFFF' : '#000000'}
|
|
style={{ marginLeft: 4 }}
|
|
/>
|
|
</TouchableOpacity>
|
|
|
|
<Modal
|
|
visible={isModalVisible}
|
|
transparent={true}
|
|
animationType="fade"
|
|
onRequestClose={() => setIsModalVisible(false)}
|
|
>
|
|
<TouchableOpacity
|
|
style={styles.modalOverlay}
|
|
activeOpacity={1}
|
|
onPress={() => setIsModalVisible(false)}
|
|
>
|
|
<View
|
|
className={`mx-4 rounded-xl p-4 ${isDarkMode ? 'bg-[#1C1C1E]' : 'bg-white'}`}
|
|
style={styles.modalContent}
|
|
>
|
|
<Text className={`text-lg font-bold mb-4 ${isDarkMode ? 'text-white' : 'text-black'}`}>
|
|
Modell auswählen
|
|
</Text>
|
|
|
|
{loading ? (
|
|
<View className="py-4 items-center">
|
|
<Text className={`${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
|
|
Modelle werden geladen...
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<FlatList
|
|
data={models}
|
|
keyExtractor={(item) => item.id}
|
|
renderItem={({ item }) => (
|
|
<TouchableOpacity
|
|
className={`flex-row items-center p-3 mb-2 rounded-lg ${
|
|
item.id === selectedModelId
|
|
? isDarkMode ? 'bg-blue-900/30' : 'bg-blue-100'
|
|
: isDarkMode ? 'bg-[#2C2C2E]' : 'bg-gray-100'
|
|
}`}
|
|
onPress={() => {
|
|
onSelectModel(item.id);
|
|
setIsModalVisible(false);
|
|
}}
|
|
>
|
|
<View className="w-8 h-8 rounded-full bg-blue-500/20 items-center justify-center mr-3">
|
|
<Ionicons
|
|
name="chatbubble-ellipses-outline"
|
|
size={16}
|
|
color="#0A84FF"
|
|
/>
|
|
</View>
|
|
|
|
<View className="flex-1">
|
|
<Text className={`font-medium ${isDarkMode ? 'text-white' : 'text-black'}`}>
|
|
{item.name}
|
|
</Text>
|
|
<Text
|
|
className={`text-xs mt-1 ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}
|
|
numberOfLines={1}
|
|
>
|
|
{item.description}
|
|
</Text>
|
|
{item.parameters?.deployment && (
|
|
<Text
|
|
className={`text-xs mt-1 ${isDarkMode ? 'text-blue-400' : 'text-blue-500'}`}
|
|
numberOfLines={1}
|
|
>
|
|
{item.parameters.deployment}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
|
|
{item.id === selectedModelId && (
|
|
<View className="w-6 h-6 rounded-full bg-blue-500 items-center justify-center">
|
|
<Ionicons name="checkmark" size={14} color="#FFFFFF" />
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
)}
|
|
/>
|
|
)}
|
|
|
|
<TouchableOpacity
|
|
className={`mt-3 py-3 rounded-lg items-center ${isDarkMode ? 'bg-[#0A84FF]' : 'bg-[#0A84FF]'}`}
|
|
onPress={() => setIsModalVisible(false)}
|
|
>
|
|
<Text className="text-white font-medium">Schließen</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
modalOverlay: {
|
|
flex: 1,
|
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
justifyContent: 'center',
|
|
},
|
|
modalContent: {
|
|
maxHeight: '80%',
|
|
},
|
|
});
|