diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml new file mode 100644 index 0000000..1c0b8e2 --- /dev/null +++ b/.github/workflows/frontend.yml @@ -0,0 +1,21 @@ +name: GCP CI/CD +on: + push: + branches: [ main, develop ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.SSH_KEY }} + passphrase: ${{ secrets.PASSPHRASE }} + port: 22 + script: | + cd ${{ secrets.PWD }} + git pull https://${{ secrets.GIT_TOKEN }}:x-oauth-basic@github.com/Tekken-Supporter/Frontend.git develop + pm2 reload tekken7 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2ba986f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/20231214_143319381.mp4 b/20231214_143319381.mp4 new file mode 100644 index 0000000..1ed4ce1 Binary files /dev/null and b/20231214_143319381.mp4 differ diff --git a/challenge.css b/challenge.css new file mode 100644 index 0000000..385cb89 --- /dev/null +++ b/challenge.css @@ -0,0 +1,842 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +.container { + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + justify-content: center; +} + +.background-clip { + position: absolute; + right: 0; + bottom: 0; + z-index: -1; +} + +@media (min-aspect-ratio:16/9) { + .background-clip { + width: 100%; + height: auto; + } +} + +@media (max-aspect-ratio:16/9) { + .background-clip { + width: auto; + height: 100%; + } +} + +header { + position: fixed; + top: 0; + left: 0; + width: 100%; + padding: 20px 100px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 99; +} + +.logo { + font-size: 2em; + color: #fff; + user-select: none; +} + +.navigation a { + position: relative; + font-size: 1.1em; + color: #fff; + text-decoration: none; + font-weight: 500; + margin-left: 40px; +} + +.navigation a::after { + content: ''; + position: absolute; + left: 0; + bottom: -6px; + width: 100%; + height: 3px; + background: #fff; + border-radius: 5px; + transform-origin: right; + transform: scaleX(0); + transition: transform .5s; +} + +.navigation a:hover::after { + transform-origin: left; + transform: scaleX(1); +} + +.navigation .btnLogout { + width: 100px; + height: 40px; + background: transparent; + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.1em; + color: #fff; + font-weight: 500; + margin-left: 40px; + transition: .5s; +} + +.btnQuest-popup { + width: 200px; + height: 50px; + top: 50%; + left: 10%; + position: absolute; + background: transparent; + backdrop-filter: blur(20px); + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 2em; + color: #fff; + font-weight: 500; + /* margin-left: 40px; */ + transition: .5s; + box-shadow: 0 0 10px rgba(0, 0, 0, .5); +} + +/* 대결 신청 팝업 */ + +.wrapper { + position: absolute; + left: 8%; + width: 400px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, .3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(20px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + transform: scale(0); + transition: transform .5s ease, height .2s ease; +} + +.wrapper.active-popup { + transform: scale(1); +} + +.wrapper.active { + height: 520px; +} + +.wrapper .icon-close { + position: absolute; + top: 0; + right: 0; + width: 45px; + height: 45px; + background: #272727; + font-size: 2em; + color: #fff; + display: flex; + justify-content: center; + align-items: center; + border-bottom-left-radius: 20px; + cursor: pointer; + z-index: 1; +} + +.wrapper .form-box { + width: 100%; + padding: 40px; +} + +.wrapper .form-box h2 { + font-size: 2em; + color: #272727; + text-align: center; +} + +.wrapper form { + width: 100%; + max-width: 600px; +} + +.wrapper .input-box { + position: relative; + width: 100%; + height: 50px; + margin-bottom: 30px; +} + +.wrapper .input-box .icon { + position: absolute; + left: 10px; + font-size: 1.2em; + color: #272727; + /*line-height: 30px;*/ +} + +.wrapper .input-box input, output{ + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; +} + +.wrapper .input-box select { + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; + cursor: pointer; +} + +.wrapper .input-box select option { + color: black; + background: white; +} + +.wrapper .input-box output { + display: block; +} + +.wrapper .input-box textarea { + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; +} + +.wrapper .input-box label { + height: 100%; + position: absolute; + left: 0; + top: -37px; + padding: 10px; + color: black; + cursor: text; + transition: 0.2s; +} + +.wrapper .quest_btn { + padding: 10px 0; + width: 100%; + height: 45px; + background: #272727; + border: none; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1em; + color: #fff; + font-weight: 500; +} + +/* 대결 수락 팝업*/ + +.wrapper_unread { + position: absolute; + left: 8%; + width: 400px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, .3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(20px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + transform: scale(0); + transition: transform .5s ease, height .2s ease; +} + +.wrapper_unread.active-popup { + transform: scale(1); +} + +.wrapper_unread.active { + height: 520px; +} + +.wrapper_unread .icon-close2 { + position: absolute; + top: 0; + right: 0; + width: 45px; + height: 45px; + background: #272727; + font-size: 2em; + color: #fff; + display: flex; + justify-content: center; + align-items: center; + border-bottom-left-radius: 20px; + cursor: pointer; + z-index: 1; +} + +.wrapper_unread .form-box { + width: 100%; + padding: 40px; +} + +.wrapper_unread .form-box h2 { + font-size: 2em; + color: #272727; + text-align: center; +} + +.wrapper_unread form { + width: 100%; + max-width: 600px; +} + +.wrapper_unread .input-box { + position: relative; + width: 100%; + height: 50px; + margin-bottom: 30px; +} + +.wrapper_unread .input-box .icon { + position: absolute; + left: 10px; + font-size: 1.2em; + color: #272727; + /*line-height: 30px;*/ +} + +.wrapper_unread .input-box input, output{ + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; +} + +.wrapper_unread .input-box output { + display: block; +} + +.wrapper_unread .input-box textarea { + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; +} + +.wrapper_unread .input-box label { + height: 100%; + position: absolute; + left: 0; + top: -37px; + padding: 10px; + color: black; + cursor: text; + transition: 0.2s; +} + +.wrapper_unread .quest_btn { + padding: 10px 0; + width: 45%; + height: 45px; + background: #272727; + border: none; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1em; + color: #fff; + font-weight: 500; + margin: 0 6.8px; +} + +/* 대결 결과 팝업*/ + +.wrapper_result { + position: absolute; + left: 8%; + width: 400px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, .3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(20px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + transform: scale(0); + transition: transform .5s ease, height .2s ease; +} + +.wrapper_result.active-popup { + transform: scale(1); +} + +.wrapper_result.active { + height: 520px; +} + +.wrapper_result .icon-close3 { + position: absolute; + top: 0; + right: 0; + width: 45px; + height: 45px; + background: #272727; + font-size: 2em; + color: #fff; + display: flex; + justify-content: center; + align-items: center; + border-bottom-left-radius: 20px; + cursor: pointer; + z-index: 1; +} + +.wrapper_result .form-box { + width: 100%; + padding: 40px; +} + +.wrapper_result .form-box h2 { + font-size: 2em; + color: #272727; + text-align: center; +} + +.wrapper_result form { + width: 100%; + max-width: 600px; +} + +.wrapper_result .input-box { + position: relative; + width: 100%; + height: 50px; + margin-bottom: 30px; +} + +.wrapper_result .input-box .icon { + position: absolute; + left: 10px; + font-size: 1.2em; + color: #272727; + /*line-height: 30px;*/ +} + +.wrapper_result .input-box output{ + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; + display: block; +} + +.wrapper_result .input-box input { + width: 20%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; +} + +.wrapper_result .input-box label { + height: 100%; + position: absolute; + left: 0; + top: -37px; + padding: 10px; + color: black; + cursor: text; + transition: 0.2s; +} + +.wrapper_result .quest_btn { + padding: 10px 0; + width: 100%; + height: 45px; + background: #272727; + border: none; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1em; + color: #fff; + font-weight: 500; + margin: 0 6.8px; +} + +/* 대결 결과 팝업*/ + +.wrapper_record { + position: absolute; + left: 8%; + width: 400px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, .3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(20px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + transform: scale(0); + transition: transform .5s ease, height .2s ease; +} + +.wrapper_record.active-popup { + transform: scale(1); +} + +.wrapper_record.active { + height: 520px; +} + +.wrapper_record .icon-close4 { + position: absolute; + top: 0; + right: 0; + width: 45px; + height: 45px; + background: #272727; + font-size: 2em; + color: #fff; + display: flex; + justify-content: center; + align-items: center; + border-bottom-left-radius: 20px; + cursor: pointer; + z-index: 1; +} + +.wrapper_record .form-box { + width: 100%; + padding: 40px; +} + +.wrapper_record .form-box h2 { + font-size: 2em; + color: #272727; + text-align: center; +} + +.wrapper_record form { + width: 100%; + max-width: 600px; +} + +.wrapper_record .input-box { + position: relative; + width: 100%; + height: 50px; + margin-bottom: 30px; +} + +.wrapper_record .input-box .icon { + position: absolute; + left: 10px; + font-size: 1.2em; + color: #272727; + /*line-height: 30px;*/ +} + +.wrapper_record .input-box output{ + width: 100%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; + display: block; +} + +.wrapper_record .input-box input { + width: 20%; + padding: 10px; + outline: 0; + border: 1px solid #fff; + color: black; + background: transparent; + font-size: 15px; + box-sizing: border-box; +} + +.wrapper_record .input-box label { + height: 100%; + position: absolute; + left: 0; + top: -37px; + padding: 10px; + color: black; + cursor: text; + transition: 0.2s; +} + +/* 리스트 */ + +.wrapper_list { + position: absolute; + right: 8%; + display: flex; + width: 1000px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, .3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(20px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + overflow: hidden; + transform: scale(1); +} + +.unread_list { + flex: 1; + display: flex; + flex-direction: column; + padding: 70px 30px 30px 30px; + border-right: 1px solid #ddd; +} + +.past_list { + flex: 1; + display: flex; + flex-direction: column; + padding: 70px 30px 30px 30px; +} + +.unread_list h2, +.past_list h2 { + margin-bottom: 20px; + text-align: center; +} + +.board_list_ur, +.board_list_p, +.board_page { + width: 100%; + text-align: center; +} + +/*미확인 보드 스타일링*/ + +.board_list_ur { + width: 100%; + border-top: 2px solid #000; +} + +.board_list_ur>div { + border-bottom: 1px solid #ddd; + font-size: 0; +} + +.board_list_ur>div.top { + border-bottom: 1.5px solid #000; +} + +.board_list_ur>div:last-child { + border-bottom: 1.5px solid #000; +} + +.board_list_ur>div>div { + display: inline-block; + padding: 15px 0; + text-align: center; + font-size: 1rem; +} + +.board_list_ur>div.top>div { + font-weight: 600; +} + +.board_list_ur .num { + width: 10%; +} + +.board_list_ur .name { + width: 70%; +} + +.btnAccept-popup { + background: none; + border: none; + color: inherit; + font: inherit; + cursor: pointer; + padding: 0; + margin: 0; + text-align: left; + display: inline; + line-height: normal; +} + +.board_list_ur .date { + width: 20%; +} + +/* 전적 보드 스타일링 */ + +.board_list_p { + width: 100%; + border-top: 2px solid #000; +} + +.board_list_p .top { + font-size: 0; +} + +.board_list_p .top > div { + display: inline-block; + padding: 15px 0; + text-align: center; + font-size: 1rem; +} + +.board_list_p>div.top>div { + font-weight: 600; +} + +.board_list_p .num, .numT { + width: 10%; +} + +.board_list_p .name, .nameT { + width: 30%; +} + +.board_list_p .result, .resultT { + width: 30%; +} + +.board_list_p .date, .dateT { + width: 30%; +} + +.list { + width: 100%; + border-top: 2px solid #000; +} + +.list > div { + border-bottom: 1px solid #ddd; + font-size: 0; +} + +.list > div:last-child { + border-bottom: 1.5px solid #000; +} + +.list > div > div { + display: inline-block; + padding: 15px 0; + text-align: center; + font-size: 1rem; +} + +.btnResult-popup { + background: none; + border: none; + color: inherit; + font: inherit; + cursor: pointer; + padding: 0; + margin: 0; + text-align: left; + display: inline; + line-height: normal; +} + +/* 페이지 */ + +.board_page { + margin-top: 30px; + text-align: center; + font-size: 0; +} + +.board_page a { + display: inline-block; + width: 32px; + height: 32px; + box-sizing: border-box; + vertical-align: middle; + border: 1px solid #ddd; + border-left: 0; + line-height: 100%; +} + +.board_page a.bt { + padding-top: 5px; + font-size: 1.2rem; + letter-spacing: -1px; + color: #272727; +} + +.board_page a.num { + padding-top: 7px; + font-size: 1rem; + color: #272727; +} + +.board_page a.num.on { + color: #fff; +} + +.board_page a:first-child { + border-left: 1px solid #ddd; +} \ No newline at end of file diff --git a/challenge.html b/challenge.html new file mode 100644 index 0000000..b33f37b --- /dev/null +++ b/challenge.html @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + Tekken Supporter + + + + +
+ + +
+ + +
+ + + +
+ +
+

