import React, { useState, useEffect, useCallback } from 'react'; import { View, Dimensions } from 'react-native'; import { useTranslation } from 'react-i18next'; import { useTheme } from '~/features/theme/ThemeProvider'; import { router } from 'expo-router'; import Text from '~/components/atoms/Text'; import Button from '~/components/atoms/Button'; import BaseModal from '~/components/atoms/BaseModal'; import { isActiveBlueprintForUser, toggleBlueprintActive } from '~/features/blueprints/lib/activeBlueprintService'; import { createClient, SupabaseClient } from '@supabase/supabase-js'; import AsyncStorage from '@react-native-async-storage/async-storage'; import colors from '~/tailwind.config.js'; import { STANDARD_BLUEPRINT_ID } from '~/features/blueprints/constants'; const { width, height } = Dimensions.get('window'); interface Prompt { id: string; memory_title: { de?: string; en?: string; }; prompt_text: { de?: string; en?: string; }; sort_order?: number; created_at?: string; } interface BlueprintModalProps { visible: boolean; onClose: () => void; blueprint: { id: string; name: { de?: string; en?: string; }; description?: { de?: string; en?: string; }; prompts?: Prompt[]; } | null; currentLanguage: string; } /** * Modal zur Anzeige von Blueprint-Details * * Zeigt Titel, Beschreibung und die zugehörigen Prompts eines Blueprints an */ const BlueprintModal: React.FC = ({ visible, onClose, blueprint, currentLanguage }) => { const { t } = useTranslation(); const { isDark, themeVariant } = useTheme(); const [isActive, setIsActive] = useState(false); const [isActivating, setIsActivating] = useState(false); const [prompts, setPrompts] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // Direkter Zugriff auf die Datenbank mit dem anon key für öffentliche Daten // Definiere den Typ für den Supabase-Client const directSupabase: SupabaseClient = createClient( 'https://npgifbrwhftlbrbaglmi.supabase.co', 'sb_publishable_HlAZpB4BxXaMcfOCNx6VJA_-64NTxu4' ); // Lade Prompts für den Blueprint, wenn das Modal geöffnet wird useEffect(() => { if (visible && blueprint) { loadPrompts(); } }, [visible, blueprint?.id]); // Lade Prompts für den aktuellen Blueprint const loadPrompts = async () => { if (!blueprint) return; try { setLoading(true); setError(null); // Zuerst die Prompt-IDs abrufen const { data: promptLinks, error: promptLinksError } = await directSupabase .from('prompt_blueprints') .select('prompt_id') .eq('blueprint_id', blueprint.id); if (promptLinksError) { setError(t('blueprints.error_loading_prompts', 'Fehler beim Laden der Prompts')); setPrompts([]); return; } if (!promptLinks || promptLinks.length === 0) { setPrompts([]); return; } // Prompt-IDs extrahieren const promptIds = promptLinks.map((link: { prompt_id: string }) => link.prompt_id); // Versuche die RPC-Funktion für die Prompts const { data: promptsData, error: promptsError } = await directSupabase .rpc('get_prompts_by_ids', { prompt_ids: promptIds }); // Wenn die RPC-Funktion nicht existiert, versuche eine alternative Abfrage if (promptsError) { // Einzelne Abfragen für jeden Prompt-ID const prompts = []; for (const id of promptIds) { const { data, error } = await directSupabase .from('prompts') .select('*') .eq('id', id); if (data && data.length > 0) { prompts.push(data[0]); } } // Sort prompts using the same logic as memories: first by sort_order ascending, then by created_at descending const sortedPrompts = prompts.sort((a, b) => { // First sort by sort_order (ascending) if (a.sort_order !== undefined && b.sort_order !== undefined) { if (a.sort_order !== b.sort_order) { return a.sort_order - b.sort_order; } } else if (a.sort_order !== undefined) { return -1; // a has sort_order, b doesn't, so a comes first } else if (b.sort_order !== undefined) { return 1; // b has sort_order, a doesn't, so b comes first } // Then sort by created_at (descending - newest first) if (a.created_at && b.created_at) { return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); } return 0; }); // Verwende die manuell gesammelten und sortierten Prompts if (sortedPrompts.length > 0) { return setPrompts(sortedPrompts); } } if (promptsError) { setError(t('blueprints.error_loading_prompts', 'Fehler beim Laden der Prompts')); setPrompts([]); return; } if (!promptsData || promptsData.length === 0) { setPrompts([]); return; } // Sort prompts using the same logic as memories: first by sort_order ascending, then by created_at descending const sortedPromptsData = [...promptsData].sort((a, b) => { // First sort by sort_order (ascending) if (a.sort_order !== undefined && b.sort_order !== undefined) { if (a.sort_order !== b.sort_order) { return a.sort_order - b.sort_order; } } else if (a.sort_order !== undefined) { return -1; // a has sort_order, b doesn't, so a comes first } else if (b.sort_order !== undefined) { return 1; // b has sort_order, a doesn't, so b comes first } // Then sort by created_at (descending - newest first) if (a.created_at && b.created_at) { return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); } return 0; }); setPrompts(sortedPromptsData); } catch (err: any) { setError(t('common.unexpected_error', 'Ein unerwarteter Fehler ist aufgetreten')); setPrompts([]); } finally { setLoading(false); } }; // Lade den Aktivierungsstatus, wenn das Modal geöffnet wird useEffect(() => { if (visible && blueprint?.id) { const loadActiveStatus = async () => { try { const active = await isActiveBlueprintForUser(blueprint.id); setIsActive(active); } catch (error) { console.debug('Fehler beim Laden des Aktivierungsstatus:', error); } }; loadActiveStatus(); } }, [visible, blueprint?.id]); // Funktion zum Umschalten des Aktivierungsstatus const handleToggleActive = useCallback(async () => { if (!blueprint?.id) return; try { setIsActivating(true); const newStatus = !isActive; const success = await toggleBlueprintActive(blueprint.id, newStatus); if (success) { setIsActive(newStatus); } } catch (error) { console.debug('Fehler beim Umschalten des Aktivierungsstatus:', error); } finally { setIsActivating(false); } }, [blueprint?.id, isActive]); // Handler für den Aufnehmen-Button const handleStartRecording = useCallback(async () => { if (!blueprint?.id) return; try { // Speichere die Blueprint-ID im AsyncStorage für die Homepage await AsyncStorage.setItem('selectedBlueprintId', blueprint.id); // Schließe das Modal onClose(); // Navigiere zur Homepage router.push('/(protected)/(tabs)/'); console.debug('Navigiere zur Homepage mit Blueprint:', blueprint.id); } catch (error) { console.debug('Fehler beim Speichern der Blueprint-ID:', error); } }, [blueprint?.id, onClose]); // Fallback auf Englisch, wenn die aktuelle Sprache nicht verfügbar ist const lang = currentLanguage.startsWith('de') ? 'de' : 'en'; // Extrahiere die lokalisierten Werte const displayName = blueprint?.name?.[lang] || blueprint?.name?.en || blueprint?.name?.de || ''; const displayDescription = blueprint?.description?.[lang] || blueprint?.description?.en || blueprint?.description?.de || ''; // Hintergrundfarben basierend auf dem Theme const backgroundColor = isDark ? '#1A1A1A' : '#F5F5F5'; const textColor = isDark ? '#FFFFFF' : '#000000'; const secondaryTextColor = isDark ? '#CCCCCC' : '#666666'; if (!blueprint) return null; // Benutzerdefinierter Footer für das Modal const customFooter = (