Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a47fb14
[fix] 챗봇 추천 페이지 수정 및 기능추가 (#130)
ahk0413 Oct 13, 2025
61bd59c
Design/main#11 (#131)
EunbinJung Oct 13, 2025
f071906
Style/main page 2#122 (#132)
mtm-git1018 Oct 13, 2025
bd767b0
Style/메인페이지 슬라이드영역 (#135)
mtm-git1018 Oct 14, 2025
1dbeb90
[fix] 로그아웃 시 auth/me api 자동호출로 401 에러 (#136)
ahk0413 Oct 14, 2025
993820d
Design/main#11 (#138)
EunbinJung Oct 15, 2025
d6035f4
[fix] 레이아웃 분리 (#139)
ahk0413 Oct 15, 2025
0a71cd0
Refactor/recipe fetch (#140)
mtm-git1018 Oct 15, 2025
8ee022c
Merge remote-tracking branch 'origin/main' into dev
mtm-git1018 Oct 15, 2025
95248c2
[fix] 경로 오류 수정
mtm-git1018 Oct 15, 2025
a160b2a
경로 수정
mtm-git1018 Oct 15, 2025
9c64186
[fix] 경로수정
mtm-git1018 Oct 15, 2025
52e82c3
Feat/write#19 (#142)
EunbinJung Oct 15, 2025
3f0e6f3
[fix] MainSlide 수정 (#143)
ahk0413 Oct 15, 2025
1d0e476
Refactor/칵테일 정렬 기능 수정 (#144)
mtm-git1018 Oct 15, 2025
0d6c6be
Merge remote-tracking branch 'origin/main' into dev
mtm-git1018 Oct 15, 2025
c3c3644
[fix]충돌에러수정
mtm-git1018 Oct 15, 2025
d28a1f4
[style] 폰트 추가
mtm-git1018 Oct 15, 2025
94a65e0
[fix]파일 내 코드중복 수정
mtm-git1018 Oct 15, 2025
9e976a5
[chore]포매팅
mtm-git1018 Oct 15, 2025
06e809c
[fix]타입중복 수정
mtm-git1018 Oct 15, 2025
fcef37f
[chore]포매팅
mtm-git1018 Oct 15, 2025
ca5539a
docs/ 폰트 추가 및 삭제 (#146)
mtm-git1018 Oct 15, 2025
1c30893
[fix] scroll 위치이동
ahk0413 Oct 15, 2025
b517217
Merge remote-tracking branch 'origin/dev' into dev
ahk0413 Oct 15, 2025
ad53efa
Feat/write#19 (#147)
EunbinJung Oct 15, 2025
13fd5e1
Merge remote-tracking branch 'origin/dev' into dev
ahk0413 Oct 15, 2025
b75f7e8
[style] 폰트 추가
mtm-git1018 Oct 15, 2025
0efeda3
Merge branch 'dev' of https://github.com/prgrms-web-devcourse-final-p…
mtm-git1018 Oct 15, 2025
82254e5
[feat] 스크롤 버튼 추가
ahk0413 Oct 15, 2025
d02add2
Merge remote-tracking branch 'origin/dev' into dev
ahk0413 Oct 15, 2025
3723a9b
[fix] 시작 애니메이션 원복
ahk0413 Oct 15, 2025
c99fd87
[docs]README
mtm-git1018 Oct 15, 2025
49a5fbd
Feat/write#19 (#148)
EunbinJung Oct 15, 2025
85690d2
Merge branch 'main' into dev
EunbinJung Oct 15, 2025
c4b7b8b
[fix] 로그인 시 여러번 뜨는 toast 알림 이슈 수정
ahk0413 Oct 15, 2025
b3ceb95
Merge branch 'dev' of https://github.com/prgrms-web-devcourse-final-p…
ahk0413 Oct 15, 2025
dfe596e
fix/메인페이지 아코디언박스 오류 수정 (#151)
mtm-git1018 Oct 15, 2025
93c9bef
Merge remote-tracking branch 'origin/main' into dev
mtm-git1018 Oct 15, 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: 0 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import '@/shared/styles/global.css';
import type { Metadata } from 'next';
import '@/shared/styles/global.css';
import { Toaster } from 'react-hot-toast';
import ScrollTopBtnWrapper from '@/shared/components/scroll-top/ScrollTopBtnWrapper';
import KaKaoScript from './api/kakao/KaKaoScript';
Expand Down
64 changes: 64 additions & 0 deletions src/domains/main/api/useSSENotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useEffect, useRef, useState } from 'react';
import { getApi } from '@/app/api/config/appConfig';

export function useSSENotification(isLoggedIn: boolean) {
const [hasNewNotification, setHasNewNotification] = useState(false);
const eventSourceRef = useRef<EventSource | null>(null);
const isConnectingRef = useRef(false);

useEffect(() => {
// 로그인 안 했으면 연결 안 함
if (!isLoggedIn) {
if (eventSourceRef.current) {
eventSourceRef.current.close();
eventSourceRef.current = null;
isConnectingRef.current = false;
}
return;
}

// 이미 연결 중이거나 연결되어 있으면 중복 방지
if (isConnectingRef.current || eventSourceRef.current) {
return;
}

isConnectingRef.current = true;

const eventSource = new EventSource(`${getApi}/me/subscribe`, {
withCredentials: true,
});

eventSourceRef.current = eventSource;

eventSource.onopen = () => {
isConnectingRef.current = false;
};

eventSource.onmessage = () => {
setHasNewNotification(true);
};

eventSource.onerror = () => {
isConnectingRef.current = false;

if (eventSource.readyState === EventSource.CLOSED) {
eventSourceRef.current = null;
}
};

// cleanup 함수
return () => {
if (eventSourceRef.current) {
eventSourceRef.current.close();
eventSourceRef.current = null;
}
isConnectingRef.current = false;
};
}, [isLoggedIn]); // isLoggedIn만 의존성으로

const clearNotification = () => {
setHasNewNotification(false);
};

return { hasNewNotification, clearNotification };
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ function MobileAbv() {
<h2 className="text-xl sm:text-2xl font-black text-white">내 알콜도수 UP</h2>
<button
type="button"
className={clsx(`block duration-300 sm:hidden`, isClick ? 'rotate-135' : 'rotate-0')}
className={clsx(
`block z-1 duration-300 sm:hidden`,
isClick ? 'rotate-[135deg]' : 'rotate-0'
)}
onClick={() => setIsClick(!isClick)}
>
<Add />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ function MobileSlideCommunity() {
<h2 className="text-xl sm:text-2xl font-black text-white">함께 나누는 칵테일 이야기</h2>
<button
type="button"
className={clsx(`block duration-300 sm:hidden`, isClick ? 'rotate-135' : 'rotate-0')}
className={clsx(
`block duration-300 z-1 sm:hidden`,
isClick ? 'rotate-[135deg]' : 'rotate-0'
)}
onClick={() => setIsClick(!isClick)}
>
<Add />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ function MobileSlideTest() {
<h2 className="text-xl sm:text-2xl font-black text-white">AI기반 취향테스트</h2>
<button
type="button"
className={clsx(`block duration-300 sm:hidden`, isClick ? 'rotate-135' : 'rotate-0')}
onClick={() => setIsClick(!isClick)}
className={clsx(
`block duration-300 z-1 sm:hidden`,
isClick ? 'rotate-[135deg]' : 'rotate-0'
)}
onClick={() => {
setIsClick(!isClick);
}}
>
<Add />
<Add className="pointer-events-none" />
</button>
</header>
<div
Expand Down
14 changes: 1 addition & 13 deletions src/domains/mypage/components/pages/my-active/MyLike.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,6 @@ function MyLike() {
fetchLike();
}, []);

useEffect(() => {
console.log(myLike);
}, [myLike]);

return (
<section className="flex justify-center">
{myLike.length > 0 ? (
<PostCard posts={myLike} isLoading={isLoading} />
) : (
<div>아직 좋아요를 누른 글이 없습니다</div>
)}
</section>
);
return <PostCard posts={myLike} isLoading={isLoading} />;
}
export default MyLike;
20 changes: 17 additions & 3 deletions src/shared/components/header/HeaderBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,34 @@ import { useAuthStore } from '@/domains/shared/store/auth';
import { setPreLoginPath } from '@/domains/shared/auth/utils/setPreLoginPath';
import { useState } from 'react';
import LogoutConfirm from '@/domains/login/components/LogoutConfirm';
import { useSSENotification } from '@/domains/main/api/useSSENotification';

function HeaderBtn({ pathname }: { pathname: string }) {
const { isLoggedIn } = useAuthStore();
const router = useRouter();
const [logoutModalOpen, setLogoutModalOpen] = useState(false);

const { hasNewNotification, clearNotification } = useSSENotification(isLoggedIn);

const navButtons = [
{
icon: Bell,
label: '알림',
className: pathname === '/mypage/my-alarm' ? 'text-tertiary' : 'text-current',
hiddenMobile: true,
onClick: () => router.push('/mypage/my-alarm'),
onClick: () => {
clearNotification();
router.push('/mypage/my-alarm');
},
showBadge: true,
},
{
icon: User,
label: '마이 페이지',
className: pathname === '/mypage' ? 'text-tertiary' : 'text-current',
hiddenMobile: true,
onClick: () => router.push('/mypage'),
showBadge: false,
},
];

Expand All @@ -50,18 +58,24 @@ function HeaderBtn({ pathname }: { pathname: string }) {
{/* 아이콘 버튼들 */}
<div className="flex gap-2">
{isLoggedIn &&
navButtons.map(({ icon: Icon, label, onClick, className, hiddenMobile }) => (
navButtons.map(({ icon: Icon, label, onClick, className, hiddenMobile, showBadge }) => (
<button
key={label}
aria-label={label}
onClick={onClick}
className={tw(
className,
hiddenMobile ? 'hidden sm:flex' : '',
'items-center justify-center rounded-full w-7 h-7 hover:bg-secondary/10 transition-colors duration-200'
'relative items-center justify-center rounded-full w-7 h-7 hover:bg-secondary/10 transition-colors duration-200'
)}
>
<Icon width={24} height={24} className="text-current" />
{showBadge && hasNewNotification && (
<span
className=" absolute items-center justify-center top-1 right-1 w-2 h-2 bg-red-500
rounded-full"
></span>
)}
</button>
))}
</div>
Expand Down