From 067e7d19b12e49e7b3cb6d85b508bf192d258faf Mon Sep 17 00:00:00 2001 From: manNomi Date: Fri, 19 Jun 2026 16:48:31 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=95=B1=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20=EB=8F=99=EC=9E=91=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/login/LoginContent.tsx | 23 +++++- .../src/app/my/_ui/MyProfileContent/index.tsx | 14 +++- .../ui/LinkedTextWithIcon/index.tsx | 2 +- apps/web/src/utils/openKakaoOpenChat.ts | 73 +++++++++++++++++++ 4 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 apps/web/src/utils/openKakaoOpenChat.ts diff --git a/apps/web/src/app/login/LoginContent.tsx b/apps/web/src/app/login/LoginContent.tsx index 928fca07..d3a76397 100644 --- a/apps/web/src/app/login/LoginContent.tsx +++ b/apps/web/src/app/login/LoginContent.tsx @@ -6,7 +6,7 @@ import { useRouter, useSearchParams } from "next/navigation"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { usePostEmailAuth } from "@/apis/Auth"; -import { IconSolidConnectionFullBlackLogo } from "@/public/svgs"; +import { IconArrowBackFilled, IconSolidConnectionFullBlackLogo } from "@/public/svgs"; import { IconAppleLogo, IconEmailIcon, IconKakaoLogo } from "@/public/svgs/auth"; import { AUTH_REDIRECT_PARAM, @@ -54,10 +54,27 @@ const LoginContent = () => { } }; + const handleBack = () => { + if (window.history.length > 1) { + router.back(); + return; + } + + router.push("/"); + }; + return (
-
- +
+ +
diff --git a/apps/web/src/app/my/_ui/MyProfileContent/index.tsx b/apps/web/src/app/my/_ui/MyProfileContent/index.tsx index ee82e5c4..ede38f0f 100644 --- a/apps/web/src/app/my/_ui/MyProfileContent/index.tsx +++ b/apps/web/src/app/my/_ui/MyProfileContent/index.tsx @@ -18,6 +18,7 @@ import { IconUniversity, } from "@/public/svgs/my"; import { UserRole } from "@/types/mentor"; +import { openKakaoOpenChat } from "@/utils/openKakaoOpenChat"; const NEXT_PUBLIC_CONTACT_LINK = process.env.NEXT_PUBLIC_CONTACT_LINK; @@ -37,8 +38,17 @@ const MyProfileContent = () => { const favoriteLocation = profileData.role === UserRole.MENTEE ? profileData.interestedCountries.slice(0, 3).join(", ") || "없음" : "없음"; + const handleContactClick = () => { + if (!NEXT_PUBLIC_CONTACT_LINK) { + showIconToast("logo", "고객센터 링크를 불러오지 못했습니다. 잠시 후 다시 시도해주세요."); + return; + } + + openKakaoOpenChat(NEXT_PUBLIC_CONTACT_LINK); + }; + return ( -
+

{nickname}님은

@@ -155,7 +165,7 @@ const MyProfileContent = () => {

- + { diff --git a/apps/web/src/components/ui/LinkedTextWithIcon/index.tsx b/apps/web/src/components/ui/LinkedTextWithIcon/index.tsx index 9c3caf9a..36919714 100644 --- a/apps/web/src/components/ui/LinkedTextWithIcon/index.tsx +++ b/apps/web/src/components/ui/LinkedTextWithIcon/index.tsx @@ -37,7 +37,7 @@ const LinkedTextWithIcon = ({ } return ( - ); diff --git a/apps/web/src/utils/openKakaoOpenChat.ts b/apps/web/src/utils/openKakaoOpenChat.ts new file mode 100644 index 00000000..a809f6bf --- /dev/null +++ b/apps/web/src/utils/openKakaoOpenChat.ts @@ -0,0 +1,73 @@ +const KAKAO_OPEN_CHAT_HOST = "open.kakao.com"; +const KAKAO_OPEN_CHAT_PATH_PATTERN = /^\/o\/([^/?#]+)/; +const KAKAO_OPEN_CHAT_REFERER = "EW"; +const OPEN_CHAT_FALLBACK_DELAY_MS = 1200; + +export const getKakaoOpenChatJoinScheme = (openChatUrl: string): string | null => { + try { + const url = new URL(openChatUrl); + + if (url.hostname !== KAKAO_OPEN_CHAT_HOST) { + return null; + } + + const linkId = url.pathname.match(KAKAO_OPEN_CHAT_PATH_PATTERN)?.[1]; + + if (!linkId) { + return null; + } + + return `kakaoopen://join?l=${encodeURIComponent(linkId)}&r=${KAKAO_OPEN_CHAT_REFERER}`; + } catch { + return null; + } +}; + +export const openExternalUrl = (url: string) => { + const openedWindow = window.open(url, "_blank", "noopener,noreferrer"); + + if (!openedWindow) { + window.location.href = url; + } +}; + +export const openKakaoOpenChat = (openChatUrl: string) => { + const joinScheme = getKakaoOpenChatJoinScheme(openChatUrl); + + if (!joinScheme) { + openExternalUrl(openChatUrl); + return; + } + + let fallbackTimer: number | undefined; + + const cleanup = () => { + if (fallbackTimer) { + window.clearTimeout(fallbackTimer); + } + + window.removeEventListener("pagehide", cleanup); + document.removeEventListener("visibilitychange", handleVisibilityChange); + }; + + const handleVisibilityChange = () => { + if (document.hidden) { + cleanup(); + } + }; + + fallbackTimer = window.setTimeout(() => { + cleanup(); + openExternalUrl(openChatUrl); + }, OPEN_CHAT_FALLBACK_DELAY_MS); + + window.addEventListener("pagehide", cleanup); + document.addEventListener("visibilitychange", handleVisibilityChange); + + try { + window.location.href = joinScheme; + } catch { + cleanup(); + openExternalUrl(openChatUrl); + } +};