index.unsigned.html
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" type="text/css"
th:href="@{/resources/stylesheets/common.css}">
<link rel="stylesheet" type="text/css"
th:href="@{/resources/stylesheets/index.unsigned.css}">
<script src="https://kit.fontawesome.com/0d51ab0f86.js" crossorigin="anonymous"></script>
<script defer th:src="@{/resources/scripts/index.unsigned.js}"></script>
<title>KakaoTalk</title>
</head>
<body class="unsigned">
<div class="cover"></div>
<div class="resolution">
<div class="exc">!</div>
<div class="message">화면 크기를 더 크게 조정 해주세요.</div>
</div>
<form class="login-form" rel="loginForm">
<div class="logo-container">
<img class="logo" alt="카카오톡" src="/resources/images/login-form.logo.png">
</div>
<div class="input-wrapper">
<label class="label">
<span hidden>이메일</span>
<input autofocus class="input" maxlength="50" name="email" placeholder="카카오계정 (이메일)" type="email">
</label>
<label class="label">
<span hidden>비밀번호</span>
<input maxlength="100" class="input" name="password" placeholder="비밀번호" type="password">
</label>
</div>
<input class="login-button" disabled type="submit" value="로그인">
<label class="auto-sign-container">
<input class="checkbox" name="autoSign" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">잠금모드로 자동로그인</span>
</label>
<ul class="menu">
<li class="item">
<a class="link" href="#" data-logic="register">카카오계정 만들기</a>
</li>
<li class="line"></li>
<li class="item">
<a class="link" href="#" data-logic="recover">비밀번호 재설정</a>
</li>
</ul>
</form>
<form class="register-form visible" rel="registerForm">
<div class="progress" rel="progress">
<div class="value" rel="value"></div>
</div>
<div class="step-container">
<div class="step terms visible">
<span class="title">카카오계정<br>서비스 약관에 동의해 주세요.</span>
<label class="check-label">
<input class="checkbox" name="terms-agree-all" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">모두 동의합니다.</span>
</label>
<span class="all-warning">전체 동의는 필수 및 선택정보에 대한 동의도 포함되어 있으며, 개별적으로도 동의를 선택하실 수 있습니다.<br>선택항목에 대한 동의를 거부하시는 경우에도 서비스는 이용이 가능합니다.</span>
<label class="check-label">
<input class="checkbox" name="terms-no-kid" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">만 14세 이상입니다.</span>
</label>
<label class="check-label">
<input class="checkbox" name="terms-term" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">[필수] 카카오계정 약관</span>
</label>
<label class="check-label">
<input class="checkbox" name="terms-privacy" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">[필수] 개인정보 수집 및 이용 동의</span>
</label>
<label class="check-label">
<input class="checkbox" name="terms-profile" type="checkbox">
<span class="checker">
<i class="icon fa-solid fa-check"></i>
</span>
<span class="text">[선택] 프로필정보 추가 수집 동의</span>
</label>
<input class="button" disabled type="button" rel="termsNext" value="동의">
</div>
<div class="step email">
<span class="title">카카오계정으로 사용할<br>이메일 주소를 입력해 주세요.</span>
<label class="email-input-container">
<input class="email-input" maxlength="50" name="email" placeholder="이메일 주소 입력" type="email">
<input class="code-request-button" disabled name="emailCodeRequestButton" type="button" value="인증요청">
<span class="warning">카카오계정 이메일을 입력해 주세요.</span>
</label>
<label class="code-input-container">
<input class="code-input" maxlength="6" name="emailCode" placeholder="인증번호 입력" type="text">
<input class="code-verify-button" disabled name="emailCodeVerifyButton" type="button" value="인증">
<span class="warning">인증번호를 입력해 주세요.</span>
</label>
<ul class="info">
<li>입력한 이메일 주소로 인증번호가 발송됩니다.</li>
<li>인증메일을 받을 수 있도록 자주 쓰는 이메일 주소를 입력해 주세요.</li>
</ul>
<input class="button" disabled name="emailNext" type="button" rel="emailNext" value="다음">
</div>
</div>
</form>
</body>
</html>
common.css
@charset "UTF-8";
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard-dynamic-subset.css');
:root {
--common-color-brown-7: 80, 50, 50;
--common-color-brown-6: 70, 40, 40;
--common-color-brown-5: 60, 30, 30;
--common-color-brown-4: 50, 20, 20;
--common-color-brown-3: 40, 10, 10;
--common-color-yellow-5: 254, 229, 0;
--common-color-yellow-4: 244, 219, 0;
--common-color-yellow-3: 234, 209, 0;
--common-text-color-5: 24, 22, 0;
--common-text-color-6: 44, 42, 0;
--common-text-color-7: 64, 62, 0;
--common-text-color-8: 84, 82, 0;
--common-text-color-9: 104, 102, 0;
}
html {
color: rgb(var(--common-text-color-5));
font-family: 'Pretendard', sans-serif;
font-size: 1rem;
font-weight: 400;
}
body {
margin: unset;
}
input {
width: 100%;
background-color: unset;
border: unset;
border-image: unset;
color: unset;
font: unset;
outline: none;
}
ol, ul {
list-style-type: none;
margin-block: unset;
margin-inline: unset;
padding-inline: unset;
}
index.unsigned.css
@charset "UTF-8";
body.unsigned {
width: 100%;
height: 100%;
background-color: rgb(var(--common-color-yellow-5));
position: absolute;
}
body.unsigned > .cover {
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 50%);
position: fixed;
}
body.unsigned > .resolution {
top: 0;
left: 0;
width: 100%;
height: 100%;
align-items: center;
background-color: rgb(var(--common-color-yellow-5));
display: none;
flex-direction: column;
justify-content: center;
position: fixed;
z-index: 2;
}
body.unsigned > .resolution > .exc {
color: rgb(var(--common-color-brown-5));
cursor: default;
font-size: 5rem;
margin-bottom: 1rem;
user-select: none;
}
body.unsigned > .login-form {
top: 50%;
left: 50%;
width: 25rem;
align-items: stretch;
background-color: rgb(var(--common-color-yellow-5));
border: 0.0625rem solid rgba(var(--common-color-yellow-5), 90%);
border-radius: 0.25rem;
box-shadow: 0 0 0.5rem 0.0625rem rgba(50, 50, 50, 50%);
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: flex-start;
opacity: 0;
padding: 5rem 2.75rem;
pointer-events: none;
position: fixed;
transform: translate(-50%, -50%);
z-index: 1;
}
body.unsigned > .login-form.visible {
opacity: 1;
pointer-events: all;
}
body.unsigned > .login-form > .logo-container {
align-items: center;
display: flex;
flex-direction: row;
justify-content: center;
margin-bottom: 3rem;
}
body.unsigned > .login-form > .logo-container > .logo {
width: 7.5rem;
user-select: none;
-webkit-user-drag: none;
}
body.unsigned > .login-form > .input-wrapper {
align-items: stretch;
background-color: rgb(255, 255, 255);
border: 0.0625rem solid rgb(var(--common-color-yellow-4));
border-radius: 0.25rem;
display: flex;
flex-grow: 0;
flex-shrink: 0;
flex-direction: column;
justify-content: flex-start;
margin-bottom: 0.45rem;
overflow: hidden;
}
body.unsigned > .login-form > .input-wrapper > .label {
align-items: stretch;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
body.unsigned > .login-form > .input-wrapper > .label:not(:last-of-type) {
border-bottom: 0.0625rem solid rgb(225, 225, 225);
}
body.unsigned > .login-form > .input-wrapper > .label > .input {
background-color: rgb(255, 255, 255);
padding: 0.7rem 1rem;
}
body.unsigned > .login-form > .login-button {
background-color: rgb(var(--common-color-brown-5));
border: 0.0625rem solid rgb(var(--common-color-yellow-4));
border-radius: 0.25rem;
color: rgb(255, 255, 255);
cursor: pointer;
margin-bottom: 0.4rem;
padding: 0.7rem 0;
}
body.unsigned > .login-form > .login-button:hover {
background-color: rgb(var(--common-color-brown-6));
}
body.unsigned > .login-form > .login-button:active {
background-color: rgb(var(--common-color-brown-4));
}
body.unsigned > .login-form > .login-button:disabled {
background-color: rgb(246, 246, 246);
color: rgb(180, 180, 180);
cursor: default;
}
body.unsigned > .login-form > .auto-sign-container {
align-items: center;
color: rgb(var(--common-text-color-9));
cursor: pointer;
display: flex;
flex-direction: row;
font-size: 0.9rem;
justify-content: flex-start;
user-select: none;
}
body.unsigned > .login-form > .auto-sign-container > .checkbox {
display: none;
}
body.unsigned > .login-form > .auto-sign-container > .checker {
width: 1rem;
height: 1rem;
background-color: rgb(255, 255, 255);
border: 0.0625rem solid rgb(var(--common-color-yellow-4));
border-radius: 0.15rem;
margin-right: 0.5rem;
position: relative;
}
body.unsigned > .login-form > .auto-sign-container > .checker > .icon {
top: calc(50% + 0.0625rem);
left: 50%;
color: rgb(var(--common-color-brown-5));
display: none;
font-size: 0.8rem;
position: absolute;
transform: translate(-50%, -50%);
}
body.unsigned > .login-form > .auto-sign-container > .checkbox:checked + .checker > .icon {
display: inline-block;
}
body.unsigned > .login-form > .menu {
align-items: center;
display: flex;
flex-direction: row;
font-size: 0.9rem;
justify-content: center;
margin-top: 8rem;
}
body.unsigned > .login-form > .menu > .item > .link {
color: rgb(var(--common-text-color-9));
text-decoration: none;
}
body.unsigned > .login-form > .menu > .item > .link:hover {
text-decoration: underline;
}
body.unsigned > .login-form > .menu > .line {
height: 1rem;
border-right: 0.0625rem solid rgb(var(--common-color-yellow-4));
margin: 0 0.75rem;
}
body.unsigned > .register-form {
top: 50%;
left: 50%;
width: 25rem;
background-color: rgb(255, 255, 255);
border: 0.0625rem solid rgb(225, 225, 225);
border-radius: 0.25rem;
box-shadow: 0 0 0.5rem 0.0625rem rgba(50, 50, 50, 50%);
box-sizing: border-box;
opacity: 0;
padding: 2rem;
pointer-events: none;
position: fixed;
transform: translate(-50%, -50%);
z-index: 1;
}
body.unsigned > .register-form.visible {
opacity: 1;
pointer-events: all;
}
body.unsigned > .register-form > .progress {
width: 6.5rem;
height: 0.25rem;
background-color: rgb(225, 225, 225);
margin-bottom: 2rem;
position: relative;
}
body.unsigned > .register-form > .progress > .value {
top: 0;
left: 0;
width: 0;
height: 100%;
background-color: rgb(100, 100, 100);
position: absolute;
}
body.unsigned > .register-form > .step-container > .step {
align-items: stretch;
display: none;
flex-direction: column;
justify-content: flex-start;
}
body.unsigned > .register-form > .step-container > .step.visible {
display: flex;
}
body.unsigned > .register-form > .step-container > .step > .title {
font-size: 1.375rem;
font-weight: 500;
margin-bottom: 2rem;
}
body.unsigned > .register-form > .step-container > .step > .check-label {
align-items: center;
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: flex-start;
margin-bottom: 0.75rem;
user-select: none;
}
body.unsigned > .register-form > .step-container > .step > .check-label > .checkbox {
display: none;
}
body.unsigned > .register-form > .step-container > .step > .check-label > .checker {
width: 1.25rem;
height: 1.25rem;
border: 0.0625rem solid rgb(220, 220, 220);
border-radius: 50%;
margin-right: 0.625rem;
position: relative;
}
body.unsigned > .register-form > .step-container > .step > .check-label > .checkbox:checked + .checker {
background-color: rgb(var(--common-color-yellow-5));
border: 0.0625rem solid rgb(var(--common-color-yellow-5));
}
body.unsigned > .register-form > .step-container > .step > .check-label > .checker > .icon {
top: 50%;
left: 50%;
color: rgb(220, 220, 220);
font-size: 0.9rem;
position: absolute;
transform: translate(-50%, -50%);
}
body.unsigned > .register-form > .step-container > .step > .check-label > .checkbox:checked + .checker > .icon {
color: rgb(255, 255, 255);
}
body.unsigned > .register-form > .step-container > .step > .check-label > .text {
font-size: 1.0625rem;
font-weight: 500;
}
body.unsigned > .register-form > .step-container > .step > .all-warning {
border-bottom: 0.0625rem solid rgb(220, 220, 220);
color: rgb(150, 150, 150);
font-size: 0.8rem;
margin-bottom: 1rem;
padding-bottom: 1rem;
padding-left: 2.125rem;
text-align: justify;
}
body.unsigned > .register-form > .step-container > .step > .button {
background-color: rgb(var(--common-color-yellow-5));
border-radius: 0.25rem;
cursor: pointer;
margin-top: 2rem;
padding: 0.75rem 0;
}
body.unsigned > .register-form > .step-container > .step > .button:hover {
background-color: rgb(var(--common-color-yellow-4));
}
body.unsigned > .register-form > .step-container > .step > .button:active {
background-color: rgb(var(--common-color-yellow-3));
}
body.unsigned > .register-form > .step-container > .step > .button:disabled {
background-color: rgb(236, 236, 236);
color: rgb(180, 180, 180);
cursor: default;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container {
align-items: stretch;
display: flex;
flex-direction: column;
justify-content: flex-start;
position: relative;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .email-input {
border-bottom: 0.125rem solid rgb(220, 220, 220);
box-sizing: border-box;
padding: 0.625rem 4.5rem 0.625rem 0;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .email-input:focus {
border-bottom: 0.125rem solid rgb(200, 200, 200);
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .email-input.invalid {
border-bottom: 0.125rem solid rgb(225, 50, 25);
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .code-request-button {
top: 0.425rem;
right: 0;
width: 4rem;
border: 0.0625rem solid rgb(220, 220, 220);
border-radius: 100rem;
box-sizing: border-box;
cursor: pointer;
font-size: 0.8rem;
padding: 0.25rem 0;
position: absolute;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .code-request-button:hover {
border: 0.0625rem solid rgb(200, 200, 200);
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .code-request-button:disabled {
border: 0.0625rem solid rgb(220, 220, 220);
color: rgb(150, 150, 150);
cursor: default;
pointer-events: none;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .warning {
color: rgb(225, 50, 25);
display: none;
font-size: 0.9rem;
margin-top: 0.625rem;
}
body.unsigned > .register-form > .step-container > .step.email > .email-input-container > .email-input.invalid ~ .warning {
display: inline-block;
}
body.unsigned > .register-form > .step-container > .step.email > .info {
color: rgb(150, 150, 150);
font-size: 0.8rem;
list-style-type: disc;
margin-top: 1rem;
margin-left: 1rem;
}
body.unsigned > .register-form > .step-container > .step.email > .info > * + * {
margin-top: 0.25rem;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container {
align-items: stretch;
display: none;
flex-direction: column;
justify-content: flex-start;
margin-top: 0.25rem;
position: relative;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container.visible {
display: flex;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-input {
border-bottom: 0.125rem solid rgb(220, 220, 220);
box-sizing: border-box;
padding: 0.625rem 4.5rem 0.625rem 0;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-input:focus {
border-bottom: 0.125rem solid rgb(200, 200, 200);
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-input:disabled {
color: rgb(150, 150, 150);
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-input.invalid {
border-bottom: 0.125rem solid rgb(225, 50, 25);
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-verify-button {
top: 0.425rem;
right: 0;
width: 4rem;
border: 0.0625rem solid rgb(220, 220, 220);
border-radius: 100rem;
box-sizing: border-box;
cursor: pointer;
font-size: 0.8rem;
padding: 0.25rem 0;
position: absolute;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-verify-button:hover {
border: 0.0625rem solid rgb(200, 200, 200);
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-verify-button:disabled {
border: 0.0625rem solid rgb(220, 220, 220);
color: rgb(150, 150, 150);
cursor: default;
pointer-events: none;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .warning {
color: rgb(225, 50, 25);
display: none;
font-size: 0.9rem;
margin-top: 0.625rem;
}
body.unsigned > .register-form > .step-container > .step.email > .code-input-container > .code-input.invalid ~ .warning {
display: inline-block;
}
@media screen and (max-width: 35rem) {
body.unsigned > .login-form.visible {
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 0;
justify-content: center;
transform: none;
}
body.unsigned > .register-form.visible {
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 0;
transform: none;
}
}
@media screen and (max-height: 45rem) {
body.unsigned > .login-form > .logo-container {
margin-bottom: 2rem;
}
body.unsigned > .login-form > .menu {
margin-top: 2rem;
}
}
@media screen and (max-height: 35rem) {
body.unsigned > .login-form.visible {
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 0;
justify-content: center;
transform: none;
}
}
@media screen and (max-height: 27.5rem) {
body.unsigned > .resolution {
display: flex;
}
body.unsigned > .login-form {
display: none;
}
body.unsigned > .register-form {
display: none;
}
}
index.unsigned.js
const Element = {
visibilityClassName: 'visible',
LoginForm: { // 로그인 화면
getElement: () => window.document.body.querySelector(':scope > [rel="loginForm"]'), // loginForm은 form태그 자체
hide: () => Element.LoginForm.getElement().classList.remove(Element.visibilityClassName), // 로그인 화면 자체를 비활성화하는 것. 즉 숨기는 것이 hide
isShown: () => Element.LoginForm.getElement().classList.contains(Element.visibilityClassName), // 현재 보여지고 있나에 대한 여부
show: () => Element.LoginForm.getElement().classList.add(Element.visibilityClassName)
}, // hide의 반대. 보여진다. 로그인 화면 자체가 보여지는 것
RegisterForm: { // 약관 동의 화면
Progress: {
Value: {
getElement: () => Element.RegisterForm.Progress.getElement().querySelector(':scope > [rel="value"]') // value는 게이지 속성을 나타낼 거임.
},
getElement: () => Element.RegisterForm.getElement().querySelector(':scope > [rel="progress"]'), // progress는 진행 과정임. 약관 동의와 이메일 인증으로 나뉠 것.
setValue: (percent) => Element.RegisterForm.Progress.Value.getElement().style.width = `${percent}%` // 두개니까 퍼센트로 나누면 50% 씩 차지.
},
Step: {
Terms: {
Next: {
getElement: () => Element.RegisterForm.Step.Terms.getElement().querySelector(':scope > [rel=termsNext]') // termsNext는 동의 버튼
},
names: [ // 각 체크 항목. 배열로 만듬.
{name: 'terms-no-kid', required: true}, // 필수
{name: 'terms-term', required: true}, // 필수
{name: 'terms-privacy', required: true}, // 필수
{name: 'terms-profile', required: false} // 선택
],
getElement: () => Element.RegisterForm.Step.getContainer().querySelector(':scope > .step.terms'), // 약관 동의 전체. (기본이 visible)
hide: () => Element.RegisterForm.Step.Terms.getElement().classList.remove(Element.visibilityClassName), // 약관 동의 화면 숨김.
isShown: () => Element.RegisterForm.Step.Terms.getElement().classList.contains(Element.visibilityClassName), // 현재 보여지고 있나에 대한 여부
show: () => Element.RegisterForm.Step.Terms.getElement().classList.add(Element.visibilityClassName) // hide의 반대. 보여진다. 약관 동의 화면 자체가 보여지는 것.
},
Email: {
getElement: () => Element.RegisterForm.Step.getContainer().querySelector(':scope > .step.email'), // 약관 동의 전체. (기본이 visible)
hide: () => Element.RegisterForm.Step.Email.getElement().classList.remove(Element.visibilityClassName), // 약관 동의 화면 숨김.
isShown: () => Element.RegisterForm.Step.Email.getElement().classList.contains(Element.visibilityClassName), // 현재 보여지고 있나에 대한 여부
show: () => Element.RegisterForm.Step.Email.getElement().classList.add(Element.visibilityClassName) // hide의 반대. 보여진다. 약관 동의 화면 자체가 보여지는 것.
},
getContainer: () => Element.RegisterForm.getElement().querySelector(':scope > .step-container') // 약관 동의 박스
},
getElement: () => window.document.body.querySelector(':scope > [rel="registerForm"]'), // registerForm 은 약관 동의 form 태그 전체
// 이메일 인증으로 넘어가기 위해서 혹은 약관 동의로 오기 위해서는 숨기고 보여주고와 그 여부를 지정해야함.
hide: () => Element.RegisterForm.getElement().classList.remove(Element.visibilityClassName),
isShown: () => Element.RegisterForm.getElement().classList.contains(Element.visibilityClassName),
show: () => Element.RegisterForm.getElement().classList.add(Element.visibilityClassName)
}
};
const Logic = {
register: () => {
Element.LoginForm.hide(); // 로그인 화면을 숨긴다.
Element.RegisterForm.show(); //
}
};
// data-logic은 카카오계정 만들기 register 임. 이게 클릭되면
window.document.body.querySelectorAll('a[data-logic]').forEach(x => {
x.addEventListener('click', e => { // data-logic : 카카오계정 만들기 버튼
e.preventDefault();
const dataLogic = x.dataset.logic; // data-logic에 click을 지정한 상수 dataLogic
if (typeof (Logic[dataLogic]) === 'function') {
Logic[dataLogic]();
// 만약 data-logic 함수가 실행되면, 즉 click이 되면
// dataLogic이 담긴 LoginForm을 hide하고 RegisterForm을 보여주겠다.
}
});
});
// HTML 태그에 접두어(data-)가 붙은 속성을 추가하고, 거기에 사용하고자 하는 값을 지정해놓는다.
// 자바스크립트에서 요소를 선택하고, dateset 객체에서 커스텀 속성을 읽어들인다. 이때 접두어는 생략
Element.RegisterForm.getElement()['terms-agree-all'].addEventListener('change', e => {
Element.RegisterForm.Step.Terms.names.forEach(x => {
Element.RegisterForm.getElement()[x.name].checked = e.target.checked;
}); // 모두 동의 누르면 전체 체크. e.target.checked 는 모두 동의와 같은 말.
if (e.target.checked) {
Element.RegisterForm.Step.Terms.Next.getElement().removeAttribute('disabled'); // 동의 활성화
} else {
Element.RegisterForm.Step.Terms.Next.getElement().setAttribute('disabled', 'disabled'); // 동의 활성화
}
});
Element.RegisterForm.Step.Terms.names.forEach(x => {
Element.RegisterForm.getElement()[x.name].addEventListener('change', e => {
if (!e.target.checked && Element.RegisterForm.getElement()['terms-agree-all'].checked) { // 만약 name 4가지가 체크되어있지 않고, 모두 동의가 체크 되어있는 상태라면,
Element.RegisterForm.getElement()['terms-agree-all'].checked = false;
} // 모두 동의 체크를 false로. 즉 체크 해제하겠다.
if (Element.RegisterForm.Step.Terms.names
.filter(x => x.required === true) // true인 것만
.every(x => Element.RegisterForm.getElement()[x.name].checked)) {
// name 속성이 true인 것 중에서만 filter를 하는데, 체크 되어있는가에 대한 여부를 every에게 준다.
Element.RegisterForm.Step.Terms.Next.getElement().removeAttribute('disabled');
// name 속성이 true인 것을 다 체크했다면, 동의 버튼의 disabled 속성을 없앤다.
} else {
Element.RegisterForm.Step.Terms.Next.getElement().setAttribute('disabled', 'disabled');
// name 속성이 true인 것의 체크가 하나라도 빠지면 disabled 속성을 유지한다.
}
/*
names: [
{name: 'terms-no-kid', required: true},
{name: 'terms-term', required: true},
{name: 'terms-privacy', required: true},
{name: 'terms-profile', required: false}
],
* */
});
});
// 동의 버튼을 클릭했을 때 일어날 일들에 대해 진행.
// 이메일 인증 쪽으로 넘어가게 할 것.
Element.RegisterForm.Step.Terms.Next.getElement().addEventListener('click', () => {
Element.RegisterForm.Step.Terms.hide(); // 약관 동의를 숨긴다.
Element.RegisterForm.Step.Email.show(); //
Element.RegisterForm.Progress.setValue(20); // 20%로 지정
const emailInput = Element.RegisterForm.getElement()['email']; // name이 email인 것. emailInput
emailInput.value = '';
emailInput.focus();
});
// Element.RegisterForm.getElement()['email'] //이렇게 적으면 name이 email인 input이 잡힌다
Element.RegisterForm.getElement()['email'].addEventListener('keyup', e => { // keyup :
const emailRegex = new RegExp('^(?=.{10,50})([0-9a-z]{4,})@([0-9a-z]{3,})\\.([a-z]{2,15})(\\.[a-z]{2})?$');
if(emailRegex.test(e.target.value)) {
e.target.classList.remove('invalid'); // e.target이 Element.RegisterForm.getElement()['email'] 이 자체이다. 즉 input임 //정규식이 맞으면 remove
Element.RegisterForm.getElement()['emailCodeRequestButton'].removeAttribute('disabled');
}else {
e.target.classList.add('invalid'); // 정규식이 틀리면 warning 태그인 카카오계정 이메일을 입력해 주세요. 가 나옴.
Element.RegisterForm.getElement()['emailCodeRequestButton'].setAttribute('disabled', 'disabled');
// 올바른 이메일일 때 인증요청 버튼이 살아나고 올바르지 않았을 때에는 주석으로 처리가 될 것
}
});
// 인증 요청을 눌렀을 때
Element.RegisterForm.getElement()['emailCodeRequestButton'].addEventListener('click', e => {
const emailInput = Element.RegisterForm.getElement()['email']; // name이 email인 것. emailInput
emailInput.setAttribute('disabled', 'disabled'); // 모든 일이 발생하기 전에 disabled
e.target.setAttribute('disabled', 'disabled'); // 모든 일이 발생하기 전에 disabled
const formData = new FormData();
const xhr = new XMLHttpRequest();
formData.append('email', e.target.value);
xhr.open('POST', 'user/request-email-code');
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE) {
if(xhr.status >= 200 && xhr.status < 300) {
const responseJson = JSON.parse(xhr.responseText);
let message = null;
switch (responseJson['result']) {
case 'SUCCESS' :
emailInput.setAttribute('disabled', 'disabled');
e.target.setAttribute('disabled', 'disabled');
Element.RegisterForm.Step.Email
.getElement()
.querySelector('code-input-container').classList
.add('visible'); // 인증번호 입력 화면을 보여줄 것.
const emailCodeInput = Element.RegisterForm.getElement()['emailCode']; // input이 emailCode. 인증번호 입력
emailCodeInput.value = ''; // 공백으로 두고
emailCodeInput.focus(); // 포커스를 둔다.
break;
case 'DUPLICATE' : // 열거형을 이렇게 만들겠구나를 정한 것.
message = '이미 사용 중인 이메일입니다.';
break;
default:
message = '잠시 후 다시 시도해 주세요.';
}
if (message !== null) {
emailInput.parentNode.querySelector(':scope > .warning').innerText = message; // 카카오계정 이메일을 입력해 주세요. or 인증번호를 입력해 주세요.
emailInput.classList.add('invalid'); // invalid로 추가.
emailInput.removeAttribute('disabled');
emailInput.focus();
emailInput.select();
e.target.removeAttribute('disabled');
}
} else {
emailInput.parentNode.querySelector(':scope ~ .warning').innerText = '잠시 후 다시 시도해 주세요.'; // parentNode : 부모한테 다시 와서.
emailInput.classList.add('invalid');
emailInput.removeAttribute('disabled');
emailInput.focus();
emailInput.select();
e.target.removeAttribute('disabled');
}
}
};
xhr.send(formData);
});
// emailInput과 emailCodeRequestButton(인증요청 버튼)을 비활성화 disabled.
// 전송하지 못했을 때 , 즉 서버와 통신하지 못했을 때 이 둘은 다시 살아나야 한다.
크게 LoginForm 과 RegisterForm 두 가지로 나누었고,
먼저 LoginForm.
작은 화면 시,
RegisterForm 영역에서 약관 동의와 이메일 인증으로 나누었음.
필수(true)3가지 체크 시 동의 버튼이 활성화
필수 버튼이 빠지면 동의 버튼은 비활성화
버튼이 하나라도 눌리면 모두 동의 체크는 해제된다.
이메일 인증 파트
양식에 맞게 입력 시 인증요청 버튼 활성화
양식에 어긋날 시에 warning 텍스트.
작은 화면일 경우엔 다르게
아주 작게 했을 경우엔 warning
지금까지 해놓은 로직. 싹 다 밀고 다음 챕터부터 다시 짜볼 것.