Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
4812cd9
feat: 공유하기 모달 ui 완성
junjeeong Apr 10, 2025
d15ba03
feat: kakao 공유 기능 추가
junjeeong Apr 14, 2025
c210f14
feat: kakao 공유 기능 추가
junjeeong Apr 14, 2025
803a5ae
fix: insta -> twitter로 수정, 디자인 나오면 svg 바꿀 예정
junjeeong Apr 17, 2025
97474e3
feat: 404.tsx 개발
junjeeong Apr 17, 2025
936ebe5
ref: 401,404,500 하나의 컴포넌트로 공통화
junjeeong Apr 17, 2025
2b569ff
feat: mbti test 결과를 select info에 반영
Soohyuniii Apr 21, 2025
b261908
feat: GA click event
Soohyuniii Apr 21, 2025
18f5eb7
fix: GA pageview element 제거 작업
Soohyuniii Apr 21, 2025
edede06
fix: 로그인 안되는 문제 해결 1차
junjeeong Apr 21, 2025
19ecd58
chore: redirect-url 배포 주소로 변경
junjeeong Apr 21, 2025
6801a89
chore: mode -> statuscode 정정
junjeeong Apr 21, 2025
15b0b8d
Merge pull request #202 from MBTips/feature/404-페이지
junjeeong Apr 21, 2025
2ea1e3d
Merge branch 'dev' of https://github.com/MBTips/FE-MBTips into feat/g…
Soohyuniii Apr 21, 2025
e49e27f
Merge pull request #206 from Soohyuniii/feat/ga-click-태깅-추가-작업-수현
Soohyuniii Apr 21, 2025
bcbee7f
Merge branch 'dev' of https://github.com/MBTips/FE-MBTips into fix--G…
Soohyuniii Apr 21, 2025
921711c
Merge pull request #207 from Soohyuniii/fix--GA-pageview-수정
Soohyuniii Apr 21, 2025
bd52a7d
Merge branch 'dev' into fix/로그인-안되는-문제-해결-1차
junjeeong Apr 21, 2025
dfcc70e
fix: 채팅 input 하단 고정
Soohyuniii Apr 21, 2025
c632e2d
feat: login 함수에서 에러 발생시 error 페이지로 이동시킴
junjeeong Apr 21, 2025
16f43af
Merge pull request #211 from Soohyuniii/feat/채팅-input-하단-고정-작업
Soohyuniii Apr 21, 2025
3d712ae
feat: 트위터 svg 모달에 추가
junjeeong Apr 22, 2025
2e5ed38
feat: HO이지에서 로그인햇을 경우 StrokeBanner -> ProifleContainer가 보이게 변경
junjeeong Apr 22, 2025
3c6e668
Merge branch 'dev' of https://github.com/MBTips/FE-MBTips into feat/m…
Soohyuniii Apr 22, 2025
24f4856
fix: confict 해결
Soohyuniii Apr 22, 2025
48ceaef
Merge pull request #204 from Soohyuniii/feat/mbti-test-결과를-select-inf…
Soohyuniii Apr 22, 2025
369adf4
Merge branch 'dev' into feature/공유하기-모달-구현
junjeeong Apr 23, 2025
0a63f0a
feat: 공유하기 모달 완성
junjeeong Apr 23, 2025
59b7318
fix: 공유하기 모달 구현
junjeeong Apr 23, 2025
1c8c4bf
chore: comment 반영
junjeeong Apr 23, 2025
7363c80
chore: PR comment 반영
junjeeong Apr 23, 2025
8820e2c
chore: pr comment 반영
junjeeong Apr 23, 2025
d8f24eb
chore: 절대경로 변경, alt 오타 수정
junjeeong Apr 23, 2025
2c88e06
Merge branch 'dev' into feature/홈페이지-로그인한-경우의-ui-구현
junjeeong Apr 23, 2025
2fb297f
feat: Home 페이지에서 로그인되었다면 친구 목록 불러오는 기능 구현
junjeeong Apr 23, 2025
e4c99b2
chore: Profile 컴포넌트 버튼 기능 활성화
junjeeong Apr 23, 2025
2f24b2f
chore: SubTitle navigate 수정
junjeeong Apr 23, 2025
57049e5
chore: useAuthStore 주석 추가
junjeeong Apr 23, 2025
fd76ef2
Merge pull request #212 from MBTips/feature/공유하기-모달-구현
junjeeong Apr 23, 2025
5d5d33a
Merge pull request #210 from MBTips/fix/로그인-안되는-문제-해결-1차
junjeeong Apr 24, 2025
1d3940a
Merge branch 'dev' into feature/홈페이지-로그인한-경우의-ui-구현
junjeeong Apr 24, 2025
976cf01
feat: 채팅 내역 저장하기 구현
Soohyuniii Apr 24, 2025
594bdd0
Merge pull request #215 from MBTips/feature/홈페이지-로그인한-경우의-ui-구현
junjeeong Apr 24, 2025
2bcf2db
Merge branch 'dev' of https://github.com/MBTips/FE-MBTips into feat/채…
Soohyuniii Apr 24, 2025
d9d2c59
Merge pull request #218 from Soohyuniii/feat/채팅-내역-보존하기
Soohyuniii Apr 24, 2025
a63f53e
feat: 탈퇴 api 연동
Soohyuniii Apr 24, 2025
bf6de4a
fix: 1.홈페이지에서 token이 없어 error 나는 문제, 2.StrokeBanner 클릭시 fast-freind로 …
junjeeong Apr 24, 2025
98aefd0
Merge pull request #220 from Soohyuniii/feat/탈퇴-기능-작업
Soohyuniii Apr 24, 2025
29a0e2a
Merge pull request #222 from MBTips/fix/홈페이지-접속시-error-페이지-렌더링-되는-문제
junjeeong Apr 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</head>
<body>
<div id="root"></div>
<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
5 changes: 4 additions & 1 deletion public/icon/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icon/error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions public/icon/kakaotalk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icon/twitter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 24 additions & 16 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,43 @@ import MbtiTestQuestions from "@/pages/MbtiTestQuestions";
import MbtiTestResult from "@/pages/MbtiTestResult";
import CenteredLayout from "@/components/CenteredLayout";
import { initGA, trackPageView } from "@/libs/analytics";
import Error from "@/pages/Error";

