박권수

feat. bottle view -> medicine Modal, User Feedback, User Register and Header button, etc...

......@@ -13,6 +13,7 @@
"axios": "^0.21.1",
"highcharts": "^9.2.0",
"highcharts-react-official": "^3.0.0",
"moment": "^2.29.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
......@@ -20,6 +21,7 @@
"recoil": "^0.4.0",
"recoil-persist": "^3.0.0",
"styled-components": "^5.3.0",
"sweetalert2": "^11.1.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
......
......@@ -16,4 +16,11 @@ export default {
logout : () => {
return client.post('/auth/logout');
},
verifyToken : (token : any) => {
return client.get('/auth/verifytoken', {
headers : {
Authorization : token,
},
});
},
};
\ No newline at end of file
......
......@@ -7,18 +7,4 @@ export const client : AxiosInstance = axios.create({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
client.interceptors.request.use(
);
client.interceptors.response.use(
function (response) {
return response;
},
function (error) {
console.log(error.message);
return error;
}
);
});
\ No newline at end of file
......
......@@ -14,7 +14,33 @@ export const Container = styled.div `
align-items : center;
`;
export const HeaderWrapper = styled.div `
export const HeaderLeftWrapper = styled.div `
flex : 1;
display : flex;
flex-direction : row;
justify-content : flex-start;
align-items : center;
border : none;
margin : 0 30px;
`;
export const HeaderRightWrapper = styled.div `
flex : 1;
display : flex;
flex-direction : row;
justify-content : flex-end;
align-items : center;
border : none;
margin : 0 30px;
`;
export const HeaderCenterWrapper = styled.div `
flex : 3;
display : flex;
flex-direction : row;
justify-content : center;
......@@ -31,8 +57,69 @@ export const TitleImg = styled.img `
`;
export const Title = styled.div `
flex : 1;
text-align : center;
font-size : 17px;
font-weight : 800;
`;
export const Backbutton = styled.button `
border : 1px solid #337DFF;
border-radius : 5px;
background-color : transparent;
color : #337DFF;
padding : 4px 17px;
transition : .25s all;
display : flex;
flex-direction : row;
justify-content : center;
cursor : pointer;
&:hover {
opacity : .5;
}
`;
export const BackbuttonImg = styled.img `
height : 14px;
width : 14px;
margin : 0 6px 0 0;
`;
export const BackbuttonText = styled.div `
font-size : 15px;
font-weight : 700;
letter-spacing : 1px;
`;
export const LogoutButton = styled.button `
display : flex;
justify-content : center;
// align-items : center;
background-color : transparent;
border : none;
border-bottom : 1px solid #a0a0a0;
padding : 0 4px 4px 4px;
cursor : pointer;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const LogoutButtonImg = styled.img `
height : 15px;
width : 15px;
margin : 0 4px 0 0;
`;
export const LogoutButtonText = styled.div `
color : #a0a0a0;
font-size : 13px;
letter-spacing : 1px;
`;
\ No newline at end of file
......
import React from 'react';
import React, { useEffect } from 'react';
import { RouteComponentProps } from 'react-router';
import { useRecoilState } from 'recoil';
import * as recoilUtil from '../../util/recoilUtil';
import * as Alert from '../../util/alertMessage';
import * as styled from './HeaderStyled';
import { authApi } from '../../api';
const headerImg = '/static/img/pharmacy.png';
const backButtonWhite = '/static/img/backButtonWhite.png';
const backButtonBlue = '/static/img/backButtonBlue.png';
const logout = '/static/img/logout.png';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface HeaderProps extends RouteComponentProps {}
const Header = (props : HeaderProps) => {
const [token, setToken] = useRecoilState(recoilUtil.token);
const onLogout = () => {
const logout = async () => {
try {
await authApi.logout();
setToken(null);
Alert.onSuccess('로그인 페이지로 이동합니다.', () => props.history.push('/login'));
} catch(e) {
Alert.onError('알 수 없는 에러가 발생했습니다.', () => props.history.push('/'));
}
};
Alert.onCheck('정말 로그아웃 하시겠습니까?', logout, () => null);
};
const verifyToken = async () => {
try {
const result = await authApi.verifyToken(token);
if(result.statusText !== 'OK') {
setToken(null);
Alert.onError('세션이 만료되었습니다. 다시 로그인하세요.', () => props.history.push('/login'));
}
} catch(e) {
console.log(e);
setToken(null);
Alert.onError('세션이 만료되었습니다. 다시 로그인하세요.', () => props.history.push('/login'));
}
};
const onGoBack = () => {
props.history.goBack();
};
useEffect(() => {
verifyToken();
}, []);
const Header = () => {
return (
<styled.Container>
<styled.HeaderWrapper>
<styled.HeaderLeftWrapper>
{
(token && token.length && props.location.pathname !== '/') || props.location.pathname === '/register' ?
<styled.Backbutton
onClick = {onGoBack}
>
<styled.BackbuttonImg src = {backButtonBlue}/>
<styled.BackbuttonText>뒤로 가기</styled.BackbuttonText>
</styled.Backbutton> : null
}
</styled.HeaderLeftWrapper>
<styled.HeaderCenterWrapper>
<styled.TitleImg src = {headerImg} />
<styled.Title>내 손 안의 주치의</styled.Title>
</styled.HeaderWrapper>
</styled.HeaderCenterWrapper>
<styled.HeaderRightWrapper>
{
token && token.length ?
<styled.LogoutButton
onClick = {onLogout}
>
<styled.LogoutButtonImg src = {logout}/>
<styled.LogoutButtonText>로그아웃</styled.LogoutButtonText>
</styled.LogoutButton> : null
}
</styled.HeaderRightWrapper>
</styled.Container>
)
};
......
import React, { useEffect } from 'react';
import * as recoilUtil from '../../util/recoilUtil';
import { useRecoilState } from 'recoil';
import * as styled from './ErrorStyled';
const ErrorContainer = () => {
const [error, setError] = useRecoilState(recoilUtil.error);
useEffect(() => {
console.log(error);
}, [error]);
return (
<>
{
error ?
<styled.Container>
{error}
</styled.Container> : null
}
</>
<styled.Container>
</styled.Container>
);
};
export default ErrorContainer;
export default ErrorContainer;
\ No newline at end of file
......
import Swal from "sweetalert2";
export const onError = (text : string, confirmAction : () => void) => {
Swal.fire({
title : '오류 발생',
icon : 'error',
text,
confirmButtonText : '확인',
confirmButtonColor : '#337DFF'
}).then((res) => {
if(res.isConfirmed) {
confirmAction();
}
});
};
export const onSuccess = (text : string, successAction : () => void) => {
Swal.fire({
title : '성공',
icon : 'success',
text,
showConfirmButton : false,
timer : 1500,
}).then(res => {
successAction();
});
};
export const onCheck = (text : string, confirmAction : () => void, denyAction : () => void) => {
Swal.fire({
title : '확인',
icon : 'question',
text,
confirmButtonText : '확인',
confirmButtonColor : '#337DFF',
showDenyButton : true,
denyButtonText : '취소',
denyButtonColor : '#343434',
}).then(res => {
if(res.isConfirmed) {
confirmAction();
} else if(res.isDenied) {
denyAction();
}
});
}
\ No newline at end of file
import moment from 'moment';
export const make = (chartData : any[], numberOfRow : number) => {
const now = new Date();
const result : any = {};
new Array(numberOfRow).fill(null).forEach((item : any, index : number) => {
const key = moment(now).format('MM/DD');
result[key] = 0;
now.setDate(now.getDate() - 1);
})
chartData.forEach((data : any) => {
const key : string = moment(data.takeDate).format('MM/DD');
result[key] = result[key] + 1;
});
const categories : any = [];
const data : any = [];
Object.entries(result).forEach((item : any) => {
categories.push(item[0]);
data.push(item[1]);
});
categories.reverse();
data.reverse();
return {
categories,
data,
}
};
\ No newline at end of file
......@@ -13,10 +13,4 @@ export const userTypeCd = atom({
key : 'userTypeCd',
default : 'NORMAL',
effects_UNSTABLE : [persistAtom],
});
export const error = atom({
key : 'error',
default : null,
effects_UNSTABLE : [persistAtom],
})
\ No newline at end of file
});
\ No newline at end of file
......
import React from "react";
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import Error from '../components/error';
import Header from '../components/Header';
import { LoginContainer } from "./login";
import { RegisterContainer } from './register';
import { MainContainer } from "./main";
......@@ -13,12 +12,12 @@ const Router = () => {
return (
<BrowserRouter>
<Error />
<Header />
<Switch>
<Route exact path = '/' component = {MainContainer}/>
<Route exact path = '/login' component = {LoginContainer}/>
<Route exact path = '/register' component = {RegisterContainer}/>
<Route exact path = '/bottle' component = {BottleInfoContainer}/>
<Route exact path = '/bottle/:bottleId' component = {BottleInfoContainer}/>
<Redirect path = '*' to = '/'/>
</Switch>
</BrowserRouter>
)
......
import React, { useState, useEffect } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import * as recoilUtil from '../../util/recoilUtil';
import * as makeChart from '../../util/makeChart';
import * as Alert from '../../util/alertMessage';
import HighCharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import moment from 'moment';
import Header from '../../components/Header';
import BottleInfoPresenter from './BottleInfoPresenter';
import { doctorApi } from '../../api';
type BottleInfoProps = RouteComponentProps
interface RouteParmas {
bottleId : string;
}
type BottleInfoProps = RouteComponentProps<RouteParmas>
const BottleInfoContainer = (props : BottleInfoProps) => {
const { bottleId } = props.match.params;
const token = useRecoilValue(recoilUtil.token);
const userTypeCd = useRecoilValue(recoilUtil.userTypeCd);
const [bottleInfo, setBottleInfo] = useState<any>({
feedbackList : [],
medicine : {},
bottleId : 0,
takeMedicineHist : [],
});
const numberOfChartItem = 7;
const [chartOption, setChartOption] = useState<any>({
chart : {
type : 'line',
height : 300,
width : 450,
},
title : {
text : '',
style : { 'color' : '#343434', 'fontSize' : '15px', 'fontWeight' : '700' },
margin : 10,
},
xAxis : {
categories : [],
},
series : [{
name : '약 복용 횟수',
color : '#337DFF',
data : [],
}],
});
const [feedback, setFeedback] = useState<string>('');
const [fdbType, setFdbType] = useState<string>('RECOMMEND');
const [medicineInfoModal, setMedicineInfoModal] = useState<boolean>(false);
const fetchData = async () => {
setFeedback('');
setFdbType('RECOMMEND');
setMedicineInfoModal(false);
try {
const result = await doctorApi.getPatientBottleDetail(token, bottleId);
if (result.statusText === 'OK') {
const { categories, data } = makeChart.make(result.data.takeMedicineHist, numberOfChartItem);
setBottleInfo({
...result.data,
feedbackList : result.data.feedbackList.map((feedback : any) => {
return {
...feedback,
fdbDtm : moment(feedback.fdbDtm).format('YYYY-MM-DD hh:mm'),
}
}),
});
setChartOption({
...chartOption,
title : {
text : result.data.medicine.name,
},
xAxis : {
categories,
},
series : [{
data,
}]
});
} else {
Alert.onError('접근 권한이 없습니다.', () => props.history.push('/'));
}
} catch(e) {
Alert.onError(e.response.data.error, () => props.history.push('/'));
console.log(e);
}
};
const onSetFeedback = (e : React.ChangeEvent<HTMLTextAreaElement>) => {
setFeedback(e.target.value);
};
const onSubmitFeedback = () => {
const register = async () => {
if(feedback.length) {
try {
const res = await doctorApi.writeBottleFeedback(token, {
bottleId,
fdbType,
feedback
});
if(res.statusText === 'OK') {
Alert.onSuccess('피드백이 등록되었습니다.', () => fetchData());
} else {
console.log(res);
Alert.onError('피드백 등록에 실패했습니다.', () => null);
}
} catch(e) {
Alert.onError(e.response.data.error, () => fetchData());
}
} else {
Alert.onError('피드백 내용을 입력하세요.', () => null);
}
}
Alert.onCheck('피드백을 등록하시겠습니까?', register, () => null);
};
useEffect(() => {
if(userTypeCd !== 'DOCTOR') {
props.history.push('/');
Alert.onError('접근 권한이 없습니다.', () => props.history.push('/'));
}
fetchData();
}, [userTypeCd]);
return (
<>
<Header {...props} />
<BottleInfoPresenter
bottleInfo = {bottleInfo}
chartOption = {chartOption}
medicineInfoModal = {medicineInfoModal}
setMedicineInfoModal = {setMedicineInfoModal}
feedback = {feedback}
onSetFeedback = {onSetFeedback}
fdbType = {fdbType}
setFdbType = {setFdbType}
onSubmitFeedback = {onSubmitFeedback}
/>
</>
);
};
......
import React from 'react';
import HighCharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import * as styled from './BottleInfoStyled';
const plus = '/static/img/plus.png';
const closeButton = '/static/img/close.png';
const BottleInfoPresenter = () => {
interface BottleInfoProps {
bottleInfo : {
feedbackList : any[];
medicine : any;
bottleId : number;
takeMedicineHist : any[];
};
chartOption : any;
medicineInfoModal : boolean;
setMedicineInfoModal : (arg0 : boolean) => void;
feedback : string;
onSetFeedback : React.ChangeEventHandler<HTMLTextAreaElement>;
fdbType : string;
setFdbType : (arg0 : string) => void;
onSubmitFeedback : () => void;
}
const BottleInfoPresenter = (props : BottleInfoProps) => {
return (
<styled.Container>
{
props.medicineInfoModal ?
<styled.ModalContainer>
<styled.ModalClsButtonWrapper>
<styled.ModalClsButton
onClick = {() => props.setMedicineInfoModal(false)}
>
<styled.ModalClsButtonImg src = {closeButton}/>
<styled.ModalClsButtonText>닫기</styled.ModalClsButtonText>
</styled.ModalClsButton>
</styled.ModalClsButtonWrapper>
<styled.ModalContentWrapper>
<styled.ModalContent>
<styled.MedicineNameWrapper>
<styled.MedicineName>{props.bottleInfo.medicine.name}</styled.MedicineName>
<styled.MedicineName style = {{color : '#343434', fontSize : 15, marginTop : 4,}}>{props.bottleInfo.medicine.company}</styled.MedicineName>
</styled.MedicineNameWrapper>
<styled.MedicineInfoWrapper>
<styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoTitle>효능</styled.MedicineEachInfoTitle>
<styled.MedicineEachInfo>{props.bottleInfo.medicine.target}</styled.MedicineEachInfo>
</styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoTitle>복용 정보</styled.MedicineEachInfoTitle>
<styled.MedicineEachInfo>{props.bottleInfo.medicine.dosage}</styled.MedicineEachInfo>
</styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoTitle style = {{color : '#FF3F3F', fontWeight : 'bold'}}>주의 사항</styled.MedicineEachInfoTitle>
<styled.MedicineEachInfo style = {{color : '#9B0000'}}>{props.bottleInfo.medicine.warn}</styled.MedicineEachInfo>
</styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoWrapper>
<styled.MedicineEachInfoTitle style = {{color : '#FF3F3F', fontWeight : 'bold'}}>부작용</styled.MedicineEachInfoTitle>
<styled.MedicineEachInfo style = {{color : '#9B0000'}}>{props.bottleInfo.medicine.antiEffect}</styled.MedicineEachInfo>
</styled.MedicineEachInfoWrapper>
</styled.MedicineInfoWrapper>
</styled.ModalContent>
</styled.ModalContentWrapper>
</styled.ModalContainer> : null
}
<styled.ChartAndFeedbackWrapper>
<styled.ChartWrapper>
<styled.MedicineDetailViewButtonWrapper>
<styled.MedicineDetailViewButton
onClick = {() => props.setMedicineInfoModal(true)}
>
<styled.MedicineDetailViewButtonImg src = {plus}/>
</styled.MedicineDetailViewButton>
</styled.MedicineDetailViewButtonWrapper>
<HighchartsReact
highCharts = {HighCharts}
options = {props.chartOption}
/>
</styled.ChartWrapper>
<styled.FeedbackWrapper>
<styled.FeedbackInfoTitle>피드백 내역</styled.FeedbackInfoTitle>
{
props.bottleInfo.feedbackList.map((feedback : any) => {
return (
<styled.FeedbackEachItemWrapper
key = {feedback._id}
>
<styled.FeedbackType fdbType = {feedback.fdbType}/>
<styled.FeedbackTitle>{feedback.feedback}</styled.FeedbackTitle>
<styled.FeedbackDtm>등록일<br/>{feedback.fdbDtm}</styled.FeedbackDtm>
</styled.FeedbackEachItemWrapper>
)
})
}
</styled.FeedbackWrapper>
</styled.ChartAndFeedbackWrapper>
<styled.NewFeedbackRegWrapper>
<styled.NewFeedbackRegInput
value = {props.feedback}
onChange = {props.onSetFeedback}
/>
<styled.NewFeedbackButtonWrapper>
<styled.NewFeedbackTypeButtonWrapper>
<styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButton
valueType = 'RECOMMEND'
selected = {props.fdbType === 'RECOMMEND'}
onClick = {() => props.setFdbType('RECOMMEND')}
/>
<styled.NewFeedbackTypeButtonText>권고</styled.NewFeedbackTypeButtonText>
</styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButton
valueType = 'CAUTION'
selected = {props.fdbType === 'CAUTION'}
onClick = {() => props.setFdbType('CAUTION')}
/>
<styled.NewFeedbackTypeButtonText>주의</styled.NewFeedbackTypeButtonText>
</styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButton
valueType = 'WARN'
selected = {props.fdbType === 'WARN'}
onClick = {() => props.setFdbType('WARN')}
/>
<styled.NewFeedbackTypeButtonText>경고</styled.NewFeedbackTypeButtonText>
</styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButtonEachWrapper>
<styled.NewFeedbackTypeButton
valueType = 'CRITICAL'
selected = {props.fdbType === 'CRITICAL'}
onClick = {() => props.setFdbType('CRITICAL')}
/>
<styled.NewFeedbackTypeButtonText>치명</styled.NewFeedbackTypeButtonText>
</styled.NewFeedbackTypeButtonEachWrapper>
</styled.NewFeedbackTypeButtonWrapper>
<styled.NewFeedbackRegButton
onClick = {props.onSubmitFeedback}
>
{/* <styled.NewFeedbackRegButtonImg /> */}
<styled.NewFeedbackRegButtonText>피드백<br/>등록</styled.NewFeedbackRegButtonText>
</styled.NewFeedbackRegButton>
</styled.NewFeedbackButtonWrapper>
</styled.NewFeedbackRegWrapper>
</styled.Container>
);
};
......
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';
const ModalOn = keyframes `
0% {
background-color : rgba(52, 52, 52, .0);
}
20% {
background-color : rgba(52, 52, 52, .2);
}
40% {
background-color : rgba(52, 52, 52, .4);
}
60% {
background-color : rgba(52, 52, 52, .5);
}
80% {
background-color : rgba(52, 52, 52, .6);
}
100% {
background-color : rgba(52, 52, 52, .7);
}
`;
export const Container = styled.div `
height : 100vh;
width : 100%;
display : flex;
flex-direction : column;
justify-content : center;
`;
export const ModalContainer = styled.div `
height : 100%;
width : 100%;
z-index : 99;
position : absolute;
display : flex;
flex-direction : column;
animation : ${ModalOn} .5s;
background-color : rgba(52, 52, 52, .7);
`;
export const ModalClsButtonWrapper = styled.div `
flex : 1;
display : flex;
justify-content : flex-end;
align-items : center;
padding : 0 20px;
border : none;
background-color : transprent;
`;
export const ModalClsButton = styled.button `
border : none;
background-color : transparent;
cursor : pointer;
color : #fff;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const ModalClsButtonImg = styled.img `
height : 20px;
width : 20px;
margin : 0 10px 0 0;
`;
export const ModalClsButtonText = styled.div `
font-size : 18px;
font-weight : 700;
`;
export const ModalContentWrapper = styled.div `
flex : 8;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
border : none;
`;
export const ModalContent = styled.div `
width : 700px;
height : 500px;
background-color : #fff;
border : 1.2px solid #337DFF;
border-radius : 5px;
display : flex;
flex-direction : column;
// justify-content : center;
align-items : center;
`;
export const MedicineNameWrapper = styled.div `
flex : 1
border : none;
border-bottom : 1px solid #ddd;
width : 100%;
padding : 4% 0;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
`;
export const MedicineName = styled.div `
font-size : 20px;
font-weight : 700;
letter-spacing : 1px;
color : #337DFF;
`;
export const MedicineInfoWrapper = styled.div `
flex : 9;
width : 100%;
overflow : scroll;
border : 1px solid;
display : flex;
flex-direction : column;
align-items : center;
padding : 0 0 0 3px;
&::-webkit-scrollbar {
width : 3px;
background-color : transparent;
height : 0px;
}
&::-webkit-scrollbar-thumb {
background-color : #337DFF;
}
`;
export const MedicineEachInfoWrapper = styled.div `
display : flex;
flex-direction : column;
width : 80%;
padding : 20px 10%;
border : none;
border-bottom : 1px solid #ddd;
`;
export const MedicineEachInfoTitle = styled.div `
font-size : 14px;
font-weight : 500;
color : #337DFF;
margin : 0 0 5px 0;
`;
export const MedicineEachInfo = styled.div `
font-size : 16px;
letter-spacing : 1px;
`;
export const ChartAndFeedbackWrapper = styled.div `
flex : 3;
display : flex;
flex-direction : row;
justify-content : space-around;
`;
export const ChartWrapper = styled.div `
border : 1px solid transparent;
padding : 10px;
border-radius : 4px;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
box-shadow: 0px 0px 10px #a0a0a0;
`;
export const MedicineDetailViewButtonWrapper = styled.div `
border : none;
width : 100%;
display : flex;
flex-direction : row;
justify-content : flex-end;
align-items : center;
`;
export const MedicineDetailViewButton = styled.button `
height : 25px;
width : 25px;
display : flex;
justify-content : center;
align-items : center;
background-color : transparent;
border : 1px solid #ddd;
border-radius : 3px;
cursor : pointer;
box-shadow: 0px 0px 3px 0 #a0a0a0;
opacity : .7;
&:hover {
opacity : 1;
}
`;
export const MedicineDetailViewButtonImg = styled.img `
height : 15px;
width : 15px;
`;
export const FeedbackWrapper = styled.div `
overflow : scroll;
border : 1px solid transparent;
width : 500px;
max-height : 420px;
border-radius : 4px;
box-shadow: 0px 0px 10px #a0a0a0;
display : flex;
flex-direction : column;
align-items : center;
padding : 0 0 0 3px;
&::-webkit-scrollbar {
width : 3px;
background-color : transparent;
height : 0px;
}
&::-webkit-scrollbar-thumb {
background-color : #337DFF;
}
`;
export const FeedbackInfoTitle = styled.div `
width : 100%;
text-align : center;
border : none;
border-bottom : 2px solid #ddd;
padding : 10px 0;
font-size : 17px;
font-weight : 600;
background-color : transparent;
`;
export const FeedbackEachItemWrapper = styled.div `
width : 100%;
padding : 10px 0;
border : none;
border-bottom : 1px solid #ddd;
background-color : transparent;
display : flex;
flex-direction : row;
align-items : center;
`;
export const FeedbackType = styled.div<{fdbType : string}> `
margin : 0 0 0 10px;
border : none;
border-radius : 100px;
height : 12px;
width : 12px;
background-color : ${props =>
props.fdbType === 'RECOMMEND' ? '#337DFF'
: props.fdbType === 'CAUTION' ? '#FFE77B'
: props.fdbType === 'WARN' ? '#FF8941'
: props.fdbType === 'CRITICAL' ? '#E40000' : 'transparent'
};
`;
export const FeedbackTitle = styled.div `
flex : 7;
height : 100%;
padding : 0 10px;
display : flex;
flex-direction : row;
align-items : center;
font-size : 12px;
font-weight : 500;
`;
export const FeedbackDtm = styled.div `
flex : 2;
height : 100%;
padding : 0 10px;
display : flex;
flex-direction : row;
align-items : center;
border : none;
border-left : 1px solid #ddd;
font-size : 10px;
font-weight : 400;
`;
export const NewFeedbackRegWrapper = styled.div `
margin : 20px 10px;
flex : 2;
display : flex;
flex-direction : row;
justify-content : center;
padding : 20px;
border : 1px solid transparent;
border-radius : 4px;
box-shadow: 0px 0px 10px #a0a0a0;
`;
export const NewFeedbackRegInput = styled.textarea `
resize : none;
flex : 10;
padding : 30px;
font-size : 14px;
border : 1px solid #a0a0a0;
border-radius : 4px;
`;
export const NewFeedbackButtonWrapper = styled.div `
flex : 2;
border : none;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
gap : 2%;
`;
export const NewFeedbackTypeButtonWrapper = styled.div `
flex : 5;
display : flex;
flex-direction : column;
border : none;
width : 70%;
`;
export const NewFeedbackTypeButtonEachWrapper = styled.div `
flex : 1;
display : flex;
flex-direction : row;
justify-content : flex-start;
align-items : center;
width : 100%;
padding : 10% 0;
border : none;
`;
export const NewFeedbackTypeButton = styled.button<{valueType : string, selected : boolean}> `
height : 15px;
width : 15px;
border : 1px solid #ddd;
border-radius : 3px;
background-color : ${props =>
props.selected && props.valueType === 'RECOMMEND' ? '#337DFF'
: props.selected && props.valueType === 'CAUTION' ? '#FFE77B'
: props.selected && props.valueType === 'WARN' ? '#FF8941'
: props.selected && props.valueType === 'CRITICAL' ? '#E40000' : 'transparent'
};
display : flex;
justify-content : center;
align-items : center;
cursor : pointer;
margin : 0 5% 0 0;
transition : .25s all;
&:hover {
background-color : ${props =>
props.valueType === 'RECOMMEND' ? '#337DFF'
: props.valueType === 'CAUTION' ? '#FFE77B'
: props.valueType === 'WARN' ? '#FF8941'
: props.valueType === 'CRITICAL' ? '#E40000' : 'transparent'
};
}
`
export const NewFeedbackTypeButtonText = styled.div `
font-size : 12px;
font-weight : 500;
letter-spacing : 1px;
`;
export const NewFeedbackRegButton = styled.button `
flex : 2;
width : 70%;
cursor : pointer;
border : 1px solid transparent;
border-radius : 4px;
background-color : #343434;
color : #fff;
transition : .25s all;
&:hover {
background-color : transparent;
border : 1px solid #343434;
color : #343434;
}
`;
export const NewFeedbackRegButtonText = styled.div `
font-size : 15px;
letter-spacing : 1px;
font-weight : 600;
font-color : #fff
`;
export const NewFeedbackRegButtonImg = styled.img `
`;
\ No newline at end of file
......
......@@ -4,12 +4,16 @@ import { RouteComponentProps } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import * as recoilUtil from '../../util/recoilUtil';
import * as Alert from '../../util/alertMessage';
import Header from '../../components/Header';
import LoginPresenter from './LoginPresenter';
import { authApi } from '../../api';
type LoginProps = RouteComponentProps
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface LoginProps extends RouteComponentProps {}
const LoginContainer = (props : LoginProps) => {
......@@ -17,9 +21,19 @@ const LoginContainer = (props : LoginProps) => {
userId : '',
password : '',
});
const [token, setToken] = useRecoilState(recoilUtil.token);
const [userTypeCd, setUserTypeCd] = useRecoilState(recoilUtil.userTypeCd);
const [error, setError] = useRecoilState(recoilUtil.error);
const fetchData = async() => {
if(token && token.length) {
const result = await authApi.verifyToken(token);
if (result.statusText === 'OK') {
props.history.push('/');
}
}
};
const onSetUserId = (e : React.ChangeEvent<HTMLInputElement>) => {
setLoginForm({
......@@ -42,23 +56,26 @@ const LoginContainer = (props : LoginProps) => {
const onLogin = async () => {
try {
const result : any = await authApi.login(loginForm);
if(result.statusText === 'OK') {
if(result.statusText === 'OK' && result.data.userTypeCd !== 'NORMAL') {
setToken(result.data.token);
setUserTypeCd(result.data.userTypeCd);
props.history.push('/');
Alert.onSuccess('로그인 성공, 메인 화면으로 이동합니다.', () => props.history.push('/'));
} else if(result.data.userTypeCd === 'NORMAL') {
Alert.onError('권한이 없는 유저입니다.', () => props.history.push('/'));
}
} catch(e) {
setError('로그인에 실패했습니다.');
console.log(e);
Alert.onError(e.response.data, () => null);
}
};
useEffect(() => {
console.log('loginPage');
fetchData();
}, []);
return (
<>
<Header {...props} />
<LoginPresenter
loginForm = {loginForm}
onSetUserId = {onSetUserId}
......@@ -66,6 +83,7 @@ const LoginContainer = (props : LoginProps) => {
onGoRegister = {onGoRegister}
onLogin = {onLogin}
/>
</>
)
};
......
......@@ -17,7 +17,7 @@ const LoginPresenter = (props : LoginProps) => {
return (
<styled.Container>
<styled.LoginWrapper>
<styled.LoginTitle>로그인</styled.LoginTitle>
<styled.LoginTitle>🩺로그인</styled.LoginTitle>
<styled.LoginInputWrapper>
<styled.LoginEachInputWrapper>
<styled.LoginInputText>
......
import styled from 'styled-components';
import styled, { keyframes} from 'styled-components';
const twinkle = keyframes `
0% {
opacity : 1;
background-color : #337DFF;
}
20% {
opacity : .75;
}
40% {
opacity : .5;
}
60% {
opacity : .5;
}
80% {
opacity : .75;
}
100% {
opacity : 1;
background-color : #337DFF;
}
`
const twinkleText = keyframes `
0% {
opacity : 1;
}
20% {
opacity : .75;
}
40% {
opacity : .5;
}
60% {
opacity : .5;
}
80% {
opacity : .75;
}
100% {
opacity : 1;
}
`;
export const Container = styled.div `
width : 100%;
......@@ -73,10 +118,8 @@ export const RegisterButton = styled.button `
font-size : 11px;
transition : .25s all;
&:hover {
opacity : .5;
animation : ${twinkleText} 2s infinite;
}
`;
......@@ -97,10 +140,10 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> `
border-radius : 5px;
padding : 10px 30px;
width : 80%;
cursor : pointer;
transition : .25s all;
color : #343434;
font-weight : 600;
......@@ -108,6 +151,7 @@ export const LoginButton = styled.button<{isLoginButton : boolean}> `
background-color : #343434;
color : #fff;
border : 1.2px solid transparent;
animation : ${twinkle} 1.5s infinite linear;
}
margin : 0 15px;
......
......@@ -4,6 +4,8 @@ import { RouteComponentProps} from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import * as recoilUtil from '../../util/recoilUtil';
import Header from '../../components/Header';
import DoctorMenuContainer from './doctor';
import ManagerMenuContainer from './manager';
......@@ -22,9 +24,15 @@ const MainContainer = (props : MainProps) => {
}, []);
return (
userTypeCd === 'DOCTOR' ?
<DoctorMenuContainer {...props}/> :
<ManagerMenuContainer {...props}/>
<>
<Header {...props}/>
{
userTypeCd === 'DOCTOR' ?
<DoctorMenuContainer {...props}/> :
userTypeCd === 'MANAGER' ?
<ManagerMenuContainer {...props}/> : null
}
</>
);
};
......
......@@ -6,6 +6,8 @@ import DoctorMenuPresenter from './DoctorMenuPresenter';
import { useRecoilState, useRecoilValue } from 'recoil';
import * as recoilUtil from '../../../util/recoilUtil';
import * as Alert from '../../../util/alertMessage';
import { doctorApi, authApi } from '../../../api';
......@@ -36,13 +38,15 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
const [searchPatientKeyword, setSearchPatientKeyword] = useState<string>('');
const [filteringPatientList, setFilteringPatientList] = useState<any>([]);
const [patientDetail, setPatientDetail] = useState<any>();
const [editModal, setEditModal] = useState<boolean>(false);
const [editPatientInfo, setEditPatientInfo] = useState<string>('');
const [newPatientRegisterModal, setNewPatientRegisterModal] = useState<boolean>(false);
const [newPatientSearchId, setNewPatientSearchId] = useState<string>('');
const [newPatientSearchResult, setNewPatientSearchResult] = useState<any | null>(null);
const fetchData = async() => {
......@@ -92,7 +96,8 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
}
};
const onInitialize = () => {
const onInitialize = async () => {
await fetchData();
setInfo({
infoType : 'DOCTOR',
userNm : doctorInfo.doctorNm,
......@@ -103,9 +108,46 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
});
setFilteringPatientList([]);
setSearchPatientKeyword('');
setEditModal(false);
setEditPatientInfo('');
setNewPatientRegisterModal(false);
setNewPatientSearchId('');
setNewPatientSearchResult(null);
setPatientDetail(null);
};
const onEditPatientInfo = (e : React.ChangeEvent<HTMLTextAreaElement>) => {
setEditPatientInfo(e.target.value);
};
const onSubmitPatientInfo = () => {
if(editPatientInfo.length && patientDetail) {
const onSubmit = async () => {
try {
const result = await doctorApi.writePatientInfo(token, {
patientId : patientDetail.profile.userId,
info : editPatientInfo,
});
if(result.statusText === 'OK') {
Alert.onSuccess('환자의 특이사항을 업데이트했습니다.', () => onInitialize());
} else {
Alert.onError('특이사항을 기록하는데 실패했습니다.', () => null);
}
} catch(e) {
Alert.onError(e.response.data.error, () => null);
}
};
Alert.onCheck('환자의 특이사항을 업데이트하시겠습니까?', onSubmit, () => null);
} else {
Alert.onError('환자의 특이사항을 기록하세요.', () => null);
}
};
const onSetNewPatientSearchId = (e : React.ChangeEvent<HTMLInputElement>) => {
setNewPatientSearchId(e.target.value);
......@@ -114,16 +156,51 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
const onSearchNewPatientByEmail = async () => {
try {
await doctorApi.searchPatientById(token, newPatientSearchId).then(res => {
console.log(res.data);
}).catch(err => console.log(err));
setNewPatientSearchResult(res.data);
}).catch(err => {
console.log(err);
Alert.onError('검색 결과가 없습니다.', () => null);
setNewPatientSearchResult(null);
});
} catch(e) {
console.log(e);
Alert.onError(e.response.data.error, () => null);
}
};
const onRegisterNewPatient = () => {
if(newPatientSearchResult) {
const { patientId, patientNm } = newPatientSearchResult;
const onRegisterReq = async () => {
try {
const result = await doctorApi.registerPatient(token, {
patientId,
});
if(result.statusText === 'OK') {
Alert.onSuccess('환자에게 담당의 등록 요청을 전송했습니다.', () => null);
} else {
Alert.onError('환자에게 담당의 등록 요청을 실패했습니다.', () => null);
}
} catch(e) {
Alert.onError(e.response.data.error, () => null);
}
};
Alert.onCheck(`${patientNm} 환자에게 담당의 등록 요청을 전송하시겠습니까?`, onRegisterReq, () => null);
} else {
Alert.onError('환자를 먼저 검색해주세요.', () => null);
}
};
const onCloseModal = async () => {
setNewPatientRegisterModal(false);
setNewPatientSearchId('');
setNewPatientSearchResult(null);
setEditModal(false);
setEditPatientInfo('');
};
const onGoBottleDetail = (bottleId : number) => {
console.log(bottleId);
props.history.push(`/bottle/${bottleId}`);
};
......@@ -158,12 +235,19 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
editModal = {editModal}
setEditModal = {setEditModal}
editPatientInfo = {editPatientInfo}
onEditPatientInfo = {onEditPatientInfo}
onSubmitPatientInfo = {onSubmitPatientInfo}
newPatientRegisterModal = {newPatientRegisterModal}
setNewPatientRegisterModal = {setNewPatientRegisterModal}
newPatientSearchId = {newPatientSearchId}
onSetNewPatientSearchId = {onSetNewPatientSearchId}
onSearchNewPatientByEmail = {onSearchNewPatientByEmail}
onRegisterNewPatient = {onRegisterNewPatient}
onCloseModal = {onCloseModal}
newPatientSearchResult = {newPatientSearchResult}
/>
);
};
......
......@@ -5,6 +5,8 @@ import * as styled from './DoctorMenuStyled';
const medicineImg = '/static/img/medicine.png';
const lensImg = '/static/img/lens.png';
const closeButton = '/static/img/close.png';
const edit = '/static/img/edit.png';
const refreshing = '/static/img/refreshing.png';
interface DoctorMenuProps {
......@@ -27,23 +29,30 @@ interface DoctorMenuProps {
editModal : boolean;
setEditModal : any;
editPatientInfo : string;
onEditPatientInfo : React.ChangeEventHandler<HTMLTextAreaElement>;
onSubmitPatientInfo : () => void;
newPatientRegisterModal : boolean;
setNewPatientRegisterModal : any;
newPatientSearchId: string;
onSetNewPatientSearchId : React.ChangeEventHandler<HTMLInputElement>;
onSearchNewPatientByEmail : () => void;
onRegisterNewPatient : () => void;
onCloseModal : () => void;
newPatientSearchResult : any;
}
const DoctorMenuPresenter = (props : DoctorMenuProps) => {
return (
<styled.Container>
{
props.editModal ?
props.newPatientRegisterModal ?
<styled.ModalContainer>
<styled.ModalClsButtonWrapper>
<styled.ModalClsButton
onClick = {() => props.setEditModal(false)}
onClick = {() => props.setNewPatientRegisterModal(false)}
>
<styled.ModalClsButtonImg src = {closeButton}/>
<styled.ModalClsButtonText>닫기</styled.ModalClsButtonText>
......@@ -65,13 +74,28 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
</styled.NewPatientSearchButton>
</styled.NewPatientSearchWrapper>
<styled.NewPatientSearchResultWrapper>
🤔검색 결과가 없습니다.
{
props.newPatientSearchResult ?
<styled.NewPatientSearchResult>
<styled.NewPatientSearchResultInfoWrapper>
<styled.NewPatientSearchResultInfo>이름 : </styled.NewPatientSearchResultInfo>
<styled.NewPatientSearchResultInfoText>
{props.newPatientSearchResult.patientNm}
</styled.NewPatientSearchResultInfoText>
</styled.NewPatientSearchResultInfoWrapper>
</styled.NewPatientSearchResult> :
'🤔검색 결과가 없습니다.'
}
</styled.NewPatientSearchResultWrapper>
<styled.NewPatientRegisterButtonWrapper>
<styled.NewPatientRegisterButton>
<styled.NewPatientRegisterButton
onClick = {props.onRegisterNewPatient}
>
확인
</styled.NewPatientRegisterButton>
<styled.NewPatientRegisterButton>
<styled.NewPatientRegisterButton
onClick = {props.onCloseModal}
>
취소
</styled.NewPatientRegisterButton>
</styled.NewPatientRegisterButtonWrapper>
......@@ -80,6 +104,60 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
<styled.ModalClsButtonWrapper/>
</styled.ModalContainer> : null
}
{
props.editModal ?
<styled.ModalContainer>
<styled.ModalClsButtonWrapper>
<styled.ModalClsButton
onClick = {() => props.setEditModal(false)}
>
<styled.ModalClsButtonImg src = {closeButton}/>
<styled.ModalClsButtonText>닫기</styled.ModalClsButtonText>
</styled.ModalClsButton>
</styled.ModalClsButtonWrapper>
<styled.ModalContentWrapper>
<styled.ModalContent>
<styled.PatientInfoViewContainer>
<styled.PatientInfoPatientNmWrapper>
<styled.PatientInfoPatientNmInfo>이름 : </styled.PatientInfoPatientNmInfo>
<styled.PatientInfoPatientNm>{props.info.userNm}</styled.PatientInfoPatientNm>
</styled.PatientInfoPatientNmWrapper>
<styled.PatientInfoView>
{
props.info.patientInfo.split('\n\n').map((patientInfoText : string) => {
return (
<div key = {patientInfoText}>
{patientInfoText}<br/><br/>
</div>
)
})
}
</styled.PatientInfoView>
</styled.PatientInfoViewContainer>
<styled.PatientInfoEditWrapper>
<styled.PatientInfoEditInput
value = {props.editPatientInfo}
onChange = {props.onEditPatientInfo}
/>
</styled.PatientInfoEditWrapper>
<styled.PatientInfoEditButtonWrapper>
<styled.PatientInfoEditButton
onClick = {props.onSubmitPatientInfo}
>
확인
</styled.PatientInfoEditButton>
<styled.PatientInfoEditButton
onClick = {props.onCloseModal}
>
취소
</styled.PatientInfoEditButton>
</styled.PatientInfoEditButtonWrapper>
</styled.ModalContent>
</styled.ModalContentWrapper>
<styled.ModalClsButtonWrapper/>
</styled.ModalContainer> : null
}
<styled.InfoAndSearchWrapper>
<styled.InfoWrapper>
{
......@@ -99,8 +177,10 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
</styled.InfoEachWrapper>
</styled.InfoSquare> :
<styled.InfoSquare>
<styled.EditPatientInfoButton>
<styled.EditPatientInfoButtonImg />
<styled.EditPatientInfoButton
onClick = {() => props.setEditModal(true)}
>
<styled.EditPatientInfoButtonImg src = {edit}/>
<styled.EditPatientInfoButtonText>수정</styled.EditPatientInfoButtonText>
</styled.EditPatientInfoButton>
<styled.InfoEachWrapper>
......@@ -134,7 +214,7 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
</styled.InfoSquare>
}
<styled.NewPatientButton
onClick = {() => props.setEditModal(true)}
onClick = {() => props.setNewPatientRegisterModal(true)}
>
새 환자 등록
</styled.NewPatientButton>
......@@ -147,12 +227,12 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
onChange = {props.onSetKeyword}
/>
<styled.SearchButton>
검색
<styled.SearchButtonImg src = {lensImg}/>
</styled.SearchButton>
<styled.SearchButton
onClick = {props.onInitialize}
>
초기화
<styled.SearchButtonImg src = {refreshing}/>
</styled.SearchButton>
</styled.SearchBarWrapper>
<styled.SearchResultWrapper>
......
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';
const ModalOn = keyframes `
0% {
background-color : rgba(52, 52, 52, .0);
}
20% {
background-color : rgba(52, 52, 52, .2);
}
40% {
background-color : rgba(52, 52, 52, .4);
}
60% {
background-color : rgba(52, 52, 52, .5);
}
80% {
background-color : rgba(52, 52, 52, .6);
}
100% {
background-color : rgba(52, 52, 52, .7);
}
`;
export const Container = styled.div `
height : 100vh;
......@@ -17,6 +41,8 @@ export const ModalContainer = styled.div `
display : flex;
flex-direction : column;
animation : ${ModalOn} .5s;
background-color : rgba(52, 52, 52, .7);
`;
......@@ -55,8 +81,8 @@ export const ModalClsButton = styled.button `
`;
export const ModalClsButtonImg = styled.img `
height : 25px;
width : 25px;
height : 20px;
width : 20px;
margin : 0 10px 0 0;
`;
......@@ -159,6 +185,35 @@ export const NewPatientSearchResultWrapper = styled.div `
font-size : 14px;
color : #a0a0a0;
font-weight : 600;
`;
export const NewPatientSearchResult = styled.div `
border : none;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
`;
export const NewPatientSearchResultInfoWrapper = styled.div `
display : flex;
`;
export const NewPatientSearchResultInfo = styled.div `
font-size : 13px;
font-weight : 600;
color : #a0a0a0;
margin : 0 5px 0 0;
`;
export const NewPatientSearchResultInfoText = styled.div `
font-size : 14px;
color : #343434;
font-weight : 600;
letter-spacing : 1px;
`;
export const NewPatientRegisterButtonWrapper = styled.div `
......@@ -195,6 +250,130 @@ export const NewPatientRegisterButton = styled.button `
`;
export const PatientInfoViewContainer = styled.div `
overflow : scroll;
flex : 6;
border : none;
width : 100%;
display : flex;
flex-direction : column;
&::-webkit-scrollbar {
width : 3px;
background-color : transparent;
height : 1px;
}
&::-webkit-scrollbar-thumb {
background-color : #337DFF;
}
`;
export const PatientInfoPatientNmWrapper = styled.div `
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
width : 100%;
padding : 15px 0;
border : none;
border-bottom : 1px solid #ddd;
`;
export const PatientInfoPatientNmInfo = styled.div `
font-size : 15px;
font-weight : 500;
margin : 0 5px;
`;
export const PatientInfoPatientNm = styled.div `
font-size : 20px;
font-weight : 700;
margin : 0 5px;
letter-spacing : 1px;
color : #337DFF;
`;
export const PatientInfoView = styled.div `
padding : 15px 15px;
font-size : 15px;
font-weight : 500;
letter-spacing : 1px;
`;
export const PatientInfoEditWrapper = styled.div `
flex : 3;
border : none;
width : 100%;
display : flex;
justify-content : center;
align-items : center;
`;
export const PatientInfoEditInput = styled.textarea `
width : 100%;
resize : none;
padding : 15px;
margin : 15px;
border : 1px solid #ddd;
`;
export const PatientInfoEditButtonWrapper = styled.div `
flex : 2;
border : none;
width : 100%;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
gap : 8%;
`;
export const PatientInfoEditButton = styled.button `
background-color : #fff;
color : #337DFF;
border : 1px solid #337DFF;
border-radius : 3px;
cursor : pointer;
transition : .25s all;
font-size : 16px;
font-weight : 600;
padding : 10px 30px;
margin : 0 10px;
&:hover {
background-color : #337DFF;
color : #fff;
border : 1px solid transparent;
}
`;
export const InfoAndSearchWrapper = styled.div `
flex : 3;
display : flex;
......@@ -369,8 +548,10 @@ export const SearchBar = styled.input `
export const SearchButton = styled.button `
border : 1px solid #ddd;
border-radius : 3px;
background-color : transparent;
opacity : .7;
height : 50px;
width : 50px;
......@@ -379,12 +560,20 @@ export const SearchButton = styled.button `
cursor : pointer;
display : flex;
justify-content : center;
align-items : center;
&:hover {
color : #fff;
background-color : #343434;
opacity : 1;
}
`;
export const SearchButtonImg = styled.img `
height : 20px;
width : 20px;
`;
export const SearchResultWrapper = styled.div `
flex : 5;
border : 1px solid #ddd;
......
import React, { useState, useEffect } from "react";
import { RouteComponentProps } from 'react-router-dom';
import { useRecoilValue } from "recoil";
import { useRecoilValue, useRecoilState } from "recoil";
import * as recoilUtil from '../../util/recoilUtil';
import Header from '../../components/Header';
import RegisterPresenter from "./RegisterPresenter";
type RegisterProps = RouteComponentProps;
import { authApi } from '../../api';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface RegisterProps extends RouteComponentProps {}
const RegisterContainer = (props : RegisterProps) => {
const [token, setToken] = useRecoilState(recoilUtil.token);
const fetchData = async() => {
if(token && token.length) {
const result = await authApi.verifyToken(token);
if (result.statusText === 'OK') {
props.history.push('/');
}
}
};
useEffect(() => {
fetchData();
}, []);
return (
<>
<Header {...props}/>
<RegisterPresenter
/>
</>
)
};
......
......@@ -9,7 +9,7 @@ const RegisterPresenter = () => {
<styled.RegisterWrapper>
<styled.RegisterTitle>회원 가입</styled.RegisterTitle>
<styled.RegisterInfo>* 의사만 회원가입이 가능합니다.</styled.RegisterInfo>
<styled.RegisterInfo style = {{fontSize : 10,}}>의사 인증을 위한 정보가 요구됩니다.</styled.RegisterInfo>
<styled.RegisterInfo style = {{fontSize : 10,}}>의사 인증을 위한 정보가 요구됩니다. 해당 정보는 인증을 위한 용도로만 사용됩니다.</styled.RegisterInfo>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>이메일</styled.RegisterInputText>
<styled.RegisterInput
......
......@@ -35,7 +35,7 @@ export const RegisterTitle = styled.div `
export const RegisterInfo = styled.div `
width : 90%;
font-size : 12px;
font-size : 13px;
color : #a0a0a0;
`;
......
This diff could not be displayed because it is too large.