ํ๋ก๊ทธ๋๋ฐ ์ธ๊ณ๋ฅผ ํ๊ตฌํฉ์๋ค.
Spring Boot๋ฅผ ํ์ฉํ์ฌ ํ์๊ฐ์ / ํ์์ ๋ณด์์ / ํ์ํํด/ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ์ ๊ตฌํํ ์ ์์ต๋๋ค.
ํ์๊ฐ์
ํ์์ ๋ณด์์ / ํ์ํํด
๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
[ํ์๊ฐ์ ]
- ์ด์ฉ์ฝ๊ด ํ์์ฌํญ ๋์, ์์ด๋ ์ค๋ณตํ์ธ, ์ด๋ฉ์ผ ์ธ์ฆ์ ์๋ฃํด์ผ ํ์๊ฐ์ ๋ฒํผ์ด ํ์ฑํ ๋ฉ๋๋ค.
- ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํตํด ํ๊ธ, ์์ด๋ฅผ ์ ๋ ฅํด์ผ ์ด๋ฆ์ ์ ๋ ฅํ ์ ์์ต๋๋ค.
- ๋น๋ฐ๋ฒํธ ์กฐ๊ฑด(์์ด, ์ซ์)๋ฅผ ์ถฉ์กฑํด์ผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ์ ์ฅ์ h2 database ์ด์ฉํ์ต๋๋ค.
https://www.h2database.com/html/main.html
์์ฑ ์ฝ๋
UserController.java
package com.example.board.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import com.example.board.model.CarType;
import com.example.board.model.Company;
import com.example.board.model.Coupon;
import com.example.board.model.Membership;
import com.example.board.model.User;
import com.example.board.repository.CarTypeRepository;
import com.example.board.repository.CompanyRepository;
import com.example.board.repository.CouponRepository;
import com.example.board.repository.MembershipRepository;
import com.example.board.repository.UserRepository;
@Controller
public class UserController {
@Autowired
UserRepository userRepository;
@Autowired
HttpSession session;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
CarTypeRepository carTypeRepository;
@Autowired
CompanyRepository companyRepository;
@Autowired
CouponRepository couponRepository;
@Autowired
MembershipRepository membershipRepository;
@GetMapping("/email-check")
@ResponseBody
public String emailCheck(@ModelAttribute User user) {
String email = user.getEmail();
User result = userRepository.findByEmail(email);
if (result != null) { // ๊ฐ ์์, ์์ด๋๊ฐ ์์, ๊ฐ์
๋ถ๊ฐ
return "๊ฐ์
๋ถ๊ฐ";
} else { // ๊ฐ ์์, ์์ด๋๊ฐ ์์, ๊ฐ์
๊ฐ๋ฅ
return "๊ฐ์
๊ฐ๋ฅ";
}
}
@GetMapping("/signin")
public String signin() {
return "signin";
}
@PostMapping("/signin")
public String signinPost(@ModelAttribute User user, Model model) {
User dbUser = userRepository.findByEmail(user.getEmail());
// ์ค๋ฅ
if (dbUser == null) {
model.addAttribute("error", "์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "signin";
}
String encodedPwd = dbUser.getPwd();
String userPwd = user.getPwd();
boolean isMatch = passwordEncoder.matches(userPwd, encodedPwd);
if (isMatch) {
// ๋ก๊ทธ์ธ ์ฑ๊ณตํ ๊ฒฝ์ฐ
session.setAttribute("user_info", dbUser);
// ๋ฉค๋ฒ์ญ ์ ๋ณด
List<Membership> memberships = membershipRepository.findByUser(dbUser);
if (memberships != null && !memberships.isEmpty()) {
session.setAttribute("has_membership", true);
} else {
session.setAttribute("has_membership", false);
}
return "redirect:/";
} else {
model.addAttribute("error", "์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "signin";
}
}
@GetMapping("/signout")
public String signout() {
session.invalidate();
return "redirect:/";
}
@GetMapping("/signup")
public String signup(Model model) {
List<CarType> carTypes = carTypeRepository.findAll();
model.addAttribute("carTypes", carTypes);
List<Company> companys = companyRepository.findAll();
model.addAttribute("companys", companys);
return "signup";
}
@PostMapping("/signup")
public String signupPost(@ModelAttribute User user,
@RequestParam(value = "isAdmin", required = false) boolean isAdmin,
@RequestParam("carname") String carname) {
String userPwd = user.getPwd();
String encodePwd = passwordEncoder.encode(userPwd);
user.setPwd(encodePwd);
user.setCreDate(new Date());
// ์ฌ์ฉ์ ์ญํ ์ค์
User.UserRole userRole = isAdmin ? User.UserRole.ADMIN : User.UserRole.CUSTOMER;
// ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
user.setRole(userRole);
user.setCarname(carname);
user.setCoin(0);
user.setCoinDate(new Date(0));
userRepository.save(user);
// User ์ ์ฆ๊ฐ
List<User> users = userRepository.findAll();
int userCount = users.size();
userCount++;
for (User u : users) {
u.setCount(userCount);
}
userRepository.saveAll(users);
return "redirect:/";
}
@GetMapping("/mypage")
public String mypage(Model model, @RequestParam String email) {
User opt = userRepository.findByEmail(email);
model.addAttribute("user", opt);
User user = (User) session.getAttribute("user_info");
if (user != null) {
int userCoins = user.getCoin();
model.addAttribute("userCoin", userCoins);
}
return "mypage";
}
@PostMapping("/mypage")
public String updatePost(@ModelAttribute User user) {
User sessionUser = (User) session.getAttribute("user_info");
long id = sessionUser.getId();
User dbUser = userRepository.findById(id);
String userPwd = user.getPwd();
String dbPwd = dbUser.getPwd();
String encodedPwd = passwordEncoder.encode(userPwd);
if (userPwd.equals(dbPwd)) {
encodedPwd = userPwd;
}
user.setPwd(encodedPwd);
user.setCreDate(new Date());
userRepository.save(user);
return "/signin";
}
@GetMapping("/loginnoti")
public String loginnoti() {
return "loginnoti";
}
@GetMapping("/getCarType")
@ResponseBody
public List<CarType> getCarType(String companyName) {
Company company = companyRepository.findByCompanyName(companyName);
List<CarType> carTypes = carTypeRepository.findByCompany(company);
return carTypes;
}
// ํํดํ๊ธฐ
@GetMapping("/exit")
public String exit() {
User user = (User) session.getAttribute("user_info");
userRepository.delete(user);
session.invalidate();
return "redirect:/";
}
// ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝํ๊ธฐ
@GetMapping("/pwdforget")
public String pwdforget() {
return "/pwdforget";
}
@PostMapping("/pwdforget")
@ResponseBody
public String pwdforgetPost(@RequestBody User user) {
// ์ธ์
์์ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
User sessionUser = (User) session.getAttribute("user");
if (sessionUser != null) {
String newPassword = user.getNewPassword();
if (newPassword != null && !newPassword.isEmpty()) {
String hashedPassword = passwordEncoder.encode(newPassword);
sessionUser.setPwd(hashedPassword);
userRepository.save(sessionUser);
return "๋น๋ฐ๋ฒํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.";
} else {
return "๋น๋ฐ๋ฒํธ ๊ฐ์ ์ฌ๋ฐ๋ฅด๊ฒ ์
๋ ฅํ์ญ์์ค.";
}
}
return "๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ์ ์คํจํ์
จ์ต๋๋ค.";
}
// ๋ณธ์ธ ์ธ์ฆํ๊ธฐ
@PostMapping("/validateUser")
public ResponseEntity<Map<String, Boolean>> validateUser(@RequestBody User user) {
String email = user.getEmail();
String name = user.getName();
Integer phone = user.getPhone();
List<User> resultList = userRepository.findByEmailAndNameAndPhone(email, name, phone);
Map<String, Boolean> response = new HashMap<>();
if (!resultList.isEmpty()) {
response.put("isValid", true);
// ์ธ์
์ ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
session.setAttribute("user", resultList.get(0));
} else {
response.put("isValid", false);
}
return ResponseEntity.ok(response);
}
}
Mailer.java
package com.example.board.email;
import java.util.Properties;
import java.util.Random;
import javax.servlet.http.HttpSession;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Mailer {
@Autowired
HttpSession session;
@GetMapping("/emailcode")
@ResponseBody
public void sendMail(
SMTPAuthenticator smtp , @RequestParam String email){
String content = Long.toString(Math.abs(new Random().nextLong()),36).substring(0,4);
Properties p = new Properties();
p.put("mail.smtp.host", "smtp.gmail.com");
p.put("mail.smtp.port", "465");
p.put("mail.smtp.starttls.enable", "true");
p.put("mail.smtp.auth", "true");
p.put("mail.smtp.debug", "true");
p.put("mail.smtp.socketFactory.port", "465");
p.put("mail.smtp.socketFactory.class", "javax.net.ssl.");
p.put("mail.smtp.socketFactory.fallback", "false");
try {
Session ses = Session.getInstance(p, smtp);
ses.setDebug(true);
MimeMessage msg = new MimeMessage(ses); // ๋ฉ์ผ์ ๋ด์ฉ์ ๋ด์ ๊ฐ์ฒด
msg.setSubject("pika์ถฉ์ ์ ํ์๊ฐ์
๋ณธ์ธ ์ธ์ฆ"); // ์ ๋ชฉ
Address fromAddr = new InternetAddress("์ด๋ฉ์ผ");
msg.setFrom(fromAddr); // ๋ณด๋ด๋ ์ฌ๋
Address toAddr = new InternetAddress(email);
msg.addRecipient(Message.RecipientType.TO, toAddr); // ๋ฐ๋ ์ฌ๋
msg.setContent(content, "text/html;charset=UTF-8"); // ๋ด์ฉ๊ณผ ์ธ์ฝ๋ฉ
Transport.send(msg); // ์ ์ก
} catch (Exception e) {
e.printStackTrace();
}
session.setAttribute("code",content);
}
@GetMapping("emailcode-check")
@ResponseBody
public String codecheck(@RequestParam String emailcode){
Object code = session.getAttribute("code");
System.out.println(code);
System.out.println(emailcode);
if(code.equals(emailcode) ){
System.out.println("yes");
return "์ฝ๋์ผ์น";
}else{
System.out.println("no");
return "์ฝ๋๋ถ์ผ์น";
}
}
}
SMTPAuthenticator.java
package com.example.board.email;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
public class SMTPAuthenticator extends Authenticator {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
"์ด๋ฉ์ผ", "ํค");
}
}
SignInCheckInterceptor.java
package com.example.board.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.example.board.model.User;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class SignInCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
log.debug("preHandle");
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user_info");
if (user == null) {
response.sendRedirect("/loginnoti");
return false;
}
return true;
}
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
log.debug("postHandle");
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
log.debug("afterCompletion");
}
}
User.java
package com.example.board.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import lombok.Data;
@Entity
@Data
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String email;
private String pwd;
private String name;
private Integer phone;
private Date creDate;
private String carname;
@Column(nullable = true)
private Integer count;
private UserRole role;
public enum UserRole {
CUSTOMER, // ์ผ๋ฐ ๊ณ ๊ฐ0
ADMIN // ๊ด๋ฆฌ์1
}
public String getRole() {
return role.name(); // ์ด๊ฑฐํ ๊ฐ์ ์ด๋ฆ์ ๋ฌธ์์ด๋ก ๋ฐํ
}
private Integer coin;
private Date coinDate;
private String newPassword;
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
List<Board> boards = new ArrayList<>();
@OneToMany(mappedBy = "user")
private List<Membership> memberships;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Coupon> coupons;
}
UserRepository.java
package com.example.board.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.board.model.User;
public interface UserRepository extends JpaRepository<User, Long> {
public User findByEmailAndPwd(String email, String pwd);
public User findByEmail(String email);
public User findById(long id);
List<User> findByEmailAndNameAndPhone(String email,String name, Integer phone);
}
loginnoti.html
<!DOCTYPE html>
<html lang="en">
<head th:replace="common/head">
</head>
<style>
@font-face {
font-family: 'TheJamsil5Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
body {
font-family: 'TheJamsil5Bold';
height: 100vh;
/* ํ๋ฉด ๋์ด์ 100%๋ก ์ค์ */
background-color: #000;
background-size: cover;
/* ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๋ง๊ฒ ์กฐ์ */
background-repeat: no-repeat;
/* ์ด๋ฏธ์ง ๋ฐ๋ณต์ ์ค์ง */
}
.btn {
background-color: rgb(228, 179, 93);
border-color: rgb(228, 179, 93);
}
.btn:hover {
background-color: rgb(228, 179, 93);
border-color: rgb(228, 179, 93);
}
</style>
<body>
<div th:replace="common/header">
</div>
<nav th:replace="common/nav">
</nav>
<div class="container mt-5">
<div class="row">
<div class="d-grid gap-2 text-center">
<h1>๋ก๊ทธ์ธ ํ ์ฌ์ฉํด์ฃผ์ธ์๐ฆ</h1>
<button class="btn btn-primary" id="loginnoti" onclick="loginnoti()">๋ก๊ทธ์ธํ์ด์ง๋ก ์ด๋</button>
</div>
</div>
</div>
<div th:replace="common/footer">
</div>
<script>
function loginnoti() {
location = '/signin';
}
</script>
</body>
</html>
mypage.html
<!DOCTYPE html>
<html lang="en">
<head th:replace="common/head">
</head>
<style>
@font-face {
font-family: 'TheJamsil5Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
body {
font-family: 'TheJamsil5Bold';
height: 100vh;
/* ํ๋ฉด ๋์ด์ 100%๋ก ์ค์ */
background-color: #000;
background-size: cover;
/* ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๋ง๊ฒ ์กฐ์ */
background-repeat: no-repeat;
/* ์ด๋ฏธ์ง ๋ฐ๋ณต์ ์ค์ง */
}
.change-color {
background-color: #ffed91;
border-color: #ffed91;
text-decoration: none;
color: black;
}
.change-color:hover {
color: black;
background-color: #fff9cd;
border-color: #fff9cd;
}
.exit {
display: flex;
justify-content: center;
color: black;
text-decoration: none;
width: 200px;
}
.exit-link {
display: grid !important;
justify-content: center;
margin-top: 50px;
}
.card {
padding: 2rem;
}
</style>
<body>
<div th:replace="common/header">
</div>
<nav th:replace="common/nav">
</nav>
<div class="container mt-5">
<div class="card">
<div class="row">
<form method="post" action="/mypage">
<div class="mb-3">
<input type="hidden" id="id" name="id" th:value="${user.id}">
<label for="email">Email:</label>
<input type="text" class="form-control" id="email" name="email" th:value="${user.email}" readonly>
</div>
<div class="mb-3">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" name="pwd" th:value="${user.pwd}" readonly hidden>
</div>
<div class="mb-3">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" th:value="${user.name}">
</div>
<div class="mb-3">
<label for="phone">Phone:</label>
<input type="text" class="form-control" id="phone" name="phone" th:value="${user.phone}">
</div>
<div class="mb-3">
<label for="car">My Car:</label>
<input type="text" class="form-control" id="car" name="car" th:value="${user.carname}">
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary change-color" id="update" th:onclick="mypage()">ํ์์ ๋ณด ์์ </button>
</div>
<input type="hidden" id="coin" name="coin" th:value="${user.coin}">
<!-- <input type="hidden" id="coinDate" name="coinDate" th:value="${user.coinDate}"> -->
<input type="hidden" id="count" name="count" th:value="${user.count}">
<!-- <input type="hidden" id="creDate" name="creDate" th:value="${user.creDate}"> -->
<input type="hidden" id="role" name="role" th:value="${user.role}">
<input type="hidden" id="newPassword" name="newPassword" th:value="${user.newPassword}">
</form>
<div class="exit-link">
<button class="exit" id="exit" th:onclick="confirmDeletion()">ํ์ํํด</button>
</div>
</div>
</div>
</div>
<div th:replace="common/footer">
</div>
<script>
function confirmDeletion() {
if (confirm("์ ๋ง๋ก ํ์ํํด๋ฅผ ํ์๊ฒ ์ต๋๊น?")) {
location.href = "/exit";
}
}
function mypage() {
// ํผ ๋ฐ์ดํฐ ์์ง
var formData = {
id: document.getElementById("id").value,
email: document.getElementById("email").value,
name: document.getElementById("name").value,
phone: document.getElementById("phone").value,
car: document.getElementById("car").value
};
// AJAX ์์ฒญ์ ์ฌ์ฉํ์ฌ ์๋ฒ๋ก ๋ฐ์ดํฐ ์ ์ก
$.ajax({
type: "POST",
url: "/mypage",
data: formData,
success: function (response) {
// ์์ ์ฑ๊ณต ์ ์ฒ๋ฆฌ
alert("ํ์ ์ ๋ณด๊ฐ ์์ ๋์์ต๋๋ค.");
location.reload(); // ํ์ด์ง ์๋ก๊ณ ์นจ ๋๋ ๋ฆฌ๋๋ ์
}
});
}
</script>
</body>
</html>
pwdforget.html
<!DOCTYPE html>
<html lang="en">
<head th:replace="common/head"></head>
<style>
@font-face {
font-family: 'TheJamsil5Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
body {
font-family: 'TheJamsil5Bold';
height: 100vh;
/* ํ๋ฉด ๋์ด์ 100%๋ก ์ค์ */
background-color: #000;
background-size: cover;
/* ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๋ง๊ฒ ์กฐ์ */
background-repeat: no-repeat;
/* ์ด๋ฏธ์ง ๋ฐ๋ณต์ ์ค์ง */
}
.btnn-primary {
background-color: #f2f5c0;
border-color: #f2f5c0;
color: black;
}
.btnn-primary:hover{
background-color: #e2ce38;
border-color: #e2ce38;
color: black;
}
#pwd i .eyes {
position: absolute;
top: 0;
bottom: 0;
right: 0;
margin: auto 2px;
height: 30px;
font-size: 22px;
cursor: pointer;
color: white;
}
label {
color: white
}
.fa-eye:before {
content: "\f06e";
color: white;
}
.fa-eye-slash:before {
content: "\f070";
color: white;
}
/* modal */
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
font-family: 'TheJamsil5Bold';
}
.modal-content {
background-color: #fefefe;
margin: auto;
width: 600px;
padding: 30px;
color: black;
overflow-y: scroll;
}
.close {
color: #aaaaaa;
}
.subscribe-title {
text-align: center;
font-size: 30px;
margin-bottom: 50px;
}
.subscribe-content {
text-align: center;
font-size: 15px;
margin-bottom: 20px;
}
.content-info {
text-align: center;
margin-top: 2px;
font-weight: bold;
font-size: large;
}
.modal2 {
font-size: 22px;
}
</style>
<body>
<div th:replace="common/header"> </div>
<nav th:replace="common/nav"></nav>
<div class="container mt-5">
<div class="row">
<form method="post" action="/pwdforget">
<div class="mb-3">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" name="email" pattern="[a-z0-9._+-]+@[a-z]+\.[a-z]{2,}$"
title=" ์ ํํ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์" placeholder="ex.daram@dotori.com" required>
</div>
<div class="mb-3">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" pattern="^[๊ฐ-ํฃ]+$" title="์ฌ๋ฐ๋ฅธ ์ด๋ฆ์ ์
๋ ฅํ์ธ์ ex.ํ๊ธธ๋"
placeholder="์ด๋ฆ" required>
</div>
<div class="mb-3">
<label for="name">Phone:</label>
<input type="text" class="form-control" id="phone" name="phone" pattern="[0-9]{10,11}"
title="10-11์๋ฆฌ์ ์ซ์๋ฅผ '-' ์์ด ์
๋ ฅํ์ธ์" placeholder="ํด๋์ ํ๋ฒํธ('-'๊ธฐํธ ์ ์ธ 10~11์๋ฆฌ)" required>
</div>
<div class="d-grid gap-2">
<button type="button" class="btn btnn-primary" id="signup" onclick="validateUser()" >๋ณธ์ธ ์ธ์ฆํ๊ธฐ</button>
</div>
<div id="error-message1" class="d-none" style="color: red; margin: 10px;">
<p>์
๋ ฅํ์ ์ ๋ณด์ ์ผ์นํ๋ ์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.</p>
</div>
<div id="change-password-form" class="d-none">
<div class="mb-3">
<label for="pwd">New Password:</label>
<input type="password" class="form-control" id="newPassword" name="newPassword"
pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}" title="์๋ฌธ๋์๋ฌธ์/์ซ์๋ก ์ด๋ฃจ์ด์ง ์ต์ 8๊ธ์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์"
placeholder="์๋ก์ด ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์" required>
<i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
</div>
<div class="d-grid gap-2">
<button type="button" class="btn btnn-primary" id="changePassword">๋น๋ฐ๋ฒํธ
๋ณ๊ฒฝ</button>
</div>
</div>
<!-- <div id="error-message1" class="d-none" style="color: red; margin: 10px;">
<p>์
๋ ฅํ์ ์ ๋ณด์ ์ผ์นํ๋ ์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.</p>
</div> -->
<!-- <div id="error-message2" class="d-none" style="color: red; margin: 10px;">
<p>๋น๋ฐ๋ฒํธ ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค. ์๋ฌธ๋์๋ฌธ์/์ซ์๋ก ์ด๋ฃจ์ด์ง ์ต์ 8๊ธ์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์.</p>
</div> -->
</form>
</div>
</div>
<script>
//๋ณธ์ธ ์ธ์ฆ
function validateUser() {
var email = document.getElementById('email').value;
var name = document.getElementById('name').value;
var phone = document.getElementById('phone').value;
// AJAX ์์ฒญ์ ์ฌ์ฉํ์ฌ ์๋ฒ์ ์ฌ์ฉ์์ ์ ๋ณด๊ฐ ์ ํจํ์ง ํ์ธํฉ๋๋ค.
$.ajax({
url: '/validateUser',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
email: email,
name: name,
phone: phone
}),
success: function (response) {
if (response.isValid) {
// ์ ํจํ๋ฉด ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ํผ์ ๋ณด์ฌ์ค๋๋ค.
document.getElementById('error-message1').classList.add('d-none');
document.getElementById('change-password-form').classList.remove('d-none');
} else {
// ์ ํจํ์ง ์์ผ๋ฉด ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
document.getElementById('error-message1').classList.remove('d-none');
}
}
});
}
//๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
const changeBtn = document.querySelector('#changePassword')
changeBtn.addEventListener('click', changePassword);
function changePassword() {
var email = document.getElementById('email').value;
var name = document.getElementById('name').value;
var phone = document.getElementById('phone').value;
var newPassword = document.getElementById('newPassword').value;
console.log(newPassword);
//data ์์ฑ์ ํตํด ๋ด์ฉ์ ์๋ฒ๋ก ์ ๋ฌ
$.ajax({
url: '/pwdforget',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
email: email,
name: name,
phone: phone,
newPassword: newPassword
}),
success: function (response) {
// ์๋ฒ์์ ์๋ต์ด ์ค๋ฉด, ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
alert(response);
location = '/signin';
},
error: function (error) {
// ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
alert("์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: " + error.responseText);
}
});
}
// ๋น๋ฐ๋ฒํธ ๋ณด์ด๊ธฐํ์
function togglePasswordVisibility() {
var $passwordInput = $('#newPassword'); // ID๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋ฐ๋ฒํธ ์
๋ ฅ๋์ ์ ํ
if ($passwordInput.attr('type') === 'password') {
$('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
$passwordInput.attr('type', 'text');
} else {
$('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
$passwordInput.attr('type', 'password');
}
}
</script>
</div>
<div th:replace="common/footer" style="margin-top: 1rem;">
</div>
</body>
</html>
signin.html
<!DOCTYPE html>
<html lang="en">
<head th:replace="common/head"></head>
<style>
@font-face {
font-family: 'TheJamsil5Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
body {
font-family: 'TheJamsil5Bold';
height: 100vh;
/* ํ๋ฉด ๋์ด์ 100%๋ก ์ค์ */
background-color: #000;
background-size: cover;
/* ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๋ง๊ฒ ์กฐ์ */
background-repeat: no-repeat;
/* ์ด๋ฏธ์ง ๋ฐ๋ณต์ ์ค์ง */
}
.btn-primary {
background-color: #f2f5c0;
border-color: #f2f5c0;
color: black;
}
.btn-primary:hover{
background-color: #e2ce38;
border-color: #e2ce38;
color: black;
}
#pwd{
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.form-control{
position: relative;
padding-right: 40px;
z-index: 1;
}
.form-control:disabled {
z-index: 1; /* ๋นํ์ฑํ๋ ์
๋ ฅ๋์ ์คํ์ผ๋ ๋ฎ์ด์ฐ๊ธฐ ์ํด z-index ์ค์ */
}
.eyes {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 10px;
cursor: pointer;
z-index: 2 ;
}
.form-control:focus + .eyes {
z-index: 3 ; /* ํฌ์ปค์ค๋ ์
๋ ฅ๋๊ณผ ์ฐ๊ฒฐ๋ ๋ ๋ชจ์ ์์ด์ฝ์ ๋ ๋์ z-index๋ก ์ค์ ํ์ฌ ํฌ์ปค์ค ์ ์๋ก ์ค๊ฒ ํฉ๋๋ค. */
}
.title h1{
text-align: center;
margin-bottom: 3rem;
color: white;
}
</style>
<body>
<div th:replace="common/header"></div>
<nav th:replace="common/nav"></nav>
<div class="title">
<h1>๋ก๊ทธ์ธ</h1>
</div>
<div class="container mt-5">
<div class="row">
<form method="post" action="/signin">
<div class="mb-3 input-group flex-nowrap">
<span class="input-group-text">๐ป</span>
<input type="email" class="form-control" id="email" name="email" placeholder="email" title="์ด๋ฉ์ผ ํ์์ด์ด์ผ ํฉ๋๋ค" required>
</div>
<div class="mb-3 input-group flex-nowrap">
<span class="input-group-text">๐</span>
<input type="password" class="form-control" id="pwd" name="pwd" placeholder="password" required>
<i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
</div>
<div th:if="${error}" class="alert alert-danger">
<p th:text="${error}"></p>
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary" id="signin">๋ก๊ทธ์ธ</button>
</div>
<div class="d-grid gap-2">
<a class="pwdforget" id="pwdforget" href="/pwdforget" style=" color: rgb(22, 208, 255); padding: 20px 5px;">๋น๋ฐ๋ฒํธ๊ฐ ๊ธฐ์ต๋์ง ์๋๋ค๋ฉด?</a>
</div>
</form>
</div>
</div>
<script>
function togglePasswordVisibility() {
var $passwordInput = $('#pwd');
if ($passwordInput.attr('type') === 'password') {
$('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
$passwordInput.attr('type', 'text');
} else {
$('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
$passwordInput.attr('type', 'password');
}
}
</script>
</body>
</html>
signup.html
<!DOCTYPE html>
<html lang="en">
<head th:replace="common/head"></head>
<style>
@font-face {
font-family: 'TheJamsil5Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
body {
font-family: 'TheJamsil5Bold';
height: 100vh;
/* ํ๋ฉด ๋์ด์ 100%๋ก ์ค์ */
background-color: #000;
background-size: cover;
/* ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๋ง๊ฒ ์กฐ์ */
background-repeat: no-repeat;
/* ์ด๋ฏธ์ง ๋ฐ๋ณต์ ์ค์ง */
}
.btnn-primary {
background-color: #f2f5c0;
border-color: #f2f5c0;
color: black;
}
.btnn-primary:disabled{
background-color: #f2f5c0;
border-color: #f2f5c0;
color: black;
}
.btnn-primary:hover{
background-color: #e2ce38;
border-color: #e2ce38;
color: black;
}
#pwd i .eyes {
position: absolute;
top: 0;
bottom: 0;
right: 0;
margin: auto 2px;
height: 30px;
font-size: 22px;
cursor: pointer;
color: white;
}
label {
color: white
}
.fa-eye:before {
content: "\f06e";
color: white;
}
.fa-eye-slash:before {
content: "\f070";
color: white;
}
/* modal */
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
font-family: 'TheJamsil5Bold';
}
.modal-content {
background-color: #fefefe;
margin: auto;
width: 600px;
padding: 30px;
color: black;
overflow-y: scroll;
}
.close {
color: #aaaaaa;
}
.subscribe-title {
text-align: center;
font-size: 30px;
margin-bottom: 50px;
}
.subscribe-content {
text-align: center;
font-size: 15px;
margin-bottom: 20px;
}
.content-info {
text-align: center;
margin-top: 2px;
font-weight: bold;
font-size: large;
}
.modal2 {
font-size: 22px;
}
.mb-3 {
width: 50%;
}
.btn-gradient {
text-decoration: none;
color: white;
padding: 10px 30px;
display: inline-block;
position: relative;
border: 1px solid rgba(0, 0, 0, 0.21);
border-bottom: 4px solid rgba(0, 0, 0, 0.21);
border-radius: 4px;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
}
.btn-gradient.yellow {
background: rgba(240, 210, 100, 1);
background: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(240, 210, 100, 1)), to(rgba(229, 201, 96, 1)));
background: -webkit-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
background: -moz-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
background: -o-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
background: linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f0d264', endColorstr='#e5c960', GradientType=0);
}
/* joinForm */
* {
margin: 0;
padding: 0;
box-sizing: border-box
}
ul>li {
list-style: none
}
a {
text-decoration: none;
}
.clearfix::after {
content: "";
display: block;
clear: both;
}
#joinForm {
width: 460px;
margin: auto;
}
ul.join_box {
border: 2px solid #ddd;
background-color: #fff;
width:500px;
padding-inline-start:40px;
padding-inline-end:40px;
}
.checkBox,
.checkBox>ul {
position: relative;
}
.checkBox>ul>li {
float: left;
}
.checkBox>ul>li:first-child {
width: 85%;
padding: 15px;
font-weight: 600;
color: #888;
}
.checkBox>ul>li:nth-child(2) {
position: absolute;
top: 50%;
right: 30px;
margin-top: -12px;
}
.checkBox textarea {
width: 96%;
height: 90px;
margin: 0 2%;
background-color: #f7f7f7;
color: #888;
border: none;
}
.footBtwrap {
margin-top: 15px;
}
.footBtwrap>li {
float: left;
width: 50%;
height: 60px;
}
.footBtwrap>li>button {
display: block;
width: 100%;
height: 100%;
font-size: 20px;
text-align: center;
line-height: 43px;
}
.fpmgBt1 {
background-color: #fff;
color: #888
}
.fpmgBt2 {
background-color: #f2f5c0;
color: #171616
}
.fpmgBt2:hover {
background-color: #e2ce38;
border-color: #e2ce38;
color: #171616
}
.fpmgBt2:disabled {
background-color: #f2f5c0;
border-color: #f2f5c0;
color: #171616
}
.signupForm{
display: flex;
margin-left: 10rem;
}
#realsignupForm{
display:inline-flex;
flex-direction: column;
align-items: center;
}
.title h1{
text-align: center;
margin-bottom: 3rem;
color: white;
}
</style>
<body>
<div th:replace="common/header"> </div>
<nav th:replace="common/nav"></nav>
<div class="title">
<h1>ํ์๊ฐ์
</h1>
</div>
<div class="signupForm">
<form action="" id="joinForm">
<ul class="join_box">
<li class="checkBox check01">
<ul class="clearfix">
<li>์ด์ฉ์ฝ๊ด, ๊ฐ์ธ์ ๋ณด ์์ง ๋ฐ ์ด์ฉ,
์์น์ ๋ณด ์ด์ฉ์ฝ๊ด(์ ํ), ํ๋ก๋ชจ์
์๋ด
๋ฉ์ผ ์์ (์ ํ)์ ๋ชจ๋ ๋์ํฉ๋๋ค.</li>
<li class="checkAllBtn">
<input type="checkbox" name="chkAll" id="chk" class="chkAll" onchange="chkAll(this.checked)">
</li>
</ul>
</li>
<li class="checkBox check02">
<ul class="clearfix">
<li>์ด์ฉ์ฝ๊ด ๋์(ํ์)</li>
<li class="checkBtn">
<input type="checkbox" name="chk">
</li>
</ul>
<textarea name="" id="">์ฌ๋ฌ๋ถ์ ํ์ํฉ๋๋ค.
Pika ์ถฉ์ ์ ์๋น์ค ๋ฐ ์ ํ(์ดํ ‘์๋น์ค’)์ ์ด์ฉํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ๋ณธ ์ฝ๊ด์ ๋ค์ํ Pika ์ถฉ์ ์ ์๋น์ค์ ์ด์ฉ๊ณผ ๊ด๋ จํ์ฌ Pika ์ถฉ์ ์ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ Pika ์ถฉ์ ์ ์ฃผ์ํ์ฌ(์ดํ ‘Pika ์ถฉ์ ์’)์ ์ด๋ฅผ ์ด์ฉํ๋ Pika ์ถฉ์ ์ ์๋น์ค ํ์(์ดํ ‘ํ์’) ๋๋ ๋นํ์๊ณผ์ ๊ด๊ณ๋ฅผ ์ค๋ช
ํ๋ฉฐ, ์์ธ๋ฌ ์ฌ๋ฌ๋ถ์ Pika ์ถฉ์ ์ ์๋น์ค ์ด์ฉ์ ๋์์ด ๋ ์ ์๋ ์ ์ตํ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์์ต๋๋ค.
</textarea>
</li>
<li class="checkBox check03">
<ul class="clearfix">
<li>๊ฐ์ธ์ ๋ณด ์์ง ๋ฐ ์ด์ฉ์ ๋ํ ์๋ด(ํ์)</li>
<li class="checkBtn">
<input type="checkbox" name="chk">
</li>
</ul>
<textarea name="" id="">๊ฐ์ธ์ ๋ณด๋ณดํธ๋ฒ์ ๋ฐ๋ผ Pika ์ถฉ์ ์์ ํ์๊ฐ์
์ ์ฒญํ์๋ ๋ถ๊ป ์์งํ๋ ๊ฐ์ธ์ ๋ณด์ ํญ๋ชฉ, ๊ฐ์ธ์ ๋ณด์ ์์ง ๋ฐ ์ด์ฉ๋ชฉ์ , ๊ฐ์ธ์ ๋ณด์ ๋ณด์ ๋ฐ ์ด์ฉ๊ธฐ๊ฐ, ๋์ ๊ฑฐ๋ถ๊ถ ๋ฐ ๋์ ๊ฑฐ๋ถ ์ ๋ถ์ด์ต์ ๊ดํ ์ฌํญ์ ์๋ด ๋๋ฆฌ์ค๋ ์์ธํ ์ฝ์ ํ ๋์ํ์ฌ ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.์ด์ฉ์๋ ํ์๊ฐ์
์ ํ์ง ์์๋ ์ ๋ณด ๊ฒ์, ๋ด์ค ๋ณด๊ธฐ ๋ฑ ๋๋ถ๋ถ์ Pika ์ถฉ์ ์ ์๋น์ค๋ฅผ ํ์๊ณผ ๋์ผํ๊ฒ ์ด์ฉํ ์ ์์ต๋๋ค. ์ด์ฉ์๊ฐ ๋ฉ์ผ, ์บ๋ฆฐ๋, ์นดํ, ๋ธ๋ก๊ทธ ๋ฑ๊ณผ ๊ฐ์ด ๊ฐ์ธํ ํน์ ํ์์ ์๋น์ค๋ฅผ ์ด์ฉํ๊ธฐ ์ํด ํ์๊ฐ์
์ ํ ๊ฒฝ์ฐ, Pika ์ถฉ์ ์๋ ์๋น์ค ์ด์ฉ์ ์ํด ํ์ํ ์ต์ํ์ ๊ฐ์ธ์ ๋ณด๋ฅผ ์์งํฉ๋๋ค.
</textarea>
</li>
<li class="checkBox check03">
<ul class="clearfix">
<li>์์น์ ๋ณด ์ด์ฉ์ฝ๊ด ๋์(์ ํ)</li>
<li class="checkBtn">
<input type="checkbox" name="chk1">
</li>
</ul>
<textarea name="" id="">์ฌ๋ฌ๋ถ์ ํ์ํฉ๋๋ค.
์์น๊ธฐ๋ฐ์๋น์ค ์ด์ฉ์ฝ๊ด์ ๋์ํ์๋ฉด, ์์น๋ฅผ ํ์ฉํ ๊ด๊ณ ์ ๋ณด ์์ ๋ฑ์ ํฌํจํ๋ Pika ์ถฉ์ ์ ์์น๊ธฐ๋ฐ ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค. ์ด ์ฝ๊ด์ Pika ์ถฉ์ ์ ์ฃผ์ํ์ฌ (์ดํ “ํ์ฌ”)๊ฐ ์ ๊ณตํ๋ ์์น๊ธฐ๋ฐ์๋น์ค์ ๊ด๋ จํ์ฌ ํ์ฌ์ ๊ฐ์ธ์์น์ ๋ณด์ฃผ์ฒด์์ ๊ถ๋ฆฌ, ์๋ฌด ๋ฐ ์ฑ
์์ฌํญ, ๊ธฐํ ํ์ํ ์ฌํญ์ ๊ท์ ํจ์ ๋ชฉ์ ์ผ๋ก ํฉ๋๋ค.
</textarea>
</li>
<li class="checkBox check04">
<ul class="clearfix">
<li>์ด๋ฒคํธ ๋ฑ ํ๋ก๋ชจ์
์๋ฆผ ๋ฉ์ผ ์์ (์ ํ)</li>
<li class="checkBtn">
<input type="checkbox" name="chk1">
</li>
</ul>
</li>
</ul>
<ul class="footBtwrap clearfix">
<li><button type="button" class="fpmgBt1 btn btnn-primary" onclick="disagreement()">๋น๋์</button></li>
<li><button type="button" class="fpmgBt2 btn btnn-primary" onclick="agreement()">๋์</button></li>
</ul>
</form>
<div class="container mt-5">
<div class="row">
<form method="post" action="/signup" id="realsignupForm">
<div class="mb-3">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" name="email" pattern="[a-z0-9._%+-]+@[a-z]+\.[a-z]{2,}$"
title=" ์ ํํ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์" placeholder="ex.daram@dotori.com" required>
<button class="btn btnn-primary" type="button" onclick="checkEmail()">์ค๋ณตํ์ธ</button>
<button class="btn btnn-primary" type="button" onclick="run()">์ด๋ฉ์ผ ์ธ์ฆ</button>
<span id="duplicateResult"></span>
</div>
<div class="mb-3">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" name="pwd" pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}"
title="์๋ฌธ๋์๋ฌธ์/์ซ์๋ก ์ด๋ฃจ์ด์ง ์ต์ 8๊ธ์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์" placeholder="์๋ฌธ๋์๋ฌธ์/์ซ์๋ก ์ด๋ฃจ์ด์ง ์ต์ 8๊ธ์์ ๋น๋ฐ๋ฒํธ" required>
<i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
</div>
<div class="mb-3">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" pattern="^[a-zA-Z๊ฐ-ํฃ]+$"
title="์ฌ๋ฐ๋ฅธ ์ด๋ฆ์ ์
๋ ฅํ์ธ์ ex.ํ๊ธธ๋" placeholder="์ด๋ฆ" required>
</div>
<div class="mb-3">
<label for="name">Phone:</label>
<input type="text" class="form-control" id="phone" name="phone" pattern="[0-9]{10,11}"
title="10-11์๋ฆฌ์ ์ซ์๋ฅผ '-' ์์ด ์
๋ ฅํ์ธ์" placeholder="ํด๋์ ํ๋ฒํธ('-'๊ธฐํธ ์ ์ธ 10~11์๋ฆฌ)" required>
</div>
<div class="mb-3">
<label for="campany">ํ์ฌ ์ ํ:</label>
<select class="form-select" id="company" name="company">
<option value="">ํ์ฌ๋ฅผ ์ ํํ์ธ์</option>
<option th:each="type : ${companys}" th:value="${type.Id}" th:text="${type.companyName}"></option>
</select>
<label for="carType">์ฐจ์ข
์ ํ:</label>
<select class="form-select" id="carname" name="carname">
<option value="">์ฐจ์ข
์ ์ ํํ์ธ์</option>
<!-- <option th:each="type : ${carTypes}" th:value="${type.name}" th:text="${type.name}"></option> -->
</select>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="isAdmin" name="isAdmin">
<label class="form-check-label" for="isAdmin">๊ด๋ฆฌ์</label>
</div>
<div class="d-grid gap-2">
<button class="btn btnn-primary" id="signup" style="width : 250px;">๊ฐ์
ํ๊ธฐ</button>
</div>
</form>
</div>
<!-- Modal -->
<div id="myModal" class="modal">
<div class="modal-dailog">
<div class="modal-content" style="color:black;">
<span class="close">×</span>
<div class="subscribe-title"> ์ด๋ฉ์ผ ๋ณธ์ธ ์ธ์ฆ </div>
<div class="subscribe-content">
์์ฑํ์ ์ด๋ฉ์ผ ์ฃผ์๋ก ๋ฐ์ก๋ ์ด๋ฉ์ผ์ ํ์ธํด์ฃผ์ธ์.
</div>
<div class="content-info">
<input type="text" class="codetext">
</div>
<div class="coupon-btn"
style="display: flex; justify-content: space-evenly;align-items: center; margin-top: 20px;">
<button class="btn-gradient yellow large" onclick="checkEmailcode()">ํ์ธ</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// ์ด์ฉ์ฝ๊ด
const pchkBoxes = document.querySelectorAll('input[name="chk"]');
const cchkBoxes = document.querySelectorAll('input[name="chk1"]');
function chkAll(isChecked) {
// ๋ชจ๋ ์ฒดํฌ๋ฐ์ค๋ฅผ ๋ฃจํ ๋๋ฉฐ ์ํ๋ฅผ chkAll๊ณผ ๋์ผํ๊ฒ ์ค์
pchkBoxes.forEach((checkbox) => {
checkbox.checked = isChecked;
});
cchkBoxes.forEach((checkbox) => {
checkbox.checked = isChecked;
});
// ์ต์ ๋ ๊ฐ์ ์ฒดํฌ๋ฐ์ค๊ฐ ์ ํ๋์๋์ง ํ์ธํ์ฌ "๋์" ๋ฒํผ์ ํ์ฑํ
const checkedCount = Array.from(pchkBoxes).filter((checkbox) => checkbox.checked).length;
agreeButton.disabled = checkedCount < 2;
}
// chkAll ์ฒดํฌ๋ฐ์ค์ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ
document.querySelector('#chk').addEventListener('change', function () {
chkAll(this.checked);
});
// "๋์" ๋ฒํผ์ ์
๋ฐ์ดํธํ๋ ๊ฐ๋ณ ์ฒดํฌ๋ฐ์ค์ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ
const individualCheckboxes = document.querySelectorAll('input[name="chk"]');
individualCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('change', function () {
const checkedCount = Array.from(individualCheckboxes).filter((checkbox) => checkbox.checked).length;
agreeButton.disabled = checkedCount < 2;
});
});
let agree;
function agreement(){
alert("์ด์ฉ์ฝ๊ด์ ๋์ํ์
จ์ต๋๋ค.")
agree = true;
}
function disagreement(){
alert("์ด์ฉ์ฝ๊ด ํ์์ฌํญ์ ๋์ํ์์ง ์์ผ์
จ์ต๋๋ค.")
}
// ํ์๊ฐ์
ํ๊ธฐ ๋ฒํผ ๋นํ์ฑ/ํ์ฑํ
const signupButton = document.getElementById('signup');
signupButton.disabled = true;
const agreeButton = document.querySelector('.fpmgBt2');
agreeButton.disabled = true;
let isEmailValid = false;
let isEmailCodeValid = false;
function updateSignupButtonState() {
if (isEmailValid && isEmailCodeValid && agree === true) {
signupButton.disabled = false;
} else {
signupButton.disabled = true;
}
}
// id์ค๋ณต์ฒดํฌ
async function checkEmail() {
const email = document.querySelector("[name=email]").value;
const response = await fetch(`/email-check?email=${encodeURIComponent(email)}`);
const result = await response.text();
// ์ค๋ณต ํ์ธ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ๋ฉ์์ง ํ์
const duplicateResultElement = document.getElementById("duplicateResult");
if (result == "๊ฐ์
๋ถ๊ฐ") {
duplicateResultElement.textContent = "์ค๋ณต๋ Email์
๋๋ค.";
duplicateResultElement.style.color = "red";
isEmailValid = false;
// ๋ค๋ฅธ ์คํ์ผ๋ง ๋ฑ์ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ ๊ฐ๋ฅ
} else if (result == "๊ฐ์
๊ฐ๋ฅ") {
duplicateResultElement.textContent = "์ฌ์ฉ ๊ฐ๋ฅํ Email์
๋๋ค.";
duplicateResultElement.style.color = "green";
isEmailValid = true;
// ๋ค๋ฅธ ์คํ์ผ๋ง ๋ฑ์ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ ๊ฐ๋ฅ
}
updateSignupButtonState();
}
// ๋น๋ฐ๋ฒํธ ๋ณด์ด๊ธฐํ์
function togglePasswordVisibility() {
var $passwordInput = $('#pwd'); // ID๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋ฐ๋ฒํธ ์
๋ ฅ๋์ ์ ํ
if ($passwordInput.attr('type') === 'password') {
$('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
$passwordInput.attr('type', 'text');
} else {
$('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
$passwordInput.attr('type', 'password');
}
}
//ํ์ฌ ์ต์
์ ๋ฐ๋ผ ํด๋น ์ฐจ ์ข
๋ฅ ๊ฐ์ ธ์ค๊ธฐ
const company = document.querySelector('#company');
const carSelect = document.querySelector('#carname');
company.addEventListener('change', async (e) => {
// console.dir(e.target);
// console.dir(e.target.selectedIndex);
const index = e.target.selectedIndex;
// console.dir(e.target[index]);
const selectedCompany = e.target[index].innerText;
// console.dir(selectedCompany);
await getCarTypes(selectedCompany);
});
async function getCarTypes(selectedCompany) {
const data = await fetch(`/getCarType?companyName=${selectedCompany}`);
const res = await data.json();
console.log(res);
// ๊ธฐ์กด ์ต์
์ ๊ฑฐ
carSelect.innerHTML = '';
// "์ฐจ์ข
์ ์ ํํ์ธ์" ๊ธฐ๋ณธ ์ต์
์ถ๊ฐ
let defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.text = '์ฐจ์ข
์ ์ ํํ์ธ์';
carSelect.appendChild(defaultOption);
// ์๋ก์ด ์ต์
์ถ๊ฐ
res.forEach(carType => {
let optionElement = document.createElement('option');
optionElement.value = carType.name;
optionElement.text = carType.name;
carSelect.appendChild(optionElement);
});
}
//์ด๋ฉ์ผ ์ธ์ฆ ๋ชจ๋ฌ์ฐฝ
async function run(code) {
const options = { backdrop: false };
var myModal = new bootstrap.Modal(document.getElementById('myModal'), options);
myModal.show();
const email = document.querySelector("[name=email]").value;
const response = await fetch(`/emailcode?email=${email}`);
$('.close').click(function () {
$('#myModal').css('display', 'none');
$('.subscribe-title').empty();
$('.subscribe-content').empty();
});
}
// ์ด๋ฉ์ผ ์ธ์ฆ
async function checkEmailcode() {
const emailcode = document.querySelector('.codetext').value;
const response = await fetch(`/emailcode-check?emailcode=${emailcode}`);
const result = await response.text();
console.log(response);
console.log(result);
if (result === "์ฝ๋๋ถ์ผ์น") {
var contentInfo = document.querySelector('.content-info');
var subscribecontent = document.querySelector('.subscribe-content');
var couponbtn = document.querySelector('.coupon-btn');
var closebtn = document.querySelector('.close');
subscribecontent.innerHTML = '<div class="modal2">๋ณธ์ธ ์ธ์ฆ์ ์คํจํ์ต๋๋ค.</div>';
contentInfo.innerHTML = '<div class="modal2">๋ค์ ์๋ํด์ฃผ์ธ์.</div>';
couponbtn.innerHTML = '<h1></h1>';
closebtn.innerHTML = '<a href ="/signup">๋์๊ฐ๊ธฐ</a>';
isEmailCodeValid = false;
} else if (result === "์ฝ๋์ผ์น") {
var contentInfo = document.querySelector('.content-info');
var subscribecontent = document.querySelector('.subscribe-content');
var couponbtn = document.querySelector('.coupon-btn');
subscribecontent.innerHTML = '<div class="modal2">์ธ์ฆ์ด ์๋ฃ๋์์ต๋๋ค.</div>';
contentInfo.innerHTML = '<div class="modal2"> ํ์๊ฐ์
์ ์งํํด์ฃผ์ธ์.</div>';
couponbtn.innerHTML = '<h1></h1>';
isEmailCodeValid = true;
}
updateSignupButtonState();
}
</script>
<div th:replace="common/footer" style="margin-top: 1rem;">
</div>
</body>
</html>