수업 정리 kakao/#3 html/css/js 소스

최동민·2022년 6월 24일
0

Spring 수업정리

목록 보기
29/47

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

지금까지 해놓은 로직. 싹 다 밀고 다음 챕터부터 다시 짜볼 것.

profile
코드를 두드리면 문이 열린다

0개의 댓글