-
Notifications
You must be signed in to change notification settings - Fork 1
[FEATURE] 전화번호 중복가입 차단 및 로그인 플로우 개선 #355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 7 commits
20eecdd
055d0a7
e53d1df
7151fb9
d878b86
54a9339
b8f096f
2405d68
5db36c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { PolygonIcon } from "@/assets/icon"; | ||
|
|
||
| interface RecentLoginDialogProps { | ||
| className?: string; | ||
| } | ||
|
|
||
| export function RecentLoginDialog({ className = "" }: RecentLoginDialogProps) { | ||
| return ( | ||
| <div className={`flex flex-col items-center self-center ${className}`}> | ||
| <div className="bg-neutral-0 rounded-lg px-2 py-1.25 text-xs font-semibold text-orange-500"> | ||
| 최근에 로그인 했어요 | ||
| </div> | ||
| <PolygonIcon className="-mt-0.5 h-2.5 w-2.5" /> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| // 서버 ErrorCode: 인증번호 발송 시 이미 가입된 전화번호 | ||
| export const PHONE_ALREADY_REGISTERED_CODE = "MEMBER_412"; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||
| import { AppleButton, KakaoButton } from "@/components/auth"; | ||||||
| import { AppleButton, KakaoButton, RecentLoginDialog } from "@/components/auth"; | ||||||
| import { CTA_Button, Press } from "@/components/common"; | ||||||
| import { Link, useNavigate, useSearchParams } from "react-router"; | ||||||
| import { useEffect, useMemo, useState } from "react"; | ||||||
|
|
@@ -9,6 +9,10 @@ import { Capacitor3KakaoLogin } from "capacitor3-kakao-login"; | |||||
| import { isNativeApp } from "@/utils/auth/envUtils"; | ||||||
| import { isAndroidApp } from "@/utils/platform"; | ||||||
| import { oauth } from "@/apis/auth"; | ||||||
| import { | ||||||
| getRecentLoginProvider, | ||||||
| setRecentLoginProvider, | ||||||
| } from "@/utils/auth/recentLoginProvider"; | ||||||
| import { tokenStorage } from "@/utils/tokenStorage"; | ||||||
| import { consumeRedirectAfterLogin } from "../demoDay/redirectAfterLogin"; | ||||||
| import { SplashScreen } from "@capacitor/splash-screen"; // 앱 초기 스플래시 제어용 | ||||||
|
|
@@ -34,6 +38,9 @@ export function LoginPage() { | |||||
| const [authCheckStatus, setAuthCheckStatus] = | ||||||
| useState<AuthCheckStatus>("pending"); | ||||||
|
|
||||||
| // 최근에 로그인했던 SNS (버튼 위 안내용) | ||||||
| const [recentLoginProvider] = useState(() => getRecentLoginProvider()); | ||||||
|
|
||||||
| // 앱 실행 시 네이티브 스플래시 숨김 & 백그라운드 토큰 검사 | ||||||
| useEffect(() => { | ||||||
| // 앱인 경우 기본 제공되는 스플래시를 즉시 가리고 리액트 애니메이션 띄우기 | ||||||
|
|
@@ -155,6 +162,8 @@ export function LoginPage() { | |||||
|
|
||||||
| const data = response.data; | ||||||
|
|
||||||
| setRecentLoginProvider("KAKAO"); | ||||||
|
|
||||||
| if ("isNewMember" in data && data.isNewMember === true) { | ||||||
| await tokenStorage.setTokens({ | ||||||
| accessToken: null, | ||||||
|
|
@@ -240,7 +249,7 @@ export function LoginPage() { | |||||
| > | ||||||
| <CTA_Button | ||||||
| text="홈으로" | ||||||
| link="/mainpage" | ||||||
| onClick={() => navigate("/mainpage", { replace: true })} | ||||||
| color="orange" | ||||||
| size="compact" | ||||||
| /> | ||||||
|
|
@@ -259,9 +268,29 @@ export function LoginPage() { | |||||
| key={ui.footerKey} | ||||||
| className={`mx-auto max-w-sm ${ui.footerAnim}`} | ||||||
| > | ||||||
| <div className="flex flex-col gap-2"> | ||||||
| {!isAndroidApp() && ( | ||||||
| <AppleButton onClick={apple.login} disabled={apple.isPending} /> | ||||||
| <div className="flex flex-col gap-3"> | ||||||
| {recentLoginProvider === "APPLE" && !isAndroidApp() && ( | ||||||
| <RecentLoginDialog /> | ||||||
| )} | ||||||
| <div | ||||||
| className={ | ||||||
| recentLoginProvider === "KAKAO" && !isAndroidApp() | ||||||
| ? "relative" | ||||||
| : undefined | ||||||
| } | ||||||
| > | ||||||
| {!isAndroidApp() && ( | ||||||
| <AppleButton | ||||||
| onClick={apple.login} | ||||||
| disabled={apple.isPending} | ||||||
| /> | ||||||
| )} | ||||||
| {recentLoginProvider === "KAKAO" && !isAndroidApp() && ( | ||||||
| <RecentLoginDialog className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/4" /> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Major] 말풍선은 겹침 계산: 말풍선 높이 34px( 재현: iOS 앱 또는 모바일 웹에서 정적 외형은 그대로 두고 히트 테스트만 통과시키면 됩니다.
Suggested change
Generated by Claude Code
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기획에 의해 의도한 것임. |
||||||
| )} | ||||||
| </div> | ||||||
| {recentLoginProvider === "KAKAO" && isAndroidApp() && ( | ||||||
| <RecentLoginDialog /> | ||||||
| )} | ||||||
| <KakaoButton onClick={handleKakaoLogin} /> | ||||||
| </div> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import type { SocialProvider } from "@/types/auth"; | ||
|
|
||
| const RECENT_LOGIN_PROVIDER_KEY = "finders:recentLoginProvider"; | ||
|
|
||
| // 로그아웃과 무관하게 남아야 해서 useAuthStore(persist)와 분리된 별도 키로 관리 | ||
| export function setRecentLoginProvider(provider: SocialProvider) { | ||
| try { | ||
| localStorage.setItem(RECENT_LOGIN_PROVIDER_KEY, provider); | ||
| } catch (e) { | ||
| console.error("최근 로그인 정보 저장에 실패했습니다.", e); | ||
| } | ||
| } | ||
|
|
||
| export function getRecentLoginProvider(): SocialProvider | null { | ||
| try { | ||
| const value = localStorage.getItem(RECENT_LOGIN_PROVIDER_KEY); | ||
| return value === "KAKAO" || value === "APPLE" ? value : null; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.