refactor(outsourcing): 입력 스타일 상수화 + goNext 방어적 재검증

1. 반복되는 INPUT_STYLE 객체를 파일 상단 상수로 추출하여 5곳에서 재사용
   - textarea (단계③)
   - input[name] (단계④)
   - input[email] (단계④)
   - input[phone] (단계④)
   - button.prev (네비게이션)

2. goNext 함수 첫 줄에 방어적 재검증 추가
   - if (!stepValid(step)) return; 추가
   - step dependency 복원 (useCallback 의존성 배열)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 05:10:03 +09:00
parent 429780d65d
commit b4f57c85ec

View File

@@ -15,6 +15,12 @@ import { trackEvent } from '@/lib/gtag';
const KOR_TIGHT = { letterSpacing: '-0.02em' } as const; const KOR_TIGHT = { letterSpacing: '-0.02em' } as const;
const KOR_BODY = { letterSpacing: '-0.01em' } as const; const KOR_BODY = { letterSpacing: '-0.01em' } as const;
const INPUT_STYLE = {
background: 'var(--jsm-surface)',
border: '1px solid var(--jsm-line)',
color: 'var(--jsm-ink)',
} as const;
const PROJECT_TYPES = [ const PROJECT_TYPES = [
'웹 서비스', '웹 서비스',
'웹사이트', '웹사이트',
@@ -117,9 +123,10 @@ export default function OutsourcingRequestForm() {
}; };
const goNext = useCallback(() => { const goNext = useCallback(() => {
if (!stepValid(step)) return;
setError(''); setError('');
setStep((s) => Math.min(s + 1, STEPS.length)); setStep((s) => Math.min(s + 1, STEPS.length));
}, []); }, [step]);
const goPrev = useCallback(() => { const goPrev = useCallback(() => {
setError(''); setError('');
@@ -398,9 +405,7 @@ export default function OutsourcingRequestForm() {
placeholder="만들고 싶은 것, 참고 서비스, 현재 상황을 자유롭게 적어주세요. 기획이 정리되지 않았어도 괜찮습니다." placeholder="만들고 싶은 것, 참고 서비스, 현재 상황을 자유롭게 적어주세요. 기획이 정리되지 않았어도 괜찮습니다."
className="w-full px-3.5 py-3 rounded-lg text-sm leading-relaxed resize-none outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="w-full px-3.5 py-3 rounded-lg text-sm leading-relaxed resize-none outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={{
background: 'var(--jsm-surface)', ...INPUT_STYLE,
border: '1px solid var(--jsm-line)',
color: 'var(--jsm-ink)',
...KOR_BODY, ...KOR_BODY,
}} }}
/> />
@@ -450,11 +455,7 @@ export default function OutsourcingRequestForm() {
disabled={submitting} disabled={submitting}
placeholder="홍길동" placeholder="홍길동"
className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={INPUT_STYLE}
background: 'var(--jsm-surface)',
border: '1px solid var(--jsm-line)',
color: 'var(--jsm-ink)',
}}
/> />
</div> </div>
@@ -476,11 +477,7 @@ export default function OutsourcingRequestForm() {
disabled={submitting} disabled={submitting}
placeholder="example@email.com" placeholder="example@email.com"
className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={INPUT_STYLE}
background: 'var(--jsm-surface)',
border: '1px solid var(--jsm-line)',
color: 'var(--jsm-ink)',
}}
/> />
</div> </div>
@@ -501,11 +498,7 @@ export default function OutsourcingRequestForm() {
disabled={submitting} disabled={submitting}
placeholder="010-0000-0000 (선택)" placeholder="010-0000-0000 (선택)"
className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="w-full px-3.5 py-2.5 rounded-lg text-sm outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={INPUT_STYLE}
background: 'var(--jsm-surface)',
border: '1px solid var(--jsm-line)',
color: 'var(--jsm-ink)',
}}
/> />
</div> </div>
</div> </div>
@@ -537,9 +530,8 @@ export default function OutsourcingRequestForm() {
disabled={submitting} disabled={submitting}
className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-surface-alt)] disabled:opacity-50 disabled:cursor-not-allowed" className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-surface-alt)] disabled:opacity-50 disabled:cursor-not-allowed"
style={{ style={{
color: 'var(--jsm-ink)', ...INPUT_STYLE,
borderColor: 'var(--jsm-line)', borderColor: 'var(--jsm-line)',
background: 'var(--jsm-surface)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >