import { useState, useRef, useEffect } from 'react' import { View, Text, TextInput, TouchableOpacity, ScrollView, StyleSheet, KeyboardAvoidingView, Platform, ActivityIndicator, } from 'react-native' import { COLORS } from '../../constants/Config' import { sendAIMessage } from '../../services/api' import { useAuth } from '../../hooks/useAuth' interface Msg { id: number; role: 'user' | 'ai'; text: string; time: string } const QUICK = ['서버 상태 확인', 'SR 목록 보여줘', '최근 인시던트', '라이선스 현황'] export default function ChatScreen() { const { user } = useAuth() const [msgs, setMsgs] = useState([ { id: 0, role: 'ai', text: `안녕하세요 ${user?.display_name ?? ''}님! 👋\nGUARDiA AI 어시스턴트입니다.\n무엇을 도와드릴까요?`, time: now() }, ]) const [input, setInput] = useState('') const [loading, setLoading] = useState(false) const scrollRef = useRef(null) function now() { return new Date().toLocaleTimeString('ko-KR', { hour: '2-digit', minute: '2-digit' }) } const send = async (text = input) => { if (!text.trim() || loading) return const userMsg: Msg = { id: Date.now(), role: 'user', text: text.trim(), time: now() } setMsgs(m => [...m, userMsg]) setInput('') setLoading(true) try { const r = await sendAIMessage(text.trim()) const reply = r.data?.reply ?? r.data?.message ?? r.data?.response ?? '응답을 받았습니다.' setMsgs(m => [...m, { id: Date.now()+1, role: 'ai', text: reply, time: now() }]) } catch { setMsgs(m => [...m, { id: Date.now()+1, role: 'ai', text: '현재 AI 서버에 연결할 수 없습니다. Ollama 서버 상태를 확인해주세요.', time: now() }]) } finally { setLoading(false) } setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 100) } useEffect(() => { setTimeout(() => scrollRef.current?.scrollToEnd({ animated: false }), 50) }, [msgs]) return ( {/* 메시지 목록 */} {msgs.map(m => ( {m.role === 'ai' && 🤖} {m.text} {m.time} ))} {loading && ( 🤖 )} {/* 빠른 질문 */} {QUICK.map(q => ( send(q)}> {q} ))} {/* 입력창 */} send()} /> send()} disabled={!input.trim() || loading}> ) } const s = StyleSheet.create({ container: { flex:1, backgroundColor:COLORS.bg }, messages: { flex:1 }, msgRow: { flexDirection:'row', alignItems:'flex-end', marginBottom:12, gap:8 }, userRow: { flexDirection:'row-reverse' }, avatar: { fontSize:24, marginBottom:4 }, bubble: { maxWidth:'75%', borderRadius:16, padding:12 }, aiBubble: { backgroundColor:'#fff', borderBottomLeftRadius:4, shadowColor:'#000', shadowOffset:{width:0,height:1}, shadowOpacity:.06, elevation:1 }, userBubble: { backgroundColor:COLORS.accent, borderBottomRightRadius:4 }, bubbleText: { fontSize:14, color:COLORS.text, lineHeight:20 }, userText: { color:'#fff' }, timeText: { fontSize:10, color:COLORS.muted, marginTop:4, textAlign:'right' }, quickScroll: { maxHeight:44, borderTopWidth:1, borderTopColor:COLORS.border, backgroundColor:'#fff' }, quickChip: { alignSelf:'center', backgroundColor:COLORS.light, paddingHorizontal:12, paddingVertical:6, borderRadius:20 }, quickChipText: { fontSize:12, color:COLORS.accent, fontWeight:'500' }, inputRow: { flexDirection:'row', padding:12, backgroundColor:'#fff', borderTopWidth:1, borderTopColor:COLORS.border, alignItems:'flex-end', gap:8 }, textInput: { flex:1, borderWidth:1.5, borderColor:COLORS.border, borderRadius:20, paddingHorizontal:14, paddingVertical:10, fontSize:14, color:COLORS.text, maxHeight:100, backgroundColor:'#fafafa' }, sendBtn: { width:42, height:42, borderRadius:21, backgroundColor:COLORS.accent, justifyContent:'center', alignItems:'center' }, sendDisabled:{ opacity:.4 }, sendIcon: { color:'#fff', fontSize:16, marginLeft:2 }, })