Showing
4 changed files
with
151 additions
and
4 deletions
... | @@ -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 | +} | ... | ... |
-
Please register or login to post a comment