// Screens 4: 온보딩(로그인·회원가입·본인인증·학적증빙·프로필설정), 구독 결제, 쪽지함 const A4 = window.MajorAtoms; const D4 = window.MajorLinkData; const D4b = window.MajorLinkData2; const Lc4 = window.lucideReact || {}; const { useState: useS4, useEffect: useE4 } = React; const BORDER4 = '#E4E4E7'; const MUTE4 = '#475569'; const FAINT4 = '#94A3B8'; function FieldRow4({ label, children, hint }) { return (
{children} {hint &&
{hint}
}
); } function TextInput4(props) { return ( ); } function ChipBtn4({ on, children, onClick }) { return ( ); } function StepDots4({ steps, current }) { return (
{steps.map((s, i) => (
{i < current ? '✓' : i + 1} {s}
{i < steps.length - 1 &&
} ))}
); } // ============================== ScreenAuth ============================== function ScreenAuth({ device, animKey }) { const isM = device === 'mobile'; const [step, setStep] = useS4('login'); // login | signup | phone | school | role | skills | done const [form, setForm] = useS4({ email: '', pw: '', pw2: '', name: '김민준', school: '한양대학교', dept: '컴퓨터공학과' }); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const [carrier, setCarrier] = useS4('SKT'); const [phoneChecking, setPhoneChecking] = useS4(false); const [phoneDone, setPhoneDone] = useS4(false); const [status, setStatus] = useS4('재학생'); const [fileName, setFileName] = useS4(null); const [aiChecking, setAiChecking] = useS4(false); const [aiDone, setAiDone] = useS4(false); const ROLE_OPTS = ['개발자', '디자이너', '기획자', '마케터', '데이터']; const [roles, setRoles] = useS4(['개발자']); const toggleRole = (r) => setRoles(rs => rs.includes(r) ? rs.filter(x => x !== r) : [...rs, r]); const [skills, setSkills] = useS4(['React', 'TypeScript']); const [skillInput, setSkillInput] = useS4(''); const addSkill = () => { const v = skillInput.trim(); if (v && !skills.includes(v)) setSkills(s => [...s, v]); setSkillInput(''); }; const removeSkill = (s) => setSkills(list => list.filter(x => x !== s)); const startPhoneVerify = () => { setPhoneChecking(true); setTimeout(() => { setPhoneChecking(false); setPhoneDone(true); }, 1300); }; const startAiVerify = () => { setAiChecking(true); setTimeout(() => { setAiChecking(false); setAiDone(true); }, 1800); }; const STEP_ORDER = ['phone', 'school', 'role', 'skills']; const stepLabels = ['본인인증', '학적인증', '역할·기술', '완료']; const Shell = ({ children, wide }) => (
{children}
); if (step === 'login' || step === 'signup') { return (
{['login', 'signup'].map(k => ( ))}
{step === 'login' ? ( <> set('email', e.target.value)} /> set('pw', e.target.value)} />
또는
) : ( <> set('email', e.target.value)} />
set('pw', e.target.value)} /> set('pw2', e.target.value)} />
set('name', e.target.value)} />
set('school', e.target.value)} /> set('dept', e.target.value)} />
)}
); } return (
{step === 'phone' && ( <>
휴대폰 본인인증
중복 가입 방지를 위해 통신사 본인인증이 필요해요
🧪 지금은 가상 인증(데모)이에요 · 실제 통신사·PASS 연동은 별도 계약 후 붙입니다
{['SKT', 'KT', 'LG U+', '알뜰요금제'].map(c => setCarrier(c)}>{c})}
{!phoneDone ? ( ) : (
본인인증 완료 (가상)
)} )} {step === 'school' && ( <>
학적 증빙 서류 제출
전공 기반 매칭을 위해 재학·졸업 상태를 확인해요
{['재학생', '졸업예정자', '졸업생', '대학원생'].map(s => setStatus(s)}>{s})}
{!aiDone ? ( ) : (
🤖 AI 서류 검증 결과
✓ 발급기관 직인·서식 대조 완료
✓ 위변조 흔적 없음
✓ 이름·학교 일치 확인
제출 후 자동 확인됨 AI 인증완료
)} )} {step === 'role' && ( <>
어떤 역할로 참여하고 싶나요? (복수 선택)
{ROLE_OPTS.map(r => toggleRole(r)}>{r})}
)} {step === 'skills' && ( <>
기술 스택을 태그로 추가해보세요
{skills.map(s => ( {s} ))}
setSkillInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && addSkill()} />
)} {step === 'done' && (
🎉
환영해요, {form.name}님!
프로필 설정이 끝났어요. 이제 팀을 탐색해볼까요?
)}
); } // ============================== ScreenBilling ============================== function ScreenBilling({ device, animKey }) { const isM = device === 'mobile'; const pro = D4.PRICING.find(p => p.id === 'pro'); const [subscribed, setSubscribed] = useS4(false); const [paying, setPaying] = useS4(false); const [history, setHistory] = useS4([ { date: '2026.06.07', item: '개인 구독', amount: '1,990원', status: 'done' }, ]); const pay = () => { setPaying(true); setTimeout(() => { setPaying(false); setSubscribed(true); setHistory(h => [{ date: '2026.07.07', item: '개인 구독', amount: '1,990원', status: 'done' }, ...h]); }, 1400); }; return (
{!subscribed ? (
구독 결제
{pro.name}
{pro.items.join(' · ')}
{pro.price}
🔒 결제 정보는 안전하게 암호화됩니다 (데모 · 실제 PG 미연동)
) : (
개인 구독 · 활성
다음 결제일 2026-08-07
등록된 카드 · •••• 1234
결제 내역
{history.map((h, i) => (
{h.date} {h.item} {h.amount} 결제완료
))}
)}
); } // ============================== ScreenMessages ============================== function ScreenMessages({ device, animKey }) { const isM = device === 'mobile'; const [threads, setThreads] = useS4(() => D4b.MESSAGE_THREADS.map(t => ({ ...t, messages: [...t.messages] }))); const [activeId, setActiveId] = useS4(D4b.MESSAGE_THREADS[0].id); const [mobileView, setMobileView] = useS4('list'); // list | thread const [draft, setDraft] = useS4(''); const active = threads.find(t => t.id === activeId); const applicant = D4.APPLICANTS.find(a => a.id === active.applicantId); const project = D4.PROJECTS.find(p => p.id === active.projectId); const openThread = (id) => { setActiveId(id); setThreads(ts => ts.map(t => t.id === id ? { ...t, unread: false } : t)); if (isM) setMobileView('thread'); }; const send = () => { const v = draft.trim(); if (!v) return; setThreads(ts => ts.map(t => t.id === activeId ? { ...t, messages: [...t.messages, { from: 'me', text: v, time: '방금' }] } : t)); setDraft(''); }; const List = (
대화 검색
{threads.map(t => { const a = D4.APPLICANTS.find(x => x.id === t.applicantId); const p = D4.PROJECTS.find(x => x.id === t.projectId); const last = t.messages[t.messages.length - 1]; return (
openThread(t.id)} className="flex gap-2.5 px-3 py-2.5 cursor-pointer border-b" style={{ borderColor: '#F1F5F9', background: t.id === activeId && !isM ? '#EEF2FF' : 'transparent' }}>
{p.title} · {a.name}
{last.from === 'me' ? '나: ' : ''}{last.text}
{last.time} {t.unread && }
); })}
); const Pane = (
{isM && }
{applicant.name}
{project.title} · 지원자
💬 쪽지는 실시간 채팅이 아니에요 · 보통 24시간 안에 답장이 와요
{active.messages.map((m, i) => (
{m.text}
{m.time}
))}
setDraft(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} />
); return (
{isM ? (mobileView === 'list' ? List : Pane) : (<>{List}{Pane})}
); } window.MajorScreens4 = { ScreenAuth, ScreenBilling, ScreenMessages };