PageSourceSearch

https://sjbnews.com/reader/login.php?redirect=%2Freader%2Fpdf_newspaper.php

html sjbnews.com collected 2026-10-02 17:35:09 UTC 47,016 bytes, 820 lines download raw bytes

1<!DOCTYPE html>
2<html lang="ko">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>독자 로그인/회원가입 - 새전북신문</title>
7    
7<script src="https://t1.kakaocdn.net/kakao_js_sdk/2.7.2/kakao.min.js"></script>
7
8    <style>
9        * { margin: 0; padding: 0; box-sizing: border-box; }
10        body {
11            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans KR', sans-serif;
12            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
13            min-height: 100vh;
14            padding: 2rem;
15            display: flex;
16            align-items: center;
17            justify-content: center;
18        }
19        .container {
20            max-width: 600px;
21            width: 100%;
22            background: white;
23            border-radius: 16px;
24            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
25            overflow: hidden;
26        }
27        .header {
28            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29            color: white;
30            padding: 2.5rem 2rem;
31            text-align: center;
32        }
33        .header h1 { font-size: 2rem; margin-bottom: 0.5rem; }
34        .header p { opacity: 0.9; font-size: 1rem; }
35        .content { padding: 2.5rem 2rem; }
36        .kakao-login-section { text-align: center; margin-bottom: 2rem; }
37        .kakao-login-btn {
38            background: #FEE500;
39            color: #000000 !important;
40            border: none;
41            padding: 1rem 2rem;
42            border-radius: 12px;
43            font-size: 1.1rem;
44            font-weight: 600;
45            cursor: pointer;
46            display: inline-flex;
47            align-items: center;
48            gap: 0.75rem;
49            transition: all 0.3s;
50            box-shadow: 0 4px 12px rgba(254, 229, 0, 0.3);
51        }
52        .kakao-login-btn:hover {
53            transform: translateY(-2px);
54            box-shadow: 0 6px 20px rgba(254, 229, 0, 0.4);
55        }
56        .kakao-logo { width: 24px; height: 24px; }
57        .form-section { display: none; }
58        .form-section.active { display: block; }
59        .form-group { margin-bottom: 1.5rem; }
60        .form-group label {
61            display: block;
62            margin-bottom: 0.5rem;
63            font-weight: 600;
64            color: #333;
65        }
66        .form-group input, .form-group select {
67            width: 100%;
68            padding: 0.75rem;
69            border: 2px solid #e0e0e0;
70            border-radius: 8px;
71            font-size: 1rem;
72            transition: border-color 0.3s;
73        }
74        .form-group input:focus, .form-group select:focus {
75            outline: none;
76            border-color: #667eea;
77        }
78        .checkbox-group { display: flex; flex-wrap: wrap; gap: 0.75rem; }
79        .checkbox-item { display: flex; align-items: center; gap: 0.5rem; }
80        .checkbox-item input[type="checkbox"] { width: auto; }
81        .btn {
82            padding: 0.75rem 1.5rem;
83            border: none;
84            border-radius: 8px;
85            font-size: 1rem;
86            font-weight: 600;
87            cursor: pointer;
88            transition: all 0.3s;
89        }
90        .btn-primary { background: #667eea; color: white; }
91        .btn-primary:hover {
92            background: #5568d3;
93            transform: translateY(-2px);
94            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
95        }
96        .btn-secondary { background: #6c757d; color: white; }
97        .btn-secondary:hover { background: #5a6268; }
98        .form-actions {
99            display: flex;
100            gap: 1rem;
101            justify-content: flex-end;
102            margin-top: 2rem;
103            padding-top: 1.5rem;
104            border-top: 2px solid #f0f0f0;
105        }
106        .alert { padding: 1rem; border-radius: 8px; margin-bottom: 1.5rem; }
107        .alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
108        .alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
109        .alert-info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
110        .login-tabs { display: flex; border-bottom: 2px solid #e0e0e0; margin-bottom: 2rem; }
111        .tab-btn {
112            flex: 1; padding: 0.85rem; border: none; background: none;
113            font-size: 1rem; font-weight: 600; cursor: pointer; color: #999;
114            border-bottom: 3px solid transparent; margin-bottom: -2px; transition: all 0.3s;
115        }
116        .tab-btn.active { color: #667eea; border-bottom-color: #667eea; }
117        .tab-btn:hover { color: #667eea; }
118        .tab-panel { display: none; }
119        .tab-panel.active { display: block; }
120        .divider { text-align: center; color: #999; margin: 1.5rem 0; font-size: 0.9rem; }
121        .link-btn { background: none; border: none; color: #667eea; font-size: 0.95rem; cursor: pointer; text-decoration: underline; }
122        .user-info {
123            background: #f8f9fa;
124            padding: 1.5rem;
125            border-radius: 8px;
126            margin-bottom: 2rem;
127        }
128        .user-info h3 { margin-bottom: 1rem; color: #667eea; }
129        .user-info p { margin-bottom: 0.5rem; color: #666; }
130        @media (max-width: 768px) {
131            body { padding: 1rem; }
132            .content { padding: 1.5rem; }
133            .header h1 { font-size: 1.5rem; }
134        }
135    </style>
136</head>
137<body>
138    <div class="container">
139        <div class="header">
140            <h1>🎉 독자 로그인/회원가입</h1>
141            <p>카카오 또는 이메일로 로그인하세요</p>
142        </div>
143        
144        <div class="content">
145            <div id="alertContainer"></div>
146            
147            <!-- 메인 로그인 섹션 (탭) -->
148            <div id="mainLoginSection">
149                <div class="login-tabs">
150                    <button class="tab-btn active" id="tabBtnKakao" onclick="switchTab('kakao')">카카오 로그인</button>
151                    <button class="tab-btn" id="tabBtnEmail" onclick="switchTab('email')">이메일 로그인</button>
152                </div>
153                
154                <!-- 카카오 탭 -->
155                <div id="tab-kakao" class="tab-panel active">
156                    <div id="kakaoLoginSection" class="kakao-login-section">
157                        <div class="alert alert-info">
158                            <strong>📱 카카오 간편 로그인</strong><br>
159                            카카오 계정으로 간편하게 로그인하세요.<br>
160                            신규 회원은 자동으로 회원가입 페이지로 이동합니다.
161                        </div>
162                        <button type="button" class="kakao-login-btn" onclick="kakaoLogin()">
163                            <svg class="kakao-logo" viewBox="0 0 24 24" fill="currentColor">
164                                <path d="M12 3C6.5 3 2 6.6 2 11c0 2.8 1.9 5.3 4.7 6.7-.2.7-.6 2.5-.7 2.8 0 .3.1.3.3.2.2-.1 2.9-1.9 3.4-2.3.8.1 1.5.2 2.3.2 5.5 0 10-3.6 10-8S17.5 3 12 3z"/>
165                            </svg>
166                            카카오 로그인
167                        </button>
168                        <div style="margin-top: 2rem; text-align: center;">
169                            <a href="/" style="color: #667eea; text-decoration: none; font-weight: 600;">← 메인으로 돌아가기</a>
170                        </div>
171                    </div>
172                </div>
173                
174                <!-- 이메일 로그인 탭 -->
175                <div id="tab-email" class="tab-panel">
176                    <div class="alert alert-info" style="font-size:0.9rem;">
177                        <strong>📧 이메일 로그인 안내</strong><br>
178                        이메일로 처음 가입하시면 <strong>입력하신 이메일로 6자리 인증 코드</strong>가 발송됩니다.<br>
179                        발신 주소: <strong>[email protected]</strong><br>
180                        메일함(스팸함 포함)을 확인하여 인증을 완료해 주세요.
181                    </div>
182                    <div class="form-group">
183                        <label>이메일</label>
184                        <input type="email" id="emailLoginEmail" placeholder="[email protected]"
185                               onkeydown="if(event.key==='Enter') emailLogin()">
186                    </div>
187                    <div class="form-group">
188                        <label>비밀번호</label>
189                        <input type="password" id="emailLoginPassword" placeholder="비밀번호 입력"
190                               onkeydown="if(event.key==='Enter') emailLogin()">
191                    </div>
192                    <button type="button" class="btn btn-primary" style="width:100%; padding:1rem;" onclick="emailLogin()">
193                        로그인
194                    </button>
195                    <div class="divider">──────── 처음 방문하셨나요? ────────</div>
196                    <div style="text-align:center;">
197                        <button class="link-btn" onclick="showEmailRegisterForm()">이메일로 회원가입</button>
198                    </div>
199                    <div style="margin-top: 1.5rem; text-align: center;">
200                        <a href="/" style="color: #667eea; text-decoration: none; font-weight: 600;">← 메인으로 돌아가기</a>
201                    </div>
202                </div>
203            </div>
204            
205            <!-- 회원정보 입력 섹션 -->
206            <div id="registerFormSection" class="form-section">
207                <div class="user-info" id="kakaoUserInfo"></div>
208                
209                <h2 style="margin-bottom: 1.5rem;">✏️ 회원 정보 입력</h2>
210                
211                <div class="form-group">
212                    <label>이름 <span style="color: #e74c3c;">*</span></label>
213                    <input type="text" id="name" placeholder="홍길동" required>
214                </div>
215                
216                <div class="form-group">
217                    <label>이메일 <span style="color: #e74c3c;">*</span></label>
218                    <input type="email" id="email" placeholder="[email protected]" required>
219                </div>
220                
221                <div class="form-group">
222                    <label>닉네임 <span style="color: #e74c3c;">*</span></label>
223                    <input type="text" id="nickname" placeholder="뉴스러버" required>
224                </div>
225                
226                <div class="form-group">
227                    <label>휴대폰 번호 <span style="color: #e74c3c;">*</span></label>
228                    <input type="tel" id="phone" placeholder="01012345678" maxlength="11" required>
229                    <small style="color: #666; display: block; margin-top: 0.5rem;">
230                        ⚠️ 카카오 계정의 휴대폰 번호와 다를 경우 회원가입이 제한될 수 있습니다.
231                    </small>
232                </div>
233                
234                <div class="form-group">
235                    <label>생년 (선택)</label>
236                    <input type="number" id="birthYear" placeholder="1990" min="1900" max="2024">
237                </div>
238                
239                <div class="form-group">
240                    <label>성별 (선택)</label>
241                    <select id="gender">
242                        <option value="">선택 안함</option>
243                        <option value="M">남성</option>
244                        <option value="F">여성</option>
245                    </select>
246                </div>
247                
248                <div class="form-group">
249                    <label>지역 (선택)</label>
250                    <select id="region">
251                        <option value="">선택하세요</option>
252                                                    <option value="전주">전주</option>
253                                                    <option value="익산">익산</option>
254                                                    <option value="군산">군산</option>
255                                                    <option value="남원">남원</option>
256                                                    <option value="정읍">정읍</option>
257                                                    <option value="김제">김제</option>
258                                                    <option value="완주">완주</option>
259                                                    <option value="임실">임실</option>
260                                                    <option value="무주">무주</option>
261                                                    <option value="진안">진안</option>
262                                                    <option value="장수">장수</option>
263                                                    <option value="ê³ ì°½">ê³ ì°½</option>
264                                                    <option value="부안">부안</option>
265                                                    <option value="순창">
265순창</option>
266                                            </select>
267                </div>
268                
269                <div class="form-group">
270                    <label>관심 카테고리 (선택)</label>
271                    <div class="checkbox-group">
272                                                    <div class="checkbox-item">
273                                <input type="checkbox" name="interests[]" value="지역" id="cat_지역">
274                                <label for="cat_지역" style="margin: 0; font-weight: normal;">지역</label>
275                            </div>
276                                                    <div class="checkbox-item">
277                                <input type="checkbox" name="interests[]" value="정치" id="cat_정치">
278                                <label for="cat_정치" style="margin: 0; font-weight: normal;">정치</label>
279                            </div>
280                                                    <div class="checkbox-item">
281                                <input type="checkbox" name="interests[]" value="경제" id="cat_경제">
282                                <label for="cat_경제" style="margin: 0; font-weight: normal;">경제</label>
283                            </div>
284                                                    <div class="checkbox-item">
285                                <input type="checkbox" name="interests[]" value="사회" id="cat_사회">
286                                <label for="cat_사회" style="margin: 0; font-weight: normal;">사회</label>
287                            </div>
288                                                    <div class="checkbox-item">
289                                <input type="checkbox" name="interests[]" value="문화" id="cat_문화">
290                                <label for="cat_문화" style="margin: 0; font-weight: normal;">문화</label>
291                            </div>
292                                                    <div class="checkbox-item">
293                                <input type="checkbox" name="interests[]" value="스포츠" id="cat_스포츠">
294                                <label for="cat_스포츠" style="margin: 0; font-weight: normal;">스포츠</label>
295                            </div>
296                                                    <div class="checkbox-item">
297                                <input type="checkbox" name="interests[]" value="교육" id="cat_교육">
298                                <label for="cat_교육" style="margin: 0; font-weight: normal;">교육</label>
299                            </div>
300                                                    <div class="checkbox-item">
301                                <input type="checkbox" name="interests[]" value="환경" id="cat_환경">
302                                <label for="cat_환경" style="margin: 0; font-weight: normal;">환경</label>
303                            </div>
304                                                    <div class="checkbox-item">
305                                <input type="checkbox" name="interests[]" value="과학" id="cat_과학">
306                                <label for="cat_과학" style="margin: 0; font-weight: normal;">과학</label>
307                            </div>
308                                                    <div class="checkbox-item">
309                                <input type="checkbox" name="interests[]" value="건강" id="cat_건강">
310                                <label for="cat_건강" style="margin: 0; font-weight: normal;">건강</label>
311                            </div>
312                                                    <div class="checkbox-item">
313                                <input type="checkbox" name="interests[]" value="연예" id="cat_연예">
314                                <label for="cat_연예" style="margin: 0; font-weight: normal;">연예</label>
315                            </div>
316                                            </div>
317                </div>
318                
319                <div class="form-group" style="margin-top: 2rem;">
320                    <div class="checkbox-item">
321                        <input type="checkbox" id="marketingAgree">
322                        <label for="marketingAgree" style="margin: 0; font-weight: normal;">
323                            마케팅 정보 수신에 동의합니다 (선택)
324                        </label>
325                    </div>
326                </div>
327                
328                <div class="form-actions">
329                    <button type="button" class="btn btn-secondary" onclick="location.href='/'">취소</button>
330                    <button type="button" class="btn btn-primary" onclick="submitRegistration()">가입 완료</button>
331                </div>
332            </div>
333            
334            <!-- 이메일 인증 코드 입력 섹션 -->
335            <div id="emailVerifySection" class="form-section">
336                <div style="text-align:center; margin-bottom:2rem;">
337                    <div style="font-size:3rem; margin-bottom:1rem;">📧</div>
338                    <h2 style="margin-bottom:0.5rem;">이메일 인증</h2>
339                    <p style="color:#666; font-size:0.95rem;">
340                        입력하신 이메일로 6자리 인증 코드를 발송했습니다.<br>
341                        발신 주소: <strong>[email protected]</strong><br>
342                        메일함(스팸함 포함)을 확인해 주세요.
343                    </p>
344                </div>
345                <input type="hidden" id="verifyMemberId" value="">
346                <div style="background:#f8f9fa; border-radius:8px; padding:0.85rem 1rem; margin-bottom:1.5rem; text-align:center; font-size:0.9rem; color:#555;">
347                    인증 코드 발송 주소: <strong id="verifyEmailDisplay" style="color:#667eea;"></strong>
348                </div>
349                <div class="form-group">
350                    <label style="text-align:center; display:block;">인증 코드 6자리</label>
351                    <input type="text" id="verifyCode" placeholder="000000" maxlength="6"
352                           style="text-align:center; font-size:1.8rem; letter-spacing:0.5rem; font-weight:bold;"
353                           onkeydown="if(event.key==='Enter') submitVerifyCode()"
354                           oninput="this.value=this.value.replace(/\D/g,'')">
355                </div>
356                <button type="button" class="btn btn-primary" style="width:100%; padding:1rem; margin-bottom:1rem;" onclick="submitVerifyCode()">
357                    인증 완료
358                </button>
359                <div style="text-align:center;">
360                    <button class="link-btn" onclick="resendVerification()">인증 코드 재발송</button>
361                    &nbsp;·&nbsp;
362                    <button class="link-btn" onclick="showEmailLoginTab()">로그인으로 돌아가기</button>
363                </div>
364            </div>
365            
366            <!-- 이메일 회원가입 섹션 -->
367            <div id="emailRegisterSection" class="form-section">
368                <h2 style="margin-bottom: 0.5rem;">✉️ 이메일 회원가입</h2>
369                <div class="alert alert-info" style="font-size:0.9rem; margin-bottom:1.5rem;">
370                    <strong>📬 이메일 인증 절차 안내</strong><br>
371                    가입 완료 후 입력하신 이메일 주소로 <strong>6자리 인증 코드</strong>가 자동 발송됩니다.<br>
372                    • 발신 주소: <strong>[email protected]</strong><br>
373                    • 인증 코드 유효시간: <strong>30분</strong><br>
374                    • 인증 완료 전까지는 로그인이 제한됩니다.<br>
375                    • 메일이 오지 않으면 <strong>스팸함</strong>을 확인해 주세요.
376                </div>
377                
378                <div class="form-group">
379                    <label>이름 <span style="color:#e74c3c;">*</span></label>
380                    <input type="text" id="erName" placeholder="홍길동" required>
381                </div>
382                <div class="form-group">
383                    <label>이메일 <span style="color:#e74c3c;">*</span></label>
384                    <input type="email" id="erEmail" placeholder="[email protected]" required>
385                </div>
386                <div class="form-group">
387                    <label>비밀번호 <span style="color:#e74c3c;">*</span></label>
388                    <input type="password" id="erPassword" placeholder="8자 이상 입력" required>
389                </div>
390                <div class="form-group">
391                    <label>비밀번호 확인 <span style="color:#e74c3c;">*</span></label>
392                    <input type="password" id="erPasswordConfirm" placeholder="비밀번호 재입력" required>
393                </div>
394                <div class="form-group">
395                    <label>닉네임 <span style="color:#e74c3c;">*</span></label>
396                    <input type="text" id="erNickname" placeholder="뉴스러버" required>
397                </div>
398                <div class="form-group">
399                    <label>휴대폰 번호 <span style="color:#e74c3c;">*</span></label>
400                    <input type="tel" id="erPhone" placeholder="01012345678" maxlength="11" required>
401                </div>
402                <div class="form-group">
403                    <label>생년 (선택)</label>
404                    <input type="number" id="erBirthYear" placeholder="1990" min="1900" max="2024">
405                </div>
406                <div class="form-group">
407                    <label>성별 (선택)</label>
408                    <select id="erGender">
409                        <option value="">선택 안함</option>
410                        <option value="M">남성</option>
411                        <option value="F">여성</option>
412                    </select>
413                </div>
414                <div class="form-group">
415                    <label>지역 (선택)</label>
416                    <select id="erRegion">
417                        <option value="">선택하세요</option>
418                                                    <option value="전주">전주</option>
419                                                    <option value="익산">익산</option>
420                                                    <option value="군산">군산</option>
421                                                    <option value="남원">남원</option>
422                                                    <option value="정읍">정읍</option>
423                                                    <option value="김제">김제</option>
424                                                    <option value="완주">완주</option>
425                                                    <option value="임실">임실</option>
426                                                    <option value="무주">무주</option>
427                                                    <option value="진안">진안</option>
428                                                    <option value="장수">장수</option>
429                                                    <option value="ê³ ì°½">ê³ ì°½</option>
430                                                    <option value="부안">부안</option>
431                                                    <option value="순창">
431순창</option>
432                                            </select>
433                </div>
434                <div class="form-group">
435                    <label>관심 카테고리 (선택)</label>
436                    <div class="checkbox-group">
437                                                    <div class="checkbox-item">
438                                <input type="checkbox" name="er_interests[]" value="지역" id="er_cat_지역">
439                                <label for="er_cat_지역" style="margin:0; font-weight:normal;">지역</label>
440                            </div>
441                                                    <div class="checkbox-item">
442                                <input type="checkbox" name="er_interests[]" value="정치" id="er_cat_정치">
443                                <label for="er_cat_정치" style="margin:0; font-weight:normal;">정치</label>
444                            </div>
445                                                    <div class="checkbox-item">
446                                <input type="checkbox" name="er_interests[]" value="경제" id="er_cat_경제">
447                                <label for="er_cat_경제" style="margin:0; font-weight:normal;">경제</label>
448                            </div>
449                                                    <div class="checkbox-item">
450                                <input type="checkbox" name="er_interests[]" value="사회" id="er_cat_사회">
451                                <label for="er_cat_사회" style="margin:0; font-weight:normal;">사회</label>
452                            </div>
453                                                    <div class="checkbox-item">
454                                <input type="checkbox" name="er_interests[]" value="문화" id="er_cat_문화">
455                                <label for="er_cat_문화" style="margin:0; font-weight:normal;">문화</label>
456                            </div>
457                                                    <div class="checkbox-item">
458                                <input type="checkbox" name="er_interests[]" value="스포츠" id="er_cat_스포츠">
459                                <label for="er_cat_스포츠" style="margin:0; font-weight:normal;">스포츠</label>
460                            </div>
461                                                    <div class="checkbox-item">
462                                <input type="checkbox" name="er_interests[]" value="교육" id="er_cat_교육">
463                                <label for="er_cat_교육" style="margin:0; font-weight:normal;">교육</label>
464                            </div>
465                                                    <div class="checkbox-item">
466                                <input type="checkbox" name="er_interests[]" value="환경" id="er_cat_환경">
467                                <label for="er_cat_환경" style="margin:0; font-weight:normal;">환경</label>
468                            </div>
469                                                    <div class="checkbox-item">
470                                <input type="checkbox" name="er_interests[]" value="과학" id="er_cat_과학">
471                                <label for="er_cat_과학" style="margin:0; font-weight:normal;">과학</label>
472                            </div>
473                                                    <div class="checkbox-item">
474                                <input type="checkbox" name="er_interests[]" value="건강" id="er_cat_건강">
475                                <label for="er_cat_건강" style="margin:0; font-weight:normal;">건강</label>
476                            </div>
477                                                    <div class="checkbox-item">
478                                <input type="checkbox" name="er_interests[]" value="연예" id="er_cat_연예">
479                                <label for="er_cat_연예" style="margin:0; font-weight:normal;">연예</label>
480                            </div>
481                                            </div>
482                </div>
483                <div class="form-group" style="margin-top:1rem;">
484                    <div class="checkbox-item">
485                        <input type="checkbox" id="erMarketingAgree">
486                        <label for="erMarketingAgree" style="margin:0; font-weight:normal;">마케팅 정보 수신에 동의합니다 (선택)</label>
487                    </div>
488                </div>
489                <div class="form-actions">
490                    <button type="button" class="btn btn-secondary" onclick="showEmailLoginTab()">← 로그인으로</button>
491                    <button type="button" class="btn btn-primary" onclick="submitEmailRegistration()">가입 완료</button>
492                </div>
493            </div>
494        </div>
495    </div>
496    
497    
497<script>
498        Kakao.init('dbf6b5259f59da50e2991f959fa4447e');
499        let kakaoUserData = null;
500        
501        // ── 탭 전환 ──
502        function switchTab(tab) {
503            document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
504            document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
505            document.getElementById('tabBtn' + tab.charAt(0).toUpperCase() + tab.slice(1)).classList.add('active');
506            document.getElementById('tab-' + tab).classList.add('active');
507        }
508        
509        // ── 이메일 로그인 ──
510        async function emailLogin() {
511            const email    = document.getElementById('emailLoginEmail').value.trim();
512            const password = document.getElementById('emailLoginPassword').value;
513            if (!email || !password) { showAlert('이메일과 비밀번호를 입력해주세요.', 'error'); return; }
514            
515            try {
516                const res = await fetch(window.location.href, {
517                    method: 'POST',
518                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
519                    body: new URLSearchParams({ ajax: '1', action: 'email_login', email, password })
520                });
521                const result = await res.json();
522                if (result.success) {
523                    showAlert(`${result.member.name}님 환영합니다!`, 'success');
524                    const redirectUrl = '/reader/pdf_newspaper.php';
525                    setTimeout(() => { location.href = redirectUrl; }, 1500);
526                } else if (!result.success && result.need_verify) {
527                    showAlert(result.message, 'error');
528                    const loginEmail = document.getElementById('emailLoginEmail').value.trim();
529                    setTimeout(() => showVerifySection(result.member_id, loginEmail), 800);
530                } else {
531                    showAlert(result.message, 'error');
532                }
533            } catch (e) {
534                showAlert('로그인 처리 중 오류가 발생했습니다.', 'error');
535            }
536        }
537        
538        // ── 이메일 회원가입 폼 표시 ──
539        function showEmailRegisterForm() {
540            document.getElementById('mainLoginSection').style.display = 'none';
541            document.getElementById('emailRegisterSection').classList.add('active');
542        }
543        
544        // ── 이메일 인증 화면 표시 ──
545        function showVerifySection(memberId, email) {
546            document.getElementById('mainLoginSection').style.display  = 'none';
547            document.getElementById('emailRegisterSection').classList.remove('active');
548            document.getElementById('verifyMemberId').value = memberId;
549            document.getElementById('verifyEmailDisplay').textContent = email || '';
550            document.getElementById('emailVerifySection').classList.add('active');
551            setTimeout(() => document.getElementById('verifyCode').focus(), 100);
552        }
553        
554        // ── 인증 코드 제출 ──
555        async function submitVerifyCode() {
556            const code     = document.getElementById('verifyCode').value.trim();
557            const memberId = document.getElementById('verifyMemberId').value;
558            if (code.length !== 6) { showAlert('6자리 인증 코드를 입력해주세요.', 'error'); return; }
559            
560            try {
561                const res = await fetch(window.location.href, {
562                    method: 'POST',
563                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
564                    body: new URLSearchParams({ ajax: '1', action: 'verify_email', member_id: memberId, code })
565                });
566                const result = await res.json();
567                if (result.success) {
568                    showAlert(result.message, 'success');
569                    const redirectUrl = '/reader/pdf_newspaper.php';
570                    setTimeout(() => { location.href = redirectUrl; }, 1500);
571                } else {
572                    showAlert(result.message, 'error');
573                }
574            } catch (e) {
575                showAlert('인증 처리 중 오류가 발생했습니다.', 'error');
576            }
577        }
578        
579        // ── 인증 코드 재발송 ──
580        async function resendVerification() {
581            const memberId = document.getElementById('verifyMemberId').value;
582            try {
583                const res = await fetch(window.location.href, {
584                    method: 'POST',
585                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
586                    body: new URLSearchParams({ ajax: '1', action: 'resend_verification', member_id: memberId })
587                });
588                const result = await res.json();
589                showAlert(result.message, result.success ? 'success' : 'error');
590            } catch (e) {
591                showAlert('재발송 중 오류가 발생했습니다.', 'error');
592            }
593        }
594        
595        // ── 이메일 로그인 탭으로 돌아가기 ──
596        function showEmailLoginTab() {
597            document.getElementById('emailRegisterSection').classList.remove('active');
598            document.getElementById('emailVerifySection').classList.remove('active');
599            document.getElementById('mainLoginSection').style.display = '';
600            switchTab('email');
601        }
602        
603        // ── 이메일 회원가입 제출 ──
604        async function submitEmailRegistration() {
605            const name            = document.getElementById('erName').value.trim();
606            const email           = document.getElementById('erEmail').value.trim();
607            const password        = document.getElementById('erPassword').value;
608            const passwordConfirm = document.getElementById('erPasswordConfirm').value;
609            const nickname        = document.getElementById('erNickname').value.trim();
610            const phone           = document.getElementById('erPhone').value.trim();
611            
612            if (!name)     { showAlert('이름을 입력해주세요.', 'error'); return; }
613            if (!email)    { showAlert('이메일을 입력해주세요.', 'error'); return; }
614            if (!password) { showAlert('비밀번호를 입력해주세요.', 'error'); return; }
615            if (password.length < 8) { showAlert('비밀번호는 8자 이상이어야 합니다.', 'error'); return; }
616            if (password !== passwordConfirm) { showAlert('비밀번호가 일치하지 않습니다.', 'error'); return; }
617            if (!nickname) { showAlert('닉네임을 입력해주세요.', 'error'); return; }
618            if (!phone)    { showAlert('휴대폰 번호를 입력해주세요.', 'error'); return; }
619            
620            if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { showAlert('올바른 이메일 형식을 입력해주세요.', 'error'); return; }
621            if (!/^01[0-9]{8,9}$/.test(phone)) { showAlert('올바른 휴대폰 번호를 입력해주세요. (예: 01012345678)', 'error'); return; }
622            
623            const interests = Array.from(document.querySelectorAll('input[name="er_interests[]"]:checked')).map(c => c.value);
624            
625            try {
626                const res = await fetch(window.location.href, {
627                    method: 'POST',
628                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
629                    body: new URLSearchParams({
630                        ajax: '1', action: 'email_register',
631                        name, email, password, nickname, phone,
632                        birth_year: document.getElementById('erBirthYear').value,
633                        gender:     document.getElementById('erGender').value,
634                        region:     document.getElementById('erRegion').value,
635                        interests:  JSON.stringify(interests),
636                        marketing_agree: document.getElementById('erMarketingAgree').checked ? '1' : '0'
637                    })
638                });
639                const result = await res.json();
640                if (result.success && result.need_verify) {
641                    showAlert(result.message, 'success');
642                    const regEmail = document.getElementById('erEmail').value.trim();
643                    setTimeout(() => showVerifySection(result.member_id, regEmail), 800);
644                } else if (result.success) {
645                    showAlert(result.message, 'success');
646                    const redirectUrl = '/reader/pdf_newspaper.php';
647                    setTimeout(() => { location.href = redirectUrl; }, 2000);
648                } else {
649                    showAlert(result.message, 'error');
650                }
651            } catch (e) {
652                showAlert('회원가입 중 오류가 발생했습니다.', 'error');
653            }
654        }
655        
656        function showAlert(message, type = 'info') {
657            const alertContainer = document.getElementById('alertContainer');
658            const alertClass = type === 'success' ? 'alert-success' : (type === 'error' ? 'alert-error' : 'alert-info');
659            alertContainer.innerHTML = `<div class="alert ${alertClass}">${message}</div>`;
660            setTimeout(() => { alertContainer.innerHTML = ''; }, 5000);
661        }
662        
663        function kakaoLogin() {
664            Kakao.Auth.authorize({
665                redirectUri: 'https://sjbnews.com/reader/kakao_callback.php'
666            });
667        }
668        
669        async function processKakaoLogin(userData) {
670            const kakaoAccount = userData.kakao_account || {};
671            const profile = kakaoAccount.profile || {};
672            
673            const formData = new URLSearchParams({
674                ajax: '1',
675                action: 'kakao_login',
676                kakao_id: userData.id,
677                kakao_email: kakaoAccount.email || '',
678                kakao_nickname: profile.nickname || ''
679            });
680            
681            try {
682                const response = await fetch(window.location.href, {
683                    method: 'POST',
684                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
685                    body: formData
686                });
687                
688                const result = await response.json();
689                
690                if (result.success) {
691                    if (result.is_new) {
692                        // 신규 회원 - 회원가입 폼 표시
693                        showRegisterForm(result.kakao_data);
694                    } else {
695                        // 기존 회원 - 로그인 완료
696                        showAlert(`${result.member.name}님 환영합니다!`, 'success');
697                        const redirectUrl = '/reader/pdf_newspaper.php';
698                        setTimeout(() => { location.href = redirectUrl; }, 1500);
699                    }
700                }
701            } catch (error) {
702                showAlert('로그인 처리 중 오류가 발생했습니다.', 'error');
703                console.error(error);
704            }
705        }
706        
707        function showRegisterForm(kakaoData) {
708            const userInfoHtml = `
709                <h3>✅ 신규 회원 가입</h3>
710                <p><strong>카카오 ID:</strong> ${kakaoData.kakao_id}</p>
711                ${kakaoData.kakao_nickname ? `<p><strong>카카오 닉네임:</strong> ${kakaoData.kakao_nickname} <span style="color: #999; font-size: 0.85rem;">(인증용)</span></p>` : ''}
712                ${kakaoData.kakao_email ? `<p><strong>카카오 이메일:</strong> ${kakaoData.kakao_email} <span style="color: #999; font-size: 0.85rem;">(인증용)</span></p>` : ''}
713                <p style="color: #666; font-size: 0.9rem; margin-top: 1rem;">
714                    ⚠️ 카카오 인증 정보는 별도 저장되며 수정할 수 없습니다.<br>
715                    아래 이메일과 닉네임은 수정 가능합니다.
716                </p>
717            `;
718            
719            // 이메일이 있으면 자동 입력
720            if (kakaoData.kakao_email) {
721                document.getElementById('email').value = kakaoData.kakao_email;
722            }
723            
724            // 닉네임이 있으면 자동 입력
725            if (kakaoData.kakao_nickname) {
726                document.getElementById('nickname').value = kakaoData.kakao_nickname;
727            }
728            
729            document.getElementById('kakaoUserInfo').innerHTML = userInfoHtml;
730            document.getElementById('kakaoLoginSection').style.display = 'none';
731            document.getElementById('registerFormSection').classList.add('active');
732        }
733        
734        async function submitRegistration() {
735            const kd = window._kakaoRegData || kakaoUserData;
736            if (!kd) {
737                showAlert('카카오 로그인이 필요합니다.', 'error');
738                return;
739            }
740            
741            const name = document.getElementById('name').value.trim();
742            const email = document.getElementById('email').value.trim();
743            const nickname = document.getElementById('nickname').value.trim();
744            const phone = document.getElementById('phone').value.trim();
745            
746            if (!name) { showAlert('이름을 입력해주세요.', 'error'); return; }
747            if (!email) { showAlert('이메일을 입력해주세요.', 'error'); return; }
748            if (!nickname) { showAlert('닉네임을 입력해주세요.', 'error'); return; }
749            if (!phone) { showAlert('휴대폰 번호를 입력해주세요.', 'error'); return; }
750            
751            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
752            if (!emailRegex.test(email)) {
753                showAlert('올바른 이메일 형식을 입력해주세요.', 'error');
754                return;
755            }
756            
757            const phoneRegex = /^01[0-9]{8,9}$/;
758            if (!phoneRegex.test(phone)) {
759                showAlert('올바른 휴대폰 번호를 입력해주세요. (예: 01012345678)', 'error');
760                return;
761            }
762            
763            const interests = Array.from(document.querySelectorAll('input[name="interests[]"]:checked'))
764                .map(cb => cb.value);
765            
766            // 리다이렉트 방식(_kakaoRegData) 및 팝업 방식(kakaoUserData) 모두 지원
767            const kakaoId    = kd.kakao_id    ?? kd.id ?? '';
768            const kakaoEmail = kd.kakao_email ?? (kd.kakao_account?.email ?? '');
769            const kakaoNick  = kd.kakao_nickname ?? (kd.kakao_account?.profile?.nickname ?? '');
770
771            const formData = new URLSearchParams({
772                ajax: '1',
773                action: 'register',
774                kakao_id: kakaoId,
775                kakao_email: kakaoEmail,
776                kakao_nickname: kakaoNick,
777                name: name,
778                email: email,
779                nickname: nickname,
780                phone: document.getElementById('phone').value,
781                birth_year: document.getElementById('birthYear').value,
782                gender: document.getElementById('gender').value,
783                region: document.getElementById('region').value,
784                interests: JSON.stringify(interests),
785                marketing_agree: document.getElementById('marketingAgree').checked ? '1' : '0'
786            });
787            
788            try {
789                const response = await fetch(window.location.href, {
790                    method: 'POST',
791                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
792                    body: formData
793                });
794                
795                const text = await response.text();
796                console.log('서버 응답:', text);
797                
798                try {
799                    const result = JSON.parse(text);
800                    if (result.success) {
801                        showAlert(result.message, 'success');
802                        const redirectUrl = '/reader/pdf_newspaper.php';
803                        setTimeout(() => { location.href = redirectUrl; }, 2000);
804                    } else {
805                        showAlert(result.message, 'error');
806                    }
807                } catch (parseError) {
808                    console.error('JSON 파싱 오류:', parseError);
809                    console.error('응답 내용:', text);
810                    showAlert('서버 응답 오류가 발생했습니다. 콘솔을 확인하세요.', 'error');
811                }
812            } catch (error) {
813                showAlert('회원가입 중 오류가 발생했습니다.', 'error');
814                console.error(error);
815            }
816        }
817
818            </script>
818
819</body>
820</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.