import { useState, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { MessageCircle, Send, X, Minimize2, Maximize2 } from "lucide-react";
interface Message {
id: string;
type: "user" | "bot";
content: string;
timestamp: Date;
}
// 연말정산 관련 키워드 매칭 데이터베이스
const knowledgeBase = [
{
keywords: ["연말정산", "정산", "환급", "세금"],
answer: "연말정산은 근로자가 1년간 납부한 세금과 실제 납부해야 할 세금의 차이를 정산하는 제도입니다. 일반적으로 2월~5월에 신청하며, 환급받거나 추가 납부할 수 있습니다."
},
{
keywords: ["신용카드", "현금영수증", "공제"],
answer: "신용카드 사용액은 총급여의 25% 초과분에 대해 15% 공제됩니다. 현금영수증은 30% 공제되므로, 총급여의 25% 기준점을 고려하여 사용 수단을 선택하면 절세에 도움이 됩니다."
},
{
keywords: ["의료비", "병원", "치과"],
answer: "의료비는 본인과 부양가족의 의료비를 합산하여 총급여의 3% 초과분에 대해 15% 공제됩니다. 미용, 보약, 건강검진 비용은 공제 대상이 아닙니다."
},
{
keywords: ["교육비", "학원", "등록금"],
answer: "자녀의 교육비는 자녀 1명당 300만원 한도로 15% 공제됩니다. 학원비, 학교 등록금, 기숙사비 등이 포함되며, 12월에 등록금을 선납하면 그 해에 공제받을 수 있습니다."
},
{
keywords: ["월세", "전세", "주거"],
answer: "무주택 세대주의 월세는 최대 17% 공제됩니다(2024년 확대). 연 750만원 한도이며, 주민등록과 임차계약서가 필요합니다. 배우자와 함께 거주하는 경우 한 명만 공제받을 수 있습니다."
},
{
keywords: ["기부금", "기부", "종교"],
answer: "법정 기부금(적십자, 모금처 등)은 15% 공제되며, 종교단체 기부금도 공제 대상입니다. 다만 공식 영수증이 필요하며, 총급여의 10% 한도입니다."
},
{
keywords: ["보험료", "보험"],
answer: "사회보험료(건강보험, 고용보험, 산재보험, 국민연금)만 공제됩니다. 민영보험료는 공제 대상이 아니며, 부양가족의 보험료도 공제받을 수 있습니다."
},
{
keywords: ["연금계좌", "IRP", "개인연금"],
answer: "연금계좌(IRP, 개인연금저축)는 최대 900만원 한도로 13.2~16.5% 공제됩니다. 12월에 추가 납입하면 그 해에 공제받을 수 있으며, 배우자 계좌도 활용할 수 있습니다."
},
{
keywords: ["부양가족", "가족", "자료제공"],
answer: "부양가족 자료 제공 동의 시 배우자, 자녀, 부모의 의료비, 교육비 등을 합산하여 공제받을 수 있습니다. 다만 소득 요건(연 100만원 이하)을 만족해야 합니다."
},
{
keywords: ["미리보기", "홈택스", "확인"],
answer: "홈택스(www.hometax.go.kr)의 '연말정산 미리보기' 서비스를 통해 예상 환급액을 미리 확인할 수 있습니다. 12월부터 이용 가능하며, 실제 신청 전에 절세 계획을 세울 수 있습니다."
},
{
keywords: ["환급금", "환급", "돈"],
answer: "연말정산 환급금은 신청 후 약 1~2주 내에 지정된 계좌로 입금됩니다. 환급액은 개인별로 다르며, 홈택스 미리보기에서 예상 환급액을 확인할 수 있습니다."
},
{
keywords: ["추가납부", "납부", "돈내기"],
answer: "세금을 많이 내야 하는 경우 추가 납부해야 합니다. 납부 기한은 일반적으로 5월 말이며, 납부하지 않으면 가산세가 부과될 수 있습니다."
},
{
keywords: ["자녀", "자녀세액공제", "아이"],
answer: "자녀세액공제는 자녀 1명당 15만원(첫째, 둘째) 또는 30만원(셋째 이상)입니다. 2024년부터 확대되어 더 많은 혜택을 받을 수 있습니다."
},
{
keywords: ["소득", "급여", "연봉"],
answer: "연말정산은 근로소득이 있는 모든 근로자를 대상으로 합니다. 다만 부양가족의 경우 소득 요건(연 100만원 이하)을 만족해야 공제 대상이 됩니다."
},
{
keywords: ["서류", "증명", "준비"],
answer: "연말정산에 필요한 서류는 신용카드 사용 내역, 의료비 영수증, 교육비 납입 증명서, 월세 계약서 등입니다. 대부분 홈택스에서 자동으로 수집되지만, 누락된 항목은 직접 제출해야 합니다."
},
{
keywords: ["기한", "마감", "언제"],
answer: "연말정산 신청 기한은 일반적으로 2월~5월입니다. 정확한 기한은 국세청 공고를 확인하시기 바랍니다. 기한을 놓치면 해당 연도 공제를 받을 수 없습니다."
},
{
keywords: ["12월", "연말", "지출"],
answer: "12월 지출은 그 해 연말정산에 포함됩니다. 신용카드 사용, 의료비 지출, 교육비 납입, 월세 선납 등을 12월에 하면 절세 효과를 볼 수 있습니다."
},
{
keywords: ["배우자", "부부", "함께"],
answer: "배우자와 함께 거주하는 경우 일부 공제(월세, 자녀세액공제 등)는 한 명만 받을 수 있습니다. 절세 효과를 고려하여 누가 신청할지 결정하는 것이 좋습니다."
},
{
keywords: ["프리랜서", "자영업", "사업"],
answer: "프리랜서와 자영업자는 근로소득세 대신 종합소득세를 신고합니다. 다만 일부 공제(신용카드, 의료비 등)는 받을 수 있으니 국세청에 문의하시기 바랍니다."
},
{
keywords: ["도움", "궁금", "질문"],
answer: "연말정산에 대한 자세한 정보는 국세청 홈페이지(www.nts.go.kr)나 정부24(www.gov.kr)에서 확인할 수 있습니다. 개인의 상황에 따라 다를 수 있으니 전문가 상담을 권장합니다."
}
];
export default function ChatBot() {
const [isOpen, setIsOpen] = useState(false);
const [isMinimized, setIsMinimized] = useState(false);
const [messages, setMessages] = useState<Message[]>([
{
id: "1",
type: "bot",
content: "안녕하세요! 👋 연말정산 Q&A 챗봇입니다. 연말정산에 대해 궁금한 점이 있으신가요?",
timestamp: new Date()
}
]);
const [inputValue, setInputValue] = useState("");
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
const findAnswer = (userMessage: string): string => {
const lowerMessage = userMessage.toLowerCase();
for (const item of knowledgeBase) {
for (const keyword of item.keywords) {
if (lowerMessage.includes(keyword)) {
return item.answer;
}
}
}
return "죄송합니다. 해당 질문에 대한 답변을 찾을 수 없습니다. 국세청(1588-0060) 또는 정부24(www.gov.kr)에 문의하시면 정확한 정보를 얻을 수 있습니다.";
};
const handleSendMessage = async () => {
if (!inputValue.trim()) return;
// 사용자 메시지 추가
const userMessage: Message = {
id: Date.now().toString(),
type: "user",
content: inputValue,
timestamp: new Date()
};
setMessages(prev => [...prev, userMessage]);
setInputValue("");
setIsLoading(true);
// 봇 응답 시뮬레이션 (0.5초 딜레이)
setTimeout(() => {
const botAnswer = findAnswer(inputValue);
const botMessage: Message = {
id: (Date.now() + 1).toString(),
type: "bot",
content: botAnswer,
timestamp: new Date()
};
setMessages(prev => [...prev, botMessage]);
setIsLoading(false);
}, 500);
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSendMessage();
}
};
if (!isOpen) {
return (
<button
onClick={() => setIsOpen(true)}
className="fixed bottom-6 right-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white rounded-full p-4 shadow-lg hover:shadow-xl transition-all duration-300 z-40"
aria-label="채팅 열기"
>
<MessageCircle className="w-6 h-6" />
</button>
);
}
return (
<div
className={`fixed bottom-6 right-6 w-96 bg-white rounded-lg shadow-2xl border border-gray-200 z-50 transition-all duration-300 ${
isMinimized ? "h-16" : "h-screen md:h-[600px]"
}`}
>
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-4 rounded-t-lg flex items-center justify-between">
<div className="flex items-center gap-2">
<MessageCircle className="w-5 h-5" />
<h3 className="font-semibold">연말정산 Q&A 챗봇</h3>
</div>
<div className="flex gap-2">
<button
onClick={() => setIsMinimized(!isMinimized)}
className="hover:bg-white/20 p-1 rounded transition-colors"
aria-label="최소화"
>
{isMinimized ? (
<Maximize2 className="w-4 h-4" />
) : (
<Minimize2 className="w-4 h-4" />
)}
</button>
<button
onClick={() => setIsOpen(false)}
className="hover:bg-white/20 p-1 rounded transition-colors"
aria-label="닫기"
>
<X className="w-4 h-4" />
</button>
</div>
</div>
{!isMinimized && (
<>
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50 max-h-[calc(100%-140px)]">
{messages.map(message => (
<div
key={message.id}
className={`flex ${
message.type === "user" ? "justify-end" : "justify-start"
}`}
>
<div
className={`max-w-xs px-4 py-2 rounded-lg ${
message.type === "user"
? "bg-blue-600 text-white rounded-br-none"
: "bg-white text-gray-800 border border-gray-200 rounded-bl-none"
}`}
>
<p className="text-sm leading-relaxed">{message.content}</p>
<span className="text-xs opacity-70 mt-1 block">
{message.timestamp.toLocaleTimeString("ko-KR", {
hour: "2-digit",
minute: "2-digit"
})}
</span>
</div>
</div>
))}
{isLoading && (
<div className="flex justify-start">
<div className="bg-white text-gray-800 border border-gray-200 px-4 py-2 rounded-lg rounded-bl-none">
<div className="flex gap-1">
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: "0.1s" }}></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: "0.2s" }}></div>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{/* Input */}
<div className="border-t border-gray-200 p-4 bg-white rounded-b-lg">
<div className="flex gap-2">
<Input
type="text"
placeholder="질문을 입력하세요..."
value={inputValue}
onChange={e => setInputValue(e.target.value)}
onKeyPress={handleKeyPress}
disabled={isLoading}
className="flex-1 text-sm"
/>
<Button
onClick={handleSendMessage}
disabled={isLoading || !inputValue.trim()}
className="bg-blue-600 hover:bg-blue-700 text-white px-3"
>
<Send className="w-4 h-4" />
</Button>
</div>
<p className="text-xs text-gray-500 mt-2">
💡 연말정산, 신용카드, 의료비, 교육비 등에 대해 물어보세요
</p>
</div>
</>
)}
</div>
);
}