박권수

feat. manager view

...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
16 }, 16 },
17 }); 17 });
18 }, 18 },
19 - acceotDoctorRegReq : (token : RecoilState<any>, Data : any) => { 19 + acceptDoctorRegReq : (token : RecoilState<any>, Data : any) => {
20 return client.post('/manage/doctor/accept', Data, { 20 return client.post('/manage/doctor/accept', Data, {
21 headers : { 21 headers : {
22 Authorization : token, 22 Authorization : token,
......
...@@ -43,4 +43,18 @@ export const onCheck = (text : string, confirmAction : () => void, denyAction : ...@@ -43,4 +43,18 @@ export const onCheck = (text : string, confirmAction : () => void, denyAction :
43 denyAction(); 43 denyAction();
44 } 44 }
45 }); 45 });
46 -}
...\ No newline at end of file ...\ No newline at end of file
46 +};
47 +
48 +export const onWarning = (text : string, confirmAction : () => void) => {
49 + Swal.fire({
50 + title : '주의',
51 + icon : 'warning',
52 + text,
53 + confirmButtonText : '확인',
54 + confirmButtonColor : '#337DFF',
55 + }).then(res => {
56 + if(res.isConfirmed) {
57 + confirmAction();
58 + }
59 + });
60 +};
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -120,7 +120,6 @@ export const ModalContent = styled.div ` ...@@ -120,7 +120,6 @@ export const ModalContent = styled.div `
120 `; 120 `;
121 121
122 export const MedicineNameWrapper = styled.div ` 122 export const MedicineNameWrapper = styled.div `
123 - flex : 1
124 border : none; 123 border : none;
125 border-bottom : 1px solid #ddd; 124 border-bottom : 1px solid #ddd;
126 width : 100%; 125 width : 100%;
......
...@@ -17,7 +17,7 @@ const LoginPresenter = (props : LoginProps) => { ...@@ -17,7 +17,7 @@ const LoginPresenter = (props : LoginProps) => {
17 return ( 17 return (
18 <styled.Container> 18 <styled.Container>
19 <styled.LoginWrapper> 19 <styled.LoginWrapper>
20 - <styled.LoginTitle>🩺로그인</styled.LoginTitle> 20 + <styled.LoginTitle>🩺 로그인</styled.LoginTitle>
21 <styled.LoginInputWrapper> 21 <styled.LoginInputWrapper>
22 <styled.LoginEachInputWrapper> 22 <styled.LoginEachInputWrapper>
23 <styled.LoginInputText> 23 <styled.LoginInputText>
......
...@@ -96,6 +96,10 @@ export const LoginInput = styled.input ` ...@@ -96,6 +96,10 @@ export const LoginInput = styled.input `
96 border-radius : 3px; 96 border-radius : 3px;
97 width : 100%; 97 width : 100%;
98 align-self : center; 98 align-self : center;
99 +
100 + &::placeholder {
101 + color : #ddd;
102 + }
99 `; 103 `;
100 104
101 export const RegisterButtonWrapper = styled.div ` 105 export const RegisterButtonWrapper = styled.div `
......
...@@ -5,15 +5,108 @@ import { RouteComponentProps} from 'react-router-dom'; ...@@ -5,15 +5,108 @@ import { RouteComponentProps} from 'react-router-dom';
5 import { useRecoilValue } from "recoil"; 5 import { useRecoilValue } from "recoil";
6 import * as recoilUtil from '../../../util/recoilUtil'; 6 import * as recoilUtil from '../../../util/recoilUtil';
7 7
8 +import * as Alert from '../../../util/alertMessage';
8 import ManagerMenuPresenter from "./ManagerMenuPresenter"; 9 import ManagerMenuPresenter from "./ManagerMenuPresenter";
9 10
11 +import { managerApi } from '../../../api';
12 +
10 13
11 type ManagerMenuProps = RouteComponentProps; 14 type ManagerMenuProps = RouteComponentProps;
12 15
13 const ManagerMenuContainer = (props : ManagerMenuProps) => { 16 const ManagerMenuContainer = (props : ManagerMenuProps) => {
17 +
18 + const token = useRecoilValue(recoilUtil.token);
19 +
20 + const [doctorRegReqList, setDoctorRegReqList] = useState<any>([]);
21 +
22 + const [doctorDetail, setDoctorDetail] = useState<any>({});
23 + const [modalUp, setModalUp] = useState<boolean>(false);
24 +
25 +
26 +
27 + const fetchData = async() => {
28 + setModalUp(false);
29 +
30 + try {
31 + await managerApi.getDoctorRegReqList(token)
32 + .then((res : any) => {
33 + if(res.statusText === 'OK') {
34 + setDoctorRegReqList(res.data.doctorRegReqList);
35 + }
36 + }).catch(err => {
37 + Alert.onError(err.response.data.error, () => null);
38 + })
39 + } catch(e) {
40 + Alert.onError(e.response.data.error, () => null);
41 + }
42 + };
43 +
44 +
45 + const onViewDetailReq = async (doctorId : string) => {
46 + try {
47 + await managerApi.getDoctorRegReqDetail(token, doctorId)
48 + .then((res : any) => {
49 + if(res.statusText === 'OK') {
50 + setDoctorDetail(res.data.doctorInfo);
51 + setModalUp(true);
52 + }
53 + })
54 + } catch(e) {
55 + Alert.onError(e.response.data.error, () => setModalUp(false));
56 + }
57 + };
58 +
59 + //회원 가입 수락
60 + const onAcceptRequest = () => {
61 + const onAccept = async() => {
62 + try {
63 + await managerApi.acceptDoctorRegReq(token, doctorDetail)
64 + .then((res : any) => {
65 + if(res.statusText === 'OK') {
66 + Alert.onSuccess('회원 등록이 완료되었습니다.', fetchData);
67 + }
68 + })
69 + } catch(e) {
70 + Alert.onError(e.response.data.error, () => setModalUp(false));
71 + }
72 + };
73 +
74 + Alert.onCheck('회원 가입 요청을 수락하시겠습니까?', onAccept, () => null);
75 + };
76 +
77 + //회원 가입 거절
78 + const onRejectRequest = () => {
79 + const onReject = async() => {
80 + try {
81 + await managerApi.rejectDoctorRegReq(token, doctorDetail)
82 + .then((res : any) => {
83 + if(res.statusText === 'OK') {
84 + Alert.onSuccess('회원 등록이 취소되었습니다.', fetchData);
85 + }
86 + })
87 + } catch(e) {
88 + Alert.onError(e.response.data.error, () => setModalUp(false));
89 + }
90 + };
91 +
92 + Alert.onCheck('회원 가입 요청을 취소하시겠습니까?', onReject, () => null);
93 + };
94 +
95 + useEffect(() => {
96 + fetchData();
97 + }, []);
98 +
14 return ( 99 return (
15 <ManagerMenuPresenter 100 <ManagerMenuPresenter
101 + doctorRegReqList = {doctorRegReqList}
102 +
103 + doctorDetail = {doctorDetail}
104 + modalUp = {modalUp}
105 + setModalUp = {setModalUp}
106 + onViewDetailReq = {onViewDetailReq}
16 107
108 + onAcceptRequest = {onAcceptRequest}
109 + onRejectRequest = {onRejectRequest}
17 /> 110 />
18 ); 111 );
19 }; 112 };
......
...@@ -2,14 +2,144 @@ import React from 'react'; ...@@ -2,14 +2,144 @@ import React from 'react';
2 2
3 import * as styled from './ManagerMenuStyled'; 3 import * as styled from './ManagerMenuStyled';
4 4
5 +const closeButton = '/static/img/close.png';
5 6
6 -// eslint-disable-next-line @typescript-eslint/no-empty-interface 7 +
7 -interface ManagerMenuProps {} 8 +
9 +interface ManagerMenuProps {
10 + doctorRegReqList : any[];
11 +
12 + doctorDetail : any;
13 + modalUp : boolean;
14 + setModalUp : any;
15 + onViewDetailReq : (arg0 : string) => void;
16 +
17 + onAcceptRequest : () => void;
18 + onRejectRequest : () => void;
19 +
20 +}
8 21
9 const ManagerMenuPresenter = (props : ManagerMenuProps) => { 22 const ManagerMenuPresenter = (props : ManagerMenuProps) => {
10 return ( 23 return (
11 <styled.Container> 24 <styled.Container>
12 - 관리자 메뉴 25 + {
26 + props.modalUp ?
27 + <styled.ModalContainer>
28 + <styled.ModalClsButtonWrapper>
29 + <styled.ModalClsButton
30 + onClick = {() => props.setModalUp(false)}
31 + >
32 + <styled.ModalClsButtonImg src = {closeButton}/>
33 + <styled.ModalClsButtonText>닫기</styled.ModalClsButtonText>
34 + </styled.ModalClsButton>
35 + </styled.ModalClsButtonWrapper>
36 + <styled.ModalContentWrapper>
37 + <styled.ModalContent>
38 + <styled.ModalTitleWrapper>
39 + <styled.ModalTitle>가입 요청 정보</styled.ModalTitle>
40 + </styled.ModalTitleWrapper>
41 + <styled.ModalBodyWrapper>
42 + <styled.ModalBodyLeftAndRight>
43 + <styled.ModalInfoWrapper>
44 + <styled.ModalInfoExplain>의사 자격 번호</styled.ModalInfoExplain>
45 + <styled.ModalInfo>{props.doctorDetail.info.doctorLicense}</styled.ModalInfo>
46 + </styled.ModalInfoWrapper>
47 + <styled.ModalInfoWrapper>
48 + <styled.ModalInfoExplain>이름</styled.ModalInfoExplain>
49 + <styled.ModalInfo>{props.doctorDetail.info.doctorNm}</styled.ModalInfo>
50 + </styled.ModalInfoWrapper>
51 + <styled.ModalInfoWrapper>
52 + <styled.ModalInfoExplain>연락처</styled.ModalInfoExplain>
53 + <styled.ModalInfo>{props.doctorDetail.info.contact}</styled.ModalInfo>
54 + </styled.ModalInfoWrapper>
55 + </styled.ModalBodyLeftAndRight>
56 + <styled.ModalBodyLeftAndRight>
57 + <styled.ModalInfoWrapper>
58 + <styled.ModalInfoExplain>전문 분야</styled.ModalInfoExplain>
59 + <styled.ModalInfo>{props.doctorDetail.info.doctorType}</styled.ModalInfo>
60 + </styled.ModalInfoWrapper>
61 + <styled.ModalInfoWrapper>
62 + <styled.ModalInfoExplain>병원명</styled.ModalInfoExplain>
63 + <styled.ModalInfo>{props.doctorDetail.info.hospitalNm}</styled.ModalInfo>
64 + </styled.ModalInfoWrapper>
65 + <styled.ModalInfoWrapper>
66 + <styled.ModalInfoExplain>병원 주소</styled.ModalInfoExplain>
67 + <styled.ModalInfo>{props.doctorDetail.info.hospitalAddr}</styled.ModalInfo>
68 + </styled.ModalInfoWrapper>
69 + </styled.ModalBodyLeftAndRight>
70 + </styled.ModalBodyWrapper>
71 + <styled.ModalButtonWrapper>
72 + <styled.ModalButton
73 + onClick = {props.onAcceptRequest}
74 + isAccept = {true}
75 + >
76 + 수락
77 + </styled.ModalButton>
78 + <styled.ModalButton
79 + onClick = {props.onRejectRequest}
80 + isAccept = {false}
81 + >
82 + 거절
83 + </styled.ModalButton>
84 + </styled.ModalButtonWrapper>
85 + </styled.ModalContent>
86 + </styled.ModalContentWrapper>
87 + <styled.ModalClsButtonWrapper/>
88 + </styled.ModalContainer> : null
89 + }
90 + <styled.ContentWrapper>
91 + <styled.ContentTitle>
92 + 가입 대기 중 의사 회원
93 + <styled.ContentExplain>
94 + *클릭하면 상세정보를 확인할 수 있습니다.
95 + </styled.ContentExplain>
96 + </styled.ContentTitle>
97 + <styled.ContentBody>
98 + <styled.ContentInfoWrapper>
99 + <styled.ContentInfo
100 + isLast = {false}
101 + >
102 + 분야
103 + </styled.ContentInfo>
104 + <styled.ContentInfo
105 + isLast = {false}
106 + >
107 + 이름
108 + </styled.ContentInfo>
109 + <styled.ContentInfo
110 + isLast = {true}
111 + >
112 + 이메일
113 + </styled.ContentInfo>
114 + </styled.ContentInfoWrapper>
115 + {
116 + props.doctorRegReqList.map((doctor : any) => {
117 + return (
118 + <styled.EachContentWrapper
119 + key = {doctor.doctorId}
120 + onClick = {() => props.onViewDetailReq(doctor.doctorId)}
121 + >
122 + <styled.EachContentNm
123 + isLast = {false}
124 + >
125 + {doctor.info.doctorType}
126 + </styled.EachContentNm>
127 + <styled.EachContentNm
128 + isLast = {false}
129 + >
130 + {doctor.info.doctorNm}
131 + </styled.EachContentNm>
132 + <styled.EachContentNm
133 + isLast = {true}
134 + >
135 + {doctor.doctorId}
136 + </styled.EachContentNm>
137 + </styled.EachContentWrapper>
138 + )
139 + })
140 + }
141 + </styled.ContentBody>
142 + </styled.ContentWrapper>
13 </styled.Container> 143 </styled.Container>
14 ) 144 )
15 }; 145 };
......
1 -import styled from 'styled-components'; 1 +import styled, { keyframes } from 'styled-components';
2 +
3 +
4 +const ModalOn = keyframes `
5 + 0% {
6 + background-color : rgba(52, 52, 52, .0);
7 + }
8 + 20% {
9 + background-color : rgba(52, 52, 52, .2);
10 + }
11 + 40% {
12 + background-color : rgba(52, 52, 52, .4);
13 + }
14 + 60% {
15 + background-color : rgba(52, 52, 52, .5);
16 + }
17 + 80% {
18 + background-color : rgba(52, 52, 52, .6);
19 + }
20 + 100% {
21 + background-color : rgba(52, 52, 52, .7);
22 + }
23 +
24 +`;
2 25
3 export const Container = styled.div ` 26 export const Container = styled.div `
27 + width : 100%;
28 + height : 80vh;
29 +
30 + display : flex;
31 + justify-content : center;
32 + align-items : center;
33 +`;
34 +
35 +
36 +export const ModalContainer = styled.div `
37 + height : 100%;
38 + width : 100%;
39 + z-index : 99;
40 + position : absolute;
41 +
42 + display : flex;
43 + flex-direction : column;
44 +
45 + animation : ${ModalOn} .5s;
46 +
47 + background-color : rgba(52, 52, 52, .7);
48 +`;
49 +
50 +export const ModalClsButtonWrapper = styled.div `
51 + flex : 1;
52 +
53 + display : flex;
54 +
55 + justify-content : flex-end;
56 + align-items : center;
57 + padding : 0 20px;
58 +
59 + border : none;
60 + background-color : transprent;
61 +`;
62 +
63 +export const ModalClsButton = styled.button `
64 + border : none;
65 + background-color : transparent;
66 +
67 + cursor : pointer;
68 +
69 + color : #fff;
70 +
71 + display : flex;
72 + flex-direction : row;
73 +
74 + justify-content : center;
75 + align-items : center;
76 +
77 + transition : .25s all;
78 + &:hover {
79 + opacity : .5;
80 + }
81 +`;
82 +
83 +export const ModalClsButtonImg = styled.img `
84 + height : 20px;
85 + width : 20px;
86 +
87 + margin : 0 10px 0 0;
88 +`;
89 +
90 +export const ModalClsButtonText = styled.div `
91 + font-size : 18px;
92 + font-weight : 700;
93 +`;
94 +
95 +export const ModalContentWrapper = styled.div `
96 + flex : 8;
97 +
98 + display : flex;
99 + flex-direction : column;
100 +
101 + justify-content : center;
102 + align-items : center;
103 +
104 + border : none;
105 +`;
106 +
107 +export const ModalContent = styled.div `
108 + width : 700px;
109 + height : 500px;
110 +
111 + background-color : #fff;
112 + border : 1.2px solid #337DFF;
113 + border-radius : 5px;
114 +
115 + display : flex;
116 + flex-direction : column;
117 +
118 + // justify-content : center;
119 + align-items : center;
120 +`;
121 +
122 +export const ModalTitleWrapper = styled.div `
123 + flex : 1;
124 + border : none;
125 + border-bottom : 1px solid #ddd;
126 + width : 100%;
127 +
128 + display : flex;
129 + flex-direction : column;
130 + justify-content : center;
131 + align-items : center;
132 +`;
133 +
134 +export const ModalTitle = styled.div `
135 + font-size : 20px;
136 + font-weight : 700;
137 + letter-spacing : 1px;
138 +
139 + color : #337DFF;
140 +`;
141 +
142 +export const ModalBodyWrapper = styled.div `
143 + flex : 5;
144 + width : 100%;
145 +
146 + border : none;
147 +
148 + display : flex;
149 + flex-direction : row;
150 +
151 +`;
152 +
153 +export const ModalBodyLeftAndRight = styled.div `
154 + flex : 1;
155 +
156 + border : none;
157 +
158 + padding : 20px;
159 +
160 + display : flex;
161 + flex-direction : column;
162 + justify-content :center;
163 + align-items : center;
164 +`;
165 +
166 +export const ModalInfoWrapper = styled.div `
167 + flex : 1;
168 + border : none;
169 +
170 + width : 80%;
171 +
172 + display : flex;
173 + flex-direction : column;
174 +
175 + justify-content : center;
176 + align-items : flex-start;
177 +
178 +`;
179 +
180 +export const ModalInfoExplain = styled.div `
181 + font-size : 16px;
182 + font-weight : 500;
183 +
184 + letter-spacing : 1px;
185 +
186 + border : none;
187 + border-bottom : 1px solid #337DFF;
188 +
189 + color : #337DFF;
190 + padding : 2px 5px;
191 +`;
192 +
193 +export const ModalInfo = styled.div `
194 + margin : 5px 0 20px 0;
195 + font-size : 20px;
196 + font-weight : 700;
197 +`;
198 +
199 +export const ModalButtonWrapper = styled.div `
200 + flex : 1.5;
201 +
202 + display : flex;
203 + flex-direction : row;
204 +
205 + justify-content : center;
206 + align-items : center;
207 +
208 + border : none
209 +`;
210 +
211 +export const ModalButton = styled.button<{isAccept : boolean}> `
212 + margin : 0 30px;
213 + border-radius : 3px;
214 + border : 1px solid #337DFF;
215 +
216 + background-color : ${props => props.isAccept ? '#337DFF' : 'transparent'};
217 + color : ${props => props.isAccept ? '#fff' : '#337DFF'};
218 +
219 + font-size : 18px;
220 + font-weight : 600;
221 + letter-spacing : 1px;
222 +
223 + padding : 10px 40px;
224 +
225 + display : flex;
226 + justify-content : center;
227 + align-items : center;
228 +
229 + cursor : pointer;
230 +
231 + transition : .25s all;
232 +
233 + &:hover {
234 + background-color : #343434;
235 + color : #fff;
236 + border : 1px solid #343434;
237 + }
238 +
239 +
240 +`;
241 +
242 +
243 +export const ContentWrapper = styled.div `
244 + height : 80%;
245 + width : 60%;
246 +
247 + border : 1px solid #ddd;
248 + border-radius : 4px;
249 +
250 + box-shadow: 0px 0px 10px #a0a0a0;
251 +
252 +`;
253 +
254 +export const ContentTitle = styled.div `
255 + width : 100%;
256 + border : none;
257 + border-bottom : 1px solid #ddd;
258 +
259 + display : flex;
260 + flex-direction : column;
261 + justify-content : center;
262 + align-items : center;
263 +
264 + padding : 4% 0;
265 + font-size : 22px;
266 + font-weight : 600;
267 + letter-spacing : 1px;
268 +
269 + color : #343434;
270 +`;
271 +
272 +export const ContentExplain = styled.div `
273 + margin : 2px 0 0 0;
274 + font-size : 14px;
275 + color : #a0a0a0;
276 + font-weight : 500;
277 + letter-spacing : 1px;
278 +
279 +`;
280 +
281 +export const ContentBody = styled.div `
282 + overflow : scroll;
283 +
284 + height : 79%;
285 +
286 + border : none;
287 +
288 + padding : 0 0 0 3px;
289 +
290 + display : flex;
291 + flex-direction : column;
292 + align-items : center;
293 +
294 + &::-webkit-scrollbar {
295 + width : 3px;
296 + background-color : transparent;
297 + height : 0px;
298 + }
299 +
300 + &::-webkit-scrollbar-thumb {
301 + background-color : #337DFF;
302 + }
303 +`;
304 +
305 +export const ContentInfoWrapper = styled.div `
306 + width : 100%;
307 + border : none;
308 + border-bottom : 1px solid #a0a0a0;
309 +
310 + display : flex;
311 + flex-direction : row;
312 +
313 + justify-content : center;
314 + align-items : center;
315 +
316 + padding : 12px 0px;
317 +`;
318 +
319 +export const ContentInfo = styled.div<{isLast : boolean}> `
320 + flex : 1;
321 + display : flex;
322 + flex-direction : row;
323 +
324 + justify-content : center;
325 + align-items : center;
326 +
327 + font-size : 16px;
328 + font-weight : 600;
329 +
330 + color : #377DFF;
331 +
332 + border : none;
333 +
334 + border-right : ${props => props.isLast ? '1px solid transparent' : '1px solid #ddd'};
335 +`;
336 +
337 +export const EachContentWrapper = styled.button `
338 + width : 100%;
339 + border : none;
340 + border-bottom : 1px solid #ddd;
341 +
342 + background-color : transparent;
343 +
344 + display : flex;
345 + flex-direction : row;
346 +
347 + justify-content : center;
348 + align-items : center;
349 +
350 + color : #343434;
351 +
352 + padding : 10px 0px;
353 +
354 + cursor : pointer;
355 +
356 + transition : .1s all;
357 +
358 + &:hover {
359 + background-color : #337DFF;
360 + color : #fff;
361 + }
362 +
363 +`;
364 +
365 +export const EachContentNm = styled.div<{isLast : boolean}> `
366 + flex : 1;
367 + display : flex;
368 + flex-direction : row;
369 +
370 + justify-content : center;
371 + align-items : center;
372 +
373 + font-size : 14px;
374 + font-weight : 500;
375 +
376 +
377 + border : none;
378 +
379 + border-right : ${props => props.isLast ? '1px solid transparent' : '1px solid #ddd'};
4 380
5 `; 381 `;
...\ No newline at end of file ...\ No newline at end of file
......