-
+
+
{`MBTI 대화에 참여하셨군요!
대화 상황에 대해 구체적으로
말씀해주시면,더 좋은 답변을 드릴 수 있어요 :)`}
-
+
언제, 어디서, 어떤 상황인지 자유롭게 알려주세요
-
+
);
};
diff --git a/src/components/input/MessageInput.tsx b/src/components/input/MessageInput.tsx
index c8bb379..08eb07c 100644
--- a/src/components/input/MessageInput.tsx
+++ b/src/components/input/MessageInput.tsx
@@ -1,17 +1,20 @@
-import { ChangeEvent } from "react";
+import { ChangeEvent, KeyboardEvent } from "react";
interface MessageInputProps {
value: string;
onChange: (e: ChangeEvent
) => void;
+ onKeyUp: (e: KeyboardEvent) => void;
}
-const MessageInput = ({ value, onChange }: MessageInputProps) => {
+const MessageInput = ({ value, onChange, onKeyUp }: MessageInputProps) => {
return (
);
};
diff --git a/src/libs/analytics.ts b/src/libs/analytics.ts
index 059f2f9..667c669 100644
--- a/src/libs/analytics.ts
+++ b/src/libs/analytics.ts
@@ -4,31 +4,28 @@ const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID || "";
const isProduction = import.meta.env.MODE === "production";
-const initGA = () => {
- console.log("import.meta.env.MODE", import.meta.env.MODE);
+export const initGA = () => {
console.log("isProduction", isProduction);
console.log("ID", GA_MEASUREMENT_ID);
if (isProduction && GA_MEASUREMENT_ID) {
+ console.log("initGA");
ReactGA.initialize(GA_MEASUREMENT_ID);
}
};
-const trackPageView = (path: string) => {
- console.log("trackPageView 1");
+export const trackPageView = (url: string, params?: Record) => {
if (isProduction && GA_MEASUREMENT_ID) {
- console.log("trackPageView 2");
- ReactGA.send({ hitType: "pageview", page: path });
+ console.log("trackPageView");
+ ReactGA.gtag("event", "page_view", {
+ page_path: url,
+ ...params
+ });
}
};
-const trackEvent = (category: string, action: string, label?: string) => {
+export const trackEvent = (name: string, params?: Record) => {
if (isProduction && GA_MEASUREMENT_ID) {
- ReactGA.event({
- category,
- action,
- label
- });
+ console.log("trackEvent");
+ ReactGA.event(name, params);
}
};
-
-export { initGA, trackPageView, trackEvent };
diff --git a/src/pages/Chat.tsx b/src/pages/Chat.tsx
index aec311f..b13f21c 100644
--- a/src/pages/Chat.tsx
+++ b/src/pages/Chat.tsx
@@ -1,5 +1,121 @@
+import { useEffect, useRef, useState, ChangeEvent, KeyboardEvent } from "react";
+import IntroGuide from "@/components/IntroGuide";
+import Header from "@/components/Header";
+import ChatMessage from "@/components/ChatMessage";
+import ChatActionBar from "@/components/ChatActionBar";
+import pickMbtiImage from "@/utils/pickMbtiImage";
+import instance from "@/api/axios";
+
+interface Message {
+ role: "user" | "assistant";
+ content: string;
+}
+
const Chat = () => {
- return Chat 페이지!
;
+ const [messages, setMessages] = useState([]);
+ const [input, setInput] = useState("");
+ const [isOpen, setIsOpen] = useState(false);
+ const bottomRef = useRef(null);
+
+ useEffect(() => {
+ bottomRef.current?.scrollIntoView({ behavior: "smooth" });
+ }, [messages]);
+
+ const chatTitle = "ENFP와 대화"; //TODO: API 연동 후 수정 필요
+ const assistantInfo = "ENFP"; //TODO: API 연동 후 수정 필요
+ const assistantImgUrl = pickMbtiImage(assistantInfo);
+
+ const handleSend = async (messageToSend: string) => {
+ if (!messageToSend.trim()) return;
+
+ const newMessages: Message[] = [
+ ...messages,
+ { role: "user", content: messageToSend }
+ ];
+ setMessages(newMessages);
+ setInput("");
+
+ try {
+ //TODO: API 분기처리 필요
+ const response = await instance.post(
+ "/api/fast-friend/message",
+ JSON.stringify({ content: messageToSend })
+ );
+
+ setMessages([
+ ...newMessages,
+ {
+ role: "assistant",
+ content: JSON.stringify(response.data) || "응답이 없어요"
+ }
+ ]);
+ } catch (e) {
+ setMessages([
+ ...newMessages,
+ { role: "assistant", content: "오류가 발생했어요. 다시 시도해 주세요." }
+ ]);
+ }
+ };
+
+ const handleChange = (e: ChangeEvent) => {
+ setInput(e.target.value);
+ };
+
+ const handleKeyup = (e: KeyboardEvent) => {
+ if (e.key === "Enter") {
+ handleSend(e.currentTarget.value);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ {/* 메시지 리스트 */}
+ {messages.map((msg, index) => (
+
+ {/* 캐릭터 아이콘 */}
+ {msg.role === "assistant" && (
+

+ )}
+
+ {/* 채팅 메시지 */}
+
+
+
+
+ ))}
+
+
+
+
+
handleSend(input)}
+ />
+
+ );
};
export default Chat;
diff --git a/src/pages/Content.tsx b/src/pages/Content.tsx
index 861e17f..c0bd3ec 100644
--- a/src/pages/Content.tsx
+++ b/src/pages/Content.tsx
@@ -178,8 +178,10 @@ const Content = () => {
const handleStartChat = async () => {
try {
- trackEvent("User", "Clicked Start Chat Button", "Start Chat");
-
+ trackEvent("Click", {
+ page: "일반 콘텐츠",
+ element: "대화 시작하기"
+ });
const response = await instance.post("/api/fast-friend");
console.log("Success!!", response.data);
} catch (error) {
diff --git a/src/pages/MyInfo.tsx b/src/pages/MyInfo.tsx
new file mode 100644
index 0000000..85b0cbe
--- /dev/null
+++ b/src/pages/MyInfo.tsx
@@ -0,0 +1,45 @@
+import Header from "@/components/Header";
+
+interface MenuItem {
+ label: string;
+ onClick?: () => void;
+}
+
+const menuItems: MenuItem[] = [
+ { label: "이용약관", onClick: () => console.log("이용약관 클릭") },
+ {
+ label: "개인정보처리방침",
+ onClick: () => console.log("개인정보처리방침 클릭")
+ },
+ { label: "로그아웃", onClick: () => console.log("로그아웃 클릭") },
+ { label: "회원탈퇴", onClick: () => console.log("회원탈퇴 클릭") }
+];
+
+const MyInfo = () => {
+ return (
+
+
+
+
+ {menuItems.map((item, index) => (
+ -
+
+ {item.label}
+
+
+
+ ))}
+
+
+ );
+};
+
+export default MyInfo;
diff --git a/src/pages/SelectInfo.tsx b/src/pages/SelectInfo.tsx
index bd33ad3..37dc439 100644
--- a/src/pages/SelectInfo.tsx
+++ b/src/pages/SelectInfo.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { ChangeEvent, useState } from "react";
import { useLocation } from "react-router-dom";
import FormButton from "@/components/button/FormButton";
import Header from "@/components/Header";
@@ -85,7 +85,7 @@ const SelectInfo = () => {
return interest.includes(option);
};
- const handleNameChange = (e: React.ChangeEvent) => {
+ const handleNameChange = (e: ChangeEvent) => {
setName(e.target.value.substring(0, 6));
};
@@ -118,6 +118,7 @@ const SelectInfo = () => {
const mbti = `${selectedMBTI.E}${selectedMBTI.N}${selectedMBTI.F}${selectedMBTI.P}`;
const commonData = {
+ gender: gender === "남자" ? "MALE" : gender === "여자" ? "FEMALE" : null,
mbti,
interests: interest
};
@@ -128,17 +129,13 @@ const SelectInfo = () => {
...commonData,
friendName: name,
age: mapAgeToNumber(age),
- relationship,
- gender:
- gender === "남자" ? "MALE" : gender === "여자" ? "FEMALE" : null
+ relationship
}
: {
...commonData,
fastFriendName: name,
fastFriendAge: mapAgeToNumber(age),
- fastFriendRelationship: relationship,
- fastFriendSex:
- gender === "남자" ? "MALE" : gender === "여자" ? "FEMALE" : null
+ fastFriendRelationship: relationship
};
const apiUrl =