Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
3 changes: 2 additions & 1 deletion apps/web/src/features/auth/model/useKakaoCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useFlow } from '@/app/routes/stackflow';

import { postSocialLogin } from '@/features/auth/api/postSocialLogin';

import { getQueryParam } from '@/shared/lib/url';
import { useAuthStore } from '@/shared/store/auth';

export const useKakaoCode = () => {
Expand All @@ -15,7 +16,7 @@ export const useKakaoCode = () => {
const { replace } = useFlow();

useEffect(() => {
const code = new URLSearchParams(window.location.search).get('code');
const code = getQueryParam('code');

if (code) {
login(code);
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/pages/onboarding/ui/OnboardingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { OnboardingRoleSelect } from '@/widgets/onboarding/ui/OnboardingRoleSele
import { postCreateCrew } from '@/features/crew-create/api/postCreateCrew';
import { postJoinCrew } from '@/features/crew-join/api/postJoinCrew';

import { getQueryParam } from '@/shared/lib/url';
import { useFunnel } from '@/shared/lib/useFunnel';
import { AppLayout } from '@/shared/ui/layout';

Expand Down Expand Up @@ -46,6 +47,7 @@ type OnboardingState = {
export function OnboardingPage() {
const { replace } = useFlow();
const { Funnel } = useFunnel<StepName>('role-select', ONBOARDING_FLOW);
const defaultInviteCode = getQueryParam('inviteCode');

const [onboardingState, setOnboardingState] = useState<OnboardingState>(
() => {
Expand Down Expand Up @@ -144,6 +146,7 @@ export function OnboardingPage() {
name="enter-invite-code"
render={(context) => (
<OnboardingCrewJoin
defaultValue={defaultInviteCode}
onNext={async (inviteCode, crewId) => {
const response = await postJoinCrew({
invitationCode: inviteCode,
Expand Down
12 changes: 12 additions & 0 deletions apps/web/src/shared/lib/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const getQueryParam = (
key: string,
search: string = window.location.search
): string | undefined => {
const value = new URLSearchParams(search).get(key);

if (!value) {
return undefined;
}

return value;
};
Comment on lines +1 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

새로 추가된 getQueryParam 유틸리티 함수의 안정성과 명확성을 높이기 위한 개선 제안입니다.

  1. window 객체 접근 시점: 함수 시그니처의 기본값으로 window.location.search를 사용하면, 코드가 서버사이드 렌더링(SSR) 등 브라우저가 아닌 환경에서 실행될 때 window 객체가 없어 에러가 발생할 수 있습니다. window 객체는 함수가 호출되는 시점에, 즉 함수 본문 내에서 접근하는 것이 더 안전합니다.

  2. 값 부재 시 처리 로직: URLSearchParams.get() 메서드는 파라미터가 없을 경우 null을 반환합니다. 현재 !value 조건문은 null 뿐만 아니라 값이 비어있는 파라미터(?key=)가 전달될 때의 결과인 빈 문자열('')까지 undefined로 처리하여, 의도치 않은 동작을 유발할 수 있습니다. null일 경우에만 undefined를 반환하도록 명확히 하는 것이 좋습니다.

아래 제안 코드는 이 두 가지를 모두 개선합니다.

Suggested change
export const getQueryParam = (
key: string,
search: string = window.location.search
): string | undefined => {
const value = new URLSearchParams(search).get(key);
if (!value) {
return undefined;
}
return value;
};
export const getQueryParam = (
key: string,
search?: string
): string | undefined => {
const searchString = search ?? window.location.search;
const value = new URLSearchParams(searchString).get(key);
// .get()은 파라미터가 없을 때 null을 반환합니다.
// null 병합 연산자(??)를 사용해 null일 경우 undefined를 반환하도록 합니다.
// 이 방식은 빈 문자열('')은 그대로 유지합니다.
return value ?? undefined;
};

4 changes: 2 additions & 2 deletions apps/web/src/widgets/onboarding/ui/OnboardingCrewJoin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export interface OnboardingCrewJoinProps {
const INVITE_CODE_LENGTH = 6;

export function OnboardingCrewJoin({
defaultValue,
defaultValue = '',
onNext,
onPrev,
}: OnboardingCrewJoinProps) {
const [hasValidationError, setHasValidationError] = useState(false);
const [inviteCode, setInviteCode] = useState(defaultValue ?? '');
const [inviteCode, setInviteCode] = useState(defaultValue);
const [crewInfo, setCrewInfo] = useState<CrewInfoResult | null>(null);
const isActive = inviteCode.length === INVITE_CODE_LENGTH;

Expand Down
Loading