1:1 대결



+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ +
+
+

미확인 신청


+
+
+
번호
+
+
신청일
+
+
+


+
+ +
+

전적


+
+
+
번호
+
상대
+
승자
+
대결일
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+

신청 대결



+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+

대결 결과



+
+
+ + +
+
+ + +
+
+ + +
+
+ : + + +
+
+ +
+
+
+
+ +
+ +
+

대결 결과



+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/challenge.js b/challenge.js new file mode 100644 index 0000000..5e9839f --- /dev/null +++ b/challenge.js @@ -0,0 +1,8 @@ +const btnLogout = document.querySelector(".btnLogout"); + +btnLogout.addEventListener("click", function (event) { + event.preventDefault(); + window.location.href = "main.html"; + console.log("Redirecting to:", window.location.href); + localStorage.removeItem("jwt"); + }); \ No newline at end of file diff --git a/challenge_accept.js b/challenge_accept.js new file mode 100644 index 0000000..e80750b --- /dev/null +++ b/challenge_accept.js @@ -0,0 +1,206 @@ +const wrapper2 = document.querySelector('.wrapper_unread') +const btnPopup2 = document.querySelector('.btnAccept-popup'); +const iconClose2 = document.querySelector('.icon-close2'); + +var jwt = localStorage.getItem("jwt"); + +// challenges 배열 초기화 (서버에서 불러온 데이터를 여기에 저장) +let challenges = []; + +// 현재 선택된 challenge 객체를 저장할 변수 +let currentSelectedChallenge = null; + +// 대결 수락/거절 응답을 서버에 보내는 함수 +function sendChallengeResponse(challenge_id, responseType) { + + const parsedChallengeId = parseInt(challenge_id, 10); + + console.log("Sending request with challenge_id:", parsedChallengeId, "and message:", responseType); + + const xhttp = new XMLHttpRequest(); + xhttp.open("POST", "http://34.127.90.191:3000/challenge/accept"); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send( + JSON.stringify({ + challenge_id: parsedChallengeId, + message: responseType + }) + ); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + console.log("Response from server:", this.responseText); + if (responseType === 'accept') { + Swal.fire({ + text: "대결이 성사되었습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./challenge.html"; //해당 페이지로 리다이렉션 + } + }); + } else if (responseType === 'deny') { + Swal.fire({ + text: "대결을 거부했습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./challenge.html"; //해당 페이지로 리다이렉션 + } + }); + } + } else { + console.error("Server returned status code " + this.status); + Swal.fire({ + text: "정보 전송에 실패했습니다", + icon: "error", + confirmButtonText: "OK", + }); + } + } + }; +} + +// 대결 수락 정보 연결 +document.addEventListener("DOMContentLoaded", loadName); +document.addEventListener("DOMContentLoaded", loadChallengeInfo); + +function loadName() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + console.log("UserID from localStorage:", userId); + console.log("JWT from localStorage:", jwt); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/user/info/${userId}`); // 본인 이름 띄우기 + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const objects = JSON.parse(this.responseText); + console.log("Response about user:", objects); + + if (objects["status"] == "ok") { + document.getElementById("contender_accept").textContent = objects["name"]; + } + } catch (e) { + console.error("Error parsing response:", e); + } + } else { + console.error("Server responded with status:", this.status); + } + } + }; +} + +function loadChallengeInfo() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/challenge/check/${userId}`); // 신청 정보 띄우기 + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const response = JSON.parse(this.responseText); + console.log("Response from challenge check:", response); + + // challengeList가 존재하는지 확인 + if (response.challengeList && Array.isArray(response.challengeList)) { + challenges = response.challengeList; // 서버로부터 받은 데이터를 challenges 배열에 저장 + const listElement = document.querySelector(".board_list_ur"); + response.challengeList.forEach((challenge, index) => { + const challengeRow = document.createElement("div"); + challengeRow.innerHTML = ` +
${index + 1}
+
+
${new Date(challenge.creationDate).toLocaleDateString()}
+ `; + listElement.appendChild(challengeRow); + }); + } else { + console.error("challengeList is not an array or undefined"); + } + + } catch (e) { + console.error("Error parsing response", e); + } + } else { + console.error("Server returned status code " + this.status); + } + } + }; +} + +// 대결 수락 함수 +function accept() { + if (!currentSelectedChallenge) { + console.error("No challenge selected"); + return; + } + sendChallengeResponse(currentSelectedChallenge.challenge_id, 'accept'); + console.log("대결 수락"); +} + +// 대결 거절 함수 +function deny() { + if (!currentSelectedChallenge) { + console.error("No challenge selected"); + return; + } + sendChallengeResponse(currentSelectedChallenge.challenge_id, 'deny'); + console.log("대결 거절"); +} + + +document.addEventListener('DOMContentLoaded', function () { + document.addEventListener('click', function (event) { + // 클릭된 요소가 btnAccept-popup 클래스를 가지고 있는지 확인 + if (event.target && event.target.classList.contains('btnAccept-popup')) { + // 해당 버튼과 관련된 challenge 객체 찾기 + const matchId = event.target.getAttribute('data-challenge-id'); + // 문자열로 가져온 matchId를 숫자로 변환 (타입 불일치 방지) + const numericChallengeId = parseInt(matchId, 10); + // 타입 변환된 ID를 사용하여 객체 찾기 + const challenge = challenges.find(ch => ch.challenge_id === numericChallengeId); + console.log(challenge); + if (challenge) { + // challenge 객체에서 정보 가져와서 설정하기 + document.getElementById("challenger_accept").textContent = challenge.challenger; + document.getElementById("date_accept").textContent = new Date(challenge.matchDate).toLocaleDateString(); + document.getElementById("message_accept").textContent = challenge.applymessage; // applymessage를 message_accept에 설정 + } + wrapper2.classList.add('active-popup'); + currentSelectedChallenge = challenge; + } + }); + + const iconClose2 = document.querySelector('.icon-close2'); + iconClose2.addEventListener('click', () => { + wrapper2.classList.remove('active-popup'); + }); +}); diff --git a/challenge_apply.js b/challenge_apply.js new file mode 100644 index 0000000..69f94a9 --- /dev/null +++ b/challenge_apply.js @@ -0,0 +1,148 @@ +const wrapper = document.querySelector('.wrapper'); +const btnPopup = document.querySelector('.btnQuest-popup'); +const iconClose = document.querySelector('.icon-close'); + +btnPopup.addEventListener('click', () => { wrapper.classList.add('active-popup'); }); +iconClose.addEventListener('click', () => { wrapper.classList.remove('active-popup'); }); + +var jwt = localStorage.getItem("jwt"); + +/* 대결 신청에 본인 이름 뜨기*/ +document.addEventListener("DOMContentLoaded", loadUser); +document.addEventListener("DOMContentLoaded", loadContenders); + +function loadUser() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + console.log("UserID from localStorage:", userId); + console.log("JWT from localStorage:", jwt); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/user/info/${userId}`); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const objects = JSON.parse(this.responseText); + console.log("Response about user:", objects); + + if (objects["status"] == "ok") { + document.getElementById("challenger_apply").textContent = objects["name"]; + document.getElementById("contender_accept").textContent = objects["name"]; + } + } catch (e) { + console.error("Error parsing response:", e); + } + } else { + console.error("Server responded with status:", this.status); + } + } + }; +} + +function loadContenders() { + const userId = localStorage.getItem("userId"); // 현재 사용자 ID 가져오기 + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/challenge/name/${userId}`); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE && this.status == 200) { + const response = JSON.parse(this.responseText); // 전체 응답 파싱 + console.log("Response about Contenders:", response); // 파싱된 응답 출력 + + if (response.status === "ok" && Array.isArray(response.namelist)) { + const namelist = response.namelist; // 'namelist'에서 이름 배열을 가져옵니다. + + const selectElement = document.getElementById("contender_apply"); + namelist.forEach(function (contenderName) { + const option = document.createElement("option"); + option.value = contenderName; // 옵션의 값 설정 + option.text = contenderName; // 옵션의 텍스트 설정 + selectElement.appendChild(option); + }); + } else { + console.error("No namelist found in the response or response format is incorrect"); + } + } + }; +} + +/* 대결 신청 */ +function quest() { + const challenger = document.getElementById("challenger_apply").value; + const contender = document.getElementById("contender_apply").value; + const date = document.getElementById("date_apply").value; + const message = document.getElementById("message_apply").value; + + const xhttp = new XMLHttpRequest(); + xhttp.open("POST", "http://34.127.90.191:3000/challenge/apply"); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + + xhttp.send( + JSON.stringify({ + challenger: challenger, + contender: contender, + matchdate: date, + applymessage: message, + }) + ); + + xhttp.onreadystatechange = function () { + if (this.readyState === XMLHttpRequest.DONE) { + try { + if (this.status >= 200 && this.status < 300) { + const objects = JSON.parse(this.responseText); + console.log(objects); + + if (objects["status"] === "ok") { + localStorage.setItem("jwt", objects["token"]); + Swal.fire({ + text: "대결을 신청했습니다!", + icon: "success", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + window.location.href = "./challenge.html"; + } + }); + } else { + Swal.fire({ + text: "신청에 실패했습니다.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Empty response received from the server"); + } + } else { + Swal.fire({ + text: "서버 오류 발생. 잠시 후 다시 시도해주세요.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Server responded with status:", this.status); + } + } catch (e) { + Swal.fire({ + text: "응답 처리 중 오류가 발생했습니다.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error parsing response:", e); + } + } + }; + return false; +} \ No newline at end of file diff --git a/challenge_result.js b/challenge_result.js new file mode 100644 index 0000000..0d67133 --- /dev/null +++ b/challenge_result.js @@ -0,0 +1,269 @@ +const wrapper3 = document.querySelector('.wrapper_result') +const btnPopup3 = document.querySelector('.btnResult-popup'); +const wrapper4 = document.querySelector('.wrapper_record') + +var jwt = localStorage.getItem("jwt"); + +// challengess 배열 초기화 (서버에서 불러온 데이터를 여기에 저장) +let challengess = []; + +// 현재 선택된 challengess 객체를 저장할 변수 +let currentSelectedChallenges = null; +let userName = null; + +// 페이지당 항목 수 +const itemsPerPage = 5; + +// 대결 전적 정보 연결 +document.addEventListener("DOMContentLoaded", loadName); + +function loadName() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + console.log("UserID from localStorage:", userId); + console.log("JWT from localStorage:", jwt); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/user/info/${userId}`); // 본인 이름 띄우기 + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const objects = JSON.parse(this.responseText); + console.log("Response about user:", objects); + + if (objects["status"] == "ok") { + userName = objects["name"]; + console.log("계정주 이름:" + userName); + loadChallengeInfo(); + updateList(1); + } + } catch (e) { + console.error("Error parsing response:", e); + } + } else { + console.error("Server responded with status:", this.status); + } + } + }; +} + + +function loadChallengeInfo() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/user/match/${userId}`); // 신청 정보 띄우기 + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const response = JSON.parse(this.responseText); + console.log("Response from challenge check:", response); + + if (response.matchlist && Array.isArray(response.matchlist)) { + challengess = response.matchlist; + updateList(1); // 첫 페이지로 초기화 + createPaginationButtons(); // 페이지네이션 버튼 생성 + } else { + console.error("matchlist is not an array or undefined"); + } + } catch (e) { + console.error("Error parsing response", e); + } + } else { + console.error("Server returned status code " + this.status); + } + } + }; +} + +function updateList(pageNumber) { + if (!userName) { + console.error("userName is not loaded yet"); + return; + } + console.log("UserName in another function:", userName); + + const startIndex = (pageNumber - 1) * itemsPerPage; + const endIndex = startIndex + itemsPerPage; + const paginatedItems = challengess.slice(startIndex, endIndex); + + const listElement = document.querySelector(".list"); + listElement.innerHTML = ""; + + paginatedItems.forEach((challenge, index) => { + let nameToShow; + if (userName === challenge.challenger) + nameToShow = challenge.contender; + if (userName === challenge.contender) + nameToShow = challenge.challenger; + console.log(nameToShow); + const challengeRow = document.createElement("div"); + challengeRow.innerHTML = ` +
${index + 1}
+
+
${challenge.winner}
+
${new Date(challenge.matchDate).toLocaleDateString()}
+ `; + console.log(challenge.match_id); + listElement.appendChild(challengeRow); + }); +} + +function createPaginationButtons() { + const pageCount = Math.ceil(challengess.length / itemsPerPage); + const paginationElement = document.querySelector(".board_page"); + paginationElement.innerHTML = ""; // 이전 페이지 버튼들을 지우고 새로 시작 + + for (let i = 1; i <= pageCount; i++) { + const pageButton = document.createElement("a"); + pageButton.href = "#"; + pageButton.textContent = i; + pageButton.className = "num"; + pageButton.addEventListener("click", function (e) { + e.preventDefault(); + updateList(i); + }); + + paginationElement.appendChild(pageButton); + } +} + +// 대결 결과 전송 +function result() { + if (!currentSelectedChallenges) { + console.error("No challenge selected"); + return; + } + const challengeId = currentSelectedChallenges.match_id; + const challengerName = document.getElementById("challenger_result").textContent; + const contenderName = document.getElementById("contender_result").textContent; + const scoreChallenger = parseInt(document.getElementById("score_challenger").value, 10); + const scoreContender = parseInt(document.getElementById("score_contender").value, 10); + + if (!challengeId || !challengerName || !contenderName || isNaN(scoreChallenger) || isNaN(scoreContender)) { + alert("모든 필드를 올바르게 입력해주세요."); + return false; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("POST", "http://34.127.90.191:3000/challenge/result"); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send( + JSON.stringify({ + challenge_id: challengeId, + challenger: challengerName, + contender: contenderName, + score_challenger: scoreChallenger, + score_contender: scoreContender + })); + + xhttp.onreadystatechange = function () { + if (this.readyState === XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + // 요청이 성공적으로 처리되었을 때의 로직 + console.log("대결 결과가 성공적으로 제출되었습니다."); + if (scoreContender > scoreChallenger) { + Swal.fire({ + text: contenderName + "님이 대결에서 승리했습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./challenge.html"; //해당 페이지로 리다이렉션 + } + }); + } else if (scoreContender == scoreChallenger) { + Swal.fire({ + text: "대결에서 비겼습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./challenge.html"; //해당 페이지로 리다이렉션 + } + }); + } else { + Swal.fire({ + text: challengerName + "님이 대결에서 승리했습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./challenge.html"; //해당 페이지로 리다이렉션 + } + }); + } + } else { + // 요청 처리 중 오류가 발생했을 때의 로직 + console.error("오류 발생:", this.status, this.responseText); + } + } + }; + + return false; +} + + +document.addEventListener('click', function (event) { + // 클릭된 요소가 btnResult-popup 클래스를 가지고 있는지 확인 + if (event.target && event.target.classList.contains('btnResult-popup')) { + // 해당 버튼과 관련된 challenge 객체 찾기 + const matchId = event.target.getAttribute('data-match-id'); + // 문자열로 가져온 matchId를 숫자로 변환 (타입 불일치 방지) + const numericMatchId = parseInt(matchId, 10); + // 타입 변환된 ID를 사용하여 객체 찾기 + const challenge = challengess.find(ch => ch.match_id === numericMatchId); + console.log(challenge); + if (challenge) { + // winscore와 losescore 값 확인 + if (challenge.winscore === "0" && challenge.losescore === "0") { + // challenge 객체에서 정보 가져와서 설정하기 (result 팝업) + document.getElementById("challenger_result").textContent = challenge.challenger; + document.getElementById("contender_result").textContent = challenge.contender; + document.getElementById("date_result").textContent = new Date(challenge.matchDate).toLocaleDateString(); + wrapper3.classList.add('active-popup'); + } else { + // challenge 객체에서 정보 가져와서 설정하기 (record 팝업) + document.getElementById("winner_record").textContent = challenge.winscore > challenge.losescore ? challenge.winner : challenge.loser; + document.getElementById("loser_record").textContent = challenge.winscore < challenge.losescore ? challenge.winner : challenge.loser; + document.getElementById("winscore").textContent = Math.max(challenge.winscore, challenge.losescore); + document.getElementById("losescore").textContent = Math.min(challenge.winscore, challenge.losescore); + wrapper4.classList.add('active-popup'); + } + currentSelectedChallenges = challenge; + } + } + const iconClose3 = document.querySelector('.icon-close3'); + iconClose3.addEventListener('click', () => { + wrapper3.classList.remove('active-popup'); + }); + const iconClose4 = document.querySelector('.icon-close4'); + iconClose4.addEventListener('click', () => { + wrapper4.classList.remove('active-popup'); + }); + +}); + diff --git a/charinfo.css b/charinfo.css new file mode 100644 index 0000000..2047a2b --- /dev/null +++ b/charinfo.css @@ -0,0 +1,280 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +.container { + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + justify-content: center; +} + +.background-clip { + position: fixed; + right: 0; + bottom: 0; + z-index: -1; +} + +@media (min-aspect-ratio:16/9) { + .background-clip { + width: 100%; + height: auto; + } +} + +@media (max-aspect-ratio:16/9) { + .background-clip { + width: auto; + height: 100%; + } +} + +body { + display: flex; + align-items: center; + background-position: center; + padding: 10px; +} + +header { + position: fixed; + top: 0; + left: 0; + width: 100%; + padding: 20px 100px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 99; +} + +.logo { + font-size: 2em; + color: #fff; + user-select: none; +} + +.navigation a { + position: relative; + font-size: 1.1em; + color: #fff; + text-decoration: none; + font-weight: 500; + margin-left: 40px; +} + +.navigation a::after { + content: ''; + position: absolute; + left: 0; + bottom: -6px; + width: 100%; + height: 3px; + background: #fff; + border-radius: 5px; + transform-origin: right; + transform: scaleX(0); + transition: transform .5s; +} + +.navigation a:hover::after { + transform-origin: left; + transform: scaleX(1); +} + +.navigation .btnLogout { + width: 100px; + height: 40px; + background: transparent; + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.1em; + color: #fff; + font-weight: 500; + margin-left: 40px; + transition: .5s; +} + +.reviews-container { + position: static; + width: calc(100%/4 - 20px); + top: 50px; + padding: 20px; + margin: 20px; + height: flex; + font-weight: 170; + font-size: 15px; + line-height: 20px; + text-transform: uppercase; + color: black; + background: linear-gradient(180deg, #D9D9D9 0%, rgba(217, 217, 217, 0.51) 0%); +} + +.reviews-container>div { + margin-bottom: 15px; + color: #333; + font-size: 14px; + width: 100%; + height: 50px; +} + +.reviews-container select, +.reviews-container input[type="text"], +.reviews-container textarea { + width: 100%; + height: 35px; + padding: 5px; + margin-bottom: 10px; +} + +.reviews-container textarea { + height: 80px; +} + +button { + padding: 5px; +} + +.pagination-container { + position: static; + width: calc(100%/4 - 20px); + margin: 20px; + padding: 20px; +} + +.pagination-container .review-list { + width: 100%; +} + + +.review-list .review { + width: 100%; + border: 1px solid #ccc; + padding: 10px; + margin-bottom: 20px; + background: linear-gradient(180deg, #D9D9D9 0%, rgba(217, 217, 217, 0.51) 0%); +} + +.content { + position: static; + width: calc(100%/4 - 20px); + margin: 20px; + padding: 20px; + height: flex; + text-align: center; + font-family: 'Inter'; + font-style: italic; + font-weight: 170; + font-size: 20px; + line-height: 30px; + text-transform: uppercase; + color: black; + background: linear-gradient(180deg, #D9D9D9 0%, rgba(217, 217, 217, 0.51) 0%); +} + +.characterlist { + width: 100%; + text-align: center; +} + +.infoandpic_char { + position: static; + width: calc(100%/4 - 20px); + margin: 20px; + padding: 20px; + height: flex; + text-align: center; + font-family: 'Inter'; + font-style: italic; + font-weight: 170; + font-size: 20px; + line-height: 30px; + text-transform: uppercase; + color: black; +} + +.character-container { + display: none; + background: linear-gradient(180deg, #D9D9D9 0%, rgba(217, 217, 217, 0.51) 0%); + border: 1px solid #ccc; + padding: 10px; +} + +.character-info { + font-weight: bold; + color: #333; +} + +.character-image { + width: 300px; + height: auto; + margin-top: 10px; +} + +.linkposition { + position: relative; + width: 100%; + height: flex; + + font-size: 12px; + display: inline-block; + background: linear-gradient(180deg, #d9d9d9e7 0%, rgba(167, 212, 227, 0.56) 0%); + font-family: 'Noto+Serif+KR', sans-serif; +} + +img { + width: 100%; +} + +.contitle { + position: absolute; + left: 100px; + height: 60px; + top: 64px; + font-family: 'Inter'; + font-style: normal; + line-height: 20px; + text-transform: uppercase; + color: white; +} + +h3 { + color: black; + text-align: center; + font-family: 'Noto+Serif+KR', sans-serif; +} + +#btn-all-close { + width: 100%; + background-color: #b1a5dd; + font-size: 13px; + border: none; + color: #fff; + cursor: pointer; + float: right; +} + +#btn-all-close:hover { + background-color: yellow; + color: #000; + transition: all.35s; +} + +.page-link { + cursor: pointer; + padding: 5px; + + margin-left: 5px; + border: 1px solid #ccc; + background: linear-gradient(180deg, #D9D9D9 0%, rgba(217, 217, 217, 0.51) 0%); +} \ No newline at end of file diff --git a/charinfo.html b/charinfo.html new file mode 100644 index 0000000..09596fd --- /dev/null +++ b/charinfo.html @@ -0,0 +1,205 @@ + + + + + + + character_info + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+

Tips & Reviews about Characters

+
+ +
+ + +
+

캐릭터 리뷰



+
+ +
+ + +
+ + +
+ + +
+
+ + +
+
+
+
+
+ + + +
+
+ + + + + + + + + +
+ + + +
+ + +
+
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+

DIFFICULTY

+

+
+ +
+ + + + +
+ + + + + \ No newline at end of file diff --git a/charinfo.js b/charinfo.js new file mode 100644 index 0000000..d33913a --- /dev/null +++ b/charinfo.js @@ -0,0 +1,405 @@ +var jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImlkIjoidGVzdCIsImlhdCI6MTY5OTYzMjA1NywiZXhwIjoxNzAyMjI0MDU3fQ.P0AX2jyS18tjHFKBQRy6Wi6OWG9AlDQ4hJtpZp3woB0"; +var reviews = []; +const reviewsPerPage = 3; +let currentPage = 1; + +document.addEventListener("DOMContentLoaded", loadReviews(currentPage)); + +var submitButton = document.getElementById("submit"); +// 이벤트 리스너를 추가하기 전에 엘리먼트가 존재하는지 확인 + +// [리뷰창 보이게 만들기] +//loadReviews > 리뷰 편집기능과는 별개로 사용자에게 리뷰공개 +loadReviews(currentPage); +loadPageNumbers();//index of lists + +function loadPageNumbers() { + const paginationContainer = document.getElementById("pagination-container"); + const totalPages = Math.ceil(20 / reviewsPerPage); + + for (let i = 0; i < totalPages; i++) { + const pageNumber = i + 1; + const pageLink = document.createElement("span"); + pageLink.textContent = pageNumber; + pageLink.classList.add("page-link"); + pageLink.addEventListener("click", () => { + currentPage = i + 1; + loadReviews(currentPage); + const pageLinks = document.querySelectorAll(".page-link"); + + pageLinks.forEach((link, index) => { + if (index + 1 === currentPage) { + link.classList.add("active"); + } else { + link.classList.remove("active"); + } + }); + }); + paginationContainer.appendChild(pageLink); + } +} + +function loadReviews(page) { + var xhr = new XMLHttpRequest(); + var url = "http://34.127.90.191:3000/character/review?c_name=&id=&reviewData=&creationTime="; + + xhr.open("GET", url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + // 서버 응답에 따른 추가 작업 수행 + reviews = JSON.parse(xhr.responseText); + console.log(reviews); + const startIndex = (page - 1) * reviewsPerPage; + const endIndex = startIndex + reviewsPerPage; + const currentPageReviews = reviews.slice(startIndex, endIndex); + displayReviews(currentPageReviews); + } else { + console.error("서버 에러:", xhr.status); + } + } + }; + xhr.send(); +} + +function displayReviews(reviews) {//loadReviews 관련 + const reviewListContainer = document.getElementById("reviewList"); + reviewListContainer.innerHTML = ""; + + reviews.forEach((review) => { + const reviewElement = document.createElement("div"); + reviewElement.classList.add("review"); + reviewElement.innerHTML = ` +

캐릭터 이름: ${review.c_name || "알 수 없음"}

+

사용자 ID: ${review.id || "알 수 없음"}

+

리뷰 내용: ${review.reviewData || "리뷰 없음"}

+

작성 시간: ${review.Creationtime || "알 수 없음"}

+ + + `; + reviewListContainer.appendChild(reviewElement); + }); +} + +// [ 캐릭터 목록들 정리버튼 ] +const btnAllClose = document.getElementById('btn-all-close'); +btnAllClose.addEventListener('click', resetCharacterContainers); +console.log('all close button click'); +function resetCharacterContainers() { + const characterContainers = document.querySelectorAll('.character-container'); + characterContainers.forEach(container => { + container.style.display = 'none'; + }); +} +// 각 캐릭터 링크에 이벤트 리스너 추가 +const characterLinks = document.querySelectorAll('.character-link'); +characterLinks.forEach(link => { + link.addEventListener('click', showCharacterInfo); +}); +// 클릭한 캐릭터의 데이터 얻기 +function showCharacterInfo(event) { + const characterId = event.target.getAttribute('data-character'); + const characterContainers = document.querySelectorAll('.character-container'); + characterContainers.forEach(container => { + container.style.display = 'none'; + }); + // 클릭한 캐릭터에 해당하는 컨테이너 보이기 + const selectedContainer = document.getElementById(characterId); + if (selectedContainer) { + selectedContainer.style.display = 'block'; + } +} + +///////////////// 캐릭터 설명창입니다 ////////////// +var xhr7 = new XMLHttpRequest(); +var url = "http://34.127.90.191:3000/character/main"; + +xhr7.open("GET", url, true); +xhr7.onreadystatechange = function () { + if (xhr7.readyState == 4) { + if (xhr7.status == 200) { + // 서버 응답에 따른 추가 작업 수행 + tips = JSON.parse(xhr7.responseText); + console.log(tips); + var akuma =tips[0]; + var alisa = tips[1]; + var armor = tips[2]; + var asuka = tips[3]; + var bob =tips[4]; + var bryan =tips[5]; + var claudio =tips[6]; + var devil =tips[7]; + var eddy =tips[9]; + + checkLevel1(akuma); + checkLevel2(alisa); + checkLevel3(armor); + checkLevel4(asuka); + checkLevel5(bob); + checkLevel6(bryan); + checkLevel7(claudio); + checkLevel8(devil); + checkLevel9(eddy); + } else { + console.error("서버 에러:", xhr7.status); + } + } + }; + xhr7.send(); + + function getChacImageDynamic(chacName) { //모두 대문자로 받음 + return `https://github.com/Tekken-Supporter/Frontend/blob/main/IMAGES/${chacName}`+ `.png?raw=true`; + } + ///~295 같은형식의 코드들 +function checkLevel1(tips) { + var characterinfo = document.getElementById('character1'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel2(tips) { + var characterinfo = document.getElementById('character2'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel3(tips) { + var characterinfo = document.getElementById('character3'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel4(tips) { + var characterinfo = document.getElementById('character4'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel5(tips) { + var characterinfo = document.getElementById('character5'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + + + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel6(tips) { + var characterinfo = document.getElementById('character6'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + + + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel7(tips) { + var characterinfo = document.getElementById('character7'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + + + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel8(tips) { + var characterinfo = document.getElementById('character8'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} +function checkLevel9(tips) { + var characterinfo = document.getElementById('character9'); + var tip = document.createElement('div'); + tip.classList.add('tips'); + console.log(tips.difficulty); + tip.innerHTML = `

${tips.difficulty}

`; + characterinfo.appendChild(tip); + + var pic = document.createElement('div'); + pic.innerHTML = ` + 캐릭터 이미지 + `; + characterinfo.appendChild(pic); +} + +//여기서부터 수정필요한 REVIEW 코드들:put, delete, post +// 1 GET, reviewsend. js에 따로 있음. +// 2 PUT, update 리뷰 수정 함수 > 미루기 +function updateReview(reviewId) { + var modifiedReviewContent = prompt("수정된 리뷰 내용을 입력하세요:"); + if (modifiedReviewContent !== null) { + var modifiedTime = new Date().toISOString(); + + var updatedData = { + reviewId: reviewId, + modifiedTime: modifiedTime, + reviewData: modifiedReviewContent, + }; + + // XMLHttpRequest 객체 생성 + var xhr3 = new XMLHttpRequest(); + var url = "http://34.127.90.191:3000/character/review?c_name=&id=&reviewData=&creationTime="; + + xhr3.open("PUT", url, true); + xhr3.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhr3.setRequestHeader("Authorization", "Bearer " + jwt); + + xhr3.onreadystatechange = function () { + if (xhr3.readyState == 4) { + if (xhr3.status == 200) { + console.log("서버 응답:", xhr3.responseText); + // 서버 응답에 따른 추가 작업 수행 + var response = JSON.parse(xhr3.responseText); + if (response.status === "success") { + // 리뷰가 성공적으로 수정된 경우에 처리할 내용 추가 + // 예: 수정된 리뷰를 웹에 보여주기 + displayReview(response.data); + } else { + // 리뷰 수정이 실패한 경우에 처리할 내용 추가 + console.error("리뷰 수정 실패:", response.message); + } + } else { + console.error("서버 에러:", xhr3.status); + } + } + }; + xhr3.send(JSON.stringify(updatedData)); + } +} + +//3 delete, Review +var deleteButtons = document.querySelectorAll(".deleteButton"); +deleteButtons.forEach(function (deleteButton) { + deleteButton.addEventListener("click", function () { + var reviewId = deleteButton.getAttribute("data-reviewid"); + console.log(reviewId); + deleteReviewFunction(reviewId); + }); +}); + +function deleteReview(reviewId) { + var xhr4 = new XMLHttpRequest(); + var url = "http://34.127.90.191:3000/character/review"; + + xhr4.open("DELETE", url + "?number" + reviewId, true); + + xhr4.onreadystatechange = function () { + if (xhr4.readyState == 4) { + if (xhr4.status == 200) { + console.log("서버 응답:", xhr4.responseText); + var response = JSON.parse(xhr4.responseText); + if (response.status === "success") { + removeReviewFromUI(reviewId); + } else { + console.error("리뷰 삭제 실패:", response.message); + } + } else { + console.error("서버 에러:", xhr4.status); + } + } + }; + xhr4.send(); +} + +// 4. 리뷰를 웹에 보여주는 함수 (UI 업데이트) +function displayReview(reviewData) { + reviews.push(reviewData);// 리뷰 배열에 추가 + // 리뷰를 웹에 표시 + updateReviewList(); +} + +// 리뷰를 웹에서 제거하는 함수 (UI 업데이트) +function removeReviewFromUI(reviewId) { + // 리뷰 목록에서 해당 리뷰를 찾아서 제거 + reviews = reviews.filter(review => review.id !== reviewId); + // 리뷰를 웹에 표시 + updateReviewList(); +} + +// 2,4 related: 리뷰 목록을 업데이트하는 함수 +function updateReviewList() { + + var reviewListContainer = document.getElementById("reviewList"); + // 이전 리뷰 목록을 지우기 + reviewListContainer.innerHTML = ""; + + // 각 리뷰에 대해 HTML 엘리먼트를 생성하여 추가 + reviews.forEach(function (review) { + var reviewElement = document.createElement("div"); + reviewElement.classList.add("review"); + reviewElement.innerHTML = ` +

캐릭터 이름: ${review.c_name}

+

사용자 ID: ${review.id}

+

리뷰 내용: ${review.reviewData}

+

작성 시간: ${review.CreationTime}

+

수정 시간: ${review.modifiedTime}

+ + + `; + reviewListContainer.appendChild(reviewElement); + }); +} + + + + + + + + + diff --git a/login.js b/login.js index 8180855..fd5a6a6 100644 --- a/login.js +++ b/login.js @@ -1,6 +1,6 @@ var jwt = localStorage.getItem("jwt"); if (jwt != null) { - window.location.href = "./index.html"; + window.location.href = "./myinfo.html"; } function login() { @@ -8,7 +8,7 @@ function login() { const password = document.getElementById("password").value; const xhttp = new XMLHttpRequest(); - xhttp.open("POST", "http://34.168.80.42:3000/auth/login"); + xhttp.open("POST", "http://34.127.90.191:3000/auth/login"); xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhttp.send( JSON.stringify({ @@ -16,29 +16,52 @@ function login() { password: password, }) ); + xhttp.onreadystatechange = function () { - if (this.readyState == 4) { - const objects = JSON.parse(this.responseText); - console.log(objects); - if (objects["status"] == "ok") { - localStorage.setItem("jwt", objects["token"]); - Swal.fire({ - text: objects["message"], - icon: "success", - confirmButtonText: "OK", - }).then((result) => { - if (result.isConfirmed) { - window.location.href = "./index.html"; + if (this.readyState === XMLHttpRequest.DONE) { + try { + if (this.status >= 200 && this.status < 300) { + const objects = JSON.parse(this.responseText); //서버로부터 받은 응답텍스트를 JSON 객체로 변환 + console.log(objects); //서버로부터 받은 응답 콘솔에 출력 + + if (objects["status"] === "ok") { //서버로부터 받은 응답의 상태가 ok일 때 + localStorage.setItem("jwt", objects["token"]); //jwt라는 이름으로 서버에서 받은 토큰을 로컬스토리지에 저장 + localStorage.setItem("userId", id); // 사용자 ID를 로컬 스토리지에 저장 + Swal.fire({ + text: "로그인 성공!", + icon: "success", + confirmButtonText: "OK", //성공 메시지를 사용자에게 보여줌 + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./myinfo.html"; //해당 페이지로 리다이렉션 + } + }); + } else { + Swal.fire({ + text: "로그인에 실패했습니다", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Empty response received from the server"); } - }); - } else { + } else { + Swal.fire({ + text: "서버 오류 발생. 잠시 후 다시 시도해주세요.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Server responded with status:", this.status); + } + } catch (e) { Swal.fire({ - text: objects["message"], + text: "응답 처리 중 오류가 발생했습니다.", icon: "error", confirmButtonText: "OK", }); + console.error("Error parsing response:", e); } } }; return false; -} \ No newline at end of file +} + diff --git a/style.css b/main.css similarity index 88% rename from style.css rename to main.css index 669f880..c66c155 100644 --- a/style.css +++ b/main.css @@ -93,26 +93,29 @@ header { transform: scaleX(1); } -.navigation .btnLogin-popup { - width: 130px; - height: 50px; +.btnLogin-popup { + width: 310px; + height: 100px; + position: absolute; background: transparent; + backdrop-filter: blur(20px); border: 2px solid #fff; outline: none; border-radius: 6px; cursor: pointer; - font-size: 1.1em; + font-size: 4em; color: #fff; font-weight: 500; - margin-left: 40px; + /* margin-left: 40px; */ transition: .5s; + box-shadow: 0 0 10px rgba(0, 0, 0, .5); } .wrapper { position: relative; width: 400px; height: 440px; - background: transparent; + background-color: rgba(255, 255, 255, 0.3); border: 2px solid rgba(255, 255, 255, .5); border-radius: 20px; backdrop-filter: blur(20px); @@ -202,6 +205,7 @@ header { transition: .5s; } + .input-box input:focus~label, .input-box input:valid~label { top: -5px; @@ -227,6 +231,14 @@ header { line-height: 57px; } +.input-box .icon-eyeoff { + position: absolute; + right: 8px; + font-size: 1.2em; + color: #272727; + line-height: 57px; +} + .remember-forgot { font-size: .9em; color: #272727; @@ -250,7 +262,20 @@ header { text-decoration: underline; } -.btn { +.register_btn { + width: 100%; + height: 45px; + background: #272727; + border: none; + outline: none; + border-radius: 6px; + font-size: 1em; + color: #fff; + cursor: pointer; + font-weight: 500; +} + +.login_btn { width: 100%; height: 45px; background: #272727; diff --git a/main.html b/main.html index 2453569..b262124 100644 --- a/main.html +++ b/main.html @@ -5,98 +5,125 @@ - - 철권 로그인과 회원가입 - + + + + + + + + + Tekken Supporter + -
- +
+ -
- - -
+
+ + +
- + + +
+ -
-

회원가입

-
-
- - - -
-
- - - -
-
- - - -
-
- -
-
- -
- -
+ + +
+

회원가입

+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+ +
+ +
+
-
- - - - - - + - \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..25a7e62 --- /dev/null +++ b/main.js @@ -0,0 +1,14 @@ +const wrapper = document.querySelector('.wrapper'); +const loginLink = document.querySelector('.login-link'); +const registerLink = document.querySelector('.register-link'); +const btnPopup = document.querySelector('.btnLogin-popup'); +const iconClose = document.querySelector('.icon-close'); + +registerLink.addEventListener('click', () => { wrapper.classList.add('active'); }); + +loginLink.addEventListener('click', () => { wrapper.classList.remove('active'); }); + +btnPopup.addEventListener('click', () => { wrapper.classList.add('active-popup'); }); + +iconClose.addEventListener('click', () => { wrapper.classList.remove('active-popup'); }); + diff --git a/myinfo.css b/myinfo.css new file mode 100644 index 0000000..a2af883 --- /dev/null +++ b/myinfo.css @@ -0,0 +1,274 @@ + @import url('https://fonts.googleapis.com/css2?family=Poppins'); + + * { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; + } + + .container { + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + justify-content: center; + } + + .background-clip { + position: absolute; + right: 0; + bottom: 0; + z-index: -1; + } + + @media (min-aspect-ratio:16/9) { + .background-clip { + width: 100%; + height: auto; + } + } + + @media (max-aspect-ratio:16/9) { + .background-clip { + width: auto; + height: 100%; + } + } + + header { + position: fixed; + top: 0; + left: 0; + width: 100%; + padding: 20px 100px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 99; + } + + .logo { + font-size: 2em; + color: #fff; + user-select: none; + } + + .navigation a { + position: relative; + font-size: 1.1em; + color: #fff; + text-decoration: none; + font-weight: 500; + margin-left: 40px; + } + + .navigation a::after { + content: ''; + position: absolute; + left: 0; + bottom: -6px; + width: 100%; + height: 3px; + background: #fff; + border-radius: 5px; + transform-origin: right; + transform: scaleX(0); + transition: transform .5s; + } + + + .navigation a:hover::after { + transform-origin: left; + transform: scaleX(1); + } + + .myinfo::after { + content: ''; + position: absolute; + left: 0; + bottom: -6px; + width: 100%; + height: 3px; + background: #fff; + border-radius: 5px; + } + + .navigation .btnLogout { + width: 100px; + height: 40px; + background: transparent; + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.1em; + color: #fff; + font-weight: 500; + margin-left: 40px; + transition: .5s; + } + + .wrapper { + position: relative; + width: 1000px; + height: 600px; + background: transparent; + background-color: rgba(255, 255, 255, 0.3); + border: 2px solid rgba(255, 255, 255, .5); + border-radius: 20px; + backdrop-filter: blur(30px); + box-shadow: 0 0 30px rgba(0, 0, 0, .5); + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + transform: scale(1); + } + + .wrapper .form-box { + width: 100%; + padding: 40px; + transition: none; + } + + .wrapper h2 { + position: absolute; + top: 10%; + font-size: 2em; + color: #272727; + text-align: center; + } + + .output-box { + position: relative; + width: 100%; + height: 50px; + border-bottom: 2px solid #272727; + margin: 30px 0; + } + + .output-box label { + position: absolute; + top: 50%; + left: 5px; + transform: translateY(-50%); + font-size: 1em; + color: #272727; + font-weight: 500; + pointer-events: none; + transition: .5s; + } + + .output-box output { + position: absolute; + left: 100px; + width: 60%; + height: 100%; + border: none; + outline: none; + font-size: 1em; + color: #272727; + font-weight: 600; + padding: 10px 35px 0 5px; + background: transparent; + align-items: center; + } + + .output-box .input_nowpassword { + position: absolute; + left: 100px; + width: 60%; + height: 100%; + border: none; + outline: none; + font-size: 1em; + color: #272727; + font-weight: 600; + padding: 0 35px 0 25px; + background: transparent; + } + + .output-box .input_newpassword { + position: absolute; + left: 100px; + width: 60%; + height: 100%; + border: none; + outline: none; + font-size: 1em; + color: #272727; + font-weight: 600; + padding: 0 35px 0 25px; + background: transparent; + } + + /* Select 드롭다운 스타일링 */ + .output-box select { + position: absolute; + left: 100px; + width: 60%; + height: 100%; + border: none; + outline: none; + font-size: 1em; + color: #272727; + font-weight: 600; + padding: 0 35px 0 5px; + cursor: pointer; + /* 드롭다운 메뉴임을 나타내는 커서 스타일 */ + -webkit-appearance: none; + /* 기본 브라우저 스타일 제거 */ + -moz-appearance: none; + appearance: none; + background: transparent; + } + + .output-box .icon { + position: absolute; + right: 8px; + font-size: 1.2em; + color: #272727; + line-height: 57px; + } + + /* 수정하기 버튼 스타일링 - 로그아웃 버튼 스타일 참조 */ + .change_btn { + width: 100px; + /* 또는 원하는 너비 */ + height: 40px; + background: transparent; + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.1em; + color: #fff; + font-weight: 500; + transition: .5s; + float: right; + } + + .change_btn:hover { + background: #fff; + /* 호버 시 배경색 변경 */ + color: #272727; + /* 호버 시 글자색 변경 */ + } + + /* Select 드롭다운 화살표 스타일링 */ + .output-box select::-ms-expand { + display: none; + } + + /* 아이콘과 함께 select 스타일링 */ + .output-box .icon { + position: absolute; + right: 8px; + font-size: 1.2em; + color: #272727; + line-height: 57px; + pointer-events: none; + /* 아이콘이 선택을 방해하지 않도록 설정 */ + } \ No newline at end of file diff --git a/myinfo.html b/myinfo.html new file mode 100644 index 0000000..7529f38 --- /dev/null +++ b/myinfo.html @@ -0,0 +1,122 @@ + + + + + + + + + + + + Tekken Supporter + + + + + +
+ + +
+ + +
+ +
+

계정 정보

+
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/myinfo.js b/myinfo.js new file mode 100644 index 0000000..9b7a570 --- /dev/null +++ b/myinfo.js @@ -0,0 +1,168 @@ +const btnLogout = document.querySelector(".btnLogout"); +const input_password = document.querySelector(".input_password"); +const input_champion = document.querySelector(".input_champion"); +const change_btn = document.querySelector(".change_btn"); +const user_id = document.querySelector(".user_id"); +const input_nowpassword = document.querySelector(".input_nowpassword"); +const input_newpassword = document.querySelector(".input_newpassword"); + +var jwt = localStorage.getItem("jwt"); + +document.addEventListener("DOMContentLoaded", loadUser); + +function loadUser() { + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + console.log("UserID from localStorage:", userId); + console.log("JWT from localStorage:", jwt); + + if (!userId || !jwt) { + console.error("No userID or JWT found in localStorage"); + return; + } + + const xhttp = new XMLHttpRequest(); + xhttp.open("GET", `http://34.127.90.191:3000/user/info/${userId}`); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + xhttp.send(); + + xhttp.onreadystatechange = function () { + if (this.readyState == XMLHttpRequest.DONE) { + if (this.status >= 200 && this.status < 300) { + try { + const objects = JSON.parse(this.responseText); + console.log("Response from server:", objects); + + if (objects["status"] == "ok") { + document.getElementById("name").textContent = objects["name"]; + document.getElementById("id").textContent = objects["id"]; + document.getElementById("tier").textContent = objects["tier"]; + document.getElementById("winrate").textContent = objects["winrate"]; + + const championSelect = document.getElementById("champion"); + if (objects["champion"] && championSelect) { + let found = false; + for (let option of championSelect.options) { + if (option.value === objects["champion"]) { + option.selected = true; + found = true; + break; + } + } + if (!found) { + console.error("Invalid champion value from server:", objects["champion"]); + } + } else { + console.error("Champion select element missing or no champion value from server"); + } + } + } catch (e) { + console.error("Error parsing response:", e); + } + } else { + console.error("Server responded with status:", this.status); + } + } + }; +} + +function modify() { + const nowpassword = document.getElementById("nowpassword").value; + const newpassword = document.getElementById("newpassword").value; + const newchampion = document.getElementById("champion").value + + const userId = localStorage.getItem("userId"); + jwt = localStorage.getItem("jwt"); + + const xhttp = new XMLHttpRequest(); + xhttp.open("PUT", `http://34.127.90.191:3000/user/updateinfo/${userId}`); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhttp.setRequestHeader("Authorization", "Bearer " + jwt); + + xhttp.send( + JSON.stringify({ + nowpassword: nowpassword, + newpassword: newpassword, + champion: newchampion + }) + ); + + xhttp.onreadystatechange = function () { + if (this.readyState === XMLHttpRequest.DONE) { + try { + if (this.status >= 200 && this.status < 300) { + const objects = JSON.parse(this.responseText); //서버로부터 받은 응답텍스트를 JSON 객체로 변환 + console.log(objects); //서버로부터 받은 응답 콘솔에 출력 + + if (objects["check"] === "yes") { //서버로부터 받은 응답의 상태가 ok일 때 + localStorage.setItem("jwt", objects["token"]); + Swal.fire({ + text: "수정 성공!", + icon: "success", + confirmButtonText: "OK", //성공 메시지를 사용자에게 보여줌 + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./myinfo.html"; //해당 페이지로 리다이렉션 + } + }); + } else if (objects["check"] === "no") { + Swal.fire({ + text: "현재 비밀번호가 틀립니다.", + icon: "error", + confirmButtonText: "OK", + }); + } else { + Swal.fire({ + text: "수정에 실패했습니다.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Empty response received from the server"); + } + } else { + Swal.fire({ + text: "서버 오류 발생. 잠시 후 다시 시도해주세요.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Server responded with status:", this.status); + } + } catch (e) { + Swal.fire({ + text: "응답 처리 중 오류가 발생했습니다.", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error parsing response:", e); + } + } + }; + return false; +} + + +btnLogout.addEventListener("click", function (event) { + event.preventDefault(); + window.location.href = "main.html"; + console.log("Redirecting to:", window.location.href); + localStorage.removeItem("jwt"); +}); + +document.querySelectorAll('input').forEach(input => { + input.addEventListener('click', function () { + if (!this.value) { + this.value = this.placeholder; + } + }); +}); + +document.querySelectorAll('input').forEach(input => { + input.addEventListener('focus', function () { + if (!this.value) { + this.value = this.placeholder; + } + }); +}); + diff --git a/ranking.css b/ranking.css new file mode 100644 index 0000000..1f4e9b5 --- /dev/null +++ b/ranking.css @@ -0,0 +1,374 @@ +@import url('https://fonts.googleapis.com/css2?family=Righteous&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300&display=swap'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +.container { + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + justify-content: center; + padding: 10px 10px 10px 10px; +} + +.background-clip { + position: fixed; + right: 0; + bottom: 0; + z-index: -1; +} + +@media (min-aspect-ratio:16/9){ + .background-clip{ + width: 100%; + height: auto; + } +} + +@media (max-aspect-ratio:16/9){ + .background-clip{ + width: auto; + height: 100%; + } +} + +/*body { + display: flex; + align-items: center; + min-height: 108vh; + background-repeat: no-repeat; + background-size: cover; + background-position: center; +}*/ + +header { + position: fixed; + top: 0; + left: 0; + width: 100%; + padding: 20px 100px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 99; +} + +.logo { + font-size: 2em; + color: #fff; + user-select: none; +} + +.navigation a { + position: relative; + font-size: 1.1em; + color: #fff; + text-decoration: none; + font-weight: 500; + margin-left: 40px; +} + +.navigation a::after { + content: ''; + position: absolute; + left: 0; + bottom: -6px; + width: 100%; + height: 3px; + background: #fff; + border-radius: 5px; + transform-origin: right; + transform: scaleX(0); + transition: transform .5s; +} + +.navigation a:hover::after { + transform-origin: left; + transform: scaleX(1); +} + +.navigation .btnLogout { + width: 100px; + height: 40px; + background: transparent; + border: 2px solid #fff; + outline: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.1em; + color: #fff; + font-weight: 500; + margin-left: 40px; + transition: .5s; +} + +.champion { + position: static; + width: 300px; + height: 90%; + margin-top: 80px; + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + background-color: rgba(17, 25, 40, 0.25); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.125); + padding: 30px; + filter: drop-shadow(0 30px 10px rgba(0, 0, 0, 0.125)); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +.wrapper { + width: 100%; + height: 50%; + margin-bottom: 10px; +} + +.banner-image { + display: flex; + align-items: center; + background-position: center; + background-size: cover; + height: 300px; + width: 100%; + border-bottom: 0px; + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.255) + +} + +.twototen { + position: static; + left: 0; + top: 0; + margin-top: 120px; + width: 600px; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + box-sizing: border-box; + padding: 5px; +} + +.layer { + display: flex; + justify-content: center; + margin: 5px ; + height: 33%; +} + +.box { + box-sizing: border-box; + padding: 3px; + width: 100%; + height: 50px; + /* 고정된 박스 높이 */ + margin: 0 5px; + /* 박스 사이의 간격 */ + /* 나머지 스타일 */ +} + +.box .container_2 { + position: static; + width: 90%; + + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + background-color: rgba(17, 25, 40, 0.25); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.125); + padding: 5px 5px 5px 5px; + filter: drop-shadow(0 10px 5px rgba(0, 0, 0, 0.125)); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +.wrapper2 { + width: 100%; + height: 100%; +} + +.banner-image2 { + height: 120px; + width: 100px; + border-radius: 12px; + border: 2px solid rgba(255, 255, 255, 0.255) +} + +.champion-image { + width: 100%; /* 부모 요소의 100% 너비로 설정 */ + height: auto; /* 높이를 가로의 비율에 맞추어 자동으로 설정 */ + max-height: 100%; /* 부모 요소의 100% 높이로 설정 */ + margin-right: 10px; + object-fit: cover; /* 이미지를 비율 유지하면서 div에 꽉 차게 채움 */ +} + +.character-image { + object-fit:cover; + height: 90%; + width: 100px; + border-radius: 12px; +} +h1 { + font-family: 'Righteous', sans-serif; + color: rgba(255, 255, 255, 0.98); + text-transform: uppercase; + font-size: 1.4rem; +} + +p { + color: #fff; + font-family: 'Lato', sans-serif; + text-align: center; + font-size: 15px; + line-height: 150%; + letter-spacing: 2px; + text-transform: uppercase; +} + +.button-wrapper { + margin-top: 18px; +} + +.button-wrapper2 { + margin-top: 5px; +} + +.btn2 { + border: none; + padding: 6px 12px; + border-radius: 22px; + font-size: 1 rem; + letter-spacing: 0px; + cursor: pointer; +} + +.btn { + border: none; + padding: 12px 24px; + border-radius: 24px; + font-size: 22px; + font-size: 0.8rem; + letter-spacing: 2px; + cursor: pointer; +} + +.btn+.btn { + margin-top : 15px; +} +.btn2 + .btn2 { + margin-top: 5px; +} + +.outlineforC{ + background: transparent; + color: rgba(226, 209, 24, 1); + border: 1px solid rgba(233, 215, 15, 0.836); + transition: all .3s ease; +} +.outline { + background: transparent; + color: rgba(0, 212, 255, 0.9); + border: 1px solid rgba(0, 212, 255, 0.6); + transition: all .3s ease; +} + +.outlineforC:hover { + transform: scale(1.125); + color: rgba(242, 250, 128, 1); + border-color: rgba(255, 255, 255, 0.9); + transition: all .3s ease; +} + +.outline:hover { + transform: scale(1.125); + color: rgba(255, 255, 255, 0.9); + border-color: rgba(255, 255, 255, 0.9); + transition: all .3s ease; +} + +.fillforC { + background: rgba(233, 215, 15, 0.836); + color: rgba(255, 255, 255, 0.95); + filter: drop-shadow(0); + font-weight: bold; + transition: all .3s ease; +} + +.fill { + background: rgba(0, 212, 255, 0.9); + color: rgba(255, 255, 255, 0.95); + filter: drop-shadow(0); + font-weight: bold; + transition: all .3s ease; +} + +.fillforC:hover { + transform: scale(1.125); + border-color: rgba(175, 128, 128, 0.9); + filter: drop-shadow(0 10px 5px rgba(0, 0, 0, 0.125)); + transition: all .3s ease; +} + +.fill:hover { + transform: scale(1.125); + border-color: rgba(175, 128, 128, 0.9); + filter: drop-shadow(0 10px 5px rgba(0, 0, 0, 0.125)); + transition: all .3s ease; +} + +.under10th { + position: static; + + padding-top: 10px; + margin-top: 80px; + height: 90%; + width: 200px; + text-align: center; + font-family: 'Inter'; + font-style: italic; + font-weight: 600; + font-size: 23px; + line-height: 23px; + text-transform: uppercase; + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + background-color: rgba(17, 25, 40, 0.25); + border-radius: 12px; +} + +.rank-opener { + position:relative; + + top: 101%; + height: 7%; + width: 100%; + text-align: center; + font-family: 'Inter'; + font-style: italic; + font-weight: 90; + font-size: 20px; + line-height: 20px; + text-transform: uppercase; + backdrop-filter: blur(16px) saturate(100%); + -webkit-backdrop-filter: blur(16px) saturate(100%); + background-color: rgba(185, 142, 202, 0.25); + border-radius: 12px; + +} diff --git a/ranking.html b/ranking.html new file mode 100644 index 0000000..8fc3367 --- /dev/null +++ b/ranking.html @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + ranking + + + + +
+ + + +
+ + +
+ +
+
+ +

1

+
+ + +
+ + +
+
+ +
+
+
+ +

2

+
+
+
+
+
+
+ +
+
+
+ +

3

+
+
+
+
+
+
+
+ +
+
+
+
+ +

4

+
+
+
+
+
+
+
+
+
+ +

5

+
+
+
+
+
+
+
+
+
+ +

6

+
+
+
+
+
+
+
+
+
+
+
+ +

7

+
+
+
+
+
+
+
+
+
+ +

8

+
+
+
+
+
+
+
+
+
+ +

9

+
+
+
+
+
+
+
+
+
+ +

10

+
+
+
+
+
+
+
+
+ + +
+

+
+
+ + + + + +
+ + + + \ No newline at end of file diff --git a/ranking.js b/ranking.js new file mode 100644 index 0000000..07dac59 --- /dev/null +++ b/ranking.js @@ -0,0 +1,301 @@ + +var jwt="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImlkIjoidGVzdCIsImlhdCI6MTY5OTYzMjA1NywiZXhwIjoxNzAyMjI0MDU3fQ.P0AX2jyS18tjHFKBQRy6Wi6OWG9AlDQ4hJtpZp3woB0"; +//API 1 >> under 10th용 + var xhttp = new XMLHttpRequest(); + //서버로부터 데이터 가져오기 + xhttp.open("GET", "http://34.127.90.191:3000/ranking/", true); + + // 데이터가 도착할 때 실행할 콜백 함수 설정 + xhttp.onreadystatechange = function () { + if (xhttp.readyState === 4 && xhttp.status === 200) { + var data = JSON.parse(xhttp.responseText); + console.log(data);// 티어별 구분 -success + var opener = data[5]; + + displayGateKeeperInfo(opener); + + const fourthTear = data[4]; + console.log(fourthTear);//under10th + extractAndDisplayData(fourthTear); + + } + }; +xhttp.send();//request sending + +function displayGateKeeperInfo(player) { + var playerInfoContainer = document.querySelector('.rank-opener'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` +

${player.tier}

+

${player.name}

+ `; + playerInfoContainer.appendChild(playerElement); +} + +function extractAndDisplayData(data) { + const names = data.name.split(','); + // HTML 클래스 "result"를 가진 요소를 찾아서 가져오기 + const resultElements = document.getElementsByClassName("under10th"); + + for (let i = 0; i < resultElements.length; i++) { + const resultElement = resultElements[i]; + names.forEach(name => { + const paragraph = document.createElement("p"); + paragraph.textContent = name.trim(); + resultElement.appendChild(paragraph); + }); + } +} + +// API 2 호출 >> 순위표 반영용(1~10위 추출) +var xhttp2 = new XMLHttpRequest(); +xhttp2.open("GET", "http://34.127.90.191:3000/ranking/rank", true); + +xhttp2.onreadystatechange = function () { + if (xhttp2.readyState === 4 && xhttp2.status === 200) { + var data2 = JSON.parse(xhttp2.responseText); + console.log(data2);// > success + + var champion=data2[0]; + var box2=data2[1]; + var box3=data2[2]; + var box4=data2[3]; + var box5=data2[4]; + var box6=data2[5]; + var box7=data2[6]; + var box8=data2[7]; + var box9=data2[8]; + var box10=data2[9]; + + displayChampionInfo(champion);//-success> champion + + boxInfo2(box2); + boxInfo3(box3); + boxInfo4(box4); + boxInfo5(box5); + boxInfo6(box6); + boxInfo7(box7); + boxInfo8(box8); + boxInfo9(box9); + boxInfo10(box10); + } +}; +xhttp2.send(); + +// 이미지 URL을 동적으로 가져오는 함수 추가 +function getChampionImageDynamic(championName) { + //const lowercaseChampionName = championName.toLowerCase(); + return `https://github.com/Tekken-Supporter/Frontend/blob/main/IMAGES/${championName}`+ `.png?raw=true`; + +} + +//개별 사람 > 1st~ 10th +function displayChampionInfo(player) { + var playerCharacter = document.querySelector('.banner-image'); + var picture = document.createElement('div'); + console.log(player.champion); + + picture.innerHTML = ` + ${player.champion} 이미지 + `; + playerCharacter.appendChild(picture); + console.log(getChampionImageDynamic(player.champion)); + + var playerInfoContainer = document.querySelector('.champion'); + var playerElement = document.createElement('div'); + playerElement.style= 'margin-top : 50px;' + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo3(player) { + var playerCharacter = document.querySelector('.banner-image2.banner3'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player3'); // 클래스로 선택 + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} + +function boxInfo2(player) { + var playerCharacter = document.querySelector('.banner-image2.banner2'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player2'); // 클래스로 선택 + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} + + +function boxInfo4(player) { + var playerCharacter = document.querySelector('.banner-image2.banner4'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player4'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo5(player) { + var playerCharacter = document.querySelector('.banner-image2.banner5'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player5'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} + +function boxInfo6(player) { + var playerCharacter = document.querySelector('.banner-image2.banner6'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + var playerInfoContainer = document.querySelector('.player6'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo7(player) { + var playerCharacter = document.querySelector('.banner-image2.banner7'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player7'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo8(player) { + var playerCharacter = document.querySelector('.banner-image2.banner8'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player8'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo9(player) { + var playerCharacter = document.querySelector('.banner-image2.banner9'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + + var playerInfoContainer = document.querySelector('.player9'); // 클래스로 선택 + + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} +function boxInfo10(player) { + var playerCharacter = document.querySelector('.banner-image2.banner10'); + var picture = document.createElement('div'); + picture.classList.add('images'); + console.log(player.champion); + picture.innerHTML = ` + ${player.champion} 이미지 + ` + ; + playerCharacter.appendChild(picture); + var playerInfoContainer = document.querySelector('.player10'); // 클래스로 선택 + var playerElement = document.createElement('div'); + playerElement.innerHTML = ` + + + `; + playerInfoContainer.appendChild(playerElement); +} + +const btnLogout = document.querySelector(".btnLogout"); + +btnLogout.addEventListener("click", function (event) { + event.preventDefault(); + window.location.href = "main.html"; + console.log("Redirecting to:", window.location.href); + localStorage.removeItem("jwt"); + }); \ No newline at end of file diff --git a/register.js b/register.js new file mode 100644 index 0000000..714d0fe --- /dev/null +++ b/register.js @@ -0,0 +1,56 @@ +var jwt = localStorage.getItem("jwt"); +if (jwt != null) { + window.location.href = "./main.html"; +} + +function register() { + const name = document.getElementById("newname").value; + const id = document.getElementById("newid").value; + const password = document.getElementById("newpassword").value; + + const xhttp = new XMLHttpRequest(); + xhttp.open("POST", "http://34.127.90.191:3000/auth/register"); + xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + + xhttp.send( + JSON.stringify({ + name: name, + id: id, + password: password, + }) + ); + + xhttp.onreadystatechange = function () { + if (this.readyState == 4) { + if (this.status == 200) { + const objects = JSON.parse(this.responseText); + console.log(objects); + if (objects["status"] == "ok") { + localStorage.setItem("jwt", objects["token"]); + Swal.fire({ + text: '회원가입 성공!', + icon: "success", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + window.location.href = "./main.html"; + } + }); + } else { + Swal.fire({ + text: '동일한 계정이 존재합니다', + icon: "error", + confirmButtonText: "Retry", + }); + } + } else { + Swal.fire({ + text: '알 수 없는 오류가 발생했습니다', + icon: "error", + confirmButtonText: "Retry", + }) + } + } + }; + return false; +} \ No newline at end of file diff --git a/reviewsend.js b/reviewsend.js new file mode 100644 index 0000000..fc8344a --- /dev/null +++ b/reviewsend.js @@ -0,0 +1,54 @@ +function submitReview() { + const cName = document.getElementById("cName").value; + const userId = document.getElementById("userId").value; + const reviewContent = document.getElementById("reviewContent").value; + console.log(cName + userId + reviewContent); + // XMLHttpRequest 객체 생성 + const xhr2 = new XMLHttpRequest(); + + xhr2.open("POST", "http://34.127.90.191:3000/character/review"); + xhr2.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhr2.send( + JSON.stringify({ + c_name: cName, + id: userId, + reviewData: reviewContent + }) + ); + + xhr2.onreadystatechange = function () { + if (this.readyState === XMLHttpRequest.DONE) { + try { + if (this.status >= 200 && this.status < 300) { + const objects = JSON.parse(this.responseText); //서버로부터 받은 응답텍스트를 JSON 객체로 변환 + console.log(objects); //서버로부터 받은 응답 콘솔에 출력 + + if (objects["c_name"] === cName && objects["id"] === userId) { + console.log("save in Local done! "); + Swal.fire({ + text: "리뷰를 작성했습니다!", + icon: "success", + confirmButtonText: "OK" + }).then((result) => { //확인 버튼 누르면 + if (result.isConfirmed) { + window.location.href = "./charinfo.html"; //해당 페이지로 리다이렉션 + } + }); + } else { + console.error("Empty response received from the server"); + } + } else { + console.error("Server responded with status:", this.status); + } + } catch (e) { + Swal.fire({ + text: "응답 처리 중 오류가 발생했습니다!", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error parsing response:", e); + } + } + }; + return false; +} \ No newline at end of file diff --git a/script.js b/script.js deleted file mode 100644 index dd5fe28..0000000 --- a/script.js +++ /dev/null @@ -1,13 +0,0 @@ -const wrapper = document.querySelector('.wrapper'); -const loginLink = document.querySelector('.login-link'); -const registerLink = document.querySelector('.register-link'); -const btnPopup = document.querySelector('.btnLogin-popup'); -const iconClose = document.querySelector('.icon-close'); - -registerLink.addEventListener('click', ()=> {wrapper.classList.add('active');}); - -loginLink.addEventListener('click', ()=> {wrapper.classList.remove('active');}); - -btnPopup.addEventListener('click', ()=> {wrapper.classList.add('active-popup');}); - -iconClose.addEventListener('click', ()=> {wrapper.classList.remove('active-popup');}); diff --git a/tekken.mp4 b/tekken.mp4 new file mode 100644 index 0000000..59c9988 Binary files /dev/null and b/tekken.mp4 differ diff --git a/test.css b/test.css new file mode 100644 index 0000000..f9a07d0 --- /dev/null +++ b/test.css @@ -0,0 +1,1142 @@ +@import url("https://fonts.googleapis.com/css?family=DM+Sans:400,500,700&display=swap"); +* { + margin: 0; + padding: 0; + -webkit-box-sizing: border-box; + box-sizing: border-box; + outline: none; +} + +html { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; +} + +body { + width: 100%; + height: 100vh; + overflow: hidden; + font-family: 'DM Sans', sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; +} + +p { + margin: 0; +} + +.app-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + width: 100%; + height: 100%; + overflow: hidden; +} + +.app-left-small { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #FEFEFF; + -webkit-box-flex: 0; + -ms-flex: 0 0 5%; + flex: 0 0 5%; + max-width: 5%; + -webkit-box-shadow: 0px 10px 10px #F5F6FA; + box-shadow: 0px 10px 10px #F5F6FA; + padding: 1.5rem; + text-align: center; +} + +.app-left-small .header-icon { + min-height: 80px; +} + +.app-left-small .header-icon svg { + color: #969EB3; + width: 20px; +} + +.app-left-small .left-logincircle { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + height: 100%; +} + +.app-left-small .left-logincircle .login-profile { + width: 50px; + height: 50px; + border: 1px solid #E8E9EF; + border-radius: 50%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.app-left-small .left-logincircle .login-profile:not(:last-child) { + margin-bottom: 1rem; +} + +.app-left-small .left-logincircle .login-profile img { + width: 30px; +} + +.app-left-small .left-logincircle .profile-bg { + background-color: #E0E5FE; + border: none; +} + +.app-left-small .left-add-icon .addicon-circle { + min-width: 40px; + min-height: 40px; + border: 1px solid #E8E9EF; + border-radius: 50%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.app-left-small .left-add-icon .addicon-circle:not(:last-child) { + margin-bottom: 1rem; +} + +.app-left-small .left-add-icon .addicon-circle svg { + width: 18px; + color: #969EB3; +} + +.app-left-medium { + -webkit-box-flex: 0; + -ms-flex: 0 0 18%; + flex: 0 0 18%; + max-width: 18%; + background-color: #F5F6FA; + border-right: 2px solid #E8E9EF; +} + +.app-left-medium .menu-top { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + padding: 1.5rem; +} + +.app-left-medium .menu-top .menu-icon-down svg { + color: #969EB3; +} + +.app-left-medium .header-icon { + height: 70px; + border-bottom: 2px solid #E8E9EF; +} + +.app-left-medium .side-menu { + padding: 2rem 1.5rem; +} + +.app-left-medium .side-menu ul { + margin: 0; + padding: 0; + width: 100%; +} + +.app-left-medium .side-menu ul li { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + padding-bottom: 0.6rem; +} + +.app-left-medium .side-menu ul li .sidebar-link { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 85%; + border: 1px solid transparent; + padding: 0.6rem 1.5rem; +} + +.app-left-medium .side-menu ul li .menu-icon svg { + color: #969EB3; + font-weight: 500; + width: 20px; +} + +.app-left-medium .side-menu ul li .menu-link { + padding-left: .8rem; +} + +.app-left-medium .side-menu ul li .menu-link span { + color: #969EB3; + font-weight: 500; + font-size: 1rem; +} + +.app-right-big { + -webkit-box-flex: 2; + -ms-flex: 2; + flex: 2; + width: auto; + background-color: #FEFEFF; +} + +.app-header-main { + height: 70px; + border-bottom: 2px solid #E8E9EF; + padding: 1.5rem 2rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; +} + +.app-container-inside { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + width: 100%; + height: 100%; +} + +.app-container-inside .app-inside-left { + width: 78%; +} + +.app-container-inside .app-inside-right { + width: 22%; + border-left: 1px solid #E8E9EF; + height: 100%; + position: relative; +} + +.app-container-inside .app-inside-right .pro-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + padding: 1rem 2rem; +} + +.app-container-inside .app-inside-right .pro-section .inside-project { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-top: 0.6rem; + width: 100%; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online .user-first { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + width: 100%; + margin-bottom: 0.6rem; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online .user-name-letter { + width: 35px; + height: 35px; + border-radius: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online .user-name-letter span { + color: #2EBDC2; + font-size: 1rem; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online .l-bg { + background-color: #DEF6FC; +} + +.app-container-inside .app-inside-right .pro-section .inside-user-online .user-name { + padding-left: 22%; +} + +.pro-img img { + width: 35px; +} + +.pro-dot svg { + color: #969EB3; +} + +.l-bg-1 { + background-color: #ECE8FC; +} + +.l-bg-1 span { + color: #5242A2 !important; +} + +.btn-invite { + border: 1px solid #E8E9EF; + border-radius: 20px; + min-width: 130px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-shadow: 0px 2px 5px #E8E9EF; + box-shadow: 0px 2px 5px #E8E9EF; + padding: 0.3rem 1.2rem; +} + +.btn-invite span { + color: #131E40; +} + +.btn-invite svg { + color: #E8E9EF; + width: 20px; +} + +.invite-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding-top: 1rem; +} + +.pro-border { + border-bottom: 1px solid #E8E9EF; +} + +.chat-area { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + overflow: auto; + max-height: calc(100vh - 70px); +} + +.chat-msg, .chat-msg-owner { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-top: 1rem; + padding: 1.5rem 2rem; +} + +.chat-smg-img { + -ms-flex-negative: 0; + flex-shrink: 0; + position: relative; +} + +.chat-smg-img .img { + width: 40px; + height: 40px; + border-radius: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.chat-smg-img .img .img-color { + color: #5242A2; +} + +.chat-smg-img .img .img-g { + color: #2EBDC2; +} + +.chat-smg-img .bg-color-1 { + background-color: #DEF6FC; +} + +.chat-smg-img .bg-color { + background-color: #ECE8FC; +} + +.chat-msg-content { + margin-left: 12px; + max-width: 70%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; +} + +.chat-msg-content .chat-msg-name { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.chat-msg-content .chat-msg-name .msg-name h6 { + color: #131E40; +} + +.chat-msg-content .chat-msg-name .msg-time { + padding-left: 0.8rem; +} + +.chat-msg-content .chat-msg-name .msg-time span { + color: #969EB3; + font-size: .8rem; + font-weight: 500; +} + +.chat-msg-content .chat-msg-text { + margin-top: 0.5em; +} + +.chat-msg-content .chat-msg-text p { + color: #969EB3; + font-size: 0.9rem; + font-weight: 500; +} + +.chat-msg-content .chat-file-box { + width: 80%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 20px; + border: 1px solid #E8E9EF; + -webkit-box-shadow: 0px 5px 5px #969eb33b; + box-shadow: 0px 5px 5px #969eb33b; + margin-top: 1rem; +} + +.chat-msg-content .chat-file-box .box-file { + width: 20%; +} + +.chat-msg-content .chat-file-box .box-file img { + background-color: #DAF0E4; + padding: 10px; + border-top-right-radius: 10px; + width: 50px; +} + +.chat-msg-content .chat-file-box .box-file-name { + width: 60%; +} + +.chat-msg-content .chat-file-box .box-file-icon { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 40%; +} + +.chat-msg-content .chat-file-box .box-file-icon .icon-file { + width: 40px; + height: 40px; + border: 1px solid #969EB3; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-radius: 50%; +} + +.chat-msg-content .chat-file-box .box-file-icon .icon-file svg { + color: #969EB3; + width: 18px; +} + +.chat-msg-content .chat-file-box .file-size span { + color: #969EB3; +} + +.chat-msg-content .user-tag { + margin-top: 1rem; + background-color: #E9EFFE; + padding: 6px 10px; + width: 150px; + border-radius: 20px; + text-align: center; +} + +.chat-msg-content .user-tag p { + color: #4B72D3; +} + +.msg-images { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.msg-images .inner-img { + position: relative; + width: 100px; + height: 100px; + padding-bottom: 30%; + border-radius: 10%; + overflow: hidden; +} + +.msg-images .inner-img:not(:first-child) { + margin-left: 10px; +} + +.msg-images .inner-img img { + position: absolute; + width: 100%; +} + +.chat-area-footer { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + border-top: 1px solid #E8E9EF; + position: -webkit-sticky; + position: sticky; + bottom: 0; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + margin-top: auto; + left: 0; + overflow: hidden; + height: 80px; + -ms-flex-negative: 0; + flex-shrink: 0; + background-color: #FEFEFF; + padding: 1.2rem 1.5rem; +} + +.header-user-profile { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 18%; +} + +.header-user-profile .pro-pic { + position: relative; + width: 40px; + height: 40px; + border-radius: 50%; + overflow: hidden; +} + +.header-user-profile .pro-pic img { + width: 100%; + position: absolute; +} + +.mid-header-select { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.left-header-title { + width: 50%; +} + +.search-bar input { + height: 100%; + width: 100%; + display: block; + background-color: transparent; + border: none; + color: #969EB3; + padding: 0 35px; + background-image: url("../images/icons/search.svg"); + background-repeat: no-repeat; + background-size: 18px; + background-position: 0 50%; + font-weight: 600; + font-size: 14px; +} + +.header-select-box { + padding-right: 1rem; +} + +.footer-chat-left { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.add { + position: -webkit-sticky; + position: sticky; + bottom: 3px; + background-color: #0086ff; + width: 30px; + height: 30px; + border: 0; + border-radius: 50%; + background-image: url("../images/icons/icons8-plus-+.svg"); + background-repeat: no-repeat; + background-position: 50%; + background-size: 18px; + -webkit-box-shadow: 0 0 16px #0086ff; + box-shadow: 0 0 16px #0086ff; + margin: auto auto -55px; + -ms-flex-negative: 0; + flex-shrink: 0; + z-index: 1; + cursor: pointer; +} + +.chat-input input { + height: 100%; + width: 100%; + display: block; + background-color: transparent; + border: none; + color: #969EB3; + padding: 0 35px; + font-weight: 600; + font-size: 14px; +} + +.tag-person { + color: #969EB3; +} + +.tag-emoji span { + color: #969EB3; +} + +.footer-chat-right { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 33%; +} + +.btn-drap { + background-color: #E8E9EF; + border: 1px dashed #969EB3; + color: #969EB3; +} + +.sidebar-link.is-active, +.sidebar-link:hover { + background-color: #FFFFFF; + border: 1px solid #E8E9EF !important; + color: #131E40; + border-radius: 50px; + text-decoration: none; + color: red; +} + +.sidebar-link.is-active svg, +.sidebar-link:hover svg { + color: #3F75FF !important; +} + +.sidebar-link.is-active span, +.sidebar-link:hover span { + color: #131E40 !important; +} + +.right-icon-arrow { + position: absolute; + left: -14px; + top: 3%; +} + +.right-icon-arrow .arrow-circle { + width: 30px; + height: 30px; + border: 1px solid #969EB3; + background-color: #FEFEFF; + border-radius: 50%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; +} + +.right-icon-arrow .arrow-circle svg { + color: #969EB3; + width: 20px; +} + +::-webkit-scrollbar { + display: none; +} + +@media screen and (min-width: 960px) and (max-width: 1279px) { + .app-inside-right { + display: none; + } + .app-container-inside .app-inside-left { + width: 100%; + } + .right-icon-arrow { + position: absolute; + left: -110px; + top: 13%; + } +} + +@media screen and (min-width: 600px) and (max-width: 959px) { + .app-inside-right { + display: none; + } + .app-inside-left { + width: 100% !important; + } + .mid-header-select { + display: none; + } + .app-left-small { + background-color: #FEFEFF; + border-right: 1px solid #E8E9EF; + } + .app-left-small .left-logincircle .login-profile { + width: 40px; + height: 40px; + } + .app-left-small .left-logincircle .login-profile img { + width: 25px; + } + .chat-msg, .chat-msg-owner { + padding: 1.5rem 1rem; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + margin-top: 0; + } + .chat-msg-content { + max-width: 100%; + margin-left: 0px; + margin-top: 0.8rem; + } + .chat-msg-content .chat-file-box { + width: 100%; + padding: 10px; + } + .chat-msg-content .chat-file-box .box-file-name { + width: 50%; + } + .file-name-title h6 { + font-size: 0.8rem; + } + .file-size span { + font-size: 0.8rem; + } + .app-header-main { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1.5rem 1rem; + } + .header-user-profile { + width: 40%; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + } + .pro-down { + display: none; + } + .pro-name { + padding-left: 5px; + display: none; + } + .drop-att { + display: block !important; + } + .drop-att svg { + color: #969EB3; + } + .footer-chat-mobile { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + } + .footer-chat-right { + display: none; + } + .chat-area-footer { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: fixed; + width: 100%; + } + .header-user-profile .pro-pic { + width: 30px; + height: 30px; + } + .app-left-small .left-add-icon .addicon-circle { + width: 30px; + height: 30px; + } + .app-left-small .left-add-icon .addicon-circle svg { + width: 15px; + } + .app-left-medium { + position: fixed; + top: 0px; + left: 0px; + max-width: 100%; + height: 100%; + z-index: 1; + display: none; + } + .side-menu { + padding: 1rem 1rem !important; + } + .sidebar-link { + width: 100% !important; + padding: 0.6rem 1rem !important; + } + .chat-area { + height: 90vh; + } + .chat-msg-content .chat-msg-text p { + width: 100%; + } + .chat-msg-content .chat-file-box .box-file-icon .icon-file { + width: 30px; + height: 30px; + } + .chat-msg-content .chat-file-box .box-file img { + width: 40px; + } + .left-header-title { + width: 60%; + } + .left-add-icon { + display: none; + } +} + +@media screen and (min-width: 320px) and (max-width: 599px) { + .app-inside-right { + display: none; + } + .app-inside-left { + width: 100% !important; + } + .mid-header-select { + display: none; + } + .app-left-small { + background-color: #FEFEFF; + border-right: 1px solid #E8E9EF; + } + .app-left-small .left-logincircle .login-profile { + width: 40px; + height: 40px; + } + .app-left-small .left-logincircle .login-profile img { + width: 25px; + } + .chat-msg, .chat-msg-owner { + padding: 1.5rem 1rem; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + margin-top: 0; + } + .chat-msg-content { + max-width: 100%; + margin-left: 0px; + margin-top: 0.8rem; + } + .chat-msg-content .chat-file-box { + width: 100%; + padding: 10px; + } + .chat-msg-content .chat-file-box .box-file-name { + width: 50%; + } + .file-name-title h6 { + font-size: 0.8rem; + } + .file-size span { + font-size: 0.8rem; + } + .app-header-main { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1.5rem 1rem; + } + .header-user-profile { + width: 40%; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + } + .pro-down { + display: none; + } + .pro-name { + padding-left: 5px; + display: none; + } + .drop-att { + display: block !important; + } + .drop-att svg { + color: #969EB3; + } + .footer-chat-mobile { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + } + .footer-chat-right { + display: none; + } + .chat-area-footer { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: fixed; + width: 100%; + } + .header-user-profile .pro-pic { + width: 30px; + height: 30px; + } + .app-left-small .left-add-icon .addicon-circle { + width: 30px; + height: 30px; + } + .app-left-small .left-add-icon .addicon-circle svg { + width: 15px; + } + .app-left-medium { + position: fixed; + top: 0px; + left: 0px; + max-width: 100%; + height: 100%; + z-index: 1; + display: none; + } + .side-menu { + padding: 1rem 1rem !important; + } + .sidebar-link { + width: 100% !important; + padding: 0.6rem 1rem !important; + } + .chat-area { + height: 90vh; + } + .chat-msg-content .chat-msg-text p { + width: 100%; + } + .chat-msg-content .chat-file-box .box-file-icon .icon-file { + width: 30px; + height: 30px; + } + .chat-msg-content .chat-file-box .box-file img { + width: 40px; + } + .left-header-title { + width: 60%; + } + .left-add-icon { + display: none; + } +} + +.drop-att { + display: none; +} + +.footer-chat-mobile { + display: none; +} +/*# sourceMappingURL=main.css.map */ \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..4e7453a --- /dev/null +++ b/test.html @@ -0,0 +1,640 @@ + + + + + + + + Messaging App UI Dashboard + + + + + +
+
+ + +
+ + +
+
+
+ + + + +
+
+ + + + +
+
+
+ +
+
+
+
+ Messanger / Design + + + +
+
+
+
+
+ Category + + + +
+
+ +
+ +
+
+
+
+ +
+
+
+ M +
+
+
+
+
+
+ Migual Logan +
+
+
+ 01:34 AM +
+
+
+

+ We've invited you to the spreadsheet we did yesterday, but in case we will + put it here for + u guys 😀 Let me know,if everything seems to be clear for you. We can + schedule the hangout + meeting later,if you want. +

+

+ Just let me know. +

+ +
+
+ +
+
+
+
+ Userstories_for_mvp +
+
+
+ + 12mbp Spreadsheet file + +
+
+ +
+ +
+

+ @ Lynda Steve +

+
+
+
+
+
+
+
+ L +
+
+
+
+
+
+ Lydia Stevens +
+
+
+ 02 :34 AM +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+ M +
+
+
+
+
+
+ Migual Logan +
+
+
+ 01:34 AM +
+
+
+

+ We are sending to you recent file, please review it internally and send us a + feedback 😀 + +

+ +
+
+ +
+
+
+
+ Userstories_for_mvp +
+
+
+ + 12mbp Spreadsheet file + +
+
+
+ +
+
+ +
+

+ @ Lynda Steve +

+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
Project
+
+
+ + + + + +
+
+
+
+
+ E +
+
+
Edward Floyd
+
+
+
+
+ M +
+
+
Miguel Logan
+
+
+
+
+ Show offline > +
+
+
+ +
+
+ +
+
+
Design
+
+
+ + + + + +
+
+
+
+
+ E +
+
+
Edward Floyd
+
+
+
+
+ M +
+
+
Miguel Logan
+
+
+
+
+ Show offline > +
+
+
+ +
+
+ +
+
+
Engine
+
+
+ + + + + +
+
+
+
+
+ E +
+
+
Edward Floyd
+
+
+
+
+ M +
+
+
Miguel Logan
+
+
+
+
+ Show offline > +
+
+ + +
+ +
+
+ + + + + + \ No newline at end of file