박권수

feat. 탈퇴 요청 뷰 구성

...@@ -9,6 +9,13 @@ export default { ...@@ -9,6 +9,13 @@ export default {
9 }, 9 },
10 }); 10 });
11 }, 11 },
12 + getDoctorSecReqList : (token : RecoilState<any>) => {
13 + return client.get('/manage/doctor/secession', {
14 + headers : {
15 + Authorization : token,
16 + },
17 + });
18 + },
12 getDoctorRegReqDetail : (token : RecoilState<any>, doctorId : string) => { 19 getDoctorRegReqDetail : (token : RecoilState<any>, doctorId : string) => {
13 return client.get(`/manage/doctor/${doctorId}`, { 20 return client.get(`/manage/doctor/${doctorId}`, {
14 headers : { 21 headers : {
...@@ -17,14 +24,21 @@ export default { ...@@ -17,14 +24,21 @@ export default {
17 }); 24 });
18 }, 25 },
19 acceptDoctorRegReq : (token : RecoilState<any>, Data : any) => { 26 acceptDoctorRegReq : (token : RecoilState<any>, Data : any) => {
20 - return client.post('/manage/doctor/accept', Data, { 27 + return client.patch('/manage/doctor/accept', Data, {
21 headers : { 28 headers : {
22 Authorization : token, 29 Authorization : token,
23 }, 30 },
24 }); 31 });
25 }, 32 },
26 rejectDoctorRegReq : (token : RecoilState<any>, Data : any) => { 33 rejectDoctorRegReq : (token : RecoilState<any>, Data : any) => {
27 - return client.post('/manage/doctor/reject', Data, { 34 + return client.patch('/manage/doctor/reject', Data, {
35 + headers : {
36 + Authorization : token,
37 + },
38 + });
39 + },
40 + acceptDoctorSecReq : (token : RecoilState<any>, Data : any) => {
41 + return client.patch('/manage/doctor/secession', Data, {
28 headers : { 42 headers : {
29 Authorization : token, 43 Authorization : token,
30 }, 44 },
......
...@@ -17,7 +17,9 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -17,7 +17,9 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
17 17
18 const token = useRecoilValue(recoilUtil.token); 18 const token = useRecoilValue(recoilUtil.token);
19 19
20 - const [doctorRegReqList, setDoctorRegReqList] = useState<any>([]); 20 + const [doctorList, setDoctorList] = useState<any>([]);
21 +
22 + const [viewType, setViewType] = useState<string>('reg');
21 23
22 const [doctorDetail, setDoctorDetail] = useState<any>({}); 24 const [doctorDetail, setDoctorDetail] = useState<any>({});
23 const [modalUp, setModalUp] = useState<boolean>(false); 25 const [modalUp, setModalUp] = useState<boolean>(false);
...@@ -31,20 +33,28 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -31,20 +33,28 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
31 setValidate('W'); 33 setValidate('W');
32 34
33 try { 35 try {
34 - await managerApi.getDoctorRegReqList(token) 36 + const res = viewType === 'reg' ? await managerApi.getDoctorRegReqList(token) : await managerApi.getDoctorSecReqList(token);
35 - .then((res : any) => { 37 + if(res.statusText === 'OK') {
36 - if(res.statusText === 'OK') { 38 + setDoctorList(res.data.doctorList);
37 - setDoctorRegReqList(res.data.doctorRegReqList); 39 + } else {
38 - } 40 + Alert.onError(res.data.error, () => null);
39 - }).catch(err => { 41 + }
40 - Alert.onError(err.response.data.error, () => null);
41 - });
42 } catch(e : any) { 42 } catch(e : any) {
43 Alert.onError(e.response.data.error, () => null); 43 Alert.onError(e.response.data.error, () => null);
44 } 44 }
45 }; 45 };
46 46
47 + //가입요청 보기
48 + const onViewRegList = () => {
49 + setViewType('reg');
50 + };
47 51
52 + //탈퇴요청 보기
53 + const onViewSecList = () => {
54 + setViewType('sec');
55 + };
56 +
57 + //가입요청 상세보기
48 const onViewDetailReq = async (doctorId : string) => { 58 const onViewDetailReq = async (doctorId : string) => {
49 setValidate('W'); 59 setValidate('W');
50 60
...@@ -72,7 +82,7 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -72,7 +82,7 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
72 }; 82 };
73 83
74 //회원 가입 수락 84 //회원 가입 수락
75 - const onAcceptRequest = () => { 85 + const onAcceptRegReq = () => {
76 if(validate === 'W') { 86 if(validate === 'W') {
77 Alert.onError('먼저 의사의 자격번호가 유효한지 검증해주세요.', () => null); 87 Alert.onError('먼저 의사의 자격번호가 유효한지 검증해주세요.', () => null);
78 return; 88 return;
...@@ -118,6 +128,7 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -118,6 +128,7 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
118 Alert.onCheck('회원 가입 요청을 취소하시겠습니까?', onReject, () => null); 128 Alert.onCheck('회원 가입 요청을 취소하시겠습니까?', onReject, () => null);
119 }; 129 };
120 130
131 + //회원 자격번호 유효 검증 api
121 const onValidate = async () => { 132 const onValidate = async () => {
122 try { 133 try {
123 await managerApi.validateDoctorLicense(token, { 134 await managerApi.validateDoctorLicense(token, {
...@@ -140,6 +151,24 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -140,6 +151,24 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
140 } 151 }
141 }; 152 };
142 153
154 + const onAcceptSecReq = (doctorId : string) => {
155 + const onAccept = async () => {
156 + try {
157 + const res = await managerApi.acceptDoctorSecReq(token, {
158 + doctorId,
159 + });
160 + if(res.statusText === 'OK') {
161 + Alert.onSuccess('탈퇴를 승인했습니다.', fetchData);
162 + }
163 + } catch (e : any) {
164 + Alert.onError(e.response.data.error, () => null);
165 + }
166 + };
167 +
168 + Alert.onCheck('회원 탈퇴를 승인하시겠습니까?\n이 작업은 되돌릴 수 없습니다.', onAccept, () => null);
169 + };
170 +
171 +
143 172
144 useEffect(() => { 173 useEffect(() => {
145 setValidate('W'); 174 setValidate('W');
...@@ -148,11 +177,15 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -148,11 +177,15 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
148 177
149 useEffect(() => { 178 useEffect(() => {
150 fetchData(); 179 fetchData();
151 - }, []); 180 + }, [viewType]);
152 181
153 return ( 182 return (
154 <ManagerMenuPresenter 183 <ManagerMenuPresenter
155 - doctorRegReqList = {doctorRegReqList} 184 + viewType = {viewType}
185 + onViewRegList = {onViewRegList}
186 + onViewSecList = {onViewSecList}
187 +
188 + doctorList = {doctorList}
156 189
157 doctorDetail = {doctorDetail} 190 doctorDetail = {doctorDetail}
158 modalUp = {modalUp} 191 modalUp = {modalUp}
...@@ -166,7 +199,8 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => { ...@@ -166,7 +199,8 @@ const ManagerMenuContainer = (props : ManagerMenuProps) => {
166 validateDoctorLicense = {validateDoctorLicense} 199 validateDoctorLicense = {validateDoctorLicense}
167 onSetValidateDoctorLicense = {onSetValidateDoctorLicense} 200 onSetValidateDoctorLicense = {onSetValidateDoctorLicense}
168 201
169 - onAcceptRequest = {onAcceptRequest} 202 + onAcceptRegReq = {onAcceptRegReq}
203 + onAcceptSecReq = {onAcceptSecReq}
170 onRejectRequest = {onRejectRequest} 204 onRejectRequest = {onRejectRequest}
171 /> 205 />
172 ); 206 );
......
...@@ -5,7 +5,11 @@ import * as styled from './ManagerMenuStyled'; ...@@ -5,7 +5,11 @@ import * as styled from './ManagerMenuStyled';
5 5
6 6
7 interface ManagerMenuProps { 7 interface ManagerMenuProps {
8 - doctorRegReqList : any[]; 8 + viewType : string;
9 + onViewRegList : () => void;
10 + onViewSecList : () => void;
11 +
12 + doctorList : any[];
9 13
10 doctorDetail : any; 14 doctorDetail : any;
11 modalUp : boolean; 15 modalUp : boolean;
...@@ -19,7 +23,8 @@ interface ManagerMenuProps { ...@@ -19,7 +23,8 @@ interface ManagerMenuProps {
19 validateDoctorLicense : string; 23 validateDoctorLicense : string;
20 onSetValidateDoctorLicense : React.ChangeEventHandler<HTMLInputElement>; 24 onSetValidateDoctorLicense : React.ChangeEventHandler<HTMLInputElement>;
21 25
22 - onAcceptRequest : () => void; 26 + onAcceptRegReq : () => void;
27 + onAcceptSecReq : (arg0 : string) => void;
23 onRejectRequest : () => void; 28 onRejectRequest : () => void;
24 29
25 } 30 }
...@@ -98,7 +103,7 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => { ...@@ -98,7 +103,7 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => {
98 </styled.ModalBodyWrapper> 103 </styled.ModalBodyWrapper>
99 <styled.ModalButtonWrapper> 104 <styled.ModalButtonWrapper>
100 <styled.ModalButton 105 <styled.ModalButton
101 - onClick = {props.onAcceptRequest} 106 + onClick = {props.onAcceptRegReq}
102 isAccept = {true} 107 isAccept = {true}
103 > 108 >
104 수락 109 수락
...@@ -114,37 +119,71 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => { ...@@ -114,37 +119,71 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => {
114 </Modal> : null 119 </Modal> : null
115 } 120 }
116 <styled.ContentWrapper> 121 <styled.ContentWrapper>
122 + <styled.ContentButtonWrapper>
123 + <styled.ContentButton
124 + isSelect = {props.viewType === 'reg'}
125 + onClick = {props.onViewRegList}
126 + >
127 + 가입 대기
128 + </styled.ContentButton>
129 + <styled.ContentButton
130 + isSelect = {props.viewType === 'sec'}
131 + onClick = {props.onViewSecList}
132 + >
133 + 탈퇴 요청
134 + </styled.ContentButton>
135 + </styled.ContentButtonWrapper>
117 <styled.ContentTitle> 136 <styled.ContentTitle>
118 - 가입 대기 중 의사 회원 137 + {
119 - <styled.ContentExplain> 138 + props.viewType === 'sec' ?
120 - *클릭하면 상세정보를 확인할 수 있습니다. 139 + <>
121 - </styled.ContentExplain> 140 + 탈퇴 대기 중 의사 회원
141 + <styled.ContentExplain>
142 + *승인을 누르면 탈퇴를 승인합니다.
143 + </styled.ContentExplain>
144 + </> :
145 + <>
146 + 가입 대기 중 의사 회원
147 + <styled.ContentExplain>
148 + *클릭하면 상세정보를 확인할 수 있습니다.
149 + </styled.ContentExplain>
150 + </>
151 + }
122 </styled.ContentTitle> 152 </styled.ContentTitle>
123 - <styled.ContentBody> 153 + <styled.ContentInfoWrapper>
124 - <styled.ContentInfoWrapper> 154 + <styled.ContentInfo
125 - <styled.ContentInfo 155 + isLast = {false}
126 - isLast = {false} 156 + >
127 - > 157 + 분야
128 - 분야 158 + </styled.ContentInfo>
129 - </styled.ContentInfo> 159 + <styled.ContentInfo
130 - <styled.ContentInfo 160 + isLast = {false}
131 - isLast = {false} 161 + >
132 - > 162 + 이름
133 - 이름 163 + </styled.ContentInfo>
134 - </styled.ContentInfo> 164 + <styled.ContentInfo
135 - <styled.ContentInfo 165 + isLast = {props.viewType !== 'sec'}
166 + >
167 + 이메일
168 + </styled.ContentInfo>
169 + {
170 + props.viewType === 'sec' ?
171 + <styled.ContentInfo
136 isLast = {true} 172 isLast = {true}
137 > 173 >
138 - 이메일 174 + 탈퇴 수락
139 - </styled.ContentInfo> 175 + </styled.ContentInfo> : null
140 - </styled.ContentInfoWrapper> 176 + }
177 + </styled.ContentInfoWrapper>
178 + <styled.ContentBody>
141 { 179 {
142 - props.doctorRegReqList.length ? 180 + props.doctorList.length ?
143 - props.doctorRegReqList.map((doctor : any) => { 181 + props.doctorList.map((doctor : any) => {
144 return ( 182 return (
145 <styled.EachContentWrapper 183 <styled.EachContentWrapper
146 key = {doctor.doctorId} 184 key = {doctor.doctorId}
147 onClick = {() => props.onViewDetailReq(doctor.doctorId)} 185 onClick = {() => props.onViewDetailReq(doctor.doctorId)}
186 + disabled = {props.viewType === 'sec'}
148 > 187 >
149 <styled.EachContentNm 188 <styled.EachContentNm
150 isLast = {false} 189 isLast = {false}
...@@ -157,10 +196,22 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => { ...@@ -157,10 +196,22 @@ const ManagerMenuPresenter = (props : ManagerMenuProps) => {
157 {doctor.info.doctorNm} 196 {doctor.info.doctorNm}
158 </styled.EachContentNm> 197 </styled.EachContentNm>
159 <styled.EachContentNm 198 <styled.EachContentNm
160 - isLast = {true} 199 + isLast = {props.viewType !== 'sec'}
161 > 200 >
162 {doctor.doctorId} 201 {doctor.doctorId}
163 </styled.EachContentNm> 202 </styled.EachContentNm>
203 + {
204 + props.viewType === 'sec' ?
205 + <styled.EachContentNm
206 + isLast = {true}
207 + >
208 + <styled.AcceptButton
209 + onClick = {() => props.onAcceptSecReq(doctor.doctorId)}
210 + >
211 + 승인
212 + </styled.AcceptButton>
213 + </styled.EachContentNm> : null
214 + }
164 </styled.EachContentWrapper> 215 </styled.EachContentWrapper>
165 ) 216 )
166 }) : 217 }) :
......
...@@ -251,8 +251,45 @@ export const ContentWrapper = styled.div ` ...@@ -251,8 +251,45 @@ export const ContentWrapper = styled.div `
251 251
252 `; 252 `;
253 253
254 +export const ContentButtonWrapper = styled.div `
255 + width : 100%;
256 + height : 10%;
257 + border : none;
258 +
259 + display : flex;
260 + flex-direction : row;
261 + justify-content : center;
262 + align-items : flex-end;
263 +
264 + gap : 10%;
265 +
266 + background-color : transparent;
267 +`;
268 +
269 +export const ContentButton = styled.button<{isSelect : boolean}> `
270 + background-color : ${props => props.isSelect ? '#337DFF' : 'transparent'};
271 + color : ${props => props.isSelect ? '#fff' : '#337DFF'};
272 + border : 1px solid #337DFF;
273 + border-radius : 4px;
274 +
275 + padding : 4px 10px;
276 +
277 + cursor : pointer;
278 +
279 + display : flex;
280 + justify-content : center;
281 + align-items : center;
282 +
283 + transition : .25s all;
284 +
285 + &:hover {
286 + opacity : .5;
287 + }
288 +`;
289 +
254 export const ContentTitle = styled.div ` 290 export const ContentTitle = styled.div `
255 width : 100%; 291 width : 100%;
292 + height : 20%;
256 border : none; 293 border : none;
257 border-bottom : 1px solid #ddd; 294 border-bottom : 1px solid #ddd;
258 295
...@@ -261,7 +298,6 @@ export const ContentTitle = styled.div ` ...@@ -261,7 +298,6 @@ export const ContentTitle = styled.div `
261 justify-content : center; 298 justify-content : center;
262 align-items : center; 299 align-items : center;
263 300
264 - padding : 4% 0;
265 font-size : 22px; 301 font-size : 22px;
266 font-weight : 600; 302 font-weight : 600;
267 letter-spacing : 1px; 303 letter-spacing : 1px;
...@@ -281,16 +317,17 @@ export const ContentExplain = styled.div ` ...@@ -281,16 +317,17 @@ export const ContentExplain = styled.div `
281 export const ContentBody = styled.div ` 317 export const ContentBody = styled.div `
282 overflow : scroll; 318 overflow : scroll;
283 319
284 - height : 79%; 320 + min-height : 60%;
321 + max-height : 60%;
285 322
286 border : none; 323 border : none;
287 324
288 - padding : 0 0 0 3px;
289 -
290 display : flex; 325 display : flex;
291 flex-direction : column; 326 flex-direction : column;
292 align-items : center; 327 align-items : center;
293 328
329 + padding : 0 0 0 3px;
330 +
294 &::-webkit-scrollbar { 331 &::-webkit-scrollbar {
295 width : 3px; 332 width : 3px;
296 background-color : transparent; 333 background-color : transparent;
...@@ -304,6 +341,7 @@ export const ContentBody = styled.div ` ...@@ -304,6 +341,7 @@ export const ContentBody = styled.div `
304 341
305 export const ContentInfoWrapper = styled.div ` 342 export const ContentInfoWrapper = styled.div `
306 width : 100%; 343 width : 100%;
344 + height : 10%;
307 border : none; 345 border : none;
308 border-bottom : 1px solid #a0a0a0; 346 border-bottom : 1px solid #a0a0a0;
309 347
...@@ -313,7 +351,6 @@ export const ContentInfoWrapper = styled.div ` ...@@ -313,7 +351,6 @@ export const ContentInfoWrapper = styled.div `
313 justify-content : center; 351 justify-content : center;
314 align-items : center; 352 align-items : center;
315 353
316 - padding : 12px 0px;
317 `; 354 `;
318 355
319 export const ContentInfo = styled.div<{isLast : boolean}> ` 356 export const ContentInfo = styled.div<{isLast : boolean}> `
...@@ -351,13 +388,15 @@ export const EachContentWrapper = styled.button ` ...@@ -351,13 +388,15 @@ export const EachContentWrapper = styled.button `
351 388
352 padding : 10px 0px; 389 padding : 10px 0px;
353 390
354 - cursor : pointer; 391 + :not(:disabled) {
392 + cursor : pointer;
355 393
356 - transition : .1s all; 394 + transition : .1s all;
357 395
358 - &:hover { 396 + &:hover {
359 - background-color : #337DFF; 397 + background-color : #337DFF;
360 - color : #fff; 398 + color : #fff;
399 + }
361 } 400 }
362 401
363 `; 402 `;
...@@ -380,10 +419,33 @@ export const EachContentNm = styled.div<{isLast : boolean}> ` ...@@ -380,10 +419,33 @@ export const EachContentNm = styled.div<{isLast : boolean}> `
380 419
381 `; 420 `;
382 421
422 +export const AcceptButton = styled.button `
423 + background-color : transparent;
424 + color : #337DFF;
425 + border : 1px solid #337DFF;
426 + border-radius : 3px;
427 + padding : 2px 10px;
428 +
429 + display : flex;
430 + justify-content : center;
431 + align-items : center;
432 +
433 + cursor : pointer;
434 +
435 + transition : .25s all;
436 +
437 + &:hover {
438 + background-color : #337DFF;
439 + color : #fff;
440 + }
441 +`;
442 +
383 export const NothingWrapper = styled.div ` 443 export const NothingWrapper = styled.div `
384 height : 100%; 444 height : 100%;
385 width : 100%; 445 width : 100%;
386 446
447 + border : none;
448 +
387 display : flex; 449 display : flex;
388 justify-content : center; 450 justify-content : center;
389 align-items : center; 451 align-items : center;
......