feat. bottle view -> medicine Modal, User Feedback, User Register and Header button, etc...
Showing
31 changed files
with
1527 additions
and
100 deletions
... | @@ -13,6 +13,7 @@ | ... | @@ -13,6 +13,7 @@ |
13 | "axios": "^0.21.1", | 13 | "axios": "^0.21.1", |
14 | "highcharts": "^9.2.0", | 14 | "highcharts": "^9.2.0", |
15 | "highcharts-react-official": "^3.0.0", | 15 | "highcharts-react-official": "^3.0.0", |
16 | + "moment": "^2.29.1", | ||
16 | "react": "^17.0.2", | 17 | "react": "^17.0.2", |
17 | "react-dom": "^17.0.2", | 18 | "react-dom": "^17.0.2", |
18 | "react-router-dom": "^5.2.0", | 19 | "react-router-dom": "^5.2.0", |
... | @@ -20,6 +21,7 @@ | ... | @@ -20,6 +21,7 @@ |
20 | "recoil": "^0.4.0", | 21 | "recoil": "^0.4.0", |
21 | "recoil-persist": "^3.0.0", | 22 | "recoil-persist": "^3.0.0", |
22 | "styled-components": "^5.3.0", | 23 | "styled-components": "^5.3.0", |
24 | + "sweetalert2": "^11.1.3", | ||
23 | "typescript": "^4.1.2", | 25 | "typescript": "^4.1.2", |
24 | "web-vitals": "^1.0.1" | 26 | "web-vitals": "^1.0.1" |
25 | }, | 27 | }, | ... | ... |
web/public/static/img/backButton.png
0 → 100644
11.6 KB
web/public/static/img/backButtonBlue.png
0 → 100644
5.63 KB
web/public/static/img/backButtonWhite.png
0 → 100644
2.66 KB
web/public/static/img/edit.png
0 → 100644
9.84 KB
web/public/static/img/logout.png
0 → 100644
6.03 KB
web/public/static/img/plus.png
0 → 100644
490 Bytes
web/public/static/img/refreshing.png
0 → 100644
7.05 KB
... | @@ -16,4 +16,11 @@ export default { | ... | @@ -16,4 +16,11 @@ export default { |
16 | logout : () => { | 16 | logout : () => { |
17 | return client.post('/auth/logout'); | 17 | return client.post('/auth/logout'); |
18 | }, | 18 | }, |
19 | + verifyToken : (token : any) => { | ||
20 | + return client.get('/auth/verifytoken', { | ||
21 | + headers : { | ||
22 | + Authorization : token, | ||
23 | + }, | ||
24 | + }); | ||
25 | + }, | ||
19 | }; | 26 | }; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -7,18 +7,4 @@ export const client : AxiosInstance = axios.create({ | ... | @@ -7,18 +7,4 @@ export const client : AxiosInstance = axios.create({ |
7 | 'Content-Type': 'application/json', | 7 | 'Content-Type': 'application/json', |
8 | 'Access-Control-Allow-Origin': '*', | 8 | 'Access-Control-Allow-Origin': '*', |
9 | }, | 9 | }, |
10 | -}); | 10 | +}); |
11 | - | ||
12 | -client.interceptors.request.use( | ||
13 | - | ||
14 | -); | ||
15 | - | ||
16 | -client.interceptors.response.use( | ||
17 | - function (response) { | ||
18 | - return response; | ||
19 | - }, | ||
20 | - function (error) { | ||
21 | - console.log(error.message); | ||
22 | - return error; | ||
23 | - } | ||
24 | -); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -14,7 +14,33 @@ export const Container = styled.div ` | ... | @@ -14,7 +14,33 @@ export const Container = styled.div ` |
14 | align-items : center; | 14 | align-items : center; |
15 | `; | 15 | `; |
16 | 16 | ||
17 | -export const HeaderWrapper = styled.div ` | 17 | +export const HeaderLeftWrapper = styled.div ` |
18 | + flex : 1; | ||
19 | + display : flex; | ||
20 | + flex-direction : row; | ||
21 | + justify-content : flex-start; | ||
22 | + align-items : center; | ||
23 | + | ||
24 | + border : none; | ||
25 | + | ||
26 | + margin : 0 30px; | ||
27 | +`; | ||
28 | + | ||
29 | +export const HeaderRightWrapper = styled.div ` | ||
30 | + flex : 1; | ||
31 | + display : flex; | ||
32 | + flex-direction : row; | ||
33 | + justify-content : flex-end; | ||
34 | + align-items : center; | ||
35 | + | ||
36 | + border : none; | ||
37 | + | ||
38 | + margin : 0 30px; | ||
39 | + | ||
40 | +`; | ||
41 | + | ||
42 | +export const HeaderCenterWrapper = styled.div ` | ||
43 | + flex : 3; | ||
18 | display : flex; | 44 | display : flex; |
19 | flex-direction : row; | 45 | flex-direction : row; |
20 | justify-content : center; | 46 | justify-content : center; |
... | @@ -31,8 +57,69 @@ export const TitleImg = styled.img ` | ... | @@ -31,8 +57,69 @@ export const TitleImg = styled.img ` |
31 | `; | 57 | `; |
32 | 58 | ||
33 | export const Title = styled.div ` | 59 | export const Title = styled.div ` |
34 | - flex : 1; | ||
35 | text-align : center; | 60 | text-align : center; |
36 | font-size : 17px; | 61 | font-size : 17px; |
37 | font-weight : 800; | 62 | font-weight : 800; |
63 | +`; | ||
64 | + | ||
65 | +export const Backbutton = styled.button ` | ||
66 | + border : 1px solid #337DFF; | ||
67 | + border-radius : 5px; | ||
68 | + background-color : transparent; | ||
69 | + color : #337DFF; | ||
70 | + padding : 4px 17px; | ||
71 | + | ||
72 | + transition : .25s all; | ||
73 | + | ||
74 | + display : flex; | ||
75 | + flex-direction : row; | ||
76 | + justify-content : center; | ||
77 | + | ||
78 | + cursor : pointer; | ||
79 | + | ||
80 | + &:hover { | ||
81 | + opacity : .5; | ||
82 | + } | ||
83 | +`; | ||
84 | + | ||
85 | +export const BackbuttonImg = styled.img ` | ||
86 | + height : 14px; | ||
87 | + width : 14px; | ||
88 | + margin : 0 6px 0 0; | ||
89 | +`; | ||
90 | + | ||
91 | +export const BackbuttonText = styled.div ` | ||
92 | + font-size : 15px; | ||
93 | + font-weight : 700; | ||
94 | + letter-spacing : 1px; | ||
95 | +`; | ||
96 | + | ||
97 | +export const LogoutButton = styled.button ` | ||
98 | + display : flex; | ||
99 | + justify-content : center; | ||
100 | + // align-items : center; | ||
101 | + | ||
102 | + background-color : transparent; | ||
103 | + border : none; | ||
104 | + border-bottom : 1px solid #a0a0a0; | ||
105 | + padding : 0 4px 4px 4px; | ||
106 | + | ||
107 | + cursor : pointer; | ||
108 | + transition : .25s all; | ||
109 | + | ||
110 | + &:hover { | ||
111 | + opacity : .5; | ||
112 | + } | ||
113 | +`; | ||
114 | + | ||
115 | +export const LogoutButtonImg = styled.img ` | ||
116 | + height : 15px; | ||
117 | + width : 15px; | ||
118 | + margin : 0 4px 0 0; | ||
119 | +`; | ||
120 | + | ||
121 | +export const LogoutButtonText = styled.div ` | ||
122 | + color : #a0a0a0; | ||
123 | + font-size : 13px; | ||
124 | + letter-spacing : 1px; | ||
38 | `; | 125 | `; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | -import React from 'react'; | 1 | +import React, { useEffect } from 'react'; |
2 | +import { RouteComponentProps } from 'react-router'; | ||
2 | 3 | ||
4 | +import { useRecoilState } from 'recoil'; | ||
5 | +import * as recoilUtil from '../../util/recoilUtil'; | ||
6 | + | ||
7 | +import * as Alert from '../../util/alertMessage'; | ||
3 | import * as styled from './HeaderStyled'; | 8 | import * as styled from './HeaderStyled'; |
4 | 9 | ||
10 | +import { authApi } from '../../api'; | ||
11 | + | ||
5 | const headerImg = '/static/img/pharmacy.png'; | 12 | const headerImg = '/static/img/pharmacy.png'; |
13 | +const backButtonWhite = '/static/img/backButtonWhite.png'; | ||
14 | +const backButtonBlue = '/static/img/backButtonBlue.png'; | ||
15 | +const logout = '/static/img/logout.png'; | ||
16 | + | ||
17 | + | ||
18 | +// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
19 | +interface HeaderProps extends RouteComponentProps {} | ||
20 | + | ||
21 | +const Header = (props : HeaderProps) => { | ||
22 | + | ||
23 | + const [token, setToken] = useRecoilState(recoilUtil.token); | ||
24 | + | ||
25 | + | ||
26 | + const onLogout = () => { | ||
27 | + const logout = async () => { | ||
28 | + try { | ||
29 | + await authApi.logout(); | ||
30 | + setToken(null); | ||
31 | + Alert.onSuccess('로그인 페이지로 이동합니다.', () => props.history.push('/login')); | ||
32 | + } catch(e) { | ||
33 | + Alert.onError('알 수 없는 에러가 발생했습니다.', () => props.history.push('/')); | ||
34 | + } | ||
35 | + }; | ||
36 | + | ||
37 | + Alert.onCheck('정말 로그아웃 하시겠습니까?', logout, () => null); | ||
38 | + }; | ||
39 | + | ||
40 | + const verifyToken = async () => { | ||
41 | + try { | ||
42 | + const result = await authApi.verifyToken(token); | ||
43 | + if(result.statusText !== 'OK') { | ||
44 | + setToken(null); | ||
45 | + Alert.onError('세션이 만료되었습니다. 다시 로그인하세요.', () => props.history.push('/login')); | ||
46 | + } | ||
47 | + } catch(e) { | ||
48 | + console.log(e); | ||
49 | + setToken(null); | ||
50 | + Alert.onError('세션이 만료되었습니다. 다시 로그인하세요.', () => props.history.push('/login')); | ||
51 | + } | ||
52 | + }; | ||
53 | + | ||
54 | + const onGoBack = () => { | ||
55 | + props.history.goBack(); | ||
56 | + }; | ||
6 | 57 | ||
58 | + useEffect(() => { | ||
59 | + verifyToken(); | ||
60 | + }, []); | ||
7 | 61 | ||
8 | -const Header = () => { | ||
9 | return ( | 62 | return ( |
10 | <styled.Container> | 63 | <styled.Container> |
11 | - <styled.HeaderWrapper> | 64 | + <styled.HeaderLeftWrapper> |
65 | + { | ||
66 | + (token && token.length && props.location.pathname !== '/') || props.location.pathname === '/register' ? | ||
67 | + <styled.Backbutton | ||
68 | + onClick = {onGoBack} | ||
69 | + > | ||
70 | + <styled.BackbuttonImg src = {backButtonBlue}/> | ||
71 | + <styled.BackbuttonText>뒤로 가기</styled.BackbuttonText> | ||
72 | + </styled.Backbutton> : null | ||
73 | + } | ||
74 | + </styled.HeaderLeftWrapper> | ||
75 | + <styled.HeaderCenterWrapper> | ||
12 | <styled.TitleImg src = {headerImg} /> | 76 | <styled.TitleImg src = {headerImg} /> |
13 | <styled.Title>내 손 안의 주치의</styled.Title> | 77 | <styled.Title>내 손 안의 주치의</styled.Title> |
14 | - </styled.HeaderWrapper> | 78 | + </styled.HeaderCenterWrapper> |
79 | + <styled.HeaderRightWrapper> | ||
80 | + { | ||
81 | + token && token.length ? | ||
82 | + <styled.LogoutButton | ||
83 | + onClick = {onLogout} | ||
84 | + > | ||
85 | + <styled.LogoutButtonImg src = {logout}/> | ||
86 | + <styled.LogoutButtonText>로그아웃</styled.LogoutButtonText> | ||
87 | + </styled.LogoutButton> : null | ||
88 | + } | ||
89 | + </styled.HeaderRightWrapper> | ||
15 | </styled.Container> | 90 | </styled.Container> |
16 | ) | 91 | ) |
17 | }; | 92 | }; | ... | ... |
1 | import React, { useEffect } from 'react'; | 1 | import React, { useEffect } from 'react'; |
2 | -import * as recoilUtil from '../../util/recoilUtil'; | ||
3 | -import { useRecoilState } from 'recoil'; | ||
4 | 2 | ||
5 | import * as styled from './ErrorStyled'; | 3 | import * as styled from './ErrorStyled'; |
6 | 4 | ||
7 | 5 | ||
8 | const ErrorContainer = () => { | 6 | const ErrorContainer = () => { |
9 | - | ||
10 | - const [error, setError] = useRecoilState(recoilUtil.error); | ||
11 | - | ||
12 | - useEffect(() => { | ||
13 | - console.log(error); | ||
14 | - }, [error]); | ||
15 | - | ||
16 | return ( | 7 | return ( |
17 | - <> | 8 | + <styled.Container> |
18 | - { | 9 | + </styled.Container> |
19 | - error ? | ||
20 | - <styled.Container> | ||
21 | - {error} | ||
22 | - </styled.Container> : null | ||
23 | - } | ||
24 | - </> | ||
25 | ); | 10 | ); |
26 | }; | 11 | }; |
27 | 12 | ||
28 | -export default ErrorContainer; | 13 | +export default ErrorContainer; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
web/src/util/alertMessage.ts
0 → 100644
1 | +import Swal from "sweetalert2"; | ||
2 | + | ||
3 | +export const onError = (text : string, confirmAction : () => void) => { | ||
4 | + Swal.fire({ | ||
5 | + title : '오류 발생', | ||
6 | + icon : 'error', | ||
7 | + text, | ||
8 | + confirmButtonText : '확인', | ||
9 | + confirmButtonColor : '#337DFF' | ||
10 | + }).then((res) => { | ||
11 | + if(res.isConfirmed) { | ||
12 | + confirmAction(); | ||
13 | + } | ||
14 | + }); | ||
15 | +}; | ||
16 | + | ||
17 | +export const onSuccess = (text : string, successAction : () => void) => { | ||
18 | + Swal.fire({ | ||
19 | + title : '성공', | ||
20 | + icon : 'success', | ||
21 | + text, | ||
22 | + showConfirmButton : false, | ||
23 | + timer : 1500, | ||
24 | + }).then(res => { | ||
25 | + successAction(); | ||
26 | + }); | ||
27 | +}; | ||
28 | + | ||
29 | +export const onCheck = (text : string, confirmAction : () => void, denyAction : () => void) => { | ||
30 | + Swal.fire({ | ||
31 | + title : '확인', | ||
32 | + icon : 'question', | ||
33 | + text, | ||
34 | + confirmButtonText : '확인', | ||
35 | + confirmButtonColor : '#337DFF', | ||
36 | + showDenyButton : true, | ||
37 | + denyButtonText : '취소', | ||
38 | + denyButtonColor : '#343434', | ||
39 | + }).then(res => { | ||
40 | + if(res.isConfirmed) { | ||
41 | + confirmAction(); | ||
42 | + } else if(res.isDenied) { | ||
43 | + denyAction(); | ||
44 | + } | ||
45 | + }); | ||
46 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
web/src/util/makeChart.ts
0 → 100644
1 | +import moment from 'moment'; | ||
2 | + | ||
3 | +export const make = (chartData : any[], numberOfRow : number) => { | ||
4 | + const now = new Date(); | ||
5 | + const result : any = {}; | ||
6 | + new Array(numberOfRow).fill(null).forEach((item : any, index : number) => { | ||
7 | + const key = moment(now).format('MM/DD'); | ||
8 | + result[key] = 0; | ||
9 | + now.setDate(now.getDate() - 1); | ||
10 | + }) | ||
11 | + | ||
12 | + chartData.forEach((data : any) => { | ||
13 | + const key : string = moment(data.takeDate).format('MM/DD'); | ||
14 | + result[key] = result[key] + 1; | ||
15 | + }); | ||
16 | + | ||
17 | + const categories : any = []; | ||
18 | + const data : any = []; | ||
19 | + | ||
20 | + Object.entries(result).forEach((item : any) => { | ||
21 | + categories.push(item[0]); | ||
22 | + data.push(item[1]); | ||
23 | + }); | ||
24 | + | ||
25 | + categories.reverse(); | ||
26 | + data.reverse(); | ||
27 | + | ||
28 | + return { | ||
29 | + categories, | ||
30 | + data, | ||
31 | + } | ||
32 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -13,10 +13,4 @@ export const userTypeCd = atom({ | ... | @@ -13,10 +13,4 @@ export const userTypeCd = atom({ |
13 | key : 'userTypeCd', | 13 | key : 'userTypeCd', |
14 | default : 'NORMAL', | 14 | default : 'NORMAL', |
15 | effects_UNSTABLE : [persistAtom], | 15 | effects_UNSTABLE : [persistAtom], |
16 | -}); | ||
17 | - | ||
18 | -export const error = atom({ | ||
19 | - key : 'error', | ||
20 | - default : null, | ||
21 | - effects_UNSTABLE : [persistAtom], | ||
22 | -}) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
16 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | import React from "react"; | 1 | import React from "react"; |
2 | -import { BrowserRouter, Route, Switch } from 'react-router-dom'; | 2 | +import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'; |
3 | 3 | ||
4 | import Error from '../components/error'; | 4 | import Error from '../components/error'; |
5 | -import Header from '../components/Header'; | ||
6 | import { LoginContainer } from "./login"; | 5 | import { LoginContainer } from "./login"; |
7 | import { RegisterContainer } from './register'; | 6 | import { RegisterContainer } from './register'; |
8 | import { MainContainer } from "./main"; | 7 | import { MainContainer } from "./main"; |
... | @@ -13,12 +12,12 @@ const Router = () => { | ... | @@ -13,12 +12,12 @@ const Router = () => { |
13 | return ( | 12 | return ( |
14 | <BrowserRouter> | 13 | <BrowserRouter> |
15 | <Error /> | 14 | <Error /> |
16 | - <Header /> | ||
17 | <Switch> | 15 | <Switch> |
18 | <Route exact path = '/' component = {MainContainer}/> | 16 | <Route exact path = '/' component = {MainContainer}/> |
19 | <Route exact path = '/login' component = {LoginContainer}/> | 17 | <Route exact path = '/login' component = {LoginContainer}/> |
20 | <Route exact path = '/register' component = {RegisterContainer}/> | 18 | <Route exact path = '/register' component = {RegisterContainer}/> |
21 | - <Route exact path = '/bottle' component = {BottleInfoContainer}/> | 19 | + <Route exact path = '/bottle/:bottleId' component = {BottleInfoContainer}/> |
20 | + <Redirect path = '*' to = '/'/> | ||
22 | </Switch> | 21 | </Switch> |
23 | </BrowserRouter> | 22 | </BrowserRouter> |
24 | ) | 23 | ) | ... | ... |
1 | import React, { useState, useEffect } from 'react'; | 1 | import React, { useState, useEffect } from 'react'; |
2 | import { RouteComponentProps } from 'react-router-dom'; | 2 | import { RouteComponentProps } from 'react-router-dom'; |
3 | import { useRecoilValue } from 'recoil'; | 3 | import { useRecoilValue } from 'recoil'; |
4 | + | ||
4 | import * as recoilUtil from '../../util/recoilUtil'; | 5 | import * as recoilUtil from '../../util/recoilUtil'; |
6 | +import * as makeChart from '../../util/makeChart'; | ||
7 | +import * as Alert from '../../util/alertMessage'; | ||
5 | 8 | ||
6 | -import HighCharts from 'highcharts'; | 9 | +import moment from 'moment'; |
7 | -import HighchartsReact from 'highcharts-react-official'; | ||
8 | 10 | ||
11 | +import Header from '../../components/Header'; | ||
9 | import BottleInfoPresenter from './BottleInfoPresenter'; | 12 | import BottleInfoPresenter from './BottleInfoPresenter'; |
10 | 13 | ||
11 | import { doctorApi } from '../../api'; | 14 | import { doctorApi } from '../../api'; |
12 | 15 | ||
13 | 16 | ||
14 | -type BottleInfoProps = RouteComponentProps | 17 | + |
18 | +interface RouteParmas { | ||
19 | + bottleId : string; | ||
20 | +} | ||
21 | + | ||
22 | +type BottleInfoProps = RouteComponentProps<RouteParmas> | ||
15 | 23 | ||
16 | const BottleInfoContainer = (props : BottleInfoProps) => { | 24 | const BottleInfoContainer = (props : BottleInfoProps) => { |
17 | 25 | ||
26 | + const { bottleId } = props.match.params; | ||
27 | + | ||
18 | const token = useRecoilValue(recoilUtil.token); | 28 | const token = useRecoilValue(recoilUtil.token); |
19 | const userTypeCd = useRecoilValue(recoilUtil.userTypeCd); | 29 | const userTypeCd = useRecoilValue(recoilUtil.userTypeCd); |
30 | + | ||
31 | + const [bottleInfo, setBottleInfo] = useState<any>({ | ||
32 | + feedbackList : [], | ||
33 | + medicine : {}, | ||
34 | + bottleId : 0, | ||
35 | + takeMedicineHist : [], | ||
36 | + }); | ||
37 | + | ||
38 | + const numberOfChartItem = 7; | ||
39 | + const [chartOption, setChartOption] = useState<any>({ | ||
40 | + chart : { | ||
41 | + type : 'line', | ||
42 | + height : 300, | ||
43 | + width : 450, | ||
44 | + }, | ||
45 | + title : { | ||
46 | + text : '', | ||
47 | + style : { 'color' : '#343434', 'fontSize' : '15px', 'fontWeight' : '700' }, | ||
48 | + margin : 10, | ||
49 | + }, | ||
50 | + xAxis : { | ||
51 | + categories : [], | ||
52 | + }, | ||
53 | + series : [{ | ||
54 | + name : '약 복용 횟수', | ||
55 | + color : '#337DFF', | ||
56 | + data : [], | ||
57 | + }], | ||
58 | + }); | ||
59 | + | ||
60 | + const [feedback, setFeedback] = useState<string>(''); | ||
61 | + const [fdbType, setFdbType] = useState<string>('RECOMMEND'); | ||
62 | + | ||
63 | + const [medicineInfoModal, setMedicineInfoModal] = useState<boolean>(false); | ||
64 | + | ||
20 | 65 | ||
66 | + const fetchData = async () => { | ||
67 | + setFeedback(''); | ||
68 | + setFdbType('RECOMMEND'); | ||
69 | + setMedicineInfoModal(false); | ||
21 | 70 | ||
71 | + try { | ||
72 | + const result = await doctorApi.getPatientBottleDetail(token, bottleId); | ||
73 | + if (result.statusText === 'OK') { | ||
74 | + const { categories, data } = makeChart.make(result.data.takeMedicineHist, numberOfChartItem); | ||
75 | + setBottleInfo({ | ||
76 | + ...result.data, | ||
77 | + feedbackList : result.data.feedbackList.map((feedback : any) => { | ||
78 | + return { | ||
79 | + ...feedback, | ||
80 | + fdbDtm : moment(feedback.fdbDtm).format('YYYY-MM-DD hh:mm'), | ||
81 | + } | ||
82 | + }), | ||
83 | + }); | ||
84 | + setChartOption({ | ||
85 | + ...chartOption, | ||
86 | + title : { | ||
87 | + text : result.data.medicine.name, | ||
88 | + }, | ||
89 | + xAxis : { | ||
90 | + categories, | ||
91 | + }, | ||
92 | + series : [{ | ||
93 | + data, | ||
94 | + }] | ||
95 | + }); | ||
96 | + } else { | ||
97 | + Alert.onError('접근 권한이 없습니다.', () => props.history.push('/')); | ||
98 | + } | ||
99 | + } catch(e) { | ||
100 | + Alert.onError(e.response.data.error, () => props.history.push('/')); | ||
101 | + | ||
102 | + console.log(e); | ||
103 | + } | ||
104 | + }; | ||
105 | + | ||
106 | + const onSetFeedback = (e : React.ChangeEvent<HTMLTextAreaElement>) => { | ||
107 | + setFeedback(e.target.value); | ||
108 | + }; | ||
109 | + | ||
110 | + const onSubmitFeedback = () => { | ||
111 | + const register = async () => { | ||
112 | + if(feedback.length) { | ||
113 | + try { | ||
114 | + const res = await doctorApi.writeBottleFeedback(token, { | ||
115 | + bottleId, | ||
116 | + fdbType, | ||
117 | + feedback | ||
118 | + }); | ||
119 | + if(res.statusText === 'OK') { | ||
120 | + Alert.onSuccess('피드백이 등록되었습니다.', () => fetchData()); | ||
121 | + } else { | ||
122 | + console.log(res); | ||
123 | + Alert.onError('피드백 등록에 실패했습니다.', () => null); | ||
124 | + } | ||
125 | + } catch(e) { | ||
126 | + Alert.onError(e.response.data.error, () => fetchData()); | ||
127 | + } | ||
128 | + } else { | ||
129 | + Alert.onError('피드백 내용을 입력하세요.', () => null); | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + Alert.onCheck('피드백을 등록하시겠습니까?', register, () => null); | ||
134 | + | ||
135 | + }; | ||
136 | + | ||
137 | + | ||
22 | useEffect(() => { | 138 | useEffect(() => { |
23 | if(userTypeCd !== 'DOCTOR') { | 139 | if(userTypeCd !== 'DOCTOR') { |
24 | - props.history.push('/'); | 140 | + Alert.onError('접근 권한이 없습니다.', () => props.history.push('/')); |
25 | } | 141 | } |
142 | + fetchData(); | ||
26 | }, [userTypeCd]); | 143 | }, [userTypeCd]); |
27 | 144 | ||
28 | return ( | 145 | return ( |
146 | + <> | ||
147 | + <Header {...props} /> | ||
29 | <BottleInfoPresenter | 148 | <BottleInfoPresenter |
149 | + bottleInfo = {bottleInfo} | ||
150 | + chartOption = {chartOption} | ||
151 | + | ||
152 | + medicineInfoModal = {medicineInfoModal} | ||
153 | + setMedicineInfoModal = {setMedicineInfoModal} | ||
30 | 154 | ||
155 | + feedback = {feedback} | ||
156 | + onSetFeedback = {onSetFeedback} | ||
157 | + fdbType = {fdbType} | ||
158 | + setFdbType = {setFdbType} | ||
159 | + onSubmitFeedback = {onSubmitFeedback} | ||
31 | /> | 160 | /> |
161 | + </> | ||
32 | ); | 162 | ); |
33 | }; | 163 | }; |
34 | 164 | ... | ... |
1 | import React from 'react'; | 1 | import React from 'react'; |
2 | +import HighCharts from 'highcharts'; | ||
3 | +import HighchartsReact from 'highcharts-react-official'; | ||
2 | 4 | ||
3 | import * as styled from './BottleInfoStyled'; | 5 | import * as styled from './BottleInfoStyled'; |
4 | 6 | ||
7 | +const plus = '/static/img/plus.png'; | ||
8 | +const closeButton = '/static/img/close.png'; | ||
5 | 9 | ||
6 | -const BottleInfoPresenter = () => { | 10 | + |
11 | +interface BottleInfoProps { | ||
12 | + bottleInfo : { | ||
13 | + feedbackList : any[]; | ||
14 | + medicine : any; | ||
15 | + bottleId : number; | ||
16 | + takeMedicineHist : any[]; | ||
17 | + }; | ||
18 | + chartOption : any; | ||
19 | + | ||
20 | + medicineInfoModal : boolean; | ||
21 | + setMedicineInfoModal : (arg0 : boolean) => void; | ||
22 | + | ||
23 | + feedback : string; | ||
24 | + onSetFeedback : React.ChangeEventHandler<HTMLTextAreaElement>; | ||
25 | + fdbType : string; | ||
26 | + setFdbType : (arg0 : string) => void; | ||
27 | + onSubmitFeedback : () => void; | ||
28 | +} | ||
29 | + | ||
30 | +const BottleInfoPresenter = (props : BottleInfoProps) => { | ||
7 | return ( | 31 | return ( |
8 | <styled.Container> | 32 | <styled.Container> |
9 | - | 33 | + { |
34 | + props.medicineInfoModal ? | ||
35 | + <styled.ModalContainer> | ||
36 | + <styled.ModalClsButtonWrapper> | ||
37 | + <styled.ModalClsButton | ||
38 | + onClick = {() => props.setMedicineInfoModal(false)} | ||
39 | + > | ||
40 | + <styled.ModalClsButtonImg src = {closeButton}/> | ||
41 | + <styled.ModalClsButtonText>닫기</styled.ModalClsButtonText> | ||
42 | + </styled.ModalClsButton> | ||
43 | + </styled.ModalClsButtonWrapper> | ||
44 | + <styled.ModalContentWrapper> | ||
45 | + <styled.ModalContent> | ||
46 | + <styled.MedicineNameWrapper> | ||
47 | + <styled.MedicineName>{props.bottleInfo.medicine.name}</styled.MedicineName> | ||
48 | + <styled.MedicineName style = {{color : '#343434', fontSize : 15, marginTop : 4,}}>{props.bottleInfo.medicine.company}</styled.MedicineName> | ||
49 | + </styled.MedicineNameWrapper> | ||
50 | + <styled.MedicineInfoWrapper> | ||
51 | + <styled.MedicineEachInfoWrapper> | ||
52 | + <styled.MedicineEachInfoTitle>효능</styled.MedicineEachInfoTitle> | ||
53 | + <styled.MedicineEachInfo>{props.bottleInfo.medicine.target}</styled.MedicineEachInfo> | ||
54 | + </styled.MedicineEachInfoWrapper> | ||
55 | + <styled.MedicineEachInfoWrapper> | ||
56 | + <styled.MedicineEachInfoTitle>복용 정보</styled.MedicineEachInfoTitle> | ||
57 | + <styled.MedicineEachInfo>{props.bottleInfo.medicine.dosage}</styled.MedicineEachInfo> | ||
58 | + </styled.MedicineEachInfoWrapper> | ||
59 | + <styled.MedicineEachInfoWrapper> | ||
60 | + <styled.MedicineEachInfoTitle style = {{color : '#FF3F3F', fontWeight : 'bold'}}>주의 사항</styled.MedicineEachInfoTitle> | ||
61 | + <styled.MedicineEachInfo style = {{color : '#9B0000'}}>{props.bottleInfo.medicine.warn}</styled.MedicineEachInfo> | ||
62 | + </styled.MedicineEachInfoWrapper> | ||
63 | + <styled.MedicineEachInfoWrapper> | ||
64 | + <styled.MedicineEachInfoTitle style = {{color : '#FF3F3F', fontWeight : 'bold'}}>부작용</styled.MedicineEachInfoTitle> | ||
65 | + <styled.MedicineEachInfo style = {{color : '#9B0000'}}>{props.bottleInfo.medicine.antiEffect}</styled.MedicineEachInfo> | ||
66 | + </styled.MedicineEachInfoWrapper> | ||
67 | + </styled.MedicineInfoWrapper> | ||
68 | + </styled.ModalContent> | ||
69 | + </styled.ModalContentWrapper> | ||
70 | + </styled.ModalContainer> : null | ||
71 | + } | ||
72 | + <styled.ChartAndFeedbackWrapper> | ||
73 | + <styled.ChartWrapper> | ||
74 | + <styled.MedicineDetailViewButtonWrapper> | ||
75 | + <styled.MedicineDetailViewButton | ||
76 | + onClick = {() => props.setMedicineInfoModal(true)} | ||
77 | + > | ||
78 | + <styled.MedicineDetailViewButtonImg src = {plus}/> | ||
79 | + </styled.MedicineDetailViewButton> | ||
80 | + </styled.MedicineDetailViewButtonWrapper> | ||
81 | + <HighchartsReact | ||
82 | + highCharts = {HighCharts} | ||
83 | + options = {props.chartOption} | ||
84 | + /> | ||
85 | + </styled.ChartWrapper> | ||
86 | + <styled.FeedbackWrapper> | ||
87 | + <styled.FeedbackInfoTitle>피드백 내역</styled.FeedbackInfoTitle> | ||
88 | + { | ||
89 | + props.bottleInfo.feedbackList.map((feedback : any) => { | ||
90 | + return ( | ||
91 | + <styled.FeedbackEachItemWrapper | ||
92 | + key = {feedback._id} | ||
93 | + > | ||
94 | + <styled.FeedbackType fdbType = {feedback.fdbType}/> | ||
95 | + <styled.FeedbackTitle>{feedback.feedback}</styled.FeedbackTitle> | ||
96 | + <styled.FeedbackDtm>등록일<br/>{feedback.fdbDtm}</styled.FeedbackDtm> | ||
97 | + </styled.FeedbackEachItemWrapper> | ||
98 | + ) | ||
99 | + }) | ||
100 | + } | ||
101 | + </styled.FeedbackWrapper> | ||
102 | + </styled.ChartAndFeedbackWrapper> | ||
103 | + <styled.NewFeedbackRegWrapper> | ||
104 | + <styled.NewFeedbackRegInput | ||
105 | + value = {props.feedback} | ||
106 | + onChange = {props.onSetFeedback} | ||
107 | + /> | ||
108 | + <styled.NewFeedbackButtonWrapper> | ||
109 | + <styled.NewFeedbackTypeButtonWrapper> | ||
110 | + <styled.NewFeedbackTypeButtonEachWrapper> | ||
111 | + <styled.NewFeedbackTypeButton | ||
112 | + valueType = 'RECOMMEND' | ||
113 | + selected = {props.fdbType === 'RECOMMEND'} | ||
114 | + onClick = {() => props.setFdbType('RECOMMEND')} | ||
115 | + /> | ||
116 | + <styled.NewFeedbackTypeButtonText>권고</styled.NewFeedbackTypeButtonText> | ||
117 | + </styled.NewFeedbackTypeButtonEachWrapper> | ||
118 | + <styled.NewFeedbackTypeButtonEachWrapper> | ||
119 | + <styled.NewFeedbackTypeButton | ||
120 | + valueType = 'CAUTION' | ||
121 | + selected = {props.fdbType === 'CAUTION'} | ||
122 | + onClick = {() => props.setFdbType('CAUTION')} | ||
123 | + /> | ||
124 | + <styled.NewFeedbackTypeButtonText>주의</styled.NewFeedbackTypeButtonText> | ||
125 | + </styled.NewFeedbackTypeButtonEachWrapper> | ||
126 | + <styled.NewFeedbackTypeButtonEachWrapper> | ||
127 | + <styled.NewFeedbackTypeButton | ||
128 | + valueType = 'WARN' | ||
129 | + selected = {props.fdbType === 'WARN'} | ||
130 | + onClick = {() => props.setFdbType('WARN')} | ||
131 | + /> | ||
132 | + <styled.NewFeedbackTypeButtonText>경고</styled.NewFeedbackTypeButtonText> | ||
133 | + </styled.NewFeedbackTypeButtonEachWrapper> | ||
134 | + <styled.NewFeedbackTypeButtonEachWrapper> | ||
135 | + <styled.NewFeedbackTypeButton | ||
136 | + valueType = 'CRITICAL' | ||
137 | + selected = {props.fdbType === 'CRITICAL'} | ||
138 | + onClick = {() => props.setFdbType('CRITICAL')} | ||
139 | + /> | ||
140 | + <styled.NewFeedbackTypeButtonText>치명</styled.NewFeedbackTypeButtonText> | ||
141 | + </styled.NewFeedbackTypeButtonEachWrapper> | ||
142 | + </styled.NewFeedbackTypeButtonWrapper> | ||
143 | + <styled.NewFeedbackRegButton | ||
144 | + onClick = {props.onSubmitFeedback} | ||
145 | + > | ||
146 | + {/* <styled.NewFeedbackRegButtonImg /> */} | ||
147 | + <styled.NewFeedbackRegButtonText>피드백<br/>등록</styled.NewFeedbackRegButtonText> | ||
148 | + </styled.NewFeedbackRegButton> | ||
149 | + </styled.NewFeedbackButtonWrapper> | ||
150 | + </styled.NewFeedbackRegWrapper> | ||
10 | </styled.Container> | 151 | </styled.Container> |
11 | ); | 152 | ); |
12 | }; | 153 | }; | ... | ... |
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 | +`; | ||
25 | + | ||
2 | 26 | ||
3 | export const Container = styled.div ` | 27 | export const Container = styled.div ` |
28 | + height : 100vh; | ||
29 | + width : 100%; | ||
30 | + display : flex; | ||
31 | + flex-direction : column; | ||
32 | + justify-content : center; | ||
33 | +`; | ||
34 | + | ||
35 | +export const ModalContainer = styled.div ` | ||
36 | + height : 100%; | ||
37 | + width : 100%; | ||
38 | + z-index : 99; | ||
39 | + position : absolute; | ||
40 | + | ||
41 | + display : flex; | ||
42 | + flex-direction : column; | ||
43 | + | ||
44 | + animation : ${ModalOn} .5s; | ||
45 | + | ||
46 | + background-color : rgba(52, 52, 52, .7); | ||
47 | + | ||
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 MedicineNameWrapper = styled.div ` | ||
123 | + flex : 1 | ||
124 | + border : none; | ||
125 | + border-bottom : 1px solid #ddd; | ||
126 | + width : 100%; | ||
127 | + | ||
128 | + padding : 4% 0; | ||
129 | + | ||
130 | + display : flex; | ||
131 | + flex-direction : column; | ||
132 | + justify-content : center; | ||
133 | + align-items : center; | ||
134 | +`; | ||
135 | + | ||
136 | +export const MedicineName = styled.div ` | ||
137 | + font-size : 20px; | ||
138 | + font-weight : 700; | ||
139 | + letter-spacing : 1px; | ||
140 | + | ||
141 | + color : #337DFF; | ||
142 | +`; | ||
143 | + | ||
144 | +export const MedicineInfoWrapper = styled.div ` | ||
145 | + flex : 9; | ||
146 | + width : 100%; | ||
147 | + | ||
148 | + overflow : scroll; | ||
149 | + border : 1px solid; | ||
150 | + | ||
151 | + display : flex; | ||
152 | + flex-direction : column; | ||
153 | + align-items : center; | ||
154 | + | ||
155 | + padding : 0 0 0 3px; | ||
156 | + | ||
157 | + &::-webkit-scrollbar { | ||
158 | + width : 3px; | ||
159 | + background-color : transparent; | ||
160 | + height : 0px; | ||
161 | + } | ||
162 | + | ||
163 | + &::-webkit-scrollbar-thumb { | ||
164 | + background-color : #337DFF; | ||
165 | + } | ||
166 | + | ||
167 | +`; | ||
168 | + | ||
169 | +export const MedicineEachInfoWrapper = styled.div ` | ||
170 | + display : flex; | ||
171 | + flex-direction : column; | ||
172 | + | ||
173 | + width : 80%; | ||
174 | + padding : 20px 10%; | ||
175 | + border : none; | ||
176 | + border-bottom : 1px solid #ddd; | ||
177 | +`; | ||
178 | + | ||
179 | +export const MedicineEachInfoTitle = styled.div ` | ||
180 | + font-size : 14px; | ||
181 | + font-weight : 500; | ||
182 | + color : #337DFF; | ||
183 | + margin : 0 0 5px 0; | ||
184 | +`; | ||
185 | + | ||
186 | +export const MedicineEachInfo = styled.div ` | ||
187 | + font-size : 16px; | ||
188 | + letter-spacing : 1px; | ||
189 | +`; | ||
190 | + | ||
191 | +export const ChartAndFeedbackWrapper = styled.div ` | ||
192 | + flex : 3; | ||
193 | + display : flex; | ||
194 | + flex-direction : row; | ||
195 | + | ||
196 | + justify-content : space-around; | ||
197 | + | ||
198 | +`; | ||
199 | + | ||
200 | +export const ChartWrapper = styled.div ` | ||
201 | + border : 1px solid transparent; | ||
202 | + padding : 10px; | ||
203 | + | ||
204 | + border-radius : 4px; | ||
205 | + | ||
206 | + display : flex; | ||
207 | + flex-direction : column; | ||
208 | + justify-content : center; | ||
209 | + align-items : center; | ||
210 | + | ||
211 | + box-shadow: 0px 0px 10px #a0a0a0; | ||
212 | + | ||
213 | +`; | ||
214 | + | ||
215 | +export const MedicineDetailViewButtonWrapper = styled.div ` | ||
216 | + border : none; | ||
217 | + width : 100%; | ||
218 | + | ||
219 | + display : flex; | ||
220 | + flex-direction : row; | ||
221 | + justify-content : flex-end; | ||
222 | + align-items : center; | ||
223 | +`; | ||
224 | + | ||
225 | +export const MedicineDetailViewButton = styled.button ` | ||
226 | + height : 25px; | ||
227 | + width : 25px; | ||
228 | + | ||
229 | + display : flex; | ||
230 | + justify-content : center; | ||
231 | + align-items : center; | ||
232 | + | ||
233 | + background-color : transparent; | ||
234 | + border : 1px solid #ddd; | ||
235 | + border-radius : 3px; | ||
236 | + | ||
237 | + cursor : pointer; | ||
238 | + | ||
239 | + box-shadow: 0px 0px 3px 0 #a0a0a0; | ||
240 | + | ||
241 | + opacity : .7; | ||
242 | + | ||
243 | + &:hover { | ||
244 | + opacity : 1; | ||
245 | + } | ||
246 | +`; | ||
247 | + | ||
248 | +export const MedicineDetailViewButtonImg = styled.img ` | ||
249 | + height : 15px; | ||
250 | + width : 15px; | ||
251 | +`; | ||
252 | + | ||
253 | +export const FeedbackWrapper = styled.div ` | ||
254 | + overflow : scroll; | ||
255 | + border : 1px solid transparent; | ||
256 | + width : 500px; | ||
257 | + | ||
258 | + max-height : 420px; | ||
259 | + | ||
260 | + border-radius : 4px; | ||
261 | + | ||
262 | + box-shadow: 0px 0px 10px #a0a0a0; | ||
263 | + | ||
264 | + display : flex; | ||
265 | + flex-direction : column; | ||
266 | + | ||
267 | + align-items : center; | ||
268 | + | ||
269 | + padding : 0 0 0 3px; | ||
270 | + | ||
271 | + &::-webkit-scrollbar { | ||
272 | + width : 3px; | ||
273 | + background-color : transparent; | ||
274 | + height : 0px; | ||
275 | + } | ||
276 | + | ||
277 | + &::-webkit-scrollbar-thumb { | ||
278 | + background-color : #337DFF; | ||
279 | + } | ||
280 | +`; | ||
281 | + | ||
282 | +export const FeedbackInfoTitle = styled.div ` | ||
283 | + width : 100%; | ||
284 | + text-align : center; | ||
285 | + | ||
286 | + border : none; | ||
287 | + border-bottom : 2px solid #ddd; | ||
288 | + | ||
289 | + padding : 10px 0; | ||
290 | + | ||
291 | + font-size : 17px; | ||
292 | + font-weight : 600; | ||
293 | + | ||
294 | + background-color : transparent; | ||
295 | +`; | ||
296 | + | ||
297 | +export const FeedbackEachItemWrapper = styled.div ` | ||
298 | + width : 100%; | ||
299 | + padding : 10px 0; | ||
300 | + | ||
301 | + border : none; | ||
302 | + border-bottom : 1px solid #ddd; | ||
303 | + | ||
304 | + background-color : transparent; | ||
305 | + | ||
306 | + display : flex; | ||
307 | + flex-direction : row; | ||
308 | + align-items : center; | ||
309 | +`; | ||
310 | + | ||
311 | +export const FeedbackType = styled.div<{fdbType : string}> ` | ||
312 | + margin : 0 0 0 10px; | ||
313 | + | ||
314 | + border : none; | ||
315 | + border-radius : 100px; | ||
316 | + | ||
317 | + height : 12px; | ||
318 | + width : 12px; | ||
319 | + | ||
320 | + | ||
321 | + background-color : ${props => | ||
322 | + props.fdbType === 'RECOMMEND' ? '#337DFF' | ||
323 | + : props.fdbType === 'CAUTION' ? '#FFE77B' | ||
324 | + : props.fdbType === 'WARN' ? '#FF8941' | ||
325 | + : props.fdbType === 'CRITICAL' ? '#E40000' : 'transparent' | ||
326 | + }; | ||
327 | +`; | ||
328 | + | ||
329 | +export const FeedbackTitle = styled.div ` | ||
330 | + flex : 7; | ||
331 | + | ||
332 | + height : 100%; | ||
333 | + | ||
334 | + padding : 0 10px; | ||
335 | + | ||
336 | + display : flex; | ||
337 | + flex-direction : row; | ||
338 | + | ||
339 | + align-items : center; | ||
340 | + | ||
341 | + font-size : 12px; | ||
342 | + font-weight : 500; | ||
343 | +`; | ||
344 | + | ||
345 | +export const FeedbackDtm = styled.div ` | ||
346 | + flex : 2; | ||
347 | + | ||
348 | + height : 100%; | ||
349 | + | ||
350 | + padding : 0 10px; | ||
351 | + | ||
352 | + display : flex; | ||
353 | + flex-direction : row; | ||
354 | + | ||
355 | + align-items : center; | ||
356 | + | ||
357 | + border : none; | ||
358 | + border-left : 1px solid #ddd; | ||
359 | + | ||
360 | + font-size : 10px; | ||
361 | + font-weight : 400; | ||
362 | +`; | ||
363 | + | ||
364 | + | ||
365 | +export const NewFeedbackRegWrapper = styled.div ` | ||
366 | + margin : 20px 10px; | ||
367 | + | ||
368 | + flex : 2; | ||
369 | + display : flex; | ||
370 | + flex-direction : row; | ||
371 | + justify-content : center; | ||
372 | + | ||
373 | + padding : 20px; | ||
374 | + | ||
375 | + border : 1px solid transparent; | ||
376 | + border-radius : 4px; | ||
377 | + | ||
378 | + box-shadow: 0px 0px 10px #a0a0a0; | ||
379 | + | ||
380 | +`; | ||
381 | + | ||
382 | +export const NewFeedbackRegInput = styled.textarea ` | ||
383 | + resize : none; | ||
384 | + flex : 10; | ||
385 | + | ||
386 | + padding : 30px; | ||
387 | + | ||
388 | + font-size : 14px; | ||
389 | + | ||
390 | + border : 1px solid #a0a0a0; | ||
391 | + border-radius : 4px; | ||
392 | +`; | ||
393 | + | ||
394 | +export const NewFeedbackButtonWrapper = styled.div ` | ||
395 | + flex : 2; | ||
396 | + border : none; | ||
397 | + | ||
398 | + display : flex; | ||
399 | + flex-direction : column; | ||
400 | + justify-content : center; | ||
401 | + align-items : center; | ||
402 | + | ||
403 | + gap : 2%; | ||
404 | + | ||
405 | +`; | ||
406 | + | ||
407 | +export const NewFeedbackTypeButtonWrapper = styled.div ` | ||
408 | + flex : 5; | ||
409 | + display : flex; | ||
410 | + flex-direction : column; | ||
411 | + | ||
412 | + border : none; | ||
413 | + width : 70%; | ||
414 | +`; | ||
415 | + | ||
416 | +export const NewFeedbackTypeButtonEachWrapper = styled.div ` | ||
417 | + flex : 1; | ||
418 | + display : flex; | ||
419 | + flex-direction : row; | ||
420 | + justify-content : flex-start; | ||
421 | + align-items : center; | ||
422 | + | ||
423 | + width : 100%; | ||
424 | + padding : 10% 0; | ||
425 | + | ||
426 | + border : none; | ||
427 | +`; | ||
428 | + | ||
429 | +export const NewFeedbackTypeButton = styled.button<{valueType : string, selected : boolean}> ` | ||
430 | + height : 15px; | ||
431 | + width : 15px; | ||
432 | + | ||
433 | + border : 1px solid #ddd; | ||
434 | + border-radius : 3px; | ||
435 | + background-color : ${props => | ||
436 | + props.selected && props.valueType === 'RECOMMEND' ? '#337DFF' | ||
437 | + : props.selected && props.valueType === 'CAUTION' ? '#FFE77B' | ||
438 | + : props.selected && props.valueType === 'WARN' ? '#FF8941' | ||
439 | + : props.selected && props.valueType === 'CRITICAL' ? '#E40000' : 'transparent' | ||
440 | + }; | ||
441 | + | ||
442 | + display : flex; | ||
443 | + justify-content : center; | ||
444 | + align-items : center; | ||
445 | + | ||
446 | + cursor : pointer; | ||
447 | + | ||
448 | + margin : 0 5% 0 0; | ||
449 | + | ||
450 | + transition : .25s all; | ||
451 | + | ||
452 | + &:hover { | ||
453 | + background-color : ${props => | ||
454 | + props.valueType === 'RECOMMEND' ? '#337DFF' | ||
455 | + : props.valueType === 'CAUTION' ? '#FFE77B' | ||
456 | + : props.valueType === 'WARN' ? '#FF8941' | ||
457 | + : props.valueType === 'CRITICAL' ? '#E40000' : 'transparent' | ||
458 | + }; | ||
459 | + } | ||
460 | +` | ||
461 | + | ||
462 | +export const NewFeedbackTypeButtonText = styled.div ` | ||
463 | + font-size : 12px; | ||
464 | + font-weight : 500; | ||
465 | + letter-spacing : 1px; | ||
466 | +`; | ||
467 | + | ||
468 | +export const NewFeedbackRegButton = styled.button ` | ||
469 | + flex : 2; | ||
470 | + width : 70%; | ||
471 | + | ||
472 | + cursor : pointer; | ||
473 | + | ||
474 | + border : 1px solid transparent; | ||
475 | + border-radius : 4px; | ||
476 | + background-color : #343434; | ||
477 | + color : #fff; | ||
478 | + | ||
479 | + transition : .25s all; | ||
480 | + | ||
481 | + &:hover { | ||
482 | + background-color : transparent; | ||
483 | + border : 1px solid #343434; | ||
484 | + color : #343434; | ||
485 | + } | ||
486 | +`; | ||
487 | + | ||
488 | +export const NewFeedbackRegButtonText = styled.div ` | ||
489 | + font-size : 15px; | ||
490 | + letter-spacing : 1px; | ||
491 | + font-weight : 600; | ||
492 | + | ||
493 | + font-color : #fff | ||
494 | + | ||
495 | + | ||
496 | +`; | ||
497 | + | ||
498 | +export const NewFeedbackRegButtonImg = styled.img ` | ||
4 | 499 | ||
5 | `; | 500 | `; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -4,12 +4,16 @@ import { RouteComponentProps } from 'react-router-dom'; | ... | @@ -4,12 +4,16 @@ import { RouteComponentProps } from 'react-router-dom'; |
4 | import { useRecoilState } from 'recoil'; | 4 | import { useRecoilState } from 'recoil'; |
5 | import * as recoilUtil from '../../util/recoilUtil'; | 5 | import * as recoilUtil from '../../util/recoilUtil'; |
6 | 6 | ||
7 | +import * as Alert from '../../util/alertMessage'; | ||
8 | + | ||
9 | +import Header from '../../components/Header'; | ||
7 | import LoginPresenter from './LoginPresenter'; | 10 | import LoginPresenter from './LoginPresenter'; |
8 | 11 | ||
9 | import { authApi } from '../../api'; | 12 | import { authApi } from '../../api'; |
10 | 13 | ||
11 | 14 | ||
12 | -type LoginProps = RouteComponentProps | 15 | +// eslint-disable-next-line @typescript-eslint/no-empty-interface |
16 | +interface LoginProps extends RouteComponentProps {} | ||
13 | 17 | ||
14 | const LoginContainer = (props : LoginProps) => { | 18 | const LoginContainer = (props : LoginProps) => { |
15 | 19 | ||
... | @@ -17,9 +21,19 @@ const LoginContainer = (props : LoginProps) => { | ... | @@ -17,9 +21,19 @@ const LoginContainer = (props : LoginProps) => { |
17 | userId : '', | 21 | userId : '', |
18 | password : '', | 22 | password : '', |
19 | }); | 23 | }); |
24 | + | ||
20 | const [token, setToken] = useRecoilState(recoilUtil.token); | 25 | const [token, setToken] = useRecoilState(recoilUtil.token); |
21 | const [userTypeCd, setUserTypeCd] = useRecoilState(recoilUtil.userTypeCd); | 26 | const [userTypeCd, setUserTypeCd] = useRecoilState(recoilUtil.userTypeCd); |
22 | - const [error, setError] = useRecoilState(recoilUtil.error); | 27 | + |
28 | + | ||
29 | + const fetchData = async() => { | ||
30 | + if(token && token.length) { | ||
31 | + const result = await authApi.verifyToken(token); | ||
32 | + if (result.statusText === 'OK') { | ||
33 | + props.history.push('/'); | ||
34 | + } | ||
35 | + } | ||
36 | + }; | ||
23 | 37 | ||
24 | const onSetUserId = (e : React.ChangeEvent<HTMLInputElement>) => { | 38 | const onSetUserId = (e : React.ChangeEvent<HTMLInputElement>) => { |
25 | setLoginForm({ | 39 | setLoginForm({ |
... | @@ -42,23 +56,26 @@ const LoginContainer = (props : LoginProps) => { | ... | @@ -42,23 +56,26 @@ const LoginContainer = (props : LoginProps) => { |
42 | const onLogin = async () => { | 56 | const onLogin = async () => { |
43 | try { | 57 | try { |
44 | const result : any = await authApi.login(loginForm); | 58 | const result : any = await authApi.login(loginForm); |
45 | - if(result.statusText === 'OK') { | 59 | + if(result.statusText === 'OK' && result.data.userTypeCd !== 'NORMAL') { |
46 | setToken(result.data.token); | 60 | setToken(result.data.token); |
47 | setUserTypeCd(result.data.userTypeCd); | 61 | setUserTypeCd(result.data.userTypeCd); |
48 | - props.history.push('/'); | 62 | + Alert.onSuccess('로그인 성공, 메인 화면으로 이동합니다.', () => props.history.push('/')); |
63 | + } else if(result.data.userTypeCd === 'NORMAL') { | ||
64 | + Alert.onError('권한이 없는 유저입니다.', () => props.history.push('/')); | ||
49 | } | 65 | } |
50 | } catch(e) { | 66 | } catch(e) { |
51 | - setError('로그인에 실패했습니다.'); | 67 | + Alert.onError(e.response.data, () => null); |
52 | - console.log(e); | ||
53 | } | 68 | } |
54 | 69 | ||
55 | }; | 70 | }; |
56 | 71 | ||
57 | useEffect(() => { | 72 | useEffect(() => { |
58 | - console.log('loginPage'); | 73 | + fetchData(); |
59 | }, []); | 74 | }, []); |
60 | 75 | ||
61 | return ( | 76 | return ( |
77 | + <> | ||
78 | + <Header {...props} /> | ||
62 | <LoginPresenter | 79 | <LoginPresenter |
63 | loginForm = {loginForm} | 80 | loginForm = {loginForm} |
64 | onSetUserId = {onSetUserId} | 81 | onSetUserId = {onSetUserId} |
... | @@ -66,6 +83,7 @@ const LoginContainer = (props : LoginProps) => { | ... | @@ -66,6 +83,7 @@ const LoginContainer = (props : LoginProps) => { |
66 | onGoRegister = {onGoRegister} | 83 | onGoRegister = {onGoRegister} |
67 | onLogin = {onLogin} | 84 | onLogin = {onLogin} |
68 | /> | 85 | /> |
86 | + </> | ||
69 | ) | 87 | ) |
70 | }; | 88 | }; |
71 | 89 | ... | ... |
... | @@ -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> | ... | ... |
1 | -import styled from 'styled-components'; | 1 | +import styled, { keyframes} from 'styled-components'; |
2 | + | ||
3 | + | ||
4 | +const twinkle = keyframes ` | ||
5 | + 0% { | ||
6 | + opacity : 1; | ||
7 | + background-color : #337DFF; | ||
8 | + } | ||
9 | + 20% { | ||
10 | + opacity : .75; | ||
11 | + } | ||
12 | + 40% { | ||
13 | + opacity : .5; | ||
14 | + } | ||
15 | + 60% { | ||
16 | + opacity : .5; | ||
17 | + } | ||
18 | + 80% { | ||
19 | + opacity : .75; | ||
20 | + } | ||
21 | + 100% { | ||
22 | + opacity : 1; | ||
23 | + background-color : #337DFF; | ||
24 | + } | ||
25 | +` | ||
26 | + | ||
27 | +const twinkleText = keyframes ` | ||
28 | + 0% { | ||
29 | + opacity : 1; | ||
30 | + } | ||
31 | + 20% { | ||
32 | + opacity : .75; | ||
33 | + } | ||
34 | + 40% { | ||
35 | + opacity : .5; | ||
36 | + } | ||
37 | + 60% { | ||
38 | + opacity : .5; | ||
39 | + } | ||
40 | + 80% { | ||
41 | + opacity : .75; | ||
42 | + } | ||
43 | + 100% { | ||
44 | + opacity : 1; | ||
45 | + } | ||
46 | +`; | ||
2 | 47 | ||
3 | export const Container = styled.div ` | 48 | export const Container = styled.div ` |
4 | width : 100%; | 49 | width : 100%; |
... | @@ -73,10 +118,8 @@ export const RegisterButton = styled.button ` | ... | @@ -73,10 +118,8 @@ export const RegisterButton = styled.button ` |
73 | 118 | ||
74 | font-size : 11px; | 119 | font-size : 11px; |
75 | 120 | ||
76 | - transition : .25s all; | ||
77 | - | ||
78 | &:hover { | 121 | &:hover { |
79 | - opacity : .5; | 122 | + animation : ${twinkleText} 2s infinite; |
80 | } | 123 | } |
81 | 124 | ||
82 | `; | 125 | `; |
... | @@ -97,10 +140,10 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> ` | ... | @@ -97,10 +140,10 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> ` |
97 | border-radius : 5px; | 140 | border-radius : 5px; |
98 | padding : 10px 30px; | 141 | padding : 10px 30px; |
99 | 142 | ||
143 | + width : 80%; | ||
144 | + | ||
100 | cursor : pointer; | 145 | cursor : pointer; |
101 | 146 | ||
102 | - transition : .25s all; | ||
103 | - | ||
104 | color : #343434; | 147 | color : #343434; |
105 | font-weight : 600; | 148 | font-weight : 600; |
106 | 149 | ||
... | @@ -108,6 +151,7 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> ` | ... | @@ -108,6 +151,7 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> ` |
108 | background-color : #343434; | 151 | background-color : #343434; |
109 | color : #fff; | 152 | color : #fff; |
110 | border : 1.2px solid transparent; | 153 | border : 1.2px solid transparent; |
154 | + animation : ${twinkle} 1.5s infinite linear; | ||
111 | } | 155 | } |
112 | 156 | ||
113 | margin : 0 15px; | 157 | margin : 0 15px; | ... | ... |
... | @@ -4,6 +4,8 @@ import { RouteComponentProps} from 'react-router-dom'; | ... | @@ -4,6 +4,8 @@ import { RouteComponentProps} from 'react-router-dom'; |
4 | import { useRecoilValue } from 'recoil'; | 4 | import { useRecoilValue } from 'recoil'; |
5 | import * as recoilUtil from '../../util/recoilUtil'; | 5 | import * as recoilUtil from '../../util/recoilUtil'; |
6 | 6 | ||
7 | + | ||
8 | +import Header from '../../components/Header'; | ||
7 | import DoctorMenuContainer from './doctor'; | 9 | import DoctorMenuContainer from './doctor'; |
8 | import ManagerMenuContainer from './manager'; | 10 | import ManagerMenuContainer from './manager'; |
9 | 11 | ||
... | @@ -22,9 +24,15 @@ const MainContainer = (props : MainProps) => { | ... | @@ -22,9 +24,15 @@ const MainContainer = (props : MainProps) => { |
22 | }, []); | 24 | }, []); |
23 | 25 | ||
24 | return ( | 26 | return ( |
25 | - userTypeCd === 'DOCTOR' ? | 27 | + <> |
26 | - <DoctorMenuContainer {...props}/> : | 28 | + <Header {...props}/> |
27 | - <ManagerMenuContainer {...props}/> | 29 | + { |
30 | + userTypeCd === 'DOCTOR' ? | ||
31 | + <DoctorMenuContainer {...props}/> : | ||
32 | + userTypeCd === 'MANAGER' ? | ||
33 | + <ManagerMenuContainer {...props}/> : null | ||
34 | + } | ||
35 | + </> | ||
28 | ); | 36 | ); |
29 | }; | 37 | }; |
30 | 38 | ... | ... |
... | @@ -6,6 +6,8 @@ import DoctorMenuPresenter from './DoctorMenuPresenter'; | ... | @@ -6,6 +6,8 @@ import DoctorMenuPresenter from './DoctorMenuPresenter'; |
6 | import { useRecoilState, useRecoilValue } from 'recoil'; | 6 | import { useRecoilState, useRecoilValue } from 'recoil'; |
7 | import * as recoilUtil from '../../../util/recoilUtil'; | 7 | import * as recoilUtil from '../../../util/recoilUtil'; |
8 | 8 | ||
9 | +import * as Alert from '../../../util/alertMessage'; | ||
10 | + | ||
9 | import { doctorApi, authApi } from '../../../api'; | 11 | import { doctorApi, authApi } from '../../../api'; |
10 | 12 | ||
11 | 13 | ||
... | @@ -36,13 +38,15 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { | ... | @@ -36,13 +38,15 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { |
36 | 38 | ||
37 | const [searchPatientKeyword, setSearchPatientKeyword] = useState<string>(''); | 39 | const [searchPatientKeyword, setSearchPatientKeyword] = useState<string>(''); |
38 | const [filteringPatientList, setFilteringPatientList] = useState<any>([]); | 40 | const [filteringPatientList, setFilteringPatientList] = useState<any>([]); |
39 | - | 41 | + |
40 | const [patientDetail, setPatientDetail] = useState<any>(); | 42 | const [patientDetail, setPatientDetail] = useState<any>(); |
41 | 43 | ||
42 | const [editModal, setEditModal] = useState<boolean>(false); | 44 | const [editModal, setEditModal] = useState<boolean>(false); |
45 | + const [editPatientInfo, setEditPatientInfo] = useState<string>(''); | ||
46 | + | ||
43 | const [newPatientRegisterModal, setNewPatientRegisterModal] = useState<boolean>(false); | 47 | const [newPatientRegisterModal, setNewPatientRegisterModal] = useState<boolean>(false); |
44 | const [newPatientSearchId, setNewPatientSearchId] = useState<string>(''); | 48 | const [newPatientSearchId, setNewPatientSearchId] = useState<string>(''); |
45 | - | 49 | + const [newPatientSearchResult, setNewPatientSearchResult] = useState<any | null>(null); |
46 | 50 | ||
47 | 51 | ||
48 | const fetchData = async() => { | 52 | const fetchData = async() => { |
... | @@ -92,7 +96,8 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { | ... | @@ -92,7 +96,8 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { |
92 | } | 96 | } |
93 | }; | 97 | }; |
94 | 98 | ||
95 | - const onInitialize = () => { | 99 | + const onInitialize = async () => { |
100 | + await fetchData(); | ||
96 | setInfo({ | 101 | setInfo({ |
97 | infoType : 'DOCTOR', | 102 | infoType : 'DOCTOR', |
98 | userNm : doctorInfo.doctorNm, | 103 | userNm : doctorInfo.doctorNm, |
... | @@ -103,9 +108,46 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { | ... | @@ -103,9 +108,46 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { |
103 | }); | 108 | }); |
104 | setFilteringPatientList([]); | 109 | setFilteringPatientList([]); |
105 | setSearchPatientKeyword(''); | 110 | setSearchPatientKeyword(''); |
111 | + setEditModal(false); | ||
112 | + setEditPatientInfo(''); | ||
113 | + setNewPatientRegisterModal(false); | ||
114 | + setNewPatientSearchId(''); | ||
115 | + setNewPatientSearchResult(null); | ||
106 | setPatientDetail(null); | 116 | setPatientDetail(null); |
107 | }; | 117 | }; |
108 | 118 | ||
119 | + const onEditPatientInfo = (e : React.ChangeEvent<HTMLTextAreaElement>) => { | ||
120 | + setEditPatientInfo(e.target.value); | ||
121 | + }; | ||
122 | + | ||
123 | + const onSubmitPatientInfo = () => { | ||
124 | + if(editPatientInfo.length && patientDetail) { | ||
125 | + const onSubmit = async () => { | ||
126 | + try { | ||
127 | + const result = await doctorApi.writePatientInfo(token, { | ||
128 | + patientId : patientDetail.profile.userId, | ||
129 | + info : editPatientInfo, | ||
130 | + }); | ||
131 | + if(result.statusText === 'OK') { | ||
132 | + Alert.onSuccess('환자의 특이사항을 업데이트했습니다.', () => onInitialize()); | ||
133 | + } else { | ||
134 | + Alert.onError('특이사항을 기록하는데 실패했습니다.', () => null); | ||
135 | + } | ||
136 | + | ||
137 | + } catch(e) { | ||
138 | + Alert.onError(e.response.data.error, () => null); | ||
139 | + } | ||
140 | + }; | ||
141 | + | ||
142 | + Alert.onCheck('환자의 특이사항을 업데이트하시겠습니까?', onSubmit, () => null); | ||
143 | + | ||
144 | + } else { | ||
145 | + Alert.onError('환자의 특이사항을 기록하세요.', () => null); | ||
146 | + } | ||
147 | + | ||
148 | + | ||
149 | + }; | ||
150 | + | ||
109 | 151 | ||
110 | const onSetNewPatientSearchId = (e : React.ChangeEvent<HTMLInputElement>) => { | 152 | const onSetNewPatientSearchId = (e : React.ChangeEvent<HTMLInputElement>) => { |
111 | setNewPatientSearchId(e.target.value); | 153 | setNewPatientSearchId(e.target.value); |
... | @@ -114,16 +156,51 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { | ... | @@ -114,16 +156,51 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { |
114 | const onSearchNewPatientByEmail = async () => { | 156 | const onSearchNewPatientByEmail = async () => { |
115 | try { | 157 | try { |
116 | await doctorApi.searchPatientById(token, newPatientSearchId).then(res => { | 158 | await doctorApi.searchPatientById(token, newPatientSearchId).then(res => { |
117 | - console.log(res.data); | 159 | + setNewPatientSearchResult(res.data); |
118 | - }).catch(err => console.log(err)); | 160 | + }).catch(err => { |
161 | + console.log(err); | ||
162 | + Alert.onError('검색 결과가 없습니다.', () => null); | ||
163 | + setNewPatientSearchResult(null); | ||
164 | + }); | ||
119 | } catch(e) { | 165 | } catch(e) { |
120 | - console.log(e); | 166 | + Alert.onError(e.response.data.error, () => null); |
167 | + } | ||
168 | + }; | ||
169 | + | ||
170 | + const onRegisterNewPatient = () => { | ||
171 | + if(newPatientSearchResult) { | ||
172 | + const { patientId, patientNm } = newPatientSearchResult; | ||
173 | + const onRegisterReq = async () => { | ||
174 | + try { | ||
175 | + const result = await doctorApi.registerPatient(token, { | ||
176 | + patientId, | ||
177 | + }); | ||
178 | + if(result.statusText === 'OK') { | ||
179 | + Alert.onSuccess('환자에게 담당의 등록 요청을 전송했습니다.', () => null); | ||
180 | + } else { | ||
181 | + Alert.onError('환자에게 담당의 등록 요청을 실패했습니다.', () => null); | ||
182 | + } | ||
183 | + } catch(e) { | ||
184 | + Alert.onError(e.response.data.error, () => null); | ||
185 | + } | ||
186 | + }; | ||
187 | + | ||
188 | + Alert.onCheck(`${patientNm} 환자에게 담당의 등록 요청을 전송하시겠습니까?`, onRegisterReq, () => null); | ||
189 | + } else { | ||
190 | + Alert.onError('환자를 먼저 검색해주세요.', () => null); | ||
121 | } | 191 | } |
122 | }; | 192 | }; |
123 | 193 | ||
194 | + const onCloseModal = async () => { | ||
195 | + setNewPatientRegisterModal(false); | ||
196 | + setNewPatientSearchId(''); | ||
197 | + setNewPatientSearchResult(null); | ||
198 | + setEditModal(false); | ||
199 | + setEditPatientInfo(''); | ||
200 | + }; | ||
124 | 201 | ||
125 | const onGoBottleDetail = (bottleId : number) => { | 202 | const onGoBottleDetail = (bottleId : number) => { |
126 | - console.log(bottleId); | 203 | + props.history.push(`/bottle/${bottleId}`); |
127 | }; | 204 | }; |
128 | 205 | ||
129 | 206 | ||
... | @@ -158,12 +235,19 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { | ... | @@ -158,12 +235,19 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { |
158 | 235 | ||
159 | editModal = {editModal} | 236 | editModal = {editModal} |
160 | setEditModal = {setEditModal} | 237 | setEditModal = {setEditModal} |
238 | + editPatientInfo = {editPatientInfo} | ||
239 | + onEditPatientInfo = {onEditPatientInfo} | ||
240 | + onSubmitPatientInfo = {onSubmitPatientInfo} | ||
161 | 241 | ||
162 | newPatientRegisterModal = {newPatientRegisterModal} | 242 | newPatientRegisterModal = {newPatientRegisterModal} |
163 | setNewPatientRegisterModal = {setNewPatientRegisterModal} | 243 | setNewPatientRegisterModal = {setNewPatientRegisterModal} |
164 | newPatientSearchId = {newPatientSearchId} | 244 | newPatientSearchId = {newPatientSearchId} |
165 | onSetNewPatientSearchId = {onSetNewPatientSearchId} | 245 | onSetNewPatientSearchId = {onSetNewPatientSearchId} |
166 | onSearchNewPatientByEmail = {onSearchNewPatientByEmail} | 246 | onSearchNewPatientByEmail = {onSearchNewPatientByEmail} |
247 | + onRegisterNewPatient = {onRegisterNewPatient} | ||
248 | + onCloseModal = {onCloseModal} | ||
249 | + | ||
250 | + newPatientSearchResult = {newPatientSearchResult} | ||
167 | /> | 251 | /> |
168 | ); | 252 | ); |
169 | }; | 253 | }; | ... | ... |
... | @@ -5,6 +5,8 @@ import * as styled from './DoctorMenuStyled'; | ... | @@ -5,6 +5,8 @@ import * as styled from './DoctorMenuStyled'; |
5 | const medicineImg = '/static/img/medicine.png'; | 5 | const medicineImg = '/static/img/medicine.png'; |
6 | const lensImg = '/static/img/lens.png'; | 6 | const lensImg = '/static/img/lens.png'; |
7 | const closeButton = '/static/img/close.png'; | 7 | const closeButton = '/static/img/close.png'; |
8 | +const edit = '/static/img/edit.png'; | ||
9 | +const refreshing = '/static/img/refreshing.png'; | ||
8 | 10 | ||
9 | 11 | ||
10 | interface DoctorMenuProps { | 12 | interface DoctorMenuProps { |
... | @@ -27,23 +29,30 @@ interface DoctorMenuProps { | ... | @@ -27,23 +29,30 @@ interface DoctorMenuProps { |
27 | 29 | ||
28 | editModal : boolean; | 30 | editModal : boolean; |
29 | setEditModal : any; | 31 | setEditModal : any; |
32 | + editPatientInfo : string; | ||
33 | + onEditPatientInfo : React.ChangeEventHandler<HTMLTextAreaElement>; | ||
34 | + onSubmitPatientInfo : () => void; | ||
30 | 35 | ||
31 | newPatientRegisterModal : boolean; | 36 | newPatientRegisterModal : boolean; |
32 | setNewPatientRegisterModal : any; | 37 | setNewPatientRegisterModal : any; |
33 | newPatientSearchId: string; | 38 | newPatientSearchId: string; |
34 | onSetNewPatientSearchId : React.ChangeEventHandler<HTMLInputElement>; | 39 | onSetNewPatientSearchId : React.ChangeEventHandler<HTMLInputElement>; |
35 | onSearchNewPatientByEmail : () => void; | 40 | onSearchNewPatientByEmail : () => void; |
41 | + onRegisterNewPatient : () => void; | ||
42 | + onCloseModal : () => void; | ||
43 | + | ||
44 | + newPatientSearchResult : any; | ||
36 | } | 45 | } |
37 | 46 | ||
38 | const DoctorMenuPresenter = (props : DoctorMenuProps) => { | 47 | const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
39 | return ( | 48 | return ( |
40 | <styled.Container> | 49 | <styled.Container> |
41 | { | 50 | { |
42 | - props.editModal ? | 51 | + props.newPatientRegisterModal ? |
43 | <styled.ModalContainer> | 52 | <styled.ModalContainer> |
44 | <styled.ModalClsButtonWrapper> | 53 | <styled.ModalClsButtonWrapper> |
45 | <styled.ModalClsButton | 54 | <styled.ModalClsButton |
46 | - onClick = {() => props.setEditModal(false)} | 55 | + onClick = {() => props.setNewPatientRegisterModal(false)} |
47 | > | 56 | > |
48 | <styled.ModalClsButtonImg src = {closeButton}/> | 57 | <styled.ModalClsButtonImg src = {closeButton}/> |
49 | <styled.ModalClsButtonText>닫기</styled.ModalClsButtonText> | 58 | <styled.ModalClsButtonText>닫기</styled.ModalClsButtonText> |
... | @@ -65,13 +74,28 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { | ... | @@ -65,13 +74,28 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
65 | </styled.NewPatientSearchButton> | 74 | </styled.NewPatientSearchButton> |
66 | </styled.NewPatientSearchWrapper> | 75 | </styled.NewPatientSearchWrapper> |
67 | <styled.NewPatientSearchResultWrapper> | 76 | <styled.NewPatientSearchResultWrapper> |
68 | - 🤔검색 결과가 없습니다. | 77 | + { |
78 | + props.newPatientSearchResult ? | ||
79 | + <styled.NewPatientSearchResult> | ||
80 | + <styled.NewPatientSearchResultInfoWrapper> | ||
81 | + <styled.NewPatientSearchResultInfo>이름 : </styled.NewPatientSearchResultInfo> | ||
82 | + <styled.NewPatientSearchResultInfoText> | ||
83 | + {props.newPatientSearchResult.patientNm} | ||
84 | + </styled.NewPatientSearchResultInfoText> | ||
85 | + </styled.NewPatientSearchResultInfoWrapper> | ||
86 | + </styled.NewPatientSearchResult> : | ||
87 | + '🤔검색 결과가 없습니다.' | ||
88 | + } | ||
69 | </styled.NewPatientSearchResultWrapper> | 89 | </styled.NewPatientSearchResultWrapper> |
70 | <styled.NewPatientRegisterButtonWrapper> | 90 | <styled.NewPatientRegisterButtonWrapper> |
71 | - <styled.NewPatientRegisterButton> | 91 | + <styled.NewPatientRegisterButton |
92 | + onClick = {props.onRegisterNewPatient} | ||
93 | + > | ||
72 | 확인 | 94 | 확인 |
73 | </styled.NewPatientRegisterButton> | 95 | </styled.NewPatientRegisterButton> |
74 | - <styled.NewPatientRegisterButton> | 96 | + <styled.NewPatientRegisterButton |
97 | + onClick = {props.onCloseModal} | ||
98 | + > | ||
75 | 취소 | 99 | 취소 |
76 | </styled.NewPatientRegisterButton> | 100 | </styled.NewPatientRegisterButton> |
77 | </styled.NewPatientRegisterButtonWrapper> | 101 | </styled.NewPatientRegisterButtonWrapper> |
... | @@ -80,6 +104,60 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { | ... | @@ -80,6 +104,60 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
80 | <styled.ModalClsButtonWrapper/> | 104 | <styled.ModalClsButtonWrapper/> |
81 | </styled.ModalContainer> : null | 105 | </styled.ModalContainer> : null |
82 | } | 106 | } |
107 | + { | ||
108 | + props.editModal ? | ||
109 | + <styled.ModalContainer> | ||
110 | + <styled.ModalClsButtonWrapper> | ||
111 | + <styled.ModalClsButton | ||
112 | + onClick = {() => props.setEditModal(false)} | ||
113 | + > | ||
114 | + <styled.ModalClsButtonImg src = {closeButton}/> | ||
115 | + <styled.ModalClsButtonText>닫기</styled.ModalClsButtonText> | ||
116 | + </styled.ModalClsButton> | ||
117 | + </styled.ModalClsButtonWrapper> | ||
118 | + <styled.ModalContentWrapper> | ||
119 | + <styled.ModalContent> | ||
120 | + <styled.PatientInfoViewContainer> | ||
121 | + <styled.PatientInfoPatientNmWrapper> | ||
122 | + <styled.PatientInfoPatientNmInfo>이름 : </styled.PatientInfoPatientNmInfo> | ||
123 | + <styled.PatientInfoPatientNm>{props.info.userNm}</styled.PatientInfoPatientNm> | ||
124 | + </styled.PatientInfoPatientNmWrapper> | ||
125 | + <styled.PatientInfoView> | ||
126 | + | ||
127 | + { | ||
128 | + props.info.patientInfo.split('\n\n').map((patientInfoText : string) => { | ||
129 | + return ( | ||
130 | + <div key = {patientInfoText}> | ||
131 | + {patientInfoText}<br/><br/> | ||
132 | + </div> | ||
133 | + ) | ||
134 | + }) | ||
135 | + } | ||
136 | + </styled.PatientInfoView> | ||
137 | + </styled.PatientInfoViewContainer> | ||
138 | + <styled.PatientInfoEditWrapper> | ||
139 | + <styled.PatientInfoEditInput | ||
140 | + value = {props.editPatientInfo} | ||
141 | + onChange = {props.onEditPatientInfo} | ||
142 | + /> | ||
143 | + </styled.PatientInfoEditWrapper> | ||
144 | + <styled.PatientInfoEditButtonWrapper> | ||
145 | + <styled.PatientInfoEditButton | ||
146 | + onClick = {props.onSubmitPatientInfo} | ||
147 | + > | ||
148 | + 확인 | ||
149 | + </styled.PatientInfoEditButton> | ||
150 | + <styled.PatientInfoEditButton | ||
151 | + onClick = {props.onCloseModal} | ||
152 | + > | ||
153 | + 취소 | ||
154 | + </styled.PatientInfoEditButton> | ||
155 | + </styled.PatientInfoEditButtonWrapper> | ||
156 | + </styled.ModalContent> | ||
157 | + </styled.ModalContentWrapper> | ||
158 | + <styled.ModalClsButtonWrapper/> | ||
159 | + </styled.ModalContainer> : null | ||
160 | + } | ||
83 | <styled.InfoAndSearchWrapper> | 161 | <styled.InfoAndSearchWrapper> |
84 | <styled.InfoWrapper> | 162 | <styled.InfoWrapper> |
85 | { | 163 | { |
... | @@ -99,8 +177,10 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { | ... | @@ -99,8 +177,10 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
99 | </styled.InfoEachWrapper> | 177 | </styled.InfoEachWrapper> |
100 | </styled.InfoSquare> : | 178 | </styled.InfoSquare> : |
101 | <styled.InfoSquare> | 179 | <styled.InfoSquare> |
102 | - <styled.EditPatientInfoButton> | 180 | + <styled.EditPatientInfoButton |
103 | - <styled.EditPatientInfoButtonImg /> | 181 | + onClick = {() => props.setEditModal(true)} |
182 | + > | ||
183 | + <styled.EditPatientInfoButtonImg src = {edit}/> | ||
104 | <styled.EditPatientInfoButtonText>수정</styled.EditPatientInfoButtonText> | 184 | <styled.EditPatientInfoButtonText>수정</styled.EditPatientInfoButtonText> |
105 | </styled.EditPatientInfoButton> | 185 | </styled.EditPatientInfoButton> |
106 | <styled.InfoEachWrapper> | 186 | <styled.InfoEachWrapper> |
... | @@ -134,7 +214,7 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { | ... | @@ -134,7 +214,7 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
134 | </styled.InfoSquare> | 214 | </styled.InfoSquare> |
135 | } | 215 | } |
136 | <styled.NewPatientButton | 216 | <styled.NewPatientButton |
137 | - onClick = {() => props.setEditModal(true)} | 217 | + onClick = {() => props.setNewPatientRegisterModal(true)} |
138 | > | 218 | > |
139 | 새 환자 등록 | 219 | 새 환자 등록 |
140 | </styled.NewPatientButton> | 220 | </styled.NewPatientButton> |
... | @@ -147,12 +227,12 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { | ... | @@ -147,12 +227,12 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { |
147 | onChange = {props.onSetKeyword} | 227 | onChange = {props.onSetKeyword} |
148 | /> | 228 | /> |
149 | <styled.SearchButton> | 229 | <styled.SearchButton> |
150 | - 검색 | 230 | + <styled.SearchButtonImg src = {lensImg}/> |
151 | </styled.SearchButton> | 231 | </styled.SearchButton> |
152 | <styled.SearchButton | 232 | <styled.SearchButton |
153 | onClick = {props.onInitialize} | 233 | onClick = {props.onInitialize} |
154 | > | 234 | > |
155 | - 초기화 | 235 | + <styled.SearchButtonImg src = {refreshing}/> |
156 | </styled.SearchButton> | 236 | </styled.SearchButton> |
157 | </styled.SearchBarWrapper> | 237 | </styled.SearchBarWrapper> |
158 | <styled.SearchResultWrapper> | 238 | <styled.SearchResultWrapper> | ... | ... |
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 | +`; | ||
25 | + | ||
2 | 26 | ||
3 | export const Container = styled.div ` | 27 | export const Container = styled.div ` |
4 | height : 100vh; | 28 | height : 100vh; |
... | @@ -17,6 +41,8 @@ export const ModalContainer = styled.div ` | ... | @@ -17,6 +41,8 @@ export const ModalContainer = styled.div ` |
17 | display : flex; | 41 | display : flex; |
18 | flex-direction : column; | 42 | flex-direction : column; |
19 | 43 | ||
44 | + animation : ${ModalOn} .5s; | ||
45 | + | ||
20 | background-color : rgba(52, 52, 52, .7); | 46 | background-color : rgba(52, 52, 52, .7); |
21 | 47 | ||
22 | `; | 48 | `; |
... | @@ -55,8 +81,8 @@ export const ModalClsButton = styled.button ` | ... | @@ -55,8 +81,8 @@ export const ModalClsButton = styled.button ` |
55 | `; | 81 | `; |
56 | 82 | ||
57 | export const ModalClsButtonImg = styled.img ` | 83 | export const ModalClsButtonImg = styled.img ` |
58 | - height : 25px; | 84 | + height : 20px; |
59 | - width : 25px; | 85 | + width : 20px; |
60 | 86 | ||
61 | margin : 0 10px 0 0; | 87 | margin : 0 10px 0 0; |
62 | `; | 88 | `; |
... | @@ -159,6 +185,35 @@ export const NewPatientSearchResultWrapper = styled.div ` | ... | @@ -159,6 +185,35 @@ export const NewPatientSearchResultWrapper = styled.div ` |
159 | 185 | ||
160 | font-size : 14px; | 186 | font-size : 14px; |
161 | color : #a0a0a0; | 187 | color : #a0a0a0; |
188 | + font-weight : 600; | ||
189 | +`; | ||
190 | + | ||
191 | +export const NewPatientSearchResult = styled.div ` | ||
192 | + border : none; | ||
193 | + | ||
194 | + display : flex; | ||
195 | + flex-direction : row; | ||
196 | + justify-content : center; | ||
197 | + align-items : center; | ||
198 | +`; | ||
199 | + | ||
200 | +export const NewPatientSearchResultInfoWrapper = styled.div ` | ||
201 | + display : flex; | ||
202 | +`; | ||
203 | + | ||
204 | +export const NewPatientSearchResultInfo = styled.div ` | ||
205 | + font-size : 13px; | ||
206 | + font-weight : 600; | ||
207 | + color : #a0a0a0; | ||
208 | + | ||
209 | + margin : 0 5px 0 0; | ||
210 | +`; | ||
211 | + | ||
212 | +export const NewPatientSearchResultInfoText = styled.div ` | ||
213 | + font-size : 14px; | ||
214 | + color : #343434; | ||
215 | + font-weight : 600; | ||
216 | + letter-spacing : 1px; | ||
162 | `; | 217 | `; |
163 | 218 | ||
164 | export const NewPatientRegisterButtonWrapper = styled.div ` | 219 | export const NewPatientRegisterButtonWrapper = styled.div ` |
... | @@ -195,6 +250,130 @@ export const NewPatientRegisterButton = styled.button ` | ... | @@ -195,6 +250,130 @@ export const NewPatientRegisterButton = styled.button ` |
195 | `; | 250 | `; |
196 | 251 | ||
197 | 252 | ||
253 | +export const PatientInfoViewContainer = styled.div ` | ||
254 | + overflow : scroll; | ||
255 | + flex : 6; | ||
256 | + | ||
257 | + border : none; | ||
258 | + width : 100%; | ||
259 | + | ||
260 | + display : flex; | ||
261 | + flex-direction : column; | ||
262 | + | ||
263 | + &::-webkit-scrollbar { | ||
264 | + width : 3px; | ||
265 | + background-color : transparent; | ||
266 | + height : 1px; | ||
267 | + } | ||
268 | + | ||
269 | + &::-webkit-scrollbar-thumb { | ||
270 | + background-color : #337DFF; | ||
271 | + } | ||
272 | +`; | ||
273 | + | ||
274 | +export const PatientInfoPatientNmWrapper = styled.div ` | ||
275 | + display : flex; | ||
276 | + flex-direction : row; | ||
277 | + | ||
278 | + justify-content : center; | ||
279 | + align-items : center; | ||
280 | + | ||
281 | + width : 100%; | ||
282 | + | ||
283 | + padding : 15px 0; | ||
284 | + | ||
285 | + border : none; | ||
286 | + border-bottom : 1px solid #ddd; | ||
287 | + | ||
288 | +`; | ||
289 | + | ||
290 | +export const PatientInfoPatientNmInfo = styled.div ` | ||
291 | + font-size : 15px; | ||
292 | + font-weight : 500; | ||
293 | + margin : 0 5px; | ||
294 | +`; | ||
295 | + | ||
296 | +export const PatientInfoPatientNm = styled.div ` | ||
297 | + font-size : 20px; | ||
298 | + font-weight : 700; | ||
299 | + margin : 0 5px; | ||
300 | + letter-spacing : 1px; | ||
301 | + | ||
302 | + color : #337DFF; | ||
303 | +`; | ||
304 | + | ||
305 | +export const PatientInfoView = styled.div ` | ||
306 | + padding : 15px 15px; | ||
307 | + | ||
308 | + font-size : 15px; | ||
309 | + font-weight : 500; | ||
310 | + letter-spacing : 1px; | ||
311 | + | ||
312 | +`; | ||
313 | + | ||
314 | +export const PatientInfoEditWrapper = styled.div ` | ||
315 | + flex : 3; | ||
316 | + | ||
317 | + border : none; | ||
318 | + width : 100%; | ||
319 | + | ||
320 | + display : flex; | ||
321 | + justify-content : center; | ||
322 | + align-items : center; | ||
323 | + | ||
324 | +`; | ||
325 | + | ||
326 | +export const PatientInfoEditInput = styled.textarea ` | ||
327 | + width : 100%; | ||
328 | + | ||
329 | + resize : none; | ||
330 | + | ||
331 | + padding : 15px; | ||
332 | + margin : 15px; | ||
333 | + border : 1px solid #ddd; | ||
334 | +`; | ||
335 | + | ||
336 | +export const PatientInfoEditButtonWrapper = styled.div ` | ||
337 | + flex : 2; | ||
338 | + | ||
339 | + border : none; | ||
340 | + width : 100%; | ||
341 | + | ||
342 | + display : flex; | ||
343 | + flex-direction : row; | ||
344 | + | ||
345 | + justify-content : center; | ||
346 | + align-items : center; | ||
347 | + | ||
348 | + gap : 8%; | ||
349 | + | ||
350 | +`; | ||
351 | + | ||
352 | +export const PatientInfoEditButton = styled.button ` | ||
353 | + background-color : #fff; | ||
354 | + color : #337DFF; | ||
355 | + border : 1px solid #337DFF; | ||
356 | + border-radius : 3px; | ||
357 | + | ||
358 | + cursor : pointer; | ||
359 | + | ||
360 | + transition : .25s all; | ||
361 | + | ||
362 | + font-size : 16px; | ||
363 | + font-weight : 600; | ||
364 | + | ||
365 | + padding : 10px 30px; | ||
366 | + margin : 0 10px; | ||
367 | + | ||
368 | + &:hover { | ||
369 | + background-color : #337DFF; | ||
370 | + color : #fff; | ||
371 | + border : 1px solid transparent; | ||
372 | + } | ||
373 | +`; | ||
374 | + | ||
375 | + | ||
376 | + | ||
198 | export const InfoAndSearchWrapper = styled.div ` | 377 | export const InfoAndSearchWrapper = styled.div ` |
199 | flex : 3; | 378 | flex : 3; |
200 | display : flex; | 379 | display : flex; |
... | @@ -369,8 +548,10 @@ export const SearchBar = styled.input ` | ... | @@ -369,8 +548,10 @@ export const SearchBar = styled.input ` |
369 | 548 | ||
370 | export const SearchButton = styled.button ` | 549 | export const SearchButton = styled.button ` |
371 | border : 1px solid #ddd; | 550 | border : 1px solid #ddd; |
551 | + border-radius : 3px; | ||
372 | 552 | ||
373 | background-color : transparent; | 553 | background-color : transparent; |
554 | + opacity : .7; | ||
374 | 555 | ||
375 | height : 50px; | 556 | height : 50px; |
376 | width : 50px; | 557 | width : 50px; |
... | @@ -379,12 +560,20 @@ export const SearchButton = styled.button ` | ... | @@ -379,12 +560,20 @@ export const SearchButton = styled.button ` |
379 | 560 | ||
380 | cursor : pointer; | 561 | cursor : pointer; |
381 | 562 | ||
563 | + display : flex; | ||
564 | + justify-content : center; | ||
565 | + align-items : center; | ||
566 | + | ||
382 | &:hover { | 567 | &:hover { |
383 | - color : #fff; | 568 | + opacity : 1; |
384 | - background-color : #343434; | ||
385 | } | 569 | } |
386 | `; | 570 | `; |
387 | 571 | ||
572 | +export const SearchButtonImg = styled.img ` | ||
573 | + height : 20px; | ||
574 | + width : 20px; | ||
575 | +`; | ||
576 | + | ||
388 | export const SearchResultWrapper = styled.div ` | 577 | export const SearchResultWrapper = styled.div ` |
389 | flex : 5; | 578 | flex : 5; |
390 | border : 1px solid #ddd; | 579 | border : 1px solid #ddd; | ... | ... |
1 | import React, { useState, useEffect } from "react"; | 1 | import React, { useState, useEffect } from "react"; |
2 | import { RouteComponentProps } from 'react-router-dom'; | 2 | import { RouteComponentProps } from 'react-router-dom'; |
3 | 3 | ||
4 | -import { useRecoilValue } from "recoil"; | 4 | +import { useRecoilValue, useRecoilState } from "recoil"; |
5 | import * as recoilUtil from '../../util/recoilUtil'; | 5 | import * as recoilUtil from '../../util/recoilUtil'; |
6 | 6 | ||
7 | +import Header from '../../components/Header'; | ||
7 | import RegisterPresenter from "./RegisterPresenter"; | 8 | import RegisterPresenter from "./RegisterPresenter"; |
8 | 9 | ||
9 | -type RegisterProps = RouteComponentProps; | 10 | +import { authApi } from '../../api'; |
11 | + | ||
12 | + | ||
13 | +// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
14 | +interface RegisterProps extends RouteComponentProps {} | ||
10 | 15 | ||
11 | const RegisterContainer = (props : RegisterProps) => { | 16 | const RegisterContainer = (props : RegisterProps) => { |
17 | + | ||
18 | + const [token, setToken] = useRecoilState(recoilUtil.token); | ||
19 | + | ||
20 | + const fetchData = async() => { | ||
21 | + if(token && token.length) { | ||
22 | + const result = await authApi.verifyToken(token); | ||
23 | + if (result.statusText === 'OK') { | ||
24 | + props.history.push('/'); | ||
25 | + } | ||
26 | + } | ||
27 | + }; | ||
28 | + | ||
29 | + useEffect(() => { | ||
30 | + fetchData(); | ||
31 | + }, []); | ||
32 | + | ||
33 | + | ||
12 | return ( | 34 | return ( |
35 | + <> | ||
36 | + <Header {...props}/> | ||
13 | <RegisterPresenter | 37 | <RegisterPresenter |
14 | 38 | ||
15 | /> | 39 | /> |
40 | + </> | ||
16 | ) | 41 | ) |
17 | }; | 42 | }; |
18 | 43 | ... | ... |
... | @@ -9,7 +9,7 @@ const RegisterPresenter = () => { | ... | @@ -9,7 +9,7 @@ const RegisterPresenter = () => { |
9 | <styled.RegisterWrapper> | 9 | <styled.RegisterWrapper> |
10 | <styled.RegisterTitle>회원 가입</styled.RegisterTitle> | 10 | <styled.RegisterTitle>회원 가입</styled.RegisterTitle> |
11 | <styled.RegisterInfo>* 의사만 회원가입이 가능합니다.</styled.RegisterInfo> | 11 | <styled.RegisterInfo>* 의사만 회원가입이 가능합니다.</styled.RegisterInfo> |
12 | - <styled.RegisterInfo style = {{fontSize : 10,}}>의사 인증을 위한 정보가 요구됩니다.</styled.RegisterInfo> | 12 | + <styled.RegisterInfo style = {{fontSize : 10,}}>의사 인증을 위한 정보가 요구됩니다. 해당 정보는 인증을 위한 용도로만 사용됩니다.</styled.RegisterInfo> |
13 | <styled.RegisterInputWrapper> | 13 | <styled.RegisterInputWrapper> |
14 | <styled.RegisterInputText>이메일</styled.RegisterInputText> | 14 | <styled.RegisterInputText>이메일</styled.RegisterInputText> |
15 | <styled.RegisterInput | 15 | <styled.RegisterInput | ... | ... |
... | @@ -35,7 +35,7 @@ export const RegisterTitle = styled.div ` | ... | @@ -35,7 +35,7 @@ export const RegisterTitle = styled.div ` |
35 | 35 | ||
36 | export const RegisterInfo = styled.div ` | 36 | export const RegisterInfo = styled.div ` |
37 | width : 90%; | 37 | width : 90%; |
38 | - font-size : 12px; | 38 | + font-size : 13px; |
39 | color : #a0a0a0; | 39 | color : #a0a0a0; |
40 | `; | 40 | `; |
41 | 41 | ... | ... |
This diff could not be displayed because it is too large.
-
Please register or login to post a comment