refactor : login 페이지 #241
Conversation
1. icon svg로 이동 2. 레거시 코드 제거 3. 리액트 쿼리 사용하도록 수정 4. 뷰 로직 분리작업
|
Caution Review failedThe pull request is closed. Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
src/utils/jwtUtils.ts (1)
75-81: 중복된 함수 제거 필요
getUserRoleFromJwtSync는 이제getUserRoleFromJwt로 대체되었으므로 제거해야 합니다. 반환 타입이string | null로 되어있어 새로운UserRole타입 시스템과 일치하지 않습니다.-// Zustand 기반 토큰 유틸리티 함수들 -export const getUserRoleFromJwtSync = (): string | null => { - const token = getAccessToken(); - if (!token) return null; - - const decoded = parseJwt(token); - return decoded?.role ?? null; -};
🧹 Nitpick comments (12)
src/app/mentor/_ui/MentorClient/_ui/MyMentorSection/index.tsx (1)
8-8: React Query 반환값(data) 구조 분해 적용: 사용성 정돈은 좋습니다
- useGetMyMentorProfile 훅의 반환을 data 별칭으로 받는 방식은 표준 패턴과 일치합니다.
- 다만 myMentorProfile가 undefined일 수 있으므로 MentorCard가 이를 온전히 처리하는지(스켈레톤/플레이스홀더) 확인을 권장합니다.
- 배열 렌더링이 아닌 단일 컴포넌트에 key를 부여하는 것은 불필요합니다. 제거하면 경고 가능성을 줄이고 의도를 명확히 할 수 있습니다.
다음과 같이 가벼운 정리도 고려해 보세요.
- <MentorCard key={myMentorProfile?.id} isMine mentor={myMentorProfile} /> + {/* 데이터 로딩/없음 처리 예시 */} + {myMentorProfile ? ( + <MentorCard isMine mentor={myMentorProfile} /> + ) : ( + <div className="h-24 rounded-md bg-gray-100 animate-pulse" /> + )}src/api/auth/client/usePostEmailAuth.ts (4)
8-16: 타입 네이밍 컨벤션 정리 제안
- Use 접두사는 일반적으로 훅에 쓰입니다. 응답/요청 타입에는 EmailSignInResponse, EmailSignInRequest처럼 도메인 기반 네이밍을 권장합니다.
- 파일 내 일관성을 유지하면 가독성과 자동완성 정확도가 개선됩니다.
-interface UsePostEmailSignInResponse { +interface EmailSignInResponse { accessToken: string; refreshToken: string; } -interface LoginRequest { +interface EmailSignInRequest { email: string; password: string; }
18-20: 요청/응답 제네릭과 함수 시그니처 일관성
- postEmailAuth의 요청/응답 타입을 위의 리네임과 맞춰 주면 타입 추론이 더 명확해집니다.
-const postEmailAuth = ({ email, password }: LoginRequest): Promise<AxiosResponse<UsePostEmailSignInResponse>> => +const postEmailAuth = ({ email, password }: EmailSignInRequest): Promise<AxiosResponse<EmailSignInResponse>> => publicAxiosInstance.post("/auth/email/sign-in", { email, password });
21-29: 에러 처리와 후속 액션(프로필 갱신/라우팅) 보강 제안
- onError에서 사용자 메시지(토스트/다이얼로그)와 로깅을 추가하면 UX가 좋아집니다.
- 로그인 직후 필요한 데이터(me/프로필 등)가 있다면 invalidateQueries나 prefetch를 통해 자연스러운 화면 전환을 유도하는 것도 좋습니다.
- 다른 로그인 훅(애플/카카오)과 정책을 맞춰, 성공 시 이동 경로나 후속 동작을 통일하면 유지보수성이 올라갑니다.
const usePostEmailAuth = () => { return useMutation({ mutationFn: postEmailAuth, onSuccess: (data) => { const { accessToken } = data.data; setAccessToken(accessToken); }, + onError: (error) => { + // TODO: 통합 에러 핸들링(토스트/로그)로 교체 + alert("이메일 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + }, }); };
8-29: 토큰 보관 전략과 refreshToken 처리 정책 정리 필요
- 서버가 refreshToken도 내려주고 있으나 현재는 accessToken만 저장하고 있습니다.
- 전반적인 토큰 수명/갱신 전략(메모리/로컬/쿠키, 자동 리프레시 주기, 재시도 정책)을 PR 범위에서 합의해 두는 것이 좋습니다.
- 특히 XSS 관점에서 토큰을 어디에 저장할지(메모리 vs localStorage vs httpOnly 쿠키)는 중요한 아키텍처 결정 포인트입니다.
원하시면 현재 앱 상태(Zustand/Interceptor/리프레시 엔드포인트)에 맞춘 토큰 전략 가이드를 정리해 드리겠습니다.
src/app/login/_hooks/useInputHandler.ts (2)
1-6: 타입 import 분리로 TS 정확도 향상
- React.ChangeEvent를 모듈에서 직접 참조하면 타입 임포트 누락 시 에러가 날 수 있습니다.
- import type으로 분리하면 번들 크기를 건드리지 않으면서 타입 안정성이 개선됩니다.
-import { useState } from "react"; +import { useState } from "react"; +import type { ChangeEvent } from "react";
12-20: 핸들러의 참조 안정성 및 미세 최적화
- handleEmailChange를 useCallback으로 감싸면 하위 메모 컴포넌트에 전달 시 불필요한 리렌더를 줄일 수 있습니다.
- 현재 로직은 간결하고 명확합니다. 필요 시에만 적용해도 좋습니다.
- const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const handleEmailChange = useCallback((e: ChangeEvent<HTMLInputElement>) => { const value = e.target.value.trim(); setShowPasswordField(value.length > 0); - }; + }, []);src/api/auth/client/usePostAppleAuth.ts (1)
37-55: 성공/실패 라우팅 UX 다듬기 및 로깅 보강
- 콜백 페이지에서의 네비게이션은 replace를 사용하면 히스토리에 콜백 URL이 남지 않아 뒤로 가기 UX가 개선됩니다.
- onError에서 console.error를 추가해 디버깅 가시성을 높이세요.
- refreshToken을 사용한다면 저장 정책을 통일(다른 소셜/이메일 로그인과 일관)하는 것이 좋습니다.
return useMutation({ mutationFn: postAppleAuth, onSuccess: (response) => { const { data } = response; if (data.isRegistered) { // 기존 회원일 시 - 토큰 저장하고 홈으로 이동 setAccessToken(data.accessToken); - router.push("/"); + router.replace("/"); } else { // 새로운 회원일 시 - 회원가입 페이지로 이동 - router.push(`/sign-up?token=${data.signUpToken}`); + router.replace(`/sign-up?token=${data.signUpToken}`); } }, onError: (error) => { - alert("애플 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); - router.push("/login"); + console.error("Apple auth 실패:", error); + alert("애플 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + router.replace("/login"); }, });public/svgs/auth/index.ts (1)
1-20: 아이콘 공개 API 추가: 네이밍/그룹 주석 미세 정리 제안
- IconEmailIcon은 ‘Icon’이 중복되어 약간冗長합니다. IconEmail 정도로 단순화하면 좋습니다.
- // Login page icons 주석은 해당 블록 상단에 배치하면 가독성이 올라갑니다. 기능상 문제는 없습니다.
-import IconEmailIcon from "./email-icon.svg"; +import IconEmail from "./email-icon.svg"; ... export { IconPrepare1, IconPrepare2, IconPrepare3, IconSignupProfileImage, IconKakaoLogo, IconAppleLogo, - IconEmailIcon, + IconEmail, }; -// Login page icons +// Login page icons기능 추가 자체는 깔끔합니다. 위 네이밍은 선택 사항입니다.
src/api/auth/client/usePostKakaoAuth.ts (1)
51-54: 사용자 경험 개선 제안
alert()대신 토스트 알림이나 에러 UI 컴포넌트를 사용하는 것이 더 나은 사용자 경험을 제공할 것 같습니다.- alert("카카오 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + // toast.error("카카오 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + // 또는 에러 상태를 저장하여 UI에서 표시 router.push("/login");src/app/login/LoginContent.tsx (2)
19-22: 비밀번호 보안 강화 제안최소 6자는 보안상 약할 수 있습니다. 다음을 고려해보세요:
- 최소 8자 이상으로 늘리기
- 대소문자, 숫자, 특수문자 포함 규칙 추가
- password: z.string().min(1, "비밀번호를 입력해주세요.").min(6, "비밀번호는 최소 6자 이상이어야 합니다."), + password: z.string() + .min(1, "비밀번호를 입력해주세요.") + .min(8, "비밀번호는 최소 8자 이상이어야 합니다.") + .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, "비밀번호는 대소문자와 숫자를 포함해야 합니다."),
47-51: 불필요한 Enter 키 핸들링 제거HTML 폼은 기본적으로 input 필드에서 Enter 키를 누르면 submit이 되므로,
handleKeyDown함수와onKeyDown속성은 불필요합니다.- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - if (e.key === "Enter") { - handleSubmit(onSubmit)(); - } - }; // input 필드에서도 onKeyDown 제거 {...register("email", { onChange: handleEmailChange, })} - onKeyDown={handleKeyDown} {...register("password")} - onKeyDown={handleKeyDown}Also applies to: 79-79, 94-94
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
public/svgs/auth/apple-logo.svgis excluded by!**/*.svgpublic/svgs/auth/email-icon.svgis excluded by!**/*.svgpublic/svgs/auth/kakao-logo.svgis excluded by!**/*.svg
📒 Files selected for processing (17)
public/svgs/auth/index.ts(1 hunks)src/api/auth/client/usePostAppleAuth.ts(1 hunks)src/api/auth/client/usePostEmailAuth.ts(1 hunks)src/api/auth/client/usePostKakaoAuth.ts(1 hunks)src/api/mentors/client/queryKey.ts(1 hunks)src/app/login/AppleLoginButton.tsx(0 hunks)src/app/login/EmailSignUpButton.tsx(0 hunks)src/app/login/KakaoLoginButton.tsx(0 hunks)src/app/login/LoginContent.tsx(2 hunks)src/app/login/_hooks/useInputHandler.ts(1 hunks)src/app/login/apple/callback/AppleLoginCallbackPage.tsx(1 hunks)src/app/login/kakao/callback/KakaoLoginCallbackPage.tsx(1 hunks)src/app/mentor/_ui/MentorClient/_hooks/useRouterHandler.ts(0 hunks)src/app/mentor/_ui/MentorClient/_ui/MyMentorSection/index.tsx(1 hunks)src/app/mentor/_ui/MentorClient/index.tsx(1 hunks)src/utils/authUtils.ts(2 hunks)src/utils/jwtUtils.ts(3 hunks)
💤 Files with no reviewable changes (4)
- src/app/mentor/_ui/MentorClient/_hooks/useRouterHandler.ts
- src/app/login/EmailSignUpButton.tsx
- src/app/login/AppleLoginButton.tsx
- src/app/login/KakaoLoginButton.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-06T06:19:56.705Z
Learnt from: manNomi
PR: solid-connection/solid-connect-web#235
File: src/app/mentor/_ui/MentorClient/_hooks/useRouterHandler.ts:16-17
Timestamp: 2025-08-06T06:19:56.705Z
Learning: manNomi는 useRouterHandler 훅에서 로그인 체크 및 리다이렉트 로직을 useEffect를 통해 관리하여 사이드 이펙트를 적절히 처리하고 있다.
Applied to files:
src/app/login/LoginContent.tsx
🧬 Code Graph Analysis (2)
src/app/mentor/_ui/MentorClient/index.tsx (1)
src/utils/jwtUtils.ts (1)
getUserRoleFromJwt(101-107)
src/utils/jwtUtils.ts (1)
src/lib/zustand/useTokenStore.ts (1)
getAccessToken(31-34)
🔇 Additional comments (5)
src/api/mentors/client/queryKey.ts (1)
1-8: QueryKeys 네이밍 변경 영향도 점검 완료
- 영향도 검토
rg를 통해queryKey및queryKeys패턴을 검색한 결과, 잔존 참조가 전혀 없습니다.- 조치 사항
- 추가 수정 불필요합니다.
src/app/login/kakao/callback/KakaoLoginCallbackPage.tsx (1)
10-24: 깔끔한 리팩토링입니다! 👍OAuth 콜백 처리를 전용 훅으로 위임한 것이 좋은 설계입니다. 코드가 훨씬 간결해지고 관심사 분리가 잘 되어있네요.
src/app/mentor/_ui/MentorClient/index.tsx (1)
10-11: 주석 처리된 코드 확인 필요멘토 관련 컴포넌트들이 주석 처리되어 있는데, 이는 의도적인 것인가요?
- 임시로 비활성화한 것이라면 TODO 주석을 추가해주세요
- 영구적으로 제거할 예정이라면 코드를 삭제해주세요
현재 멘토일 경우 빈 화면이 렌더링되는 것 같은데, 이것이 의도된 동작인지 확인 부탁드립니다.
Also applies to: 22-24
src/utils/jwtUtils.ts (1)
95-107: UserRole 변환 로직 잘 구현되었습니다! ✅PR 목표에 명시된 대로 사용자 역할 비교 로직이 upperCase를 사용하도록 표준화되었네요. 타입 안전성도 잘 보장됩니다.
src/app/login/LoginContent.tsx (1)
26-148: 전반적으로 훌륭한 리팩토링입니다! 🎉변경사항 요약:
- 폼 관리 개선: react-hook-form + zod로 견고한 폼 검증 구현
- 관심사 분리: 소셜 로그인 로직을 authUtils로 위임
- React Query 통합: 이메일 로그인에 mutation 패턴 적용
- UX 개선: 로딩 상태 표시 및 실시간 검증 메시지
코드가 훨씬 깔끔하고 유지보수하기 좋아졌네요!
| const { mutate: postAppleAuth } = usePostAppleAuth(); | ||
|
|
||
| useEffect(() => { | ||
| const code = searchParams?.get("code"); | ||
| if (code) { | ||
| sendCodeToBackend(code); | ||
| postAppleAuth({ code }); | ||
| } | ||
| }, [searchParams]); | ||
| }, [searchParams, postAppleAuth]); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
StrictMode 이중 실행 대비: 중복 요청 가드 추가 권장
-
- Next.js 개발 모드의 StrictMode에서 useEffect가 두 번 실행되어 동일 코드로 두 번 mutate될 수 있습니다.
-
- useRef 가드로 단 한 번만 요청을 보내도록 방지하면 안전합니다.
-import usePostAppleAuth from "@/api/auth/client/usePostAppleAuth";
+import usePostAppleAuth from "@/api/auth/client/usePostAppleAuth";
+import { useRef } from "react";
const AppleLoginCallbackPage = () => {
const searchParams = useSearchParams();
- const { mutate: postAppleAuth } = usePostAppleAuth();
+ const { mutate: postAppleAuth } = usePostAppleAuth();
+ const requestedRef = useRef(false);
useEffect(() => {
const code = searchParams?.get("code");
- if (code) {
- postAppleAuth({ code });
- }
- }, [searchParams, postAppleAuth]);
+ if (!code || requestedRef.current) return;
+ requestedRef.current = true;
+ postAppleAuth({ code });
+ }, [searchParams, postAppleAuth]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const { mutate: postAppleAuth } = usePostAppleAuth(); | |
| useEffect(() => { | |
| const code = searchParams?.get("code"); | |
| if (code) { | |
| sendCodeToBackend(code); | |
| postAppleAuth({ code }); | |
| } | |
| }, [searchParams]); | |
| }, [searchParams, postAppleAuth]); | |
| import usePostAppleAuth from "@/api/auth/client/usePostAppleAuth"; | |
| import { useRef } from "react"; | |
| const AppleLoginCallbackPage = () => { | |
| const searchParams = useSearchParams(); | |
| const { mutate: postAppleAuth } = usePostAppleAuth(); | |
| const requestedRef = useRef(false); | |
| useEffect(() => { | |
| const code = searchParams?.get("code"); | |
| if (!code || requestedRef.current) return; | |
| requestedRef.current = true; | |
| postAppleAuth({ code }); | |
| }, [searchParams, postAppleAuth]); | |
| // ...rest of component | |
| }; |
🤖 Prompt for AI Agents
In src/app/login/apple/callback/AppleLoginCallbackPage.tsx around lines 12 to
20, useEffect can run twice in Next.js StrictMode and cause duplicate
postAppleAuth calls; add a useRef boolean guard (e.g., hasSentRef) initialized
false, check it before calling postAppleAuth, set it to true immediately when
sending to prevent a second mutate, and leave it persistent across renders so
the request is only sent once for a given mount.
There was a problem hiding this comment.
개발모드를 위해서 ref를 삽입하는건 손해아닙니까?
There was a problem hiding this comment.
@manNomi 좋은 지적이십니다! 맞습니다, StrictMode는 개발 환경에서만 작동하므로 프로덕션을 위한 코드에 useRef 가드를 추가하는 것은 과도할 수 있습니다.
더 실용적인 대안들:
1. React Query의 기본 기능 활용
const { mutate: postAppleAuth, isPending } = usePostAppleAuth();
useEffect(() => {
const code = searchParams?.get("code");
if (code && !isPending) { // isPending으로 중복 방지
postAppleAuth({ code });
}
}, [searchParams, postAppleAuth, isPending]);2. 서버 측에서 idempotency 보장
- 동일한 Apple auth code로 중복 요청이 와도 서버에서 처리
- 이미 사용된 code는 거부하거나 동일한 토큰 반환
3. 개발 환경에서만 경고 표시
useEffect(() => {
const code = searchParams?.get("code");
if (code) {
if (process.env.NODE_ENV === 'development') {
console.log('Apple auth 요청:', code);
}
postAppleAuth({ code });
}
}, [searchParams, postAppleAuth]);실제로 Apple OAuth code는 일회용이므로 서버에서 이미 중복 요청을 거부할 가능성이 높습니다. 따라서 useRef 가드 없이 현재 코드를 유지하는 것이 더 간결하고 실용적일 수 있습니다.
| export const kakaoLogin = () => { | ||
| if (window.Kakao && window.Kakao.Auth) { | ||
| window.Kakao.Auth.authorize({ | ||
| redirectUri: `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`, | ||
| }); | ||
| } else { | ||
| alert("Kakao SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
kakaoLogin 안정성 보강 제안
-
- SSR 환경 가드를 추가해 window 접근 오류를 예방하세요.
-
- SDK 미로딩 시 alert 외에 재시도 유도 또는 로그 수집을 추가하면 문제 추적이 쉬워집니다.
-
- TypeScript에서 window.Kakao 타입 미정의라면 전역 선언을 추가해 any 누수를 줄이세요.
-export const kakaoLogin = () => {
- if (window.Kakao && window.Kakao.Auth) {
+export const kakaoLogin = () => {
+ if (typeof window === "undefined") {
+ return;
+ }
+ if (window.Kakao && window.Kakao.Auth) {
window.Kakao.Auth.authorize({
redirectUri: `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`,
});
} else {
alert("Kakao SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요.");
}
};추가: 전역 타입 선언 예시(별도 d.ts)
// global.d.ts
declare global {
interface Window {
Kakao?: { Auth?: { authorize: (opts: { redirectUri: string }) => void } };
}
}
export {};🤖 Prompt for AI Agents
In src/utils/authUtils.ts around lines 25 to 33, the kakaoLogin function
directly accesses window.Kakao (causing SSR/runtime errors), only shows an alert
on SDK missing (no retry or logging), and may leak any through undeclared window
types; fix by adding an SSR guard (return early if typeof window ===
"undefined"), check for window.Kakao and window.Kakao.Auth before calling
authorize, and when SDK is missing replace the bare alert with a retry mechanism
or a user-friendly prompt and emit a console.error/telemetry event for
diagnostics; additionally add or reference a global.d.ts declaration for
Window.Kakao (as per the suggested shape) to avoid any type leaks and ensure
TypeScript knows Kakao.Auth.authorize signature.
There was a problem hiding this comment.
@manNomi, 네, 알겠습니다. 결정을 존중하겠습니다.
| export const appleLogin = async () => { | ||
| if (!window.AppleID || !window.AppleID.auth) { | ||
| alert("Apple SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); | ||
| return; | ||
| } | ||
|
|
||
| window.AppleID.auth.init({ | ||
| clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID, | ||
| scope: process.env.NEXT_PUBLIC_APPLE_SCOPE, | ||
| redirectURI: `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`, | ||
| usePopup: true, | ||
| }); | ||
|
|
||
| try { | ||
| const res: appleOAuth2CodeResponse = await window.AppleID.auth.signIn(); | ||
| if (res.authorization) { | ||
| window.location.href = `/login/apple/callback?code=${encodeURIComponent(res.authorization.code)}`; | ||
| } | ||
| } catch (error) { | ||
| console.log(error); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
appleLogin 초기화/예외 처리 강화와 명시 옵션 제안
-
- 환경변수 누락 시 초기화가 실패하므로 사전 검증을 권장합니다.
-
- response_type: "code"를 명시하면 의도가 분명해집니다.
-
- 에러는 console.error로 기록하고, 필요 시 location.replace로 히스토리 오염을 줄일 수 있습니다.
-
- SSR 가드 및 window.AppleID 타입 선언도 함께 권장드립니다.
export const appleLogin = async () => {
- if (!window.AppleID || !window.AppleID.auth) {
+ if (typeof window === "undefined" || !window.AppleID || !window.AppleID.auth) {
alert("Apple SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요.");
return;
}
+ const clientId = process.env.NEXT_PUBLIC_APPLE_CLIENT_ID;
+ const scope = process.env.NEXT_PUBLIC_APPLE_SCOPE;
+ const webUrl = process.env.NEXT_PUBLIC_WEB_URL;
+ if (!clientId || !scope || !webUrl) {
+ console.error("Apple OAuth 환경변수가 설정되지 않았습니다.");
+ alert("로그인 설정에 문제가 있습니다. 잠시 후 다시 시도해주세요.");
+ return;
+ }
+
window.AppleID.auth.init({
- clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID,
- scope: process.env.NEXT_PUBLIC_APPLE_SCOPE,
- redirectURI: `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`,
+ clientId,
+ scope,
+ redirectURI: `${webUrl}/login/apple/callback`,
+ response_type: "code",
usePopup: true,
});
try {
const res: appleOAuth2CodeResponse = await window.AppleID.auth.signIn();
if (res.authorization) {
- window.location.href = `/login/apple/callback?code=${encodeURIComponent(res.authorization.code)}`;
+ window.location.replace(`/login/apple/callback?code=${encodeURIComponent(res.authorization.code)}`);
}
} catch (error) {
- console.log(error);
+ console.error("Apple 로그인 오류:", error);
+ alert("애플 로그인 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.");
}
};전역 타입 선언 예시(별도 d.ts)
declare global {
interface Window {
AppleID?: {
auth?: {
init: (opts: { clientId: string; scope: string; redirectURI: string; response_type?: "code"; usePopup?: boolean }) => void;
signIn: () => Promise<{ authorization?: { code: string } }>;
};
};
}
}
export {};🤖 Prompt for AI Agents
In src/utils/authUtils.ts around lines 35 to 56, the appleLogin init lacks env
validation, explicit response_type, stronger error handling and SSR/type safety;
validate NEXT_PUBLIC_APPLE_CLIENT_ID, NEXT_PUBLIC_APPLE_SCOPE and
NEXT_PUBLIC_WEB_URL before calling window.AppleID.auth.init and bail with a
user-friendly alert if missing; include response_type: "code" in the init
options; replace console.log with console.error in the catch and use
location.replace for redirecting to /login/apple/callback to avoid history
pollution; add an SSR guard (if typeof window === "undefined" return) and add
the suggested global Window AppleID type declaration in a .d.ts file to make
types explicit.
There was a problem hiding this comment.
로그인 관련 로직은 기존의 요소에서 큰 변경사항을 만들지 않겠습니다
There was a problem hiding this comment.
@manNomi, 이해했습니다. 기존 로그인 로직을 안정적으로 유지하시는 방향으로 진행하시는 것이 좋겠네요. 제안드린 개선사항들은 추후 필요시 참고하실 수 있도록 남겨두겠습니다.
( ◡ _ ◡ )
✏️ Learnings added
Learnt from: manNomi
PR: solid-connection/solid-connect-web#241
File: src/utils/authUtils.ts:35-56
Timestamp: 2025-08-11T08:44:01.653Z
Learning: The user (manNomi) prefers to avoid making significant changes to existing login-related logic in the auth utilities to maintain stability and minimize risk.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
관련 이슈
작업 내용
getUserRoleFromJwt의 반환 타입을UserRole로 지정upperCase기반으로 통일authUtil내부 버그 수정특이 사항