공식은 아닌것같고 어떤분이 만든듯?
vscode 실행
workspace로 이동
프로젝트 폴더 생성
npx create-react-app my-app
cd my-app
npm start
localhost:3000
npm install react-router-dom
npm install axios
server 폴더 생성
server 폴더 안에 server.js 생성
server 터미널 오픈
npm init
npm install express cors
npm install nodemon
server 폴더에 있는 package.json의 start 항목을 nodemon server.js로 변경
내가 구현해야 할 메인 페이지 화면
일단 App.js에서 html/css 적용부터
그 후에 router 적용하는걸로
App.css
/* 노멀라이즈 */
* {
box-sizing: border-box;
padding: 0px;
margin: 0px;
}
a {
color: inherit;
text-decoration: none;
}
ul,
li {
list-style: none;
color: inherit;
}
button {
cursor: pointer;
outline: none;
border: none;
}
.app {
background-color: #a6c0d5;
}
.content-box {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
/* 화면 크기에 따른 버튼 크기 변경 -> 일단 나중에 */
.button {
font-size: 18px;
font-weight: bold;
color: black;
background-color: #fbe400;
margin: 20px;
padding: 10px 40px;
border-radius: 5px;
box-shadow: grey 2px 2px 4px;
}
p {
padding-top: 20px;
}
App.js
import react from "react";
import logo from "./logo.svg";
import "./App.css";
function App() {
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="#"
/>
</div>
<button className="button">시작하기</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
export default App;
index.js에서
import { BrowserRouter } from "react-router-dom";
App을 BrowserRouter로 감싼다.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
App.js에서
import { Routes, Route } from "react-router-dom";
App()함수에서 컴포넌트를 Routes,Route로 감싼다.
import react from "react";
import logo from "./logo.svg";
import "./App.css";
import { Routes, Route } from "react-router-dom";
function Main() {
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="#"
/>
</div>
<button className="button">시작하기</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
function App() {
return (
<Routes>
<Route exact path="/" element={<Main />} />
</Routes>
);
}
export default App;
시작하기 누르면 나오는 선택지가 있는 페이지
페이지 구조가 같음
한 페이지를 만들어서 컴포넌트화 해야함
App.css
서브 페이지 관련 css 추가
/* 노멀라이즈 */
* {
box-sizing: border-box;
padding: 0px;
margin: 0px;
}
a {
color: inherit;
text-decoration: none;
}
ul,
li {
list-style: none;
color: inherit;
}
button {
cursor: pointer;
outline: none;
border: none;
}
.app {
background-color: #a6c0d5;
}
.content-box {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 480px;
margin: 0px auto;
}
/* 화면 크기에 따른 버튼 크기 변경 -> 일단 나중에 */
.button {
font-size: 18px;
font-weight: bold;
color: black;
background-color: #fbe400;
margin: 20px;
padding: 10px 40px;
border-radius: 5px;
box-shadow: grey 2px 2px 4px;
}
p {
padding-top: 20px;
}
.sub {
width: 390px;
height: 261px;
margin: 60px 0;
}
.progress-bar {
width: 100%;
background-color: #ffffff;
height: 30px;
border-radius: 12px;
}
.percent {
/* width 값을 바꾸면서 프로그레스바 채움 */
/* width: 30px; */
background-color: #fbe400;
height: 30px;
border-radius: 10px;
}
App.js
On1 함수 생성
import react from "react";
import logo from "./logo.svg";
import "./App.css";
import { Routes, Route } from "react-router-dom";
function Main() {
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="#"
/>
</div>
<button className="button">시작하기</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
function On1() {
return (
<div className="app">
<div className="content-box">
<div className="progress-bar">
<div className="percent"></div>
</div>
<div className="img-box sub">
<img
src=" https://kakaofriendsmbti.netlify.app/images/01-01.png"
alt="#"
/>
</div>
<button className="button">당연하지! 어디서 할지 고민 중이야!</button>
<button className="button">
그냥 맛있는거 먹으러 갈까 생각 중이야!
</button>
</div>
</div>
);
}
function App() {
return (
<Routes>
<Route exact path="/" element={<Main />} />
<Route exact path="/on1" element={<On1 />} />
</Routes>
);
}
export default App;
프로그레스바 : 페이지에 따른 진행 정도 표시
버튼 데이터 저장
이전에 수업에서는 서브페이지를 전체적인 구조 틀만 맞추고 1페이지부터 5페이지까지 텍스트만 바뀌는 식으로 서브 페이지 함수를 페이지 개수만큼 생성함
이를 개선하여 중복되는 서브 페이지 함수를 하나로 1페이지부터 12페이지까지 보여줄 수 있도록함
서브 페이지 이동시에 /on:seq로 on뒤에 숫자가 붙도록 하여 sub 함수에서는 useParams를 이용하여 on뒤에 입력된 숫자를 받아와 사용함
받아온 숫자는 progressbar에 props로 img url의 변수로 질문 배열을 찾는데 사용함
질문은 배열에 객체로 저장함
App.js
import react from "react";
import logo from "./logo.svg";
import "./App.css";
import { Routes, Route, useParams } from "react-router-dom";
const question = [
{
text1: "당연하지! 어디서 할지 고민 중이야!",
text2: "그냥 맛있는거 먹으러 갈까 생각 중이야!",
},
{
text1: "영화 완전 재밌었어! 너도 한번 봐봐!",
text2: "좀비가 너무 리얼했어. 실제 상황이면 난 바로 죽었을거야...",
},
{
text1: "무슨 꽃 샀어? 향은 좋아?",
text2: "왜 우울해? 무슨 일 있어?",
},
{
text1: "지금 PPT 만드는 중이니까 아마 한 2시간 뒤면 끝날거 같아!",
text2: "모르겠어. 근데 지금 PPT 만들고 있어!",
},
{
text1: "그래! 역시 사람 많고 유명한 벚꽃 명소가 예쁘겠지 어디로 갈까?",
text2: "그래! 사람 적은 볓꽃 명소 한번 찾아볼까?",
},
{
text1: "지구는 멸망하지 않아!",
text2: "일단 가장 좋아하는 음식부터 먹으러 갈거야!",
},
{
text1: "드라이샴푸? 마른 머리에 비비면 되는건가? 완전 티 안나!",
text2: "어제 무슨 일 있었어? 지금은 피곤한거 좀 괜찮아?",
},
{
text1:
"우선 2시에 도착하니까 버스 타고 숙소가서 체크인하고 늦은 점심 먹을까?",
text2: "글쎄... 너는 가고 싶은데 없어? 난 현지 맛집이면 다 좋아!",
},
{
text1: "아니! 나 지금 밖이야! 친구랑 있어. 무슨 일 있어?",
text2: "응! 나 지금 넷플릭스 보고 있어! 무슨 일 있어?",
},
{
text1: "이해는 안가는데 시험번위고 종요하다니까 그냥 외우려고!",
text2: "이따가 선생님한테 가서 다시 물어보려고!",
},
{
text1: "무슨 시험 봤어? 다음 시험은 언제야? 괜찮아?",
text2: "다음에 꼭 붙을거야! 다음 시험을 기약하자! 너무 슬퍼하지마!",
},
{
text1: "진짜로? 왜? 갑자기? 다른 사람들은 뭐래?",
text2: "오! 갑자기 왜? 그럼 조는 어떻게 정한대?",
},
];
function Main() {
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="메인페이지이미지"
/>
</div>
<button className="button">시작하기</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
const ProgressBar = (props) => {
// 서브페이지는 총 12개
const width = (480 / 12) * props.step;
return (
<div className="progress-bar">
<div className="percent" style={{ width: width }}></div>
</div>
);
};
function Sub() {
const { seq } = useParams();
const imgseq = seq.length === 1 ? "0" + seq : seq;
const srcurl = `https://kakaofriendsmbti.netlify.app/images/${imgseq}-01.png`;
return (
<div className="app">
<div className="content-box">
<ProgressBar step={seq} />
<div className="img-box sub">
<img src={srcurl} alt="서브페이지이미지" />
</div>
<button className="button">{question[parseInt(seq) - 1].text1}</button>
<button className="button">{question[parseInt(seq) - 1].text2}</button>
</div>
</div>
);
}
function Result() {}
function App() {
return (
<Routes>
<Route exact path="/" element={<Main />} />
<Route exact path="/on:seq" element={<Sub />} />
<Route exact path="/result" element={<Result />} />
</Routes>
);
}
export default App;
App.js
import react from "react";
import logo from "./logo.svg";
import "./App.css";
import { Routes, Route, useNavigate, useParams } from "react-router-dom";
const question = [
{
text1: "당연하지! 어디서 할지 고민 중이야!",
text2: "그냥 맛있는거 먹으러 갈까 생각 중이야!",
},
{
text1: "영화 완전 재밌었어! 너도 한번 봐봐!",
text2: "좀비가 너무 리얼했어. 실제 상황이면 난 바로 죽었을거야...",
},
{
text1: "무슨 꽃 샀어? 향은 좋아?",
text2: "왜 우울해? 무슨 일 있어?",
},
{
text1: "지금 PPT 만드는 중이니까 아마 한 2시간 뒤면 끝날거 같아!",
text2: "모르겠어. 근데 지금 PPT 만들고 있어!",
},
{
text1: "그래! 역시 사람 많고 유명한 벚꽃 명소가 예쁘겠지 어디로 갈까?",
text2: "그래! 사람 적은 볓꽃 명소 한번 찾아볼까?",
},
{
text1: "지구는 멸망하지 않아!",
text2: "일단 가장 좋아하는 음식부터 먹으러 갈거야!",
},
{
text1: "드라이샴푸? 마른 머리에 비비면 되는건가? 완전 티 안나!",
text2: "어제 무슨 일 있었어? 지금은 피곤한거 좀 괜찮아?",
},
{
text1:
"우선 2시에 도착하니까 버스 타고 숙소가서 체크인하고 늦은 점심 먹을까?",
text2: "글쎄... 너는 가고 싶은데 없어? 난 현지 맛집이면 다 좋아!",
},
{
text1: "아니! 나 지금 밖이야! 친구랑 있어. 무슨 일 있어?",
text2: "응! 나 지금 넷플릭스 보고 있어! 무슨 일 있어?",
},
{
text1: "이해는 안가는데 시험번위고 종요하다니까 그냥 외우려고!",
text2: "이따가 선생님한테 가서 다시 물어보려고!",
},
{
text1: "무슨 시험 봤어? 다음 시험은 언제야? 괜찮아?",
text2: "다음에 꼭 붙을거야! 다음 시험을 기약하자! 너무 슬퍼하지마!",
},
{
text1: "진짜로? 왜? 갑자기? 다른 사람들은 뭐래?",
text2: "오! 갑자기 왜? 그럼 조는 어떻게 정한대?",
},
];
function Main() {
const navigation = useNavigate();
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="메인페이지이미지"
/>
</div>
<button
className="button"
onClick={() => {
navigation("/on1");
}}
>
시작하기
</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
const ProgressBar = (props) => {
// 서브페이지는 총 12개
const width = (480 / 12) * props.step;
return (
<div className="progress-bar">
<div className="percent" style={{ width: width }}></div>
</div>
);
};
function Sub() {
const navigation = useNavigate();
const { seq } = useParams();
const imgseq = seq.length === 1 ? "0" + seq : seq;
const srcurl = `https://kakaofriendsmbti.netlify.app/images/${imgseq}-01.png`;
const seqn = parseInt(seq);
const 페이지이동 = () => {
if (seqn < 12) {
navigation(`/on${seqn + 1}`);
} else {
navigation("/result");
}
};
return (
<div className="app">
<div className="content-box">
<ProgressBar step={seq} />
<div className="img-box sub">
<img src={srcurl} alt="서브페이지이미지" />
</div>
<button className="button" onClick={페이지이동}>
{question[seqn - 1].text1}
</button>
<button className="button" onClick={페이지이동}>
{question[seqn - 1].text2}
</button>
</div>
</div>
);
}
function Result() {
const navigation = useNavigate();
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/images/ENFJ.png"
alt="결과페이지이미지"
/>
</div>
<button
className="button"
onClick={() => {
navigation("/on1");
}}
>
다시하기
</button>
</div>
</div>
);
}
function App() {
return (
<Routes>
<Route exact path="/" element={<Main />} />
<Route exact path="/on:seq" element={<Sub />} />
<Route exact path="/result" element={<Result />} />
</Routes>
);
}
export default App;
App.js
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import axios from "axios";
import {
Routes,
Route,
useNavigate,
useLocation,
useParams,
} from "react-router-dom";
const question = [
{
text1: "당연하지! 어디서 할지 고민 중이야!",
text2: "그냥 맛있는거 먹으러 갈까 생각 중이야!",
re1: "E",
re2: "I",
},
{
text1: "영화 완전 재밌었어! 너도 한번 봐봐!",
text2: "좀비가 너무 리얼했어. 실제 상황이면 난 바로 죽었을거야...",
re1: "S",
re2: "N",
},
{
text1: "무슨 꽃 샀어? 향은 좋아?",
text2: "왜 우울해? 무슨 일 있어?",
re1: "T",
re2: "F",
},
{
text1: "지금 PPT 만드는 중이니까 아마 한 2시간 뒤면 끝날거 같아!",
text2: "모르겠어. 근데 지금 PPT 만들고 있어!",
re1: "J",
re2: "P",
},
{
text1: "그래! 역시 사람 많고 유명한 벚꽃 명소가 예쁘겠지 어디로 갈까?",
text2: "그래! 사람 적은 볓꽃 명소 한번 찾아볼까?",
re1: "E",
re2: "I",
},
{
text1: "지구는 멸망하지 않아!",
text2: "일단 가장 좋아하는 음식부터 먹으러 갈거야!",
re1: "S",
re2: "N",
},
{
text1: "드라이샴푸? 마른 머리에 비비면 되는건가? 완전 티 안나!",
text2: "어제 무슨 일 있었어? 지금은 피곤한거 좀 괜찮아?",
re1: "T",
re2: "F",
},
{
text1:
"우선 2시에 도착하니까 버스 타고 숙소가서 체크인하고 늦은 점심 먹을까?",
text2: "글쎄... 너는 가고 싶은데 없어? 난 현지 맛집이면 다 좋아!",
re1: "J",
re2: "P",
},
{
text1: "아니! 나 지금 밖이야! 친구랑 있어. 무슨 일 있어?",
text2: "응! 나 지금 넷플릭스 보고 있어! 무슨 일 있어?",
re1: "E",
re2: "I",
},
{
text1: "이해는 안가는데 시험번위고 종요하다니까 그냥 외우려고!",
text2: "이따가 선생님한테 가서 다시 물어보려고!",
re1: "S",
re2: "N",
},
{
text1: "무슨 시험 봤어? 다음 시험은 언제야? 괜찮아?",
text2: "다음에 꼭 붙을거야! 다음 시험을 기약하자! 너무 슬퍼하지마!",
re1: "T",
re2: "F",
},
{
text1: "진짜로? 왜? 갑자기? 다른 사람들은 뭐래?",
text2: "오! 갑자기 왜? 그럼 조는 어떻게 정한대?",
re1: "J",
re2: "P",
},
];
function Main() {
const navigation = useNavigate();
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="메인페이지이미지"
/>
</div>
<button
className="button"
onClick={() => {
navigation("/on1");
}}
>
시작하기
</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
const ProgressBar = (props) => {
// 서브페이지는 총 12개
const width = (480 / 12) * props.step;
return (
<div className="progress-bar">
<div className="percent" style={{ width: width }}></div>
</div>
);
};
function Sub() {
const { setDispatchType } = React.useContext(StoreContext);
const { seq } = useParams();
const imgseq = seq.length === 1 ? "0" + seq : seq;
const srcurl = `https://kakaofriendsmbti.netlify.app/images/${imgseq}-01.png`;
const seqn = parseInt(seq);
const 데이터저장 = (props) => {
const value = props === 1 ? question[seqn - 1].re1 : question[seqn - 1].re2;
setDispatchType({
code: "answer",
params: { value: value, page: seqn },
});
};
return (
<div className="app">
<div className="content-box">
<ProgressBar step={seq} />
<div className="img-box sub">
<img src={srcurl} alt="서브페이지이미지" />
</div>
<button className="button" onClick={() => 데이터저장(1)}>
{question[seqn - 1].text1}
</button>
<button className="button" onClick={() => 데이터저장(2)}>
{question[seqn - 1].text2}
</button>
</div>
</div>
);
}
function Result() {
const navigation = useNavigate();
const { state } = useLocation();
const { setDispatchType } = React.useContext(StoreContext);
const [result, setResult] = React.useState(undefined);
//결과 서버로 전송
const MBTISend = async () => {
await axios({
url: "http://localhost:5000/mbti",
method: "GET",
responseType: "json",
params: state,
})
.then((res) => {
// console.log(res.data);
setResult(res.data);
})
.catch((e) => {
console.log("error!!", e);
});
};
React.useEffect(() => {
MBTISend();
}, []);
if (result === undefined) {
return <div></div>;
}
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img src={result.content} alt="결과페이지이미지" />
</div>
<button
className="button"
onClick={() => {
setDispatchType({
code: "dataReset",
});
navigation("/on1");
}}
>
다시하기
</button>
</div>
</div>
);
}
const StoreContext = React.createContext({});
function App() {
const navigation = useNavigate();
const [dispatch, setDispatchType] = React.useState({
code: null,
params: null,
});
const [mbti, setMbti] = React.useState([
{ E: 0, I: 0 },
{ N: 0, S: 0 },
{ T: 0, F: 0 },
{ J: 0, P: 0 },
]);
React.useEffect(() => {
switch (dispatch.code) {
case "answer":
// mbti 결과 저장
const { value, page } = dispatch.params;
const clonembti = [...mbti];
const findIndex = clonembti.findIndex((item) => {
return item[value] !== undefined;
});
clonembti[findIndex][value]++;
console.log(clonembti);
setMbti(clonembti);
//페이지 이동
if (page < 12) {
navigation(`/on${page + 1}`);
} else {
navigation("/result", { state: mbti });
}
break;
case "dataReset":
setMbti([
{ E: 0, I: 0 },
{ N: 0, S: 0 },
{ F: 0, T: 0 },
{ J: 0, P: 0 },
]);
break;
default:
break;
}
}, [dispatch]);
return (
<StoreContext.Provider value={{ setDispatchType }}>
<Routes>
<Route exact path="/" element={<Main />} />
<Route exact path="/on:seq" element={<Sub />} />
<Route exact path="/result" element={<Result />} />
</Routes>
</StoreContext.Provider>
);
}
export default App;
server.js
const express = require("express");
const cors = require("cors");
const app = express();
const port = 5000;
const characters = [
{
name: "스카피",
content: "https://kakaofriendsmbti.netlify.app/images/ENTJ.png",
mbti: "ENTJ",
},
{
name: "어피치",
content: "https://kakaofriendsmbti.netlify.app/images/ENTP.png",
mbti: "ENTP",
},
{
name: "콘",
content: "https://kakaofriendsmbti.netlify.app/images/ENFJ.png",
mbti: "ENFJ",
},
{
name: "케로",
content: "https://kakaofriendsmbti.netlify.app/images/ENFP.png",
mbti: "ENFP",
},
{
name: "빠냐",
content: "https://kakaofriendsmbti.netlify.app/images/ESTJ.png",
mbti: "ESTJ",
},
{
name: "프로도",
content: "https://kakaofriendsmbti.netlify.app/images/ESTP.png",
mbti: "ESTP",
},
{
name: "제이지",
content: "https://kakaofriendsmbti.netlify.app/images/ESFJ.png",
mbti: "ESFJ",
},
{
name: "팬다주니어",
content: "https://kakaofriendsmbti.netlify.app/images/ESFP.png",
mbti: "ESFP",
},
{
name: "콥",
content: "https://kakaofriendsmbti.netlify.app/images/INTJ.png",
mbti: "INTJ",
},
{
name: "춘식이",
content: "https://kakaofriendsmbti.netlify.app/images/INTP.png",
mbti: "INTP",
},
{
name: "네오",
content: "https://kakaofriendsmbti.netlify.app/images/INFJ.png",
mbti: "INFJ",
},
{
name: "앙몬드",
content: "https://kakaofriendsmbti.netlify.app/images/INFP.png",
mbti: "INFP",
},
{
name: "라이언",
content: "https://kakaofriendsmbti.netlify.app/images/ISTJ.png",
mbti: "ISTJ",
},
{
name: "튜브",
content: "https://kakaofriendsmbti.netlify.app/images/ISTP.png",
mbti: "ISTP",
},
{
name: "죠르디",
content: "https://kakaofriendsmbti.netlify.app/images/ISFJ.png",
mbti: "ISFJ",
},
{
name: "무지",
content: "https://kakaofriendsmbti.netlify.app/images/ISFP.png",
mbti: "ISFP",
},
];
app.use(cors());
app.get("/", (req, res) => {
res.send("서버 요청");
});
app.get("/mbti", (req, res) => {
// console.log(req.query);
let result = "";
const mbti = req.query;
for (let key in mbti) {
const 객체 = mbti[key];
const [leftk, rightk] = Object.keys(객체);
const [leftv, rightv] = Object.values(객체);
if (leftv >= rightv) {
result += leftk;
} else {
result += rightk;
}
}
const [result2] = characters.filter((item, index) => {
return item.mbti === result;
});
res.send(result2);
});
app.listen(port, () => {
console.log("서버가 실행되었습니다.");
});
실행 결과는 위에 움짤과 같아요~
post 전송은 data -> .body
get 전송은 params -> .query
결과창에서 로컬스토리지 삭제하는거 생각해봤는데 useEffect에 넣으면 새로고침 할때마다 로컬스토리지 계속 삭제하니까 불필요한 코드 계속 실행하는 것 같음
다시하기 버튼 누를 때 데이터리셋 & 로컬스토리지 삭제하면 버튼 안 누르고 주소로 메인 들어갔을 때 로컬스토리지가 남아있음 어차피 삭제해야 됨
그래서 메인으로 갔을 때 저장된 페이지가 12일 때 로컬스토리지 삭제함~
App.js
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import axios from "axios";
import {
Routes,
Route,
useNavigate,
useLocation,
useParams,
} from "react-router-dom";
const question = [
{
text1: "당연하지! 어디서 할지 고민 중이야!",
text2: "그냥 맛있는거 먹으러 갈까 생각 중이야!",
re1: "E",
re2: "I",
},
{
text1: "영화 완전 재밌었어! 너도 한번 봐봐!",
text2: "좀비가 너무 리얼했어. 실제 상황이면 난 바로 죽었을거야...",
re1: "S",
re2: "N",
},
{
text1: "무슨 꽃 샀어? 향은 좋아?",
text2: "왜 우울해? 무슨 일 있어?",
re1: "T",
re2: "F",
},
{
text1: "지금 PPT 만드는 중이니까 아마 한 2시간 뒤면 끝날거 같아!",
text2: "모르겠어. 근데 지금 PPT 만들고 있어!",
re1: "J",
re2: "P",
},
{
text1: "그래! 역시 사람 많고 유명한 벚꽃 명소가 예쁘겠지 어디로 갈까?",
text2: "그래! 사람 적은 볓꽃 명소 한번 찾아볼까?",
re1: "E",
re2: "I",
},
{
text1: "지구는 멸망하지 않아!",
text2: "일단 가장 좋아하는 음식부터 먹으러 갈거야!",
re1: "S",
re2: "N",
},
{
text1: "드라이샴푸? 마른 머리에 비비면 되는건가? 완전 티 안나!",
text2: "어제 무슨 일 있었어? 지금은 피곤한거 좀 괜찮아?",
re1: "T",
re2: "F",
},
{
text1:
"우선 2시에 도착하니까 버스 타고 숙소가서 체크인하고 늦은 점심 먹을까?",
text2: "글쎄... 너는 가고 싶은데 없어? 난 현지 맛집이면 다 좋아!",
re1: "J",
re2: "P",
},
{
text1: "아니! 나 지금 밖이야! 친구랑 있어. 무슨 일 있어?",
text2: "응! 나 지금 넷플릭스 보고 있어! 무슨 일 있어?",
re1: "E",
re2: "I",
},
{
text1: "이해는 안가는데 시험번위고 종요하다니까 그냥 외우려고!",
text2: "이따가 선생님한테 가서 다시 물어보려고!",
re1: "S",
re2: "N",
},
{
text1: "무슨 시험 봤어? 다음 시험은 언제야? 괜찮아?",
text2: "다음에 꼭 붙을거야! 다음 시험을 기약하자! 너무 슬퍼하지마!",
re1: "T",
re2: "F",
},
{
text1: "진짜로? 왜? 갑자기? 다른 사람들은 뭐래?",
text2: "오! 갑자기 왜? 그럼 조는 어떻게 정한대?",
re1: "J",
re2: "P",
},
];
function Main() {
const navigation = useNavigate();
const { setDispatchType } = React.useContext(StoreContext);
React.useEffect(() => {
setDispatchType({
code: "tmpStorage",
});
}, []);
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img
src="https://kakaofriendsmbti.netlify.app/static/media/00.88f71908.png"
alt="메인페이지이미지"
/>
</div>
<button
className="button"
onClick={() => {
navigation("/on1");
}}
>
시작하기
</button>
<p>MADE BY @geenee</p>
</div>
</div>
);
}
const ProgressBar = (props) => {
// 서브페이지는 총 12개
const width = (480 / 12) * props.step;
return (
<div className="progress-bar">
<div className="percent" style={{ width: width }}></div>
</div>
);
};
function Sub() {
const { setDispatchType } = React.useContext(StoreContext);
const { seq } = useParams();
const imgseq = seq.length === 1 ? "0" + seq : seq;
const srcurl = `https://kakaofriendsmbti.netlify.app/images/${imgseq}-01.png`;
const seqn = parseInt(seq);
const 데이터저장 = (props) => {
const value = props === 1 ? question[seqn - 1].re1 : question[seqn - 1].re2;
setDispatchType({
code: "answer",
params: { value: value, page: seqn },
});
};
return (
<div className="app">
<div className="content-box">
<ProgressBar step={seq} />
<div className="img-box sub">
<img src={srcurl} alt="서브페이지이미지" />
</div>
<button className="button" onClick={() => 데이터저장(1)}>
{question[seqn - 1].text1}
</button>
<button className="button" onClick={() => 데이터저장(2)}>
{question[seqn - 1].text2}
</button>
</div>
</div>
);
}
function Result() {
const navigation = useNavigate();
const { state } = useLocation();
const { setDispatchType } = React.useContext(StoreContext);
const [result, setResult] = React.useState(undefined);
//결과 서버로 전송
const MBTISend = async () => {
await axios({
url: "http://localhost:5000/mbti",
method: "GET",
responseType: "json",
params: state,
})
.then((res) => {
// console.log(res.data);
setResult(res.data);
})
.catch((e) => {
console.log("error!!", e);
});
};
React.useEffect(() => {
MBTISend();
}, []);
if (result === undefined) {
return <div></div>;
}
return (
<div className="app">
<div className="content-box">
<div className="img-box">
<img src={result.content} alt="결과페이지이미지" />
</div>
<button
className="button"
onClick={() => {
setDispatchType({
code: "dataReset",
});
navigation("/on1");
}}
>
다시하기
</button>
</div>
</div>
);
}
const StoreContext = React.createContext({});
function App() {
const navigation = useNavigate();
const [dispatch, setDispatchType] = React.useState({
code: null,
params: null,
});
const [mbti, setMbti] = React.useState([
{ E: 0, I: 0 },
{ N: 0, S: 0 },
{ T: 0, F: 0 },
{ J: 0, P: 0 },
]);
React.useEffect(() => {
switch (dispatch.code) {
case "answer":
// mbti 결과 저장
const { value, page } = dispatch.params;
const clonembti = [...mbti];
const findIndex = clonembti.findIndex((item) => {
return item[value] !== undefined;
});
clonembti[findIndex][value]++;
// console.log(clonembti);
setMbti(clonembti);
//로컬 스토리지 저장
localStorage.setItem("MBTI", JSON.stringify(clonembti));
localStorage.setItem("PAGE", page);
//페이지 이동
if (page < 12) {
navigation(`/on${page + 1}`);
} else {
navigation("/result", { state: mbti });
}
break;
case "dataReset":
setMbti([
{ E: 0, I: 0 },
{ N: 0, S: 0 },
{ F: 0, T: 0 },
{ J: 0, P: 0 },
]);
break;
case "tmpStorage":
const tmpMbti = localStorage.getItem("MBTI");
const tmpPage = localStorage.getItem("PAGE");
// console.log(tmpMbti, tmpPage);
if (tmpPage === "12") {
localStorage.removeItem("MBTI");
localStorage.removeItem("PAGE");
return;
}
if (tmpMbti && tmpPage) {
const tmpMbtiarray = JSON.parse(tmpMbti);
setMbti(tmpMbtiarray);
const currentpage = Number(tmpPage);
navigation(`/on${currentpage + 1}`);
}
break;
default:
break;
}
}, [dispatch]);
return (
<StoreContext.Provider value={{ setDispatchType }}>
<Routes>
<Route exact path="/" element={<Main />} />
<Route exact path="/on:seq" element={<Sub />} />
<Route exact path="/result" element={<Result />} />
</Routes>
</StoreContext.Provider>
);
}
export default App;