회원가입 폼에서 베타 사용자 6 명이 막힌 곳들 — 비밀번호 보기 토글, 휴대전화 자동 정리, 한글 입력 차단 — POP-SPOT v1.6 (+v1.6.1~v1.6.6)
베타 사용자 6 명이 회원가입에서 막힌 6 군데를 정리. 비밀번호 토글은 다음 동작 의미(토스/네이버 방식), 휴대전화 자동 정리, 한글 입력 차단, BirthSelect 통일. v1.6.1~v1.6.6 재손질 6 건 종합.
베타 사용자 6 명을 초대했고 6 명 전원이 회원가입 어딐가에서 막혀 알려주었다. 한 사람 한 사람 먹어 고치는 대신 6 군데를 한 번에 정리한 버전.
이 글에서 다루는 것
모르는 단어 한 줄로
| 용어 | 한 줄 설명 |
|---|---|
| CLS | Cumulative Layout Shift. 페이지 로드 중에 레이아웃이 이리저리 틀어지는 현상 |
| scrollbar-gutter | 스크롤바 자리를 미리 비워두는 CSS 속성. 설정하면 스크롤바 뜨고 지면서 화면이 떨리지 않음 |
| placeholder | 입력칸에 흐릿하게 뜨는 회색 안내 문구. 눈대중용 가이드 |
| BirthSelect | 이번에 만든 생년월일 용 공용 선택 컴포넌트 이름 |
무엇이 바뀌었나
| 항목 | v1.5.2 | v1.6 |
|---|---|---|
| 비밀번호 토글 | 눈 아이콘이 현재 상태 표시 → 헷갈림 | 다음 동작 의미 (눈=보기) → 토스·네이버 동일 |
| 이메일 입력 | 한글 입력하면 무시되는데 사용자는 당황 | 한글 키 자체를 막음 |
| 휴대전화 | "010-1234-5678" 붙여넣으면 검증 실패 | 하이픈·공백·괄호 자동 제거 |
| 생년월일 | 3 개 select 넓이·placeholder 제각각 | 공용 BirthSelect 로 통일 |
| 데스크탑 | 모바일 폭 그대로 → 1920px 좌우 공백 ★★★★ | md 이상 폭 조정 |
그 뒤로 따라붙은 v1.6.1~v1.6.6 재손질 6 건:
| 버전 | 재손질 |
|---|---|
| v1.6.1 | CLS 해결 — <code>scrollbar-gutter: stable</code> + 버튼 아이콘 순서 통일 |
| v1.6.2 | 메인의 지도·랭킹·캘린더·AI 4 영역을 각각 카드 블록화 |
| v1.6.3 | 호버/클릭 시각 피드백 (<code>scale-1.01</code> / <code>scale-0.99</code>) |
| v1.6.4 | "내 위치" 파란 핀 지도에 표시 — 메모리만 저장, 서버 전송 0 |
| v1.6.5 | Twitter 아이콘 → "X" 로고로 교체 (inline SVG) |
| v1.6.6 | 인트로 카피 회화체로 변경 — "매일 새로 열리는 팝업을 놓치지 마세요" |
왜 이렇게 했음
비밀번호 토글을 다음 동작 의미로 — 토스/네이버 결제 화면의 UX 패턴과 같이 둕. "눈 아이콘 = 눌러보면 보이게 됨" 으로 읽어야 사용자가 헷갈린다. 이전에는 "눈 아이콘 = 지금 보이는 상태" 로 둔 사람이 반 ("그럼 왜 명시 되어 있을까") 이고, 둕 장도의 웹을 쓰다 온 사람은 테스트 없이 그대로 토스 식으로 읽는다.
한글 입력 차단 — 이메일 캸은 ASCII 만 허용. 한글 키 입력을 자바스크립트로 좀 차단해서 "한글도 이메일로 되는 건 아닌가?" 의문 자체가 안 생기게 한다. 자바스크립트 입력 이벤트에서 이메일 패턴을 사전 검사.
휴대전화 자동 정리 — 사용자 입력 습관을 받아주는 게 더 안전한 방법이다. 010-1234-5678 도 01012345678 도 다 받아서 서버 쪽 경계에서 정규화했다.
v1.6.x 재손질 — "v1.6 한 번으로 끝임" 이 아니라 한 번 더 돌려보니 안 보이던 게 이제 보이는 패턴. CLS, 메인 카드 레이아웃, 호버 피드백, X 로고 교체, 인트로 말투 등.
코드로는 어떻게 (필요한 부분만)
비밀번호 토글 — "다음 동작" 을 보여주는 패턴.
파일: popspot-frontend/src/app/signup/page.tsx (회원가입 폼의 비밀번호 입력칸)
// v1.5.2 까지 — 아이콘이 "현재 상태" 를 직접 보여줌
const [show, setShow] = useState(false);
// ^^^^ ^^^^^^^ ^^^^^ 이메일/회원 입력 타입: 기본 가린 상태
// | +-- 토글 함수 — 상태 반전에만 쓰임
// +-- 현재 보이는지 안 보이는지 부울값
<input type={show ? 'text' : 'password'} />
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ show=true면 읽을 수 있는 텍스트, 아니면 마스킹
<button>{show ? <EyeOff/> : <Eye/>}</button>
// ^^^^^^^^ ^^^^^^^ 문제: show=true(보이는 중) → 임시 감춘 아이콘 표시
// ^^^^^^^^ 사용자: "이 모양을 눌러야 보이는 건가?" 와·괌핇
// ^^^^^^^^ 토스·네이버와 반대되는 UX 이용자의 직관파일: 같은 signup/page.tsx (v1.6 교체 후)
// v1.6 — 아이콘 의미를 "현재 상태" 에서 "눌러야 할 다음 동작" 으로 이동
<button aria-label={show ? '비밀번호 감추기' : '비밀번호 보기'}>
// ^^^^^^^^^^^^ 스크린리더 사용자용 텍스트
// — 아이콘만의 의미 전달을 보완하는 접근성 속성
{show ? <Eye/> : <EyeOff/>}
// ^^^^^^ ^^^^^^^^^^ 이제 처음: show=true 이면 "이미 보이고 있으니 눌러야 감추면 됨→ 눌아 튬구·지며 감추" 의미로 눌·이·콘
// ^^^^^^^ show=false 이면 "감추점 있으니 눌러야 보기" → 감축 아이콘
// 토스·네이버·구글 로그인 아래·대항공사 등 대부분의 풌덼조 웩의 표준
</button>휴대전화 입력 정리.
파일: popspot-frontend/src/lib/normalizePhone.ts + popspot-frontend/src/app/signup/page.tsx 에서 사용
// v1.6 — 휴대전화 입력 자동 정리
function normalizePhone(input: string) {
// ^^^^^^^^^^^^^ 사용자가 입력/붙여넣기한 원시 문자열
// 예: "010-1234-5678", "010 1234 5678", "(010)1234-5678"
return input.replace(/[^0-9]/g, '');
// ^^^^^^^ ^^^^^^^^ ^^^
// | | |
// | | +-- 빈 문자열로 교체 (단순 제거)
// | +-- /[^0-9]/g — 숫자가 아닌 모든 문자 (^ = 부정, g = 전역)
// +-- 변경 불가능 원본 유지 — 레퍼런스 이 결과로 교체되며 교체된 새 문자열 리턴
//
// 결과 예시:
// "010-1234-5678" → "01012345678"
// " 010 1234 5678 " → "01012345678"
// "(010)1234-5678" → "01012345678"
// "010-abcd-5678" → "0105678" … 이 경우는 길이 11자 검증 단계에서 걸러냄
}
// onChange 에서마다 정리해서 state 에 저장 — 이후 모든 검증·서버 전송은 이 값으로
// onChange={(e) => setPhone(normalizePhone(e.target.value))}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 입력 시점에 정규화 1회만
// state 에는 항상 숫자만 남은 형태로 저장됨이메일 캸 한글 차단.
// 한글 입력 모드 (IME) 로 입력 시작되면 거부
<input
onCompositionStart={(e) => e.preventDefault()}
onChange={(e) => setEmail(e.target.value.replace(/[ㄱ-힝]/g, ''))}
/>핵심 파일: popspot-frontend/src/app/signup/page.tsx
직접 보는 법
회원가입 페이지 (popspot.co.kr/signup) 을 열고 비밀번호 캸 우측 눈 버튼을 눌러보면 아이콘 의미가 토스 방식으로 바뀜 있음을 확인. 휴대전화 캸에 010-1234-5678 를 붙여넣으면 01012345678 로 자동 정리된다.