| 'use client'; |
|
|
| import { useEffect, type ReactNode } from 'react'; |
| import { AnimatePresence, motion } from 'framer-motion'; |
| import { AmbientBackground } from '@/components/effects/ambient-background'; |
| import { Header } from './header'; |
| import { MobileTabBar } from './tab-navigation'; |
| import { useAppStore, useActiveTab } from '@/store/app-store'; |
|
|
| interface AppShellProps { |
| analyzeContent: ReactNode; |
| settingsContent: ReactNode; |
| } |
|
|
| export function AppShell({ analyzeContent, settingsContent }: AppShellProps) { |
| const activeTab = useActiveTab(); |
| const setConnectionStatus = useAppStore((state) => state.setConnectionStatus); |
| const setMedgemmaStatus = useAppStore((state) => state.setMedgemmaStatus); |
| const setLocalStatus = useAppStore((state) => state.setLocalStatus); |
| const setAvailableModels = useAppStore((state) => state.setAvailableModels); |
| const updateSettings = useAppStore((state) => state.updateSettings); |
| const settings = useAppStore((state) => state.settings); |
|
|
| |
| useEffect(() => { |
| const abortController = new AbortController(); |
|
|
| const checkConnection = async () => { |
| |
| try { |
| const response = await fetch('/api/ollama', { |
| signal: abortController.signal, |
| }); |
| const data = await response.json(); |
| if (data.success) { |
| setConnectionStatus('connected'); |
| setAvailableModels(data.data.models); |
| |
| if (data.data.models.length > 0 && !settings.selectedModel) { |
| updateSettings({ selectedModel: data.data.models[0] }); |
| } |
| } else { |
| setConnectionStatus('disconnected'); |
| } |
| } catch (error) { |
| if (error instanceof Error && error.name !== 'AbortError') { |
| setConnectionStatus('disconnected'); |
| } |
| } |
|
|
| |
| try { |
| const response = await fetch('/api/analyze-medgemma?provider=local', { |
| signal: abortController.signal, |
| }); |
| const data = await response.json(); |
| if (data.success && data.data?.connected) { |
| setMedgemmaStatus('connected'); |
| } else { |
| setMedgemmaStatus('disconnected'); |
| } |
| } catch (error) { |
| if (error instanceof Error && error.name !== 'AbortError') { |
| setMedgemmaStatus('disconnected'); |
| } |
| } |
|
|
| |
| try { |
| const response = await fetch('/api/analyze-medgemma?provider=local', { |
| signal: abortController.signal, |
| }); |
| const data = await response.json(); |
| if (data.success && data.data?.connected) { |
| setLocalStatus('connected'); |
| } else { |
| setLocalStatus('disconnected'); |
| } |
| } catch (error) { |
| if (error instanceof Error && error.name !== 'AbortError') { |
| setLocalStatus('disconnected'); |
| } |
| } |
| }; |
|
|
| checkConnection(); |
|
|
| return () => { |
| abortController.abort(); |
| }; |
| |
| }, []); |
|
|
| return ( |
| <div className="min-h-screen"> |
| <AmbientBackground /> |
| <Header /> |
| |
| {/* Main content area */} |
| <main className="pt-20 pb-24 md:pb-8 px-4 sm:px-6 lg:px-8"> |
| <div className="max-w-7xl mx-auto"> |
| {/* Content */} |
| <AnimatePresence mode="wait"> |
| <motion.div |
| key={activeTab} |
| initial={{ opacity: 0, y: 10 }} |
| animate={{ opacity: 1, y: 0 }} |
| exit={{ opacity: 0, y: -10 }} |
| transition={{ duration: 0.2 }} |
| > |
| {activeTab === 'analyze' ? analyzeContent : settingsContent} |
| </motion.div> |
| </AnimatePresence> |
| </div> |
| </main> |
| |
| {/* Mobile bottom tab bar */} |
| <MobileTabBar /> |
| </div> |
| ); |
| } |
|
|