HyeonJun Jeon

[Add] Nickname, color popup

...@@ -40,6 +40,24 @@ async function route() { ...@@ -40,6 +40,24 @@ async function route() {
40 res.end(); 40 res.end();
41 } 41 }
42 }); 42 });
43 +
44 + // (userID, subjectID, nickname, color)
45 + userSubjectRouter.put("/modify", async (req, res) => {
46 + console.log("/db/user-subject/modify");
47 + try {
48 + const queryString = `
49 + UPDATE \`user-subject\`
50 + SET color = '${req.body.color}',
51 + nickname = '${req.body.nickname}'
52 + WHERE userID = ${req.body.userID}
53 + AND subjectID = ${req.body.subjectID}`;
54 + await connection.query(queryString);
55 + res.end();
56 + } catch (e) {
57 + console.log(e);
58 + res.end();
59 + }
60 + });
43 } 61 }
44 route(); 62 route();
45 63
......
1 +import { useState } from "react";
2 +
1 const SideSubject = ({ subject, dispatch }) => { 3 const SideSubject = ({ subject, dispatch }) => {
2 const defaultColor = "#EFEFEF"; 4 const defaultColor = "#EFEFEF";
5 + const [state, setState] = useState({
6 + nickname: subject.nickname || subject.name,
7 + color: subject.color,
8 + });
9 +
10 + const handleChangeState = (e) => {
11 + setState({
12 + ...state,
13 + [e.target.name]: e.target.value,
14 + });
15 + };
3 16
4 const check = (e) => { 17 const check = (e) => {
5 dispatch({ type: "CHECKED", subjectID: subject.subjectID }); 18 dispatch({ type: "CHECKED", subjectID: subject.subjectID });
...@@ -7,6 +20,37 @@ const SideSubject = ({ subject, dispatch }) => { ...@@ -7,6 +20,37 @@ const SideSubject = ({ subject, dispatch }) => {
7 else e.target.style["background-color"] = subject.color; 20 else e.target.style["background-color"] = subject.color;
8 }; 21 };
9 22
23 + const labelClick = (e) => {
24 + e.target.nextSibling.style.display = "flex";
25 + };
26 +
27 + const popupClose = (e) => {
28 + setState({
29 + nickname: subject.nickname || subject.name,
30 + color: subject.color,
31 + });
32 + e.target.offsetParent.style.display = "none";
33 + };
34 +
35 + const popupApply = (e) => {
36 + if (state.nickname.length < 1) alert("이름을 입력해 주세요");
37 + else if (state.color.length !== 6) alert("색상은 6자리 16진수 값 입니다");
38 + else {
39 + let check = true;
40 + for (const c of state.color) if (isNaN(parseInt(c, 16))) check = false;
41 + if (!check) alert("색상은 16진수 값 입니다");
42 + else {
43 + dispatch({
44 + type: "MODIFY",
45 + subjectID: subject.subjectID,
46 + nickname: state.nickname,
47 + color: state.color,
48 + });
49 + e.target.offsetParent.style.display = "none";
50 + }
51 + }
52 + };
53 +
10 return ( 54 return (
11 <div className="SideSubject"> 55 <div className="SideSubject">
12 <div 56 <div
...@@ -16,8 +60,33 @@ const SideSubject = ({ subject, dispatch }) => { ...@@ -16,8 +60,33 @@ const SideSubject = ({ subject, dispatch }) => {
16 backgroundColor: subject.status ? "#" + subject.color : defaultColor, 60 backgroundColor: subject.status ? "#" + subject.color : defaultColor,
17 }} 61 }}
18 ></div> 62 ></div>
19 - 63 + <span className="ssl" onClick={labelClick}>
20 - <span>{subject.name}</span> 64 + {subject.nickname || subject.name}
65 + </span>
66 + <div className="ss_popup">
67 + <div className="sspd">
68 + <div className="sspd_1">
69 + <span>이름</span>
70 + <input
71 + name="nickname"
72 + value={state.nickname}
73 + onChange={handleChangeState}
74 + />
75 + </div>
76 + <div className="sspd_2">
77 + <span>색상</span>
78 + <input
79 + name="color"
80 + value={state.color}
81 + onChange={handleChangeState}
82 + />
83 + </div>
84 + </div>
85 + <div className="ssp_btns">
86 + <button onClick={popupApply}>적용 </button>
87 + <button onClick={popupClose}>취소</button>
88 + </div>
89 + </div>
21 </div> 90 </div>
22 ); 91 );
23 }; 92 };
......
...@@ -10,9 +10,10 @@ import axios from "axios"; ...@@ -10,9 +10,10 @@ import axios from "axios";
10 export const CalendarStateContext = React.createContext(); 10 export const CalendarStateContext = React.createContext();
11 11
12 const render = (subsObj, args) => { 12 const render = (subsObj, args) => {
13 + let sub;
13 switch (args.type) { 14 switch (args.type) {
14 case "CHECKED": 15 case "CHECKED":
15 - const sub = subsObj[args.subjectID]; 16 + sub = subsObj[args.subjectID];
16 sub.status = !sub.status; 17 sub.status = !sub.status;
17 axios.put("http://localhost:3001/db/user-subject/check", { 18 axios.put("http://localhost:3001/db/user-subject/check", {
18 userID: sub.userID, 19 userID: sub.userID,
...@@ -20,6 +21,17 @@ const render = (subsObj, args) => { ...@@ -20,6 +21,17 @@ const render = (subsObj, args) => {
20 status: +sub.status, 21 status: +sub.status,
21 }); 22 });
22 return { ...subsObj, [args.subjectID]: sub }; 23 return { ...subsObj, [args.subjectID]: sub };
24 + case "MODIFY":
25 + sub = subsObj[args.subjectID];
26 + sub.nickname = args.nickname;
27 + sub.color = args.color;
28 + axios.put("http://localhost:3001/db/user-subject/modify", {
29 + userID: sub.userID,
30 + subjectID: args.subjectID,
31 + nickname: sub.nickname,
32 + color: sub.color,
33 + });
34 + return { ...subsObj, [args.subjectID]: sub };
23 case "INIT": 35 case "INIT":
24 return args.subsObj; 36 return args.subsObj;
25 default: 37 default:
......
...@@ -6,9 +6,9 @@ aside { ...@@ -6,9 +6,9 @@ aside {
6 } 6 }
7 7
8 .SideSubject { 8 .SideSubject {
9 - height: 25px;
10 padding: 5px 0px 5px 0px; 9 padding: 5px 0px 5px 0px;
11 display: flex; 10 display: flex;
11 + position: relative;
12 } 12 }
13 13
14 .ssc { 14 .ssc {
...@@ -21,5 +21,53 @@ aside { ...@@ -21,5 +21,53 @@ aside {
21 } 21 }
22 22
23 .SideSubject > span { 23 .SideSubject > span {
24 + cursor: pointer;
24 line-height: 25px; 25 line-height: 25px;
25 } 26 }
27 +
28 +.ss_popup {
29 + flex-direction: column;
30 + align-items: flex-end;
31 + position: absolute;
32 + z-index: 1000;
33 + top: 30px;
34 + left: 30px;
35 + /* height: 150px;
36 + width: 250px; */
37 + /* transform: translate(-50%, -50%); */
38 + background: rgb(241, 241, 241);
39 + display: none;
40 + border: solid thin black;
41 + padding: 5px;
42 +}
43 +
44 +.sspd {
45 + display: flex;
46 + flex-direction: column;
47 +}
48 +
49 +.sspd > div {
50 + display: flex;
51 + margin-bottom: 3px;
52 +}
53 +
54 +.sspd > div > span {
55 + text-align: center;
56 + line-height: 30px;
57 + margin-right: 5px;
58 + width: 35px;
59 +}
60 +
61 +.sspd > div > input {
62 + flex-grow: 1;
63 + height: 24px;
64 +}
65 +
66 +.ssp_btns {
67 + margin-top: 2px;
68 +}
69 +
70 +.ssp_btns > button {
71 + padding: 5px 9px 5px 9px;
72 + margin-left: 2px;
73 +}
......