const PageTracker = () => {
const location = useLocation();
const { pathname, state } = location;

const trackedPaths = [
{ path: "/", page: "홈", element: "" },
{ path: "/login", page: "로그인/회원가입", element: "로그인" },
{ path: "/contents", page: "일반콘텐츠", element: "" },
{ path: "/my-info", page: "내 정보", element: "" },
{ path: "/chat", page: "채팅방", element: "" },
{ path: "/select-info", page: "빠른 대화 설정", element: "" },
{ path: "/select-info", page: "친구 저장", element: "대화 시작하기" }
{ path: "/", page: "홈" },
{ path: "/login", page: "로그인/회원가입" },
{ path: "/contents", page: "일반콘텐츠" },
{ path: "/my-info", page: "내 정보" },
{ path: "/chat", page: "채팅방" },
{ path: "/select-info", page: "빠른 대화 설정" },
{ path: "/select-info", page: "친구 저장" }
];

useEffect(() => {
const trackedContentPaths = ["/contents/1", "/contents/2"];

trackedPaths.forEach(({ path, page, element }) => {
trackedPaths.forEach(({ path, page }) => {
// 콘텐츠 상세 페이지 (일반 콘텐츠만 추적)
if (trackedContentPaths.includes(pathname)) {
if (path === "/contents") {
trackPageView(path, { page, element });
trackPageView(path, page);
}
}
// select-info 페이지에서 state로 분기
else if (pathname === "/select-info" && path === pathname) {
if (state === "fastFriend" && page === "빠른 대화 설정") {
trackPageView(path, { page, element });
trackPageView(path, page);
} else if (state === "virtualFriend" && page === "친구 저장") {
trackPageView(path, { page, element });
trackPageView(path, page);
}
}
// 나머지 일반 path
else if (pathname === path && path !== "/select-info") {
trackPageView(path, { page, element });
trackPageView(path, page);
}
});
}, [location.pathname, location.state]);
Expand All @@ -77,16 +78,23 @@ const App = () => {
<Route path="/" element={<Home />} />
<Route path="/select-info" element={<SelectInfo />} />
<Route path="/chat" element={<Chat />} />
<Route path="/chat-recommend" element={<ChatRecommend />} />
<Route path="/chat-tips" element={<ChatTips />} />
<Route path="/chat-temporature" element={<ChatTemporature />} />
<Route
path="/chat-recommend/:virtualFriendId"
element={<ChatRecommend />}
/>
<Route path="/chat-tips/:virtualFriendId" element={<ChatTips />} />
<Route
path="/chat-temporature/:conversationId"
element={<ChatTemporature />}
/>
<Route path="/contents/:id" element={<Content />} />
<Route path="/login" element={<Login />} />
<Route path="/my-info" element={<MyInfo />} />
<Route path="/kakao-login" element={<KaKaoLogin />} />
<Route path="/mbti-test" element={<MbtiTestIntro />} />
<Route path="/mbti-test" element={<MbtiTestIntro />} />
<Route path="/mbti-test-progress" element={<MbtiTestQuestions />} />
<Route path="/mbti-test-result" element={<MbtiTestResult />} />
<Route path="*" element={<Error statusCode="500" />} />
</Routes>
</CenteredLayout>
</Router>
Expand Down
30 changes: 30 additions & 0 deletions src/api/axios.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from "axios";
import useAuthStore from "@/store/useAuthStore";

const instance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
Expand All @@ -8,4 +9,33 @@ const instance = axios.create({
}
});

// 인증 절차가 필요한 API는 authInstance로 HTTP요청
const authInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
headers: {
"Content-Type": "application/json"
}
});

// authInstance 헤더에 accessToken 추가하는 로직
authInstance.interceptors.request.use(
(config) => {
if (!config.headers) {
config.headers = {};
}

const { accessToken } = useAuthStore.getState();

if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);

export default instance;
export { authInstance };
6 changes: 6 additions & 0 deletions src/api/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { authInstance } from "@/api/axios";

export const deleteUser = async () => {
const response = await authInstance.delete("/api/users");
return response.data;
};
26 changes: 22 additions & 4 deletions src/components/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { cls } from "@/utils/cls";
import Indicator from "@/components/Indicator";
import { trackEvent } from "@/libs/analytics";

interface BannerImage {
sm: string;
Expand All @@ -28,12 +29,14 @@ const bannerImages: BannerImage[] = [
md: "/image/home_banner3_md.png",
lg: "/image/home_banner3_lg.png",
description: "MBTI별 피해야 할 대화스타일 및 주제"
},
}
];

const Banner = () => {
const [order, setOrder] = useState<number>(0);

const bannerEventElements = ["배너 1", "배너 2", "배너 3"];

useEffect(() => {
const interval = setInterval(() => {
setOrder((prev) => (prev + 1) % bannerImages.length);
Expand All @@ -43,18 +46,33 @@ const Banner = () => {

return (
<div className="relative flex h-[184px] w-full">
<Link to={order === 0 ? "/mbti-test" : `/contents/${order}`} className="absolute w-full h-full">
<Link
to={order === 0 ? "/mbti-test" : `/contents/${order}`}
className="absolute h-full w-full"
onClick={() => {
if (bannerEventElements[order]) {
trackEvent("Click", {
page: "홈",
element: bannerEventElements[order]
});
}
}}
>
{bannerImages.map((image, index) => (
<picture
key={index}
className={cls(
"absolute transition-opacity duration-500 w-full h-full",
"absolute h-full w-full transition-opacity duration-500",
order === index ? "opacity-100" : "opacity-0"
)}
>
<source media="(min-width: 500px)" srcSet={image.lg} />
<source media="(min-width: 375px)" srcSet={image.md} />
<img src={image.sm} alt={image.description} className="w-full h-full object-cover" />
<img
src={image.sm}
alt={image.description}
className="h-full w-full object-cover"
/>
</picture>
))}
</Link>
Expand Down
77 changes: 57 additions & 20 deletions src/components/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,68 @@
const Profile = () => {
return (
<div className="w-[157px] h-[192px] bg-white rounded-[8px] overflow-hidden relative border border-[#EEEEEE]">
<img
src="/public/icon/dustbin.svg"
alt="Delete"
className="absolute top-3 right-3 w-5 h-5 cursor-pointer"
width={16}
height={16}
/>
import { SetStateAction } from "react";
import { useNavigate } from "react-router-dom";
import { authInstance } from "@/api/axios";
import { VirtualFriend } from "@/types/virtualFreind";

interface ProfileProps {
info: VirtualFriend;
deleteIndex: number;
setVirtualFriendList: React.Dispatch<SetStateAction<VirtualFriend[]>>;
}
const Profile = ({ info, deleteIndex, setVirtualFriendList }: ProfileProps) => {
const navigate = useNavigate();

const handleDelete = async () => {
const res = await authInstance.delete(
`/api/virtual-friend/${info.virtualFriendId}`
);
if (res.status === 200) {
setVirtualFriendList((prevList) =>
prevList.filter((_, index) => index !== deleteIndex)
);
}
};

const handleNavigate = () => {
navigate("/chat", {
state: {
mode: "virtualFriend",
mbti: info.mbti,
id: info.virtualFriendId
}
});
};

return (
<div className="relative h-[192px] w-[157px] overflow-hidden rounded-[8px] border border-[#EEEEEE] bg-white lg:w-[200px]">
<button onClick={handleDelete}>
<img
src="/public/icon/dustbin.svg"
alt="Delete"
className="absolute top-3 right-3 h-5 w-5 cursor-pointer"
width={16}
height={16}
/>
</button>
<img
src="/public/image/ENTP.png"
src={`/public/image/${info.mbti}_profile.png`}
alt="Profile"
className="absolute top-[12px] left-[11px] w-12 h-12 object-cover rounded-full"
className="absolute top-[12px] left-[11px] h-12 w-12 rounded-full object-cover"
/>

<div className="pt-[69px] px-4">
<h2 className="text-base flex items-center space-x-1">
<span className="font-bold">김엠비</span>
<span className="font-light text-gray-600">ENTP</span>
<div className="px-4 pt-[69px]">
<h2 className="flex items-center space-x-1 text-base">
<span className="font-bold">{info.virtualFriendName}</span>
<span className="font-light text-gray-600">{info.mbti}</span>
</h2>
<p className="text-xs text-gray-600 mt-2 font-light">
20대 · 여자 · 직장동료 · 여행 · 사회생활
<p className="mt-2 text-xs font-light text-gray-600">
{info.virtualFriendAge} · {info.virtualFriendSex} ·{" "}
{info.virtualFriendRelationship}
</p>
</div>

<button className="w-full h-[41px] bg-primary-pale text-primary-normal font-bold py-2 text-sm absolute bottom-0">
<button
className="absolute bottom-0 h-[41px] w-full bg-primary-pale py-2 text-sm font-bold text-primary-normal"
onClick={handleNavigate}
>
바로 대화하기
</button>
</div>
Expand Down
27 changes: 27 additions & 0 deletions src/components/ProfileContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Profile from "@/components/Profile";
import { VirtualFriend } from "@/types/virtualFreind";
import { SetStateAction } from "react";

interface ProfileContainerProps {
list: VirtualFriend[];
setVirtualFriendList: React.Dispatch<SetStateAction<VirtualFriend[]>>;
}
const ProfileContainer = ({
list,
setVirtualFriendList
}: ProfileContainerProps) => {
return (
<div className="grid grid-cols-2 gap-7">
{list.map((el, index) => (
<Profile
key={index}
info={el}
deleteIndex={index}
setVirtualFriendList={setVirtualFriendList}
/>
))}
</div>
);
};

export default ProfileContainer;
2 changes: 1 addition & 1 deletion src/components/StrokeBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const StrokeBanner = () => {

const handleNavigate = () => {
const mode = "virtualFriend";
navigate("/select-info", { state: mode });
navigate("/select-info", { state: { type: mode } });
};

return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/SubTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const SubTitle = ({ mode }: { mode: "빠른대화" | "친구목록" }) => {
};

const handleNavigate = () => {
const mode = "virtualFriend";
navigate("/select-info", { state: mode });
const type = mode === "빠른대화" ? "fastFriend" : "virtualFriend";
navigate("/select-info", { state: { type: type } });
};

return (
Expand Down
Loading