박권수

feat. Main View seperated by Uesr Type / Main View (Doctor)

......@@ -2,6 +2,13 @@ import { client } from "./client";
import { RecoilState } from "recoil";
export default {
getDoctorsInfo : (token : RecoilState<any>) => {
return client.get('/doctor', {
headers : {
Authorization : token,
},
});
},
getPatientList : (token : RecoilState<any>) => {
return client.get('/doctor/patient', {
headers : {
......
import React, { useState, useEffect } from 'react';
import { RouteComponentProps} from 'react-router-dom';
import MainPresenter from './MainPresenter';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilValue } from 'recoil';
import * as recoilUtil from '../../util/recoilUtil';
import { doctorApi, managerApi, userApi, authApi } from '../../api';
import DoctorMenuContainer from './doctor';
import ManagerMenuContainer from './manager';
type MainProps = RouteComponentProps
......@@ -23,9 +22,9 @@ const MainContainer = (props : MainProps) => {
}, []);
return (
<MainPresenter
userTypeCd = {userTypeCd}
/>
userTypeCd === 'DOCTOR' ?
<DoctorMenuContainer {...props}/> :
<ManagerMenuContainer {...props}/>
);
};
......
import React, { useState, useEffect } from 'react';
import { RouteComponentProps} from 'react-router-dom';
import DoctorMenuPresenter from './DoctorMenuPresenter';
import { useRecoilState, useRecoilValue } from 'recoil';
import * as recoilUtil from '../../../util/recoilUtil';
import { doctorApi, authApi } from '../../../api';
type DoctorMenuProps = RouteComponentProps
const DoctorMenuContainer = (props : DoctorMenuProps) => {
const token = useRecoilValue(recoilUtil.token);
const [doctorInfo, setDoctorInfo] = useState<any>({
doctorNm : '',
doctorType : '',
hospitalNm : '',
hospitalAddr : '',
contact : '',
});
const [patientList, setPatientList] = useState<any>([]);
const [info, setInfo] = useState<any>({
infoType : 'DOCTOR',
userNm : '',
userAge : 0,
contact : '',
doctorType : '',
patientInfo : '',
});
const [searchPatientKeyword, setSearchPatientKeyword] = useState<string>('');
const [filteringPatientList, setFilteringPatientList] = useState<any>([]);
const [patientDetail, setPatientDetail] = useState<any>();
const [editModal, setEditModal] = useState<boolean>(false);
const [newPatientRegisterModal, setNewPatientRegisterModal] = useState<boolean>(false);
const fetchData = async() => {
try {
const res = await doctorApi.getDoctorsInfo(token);
if(res.statusText === 'OK') {
setDoctorInfo(res.data);
setInfo({
infoType : 'DOCTOR',
userNm : res.data.doctorNm,
doctorType : res.data.doctorType,
contact : res.data.contact,
userAge : null,
patientInfo : '',
});
//로그인한 환자의 리스트를 가져옴 : 프론트에서 필터로 검색
await doctorApi.getPatientList(token).then(res => {
setPatientList(res.data);
}).catch(error => console.log(error));
}
} catch(e) {
console.log(e);
}
};
const onSetKeyword = (e : React.ChangeEvent<HTMLInputElement>) => {
setSearchPatientKeyword(e.target.value);
};
const onFetchPatientDetail = async (patientId : string) => {
try {
await doctorApi.getPatientDetail(token, patientId).then(res => {
setPatientDetail(res.data);
setInfo({
infoType : 'PATIENT',
userNm : res.data.profile.userNm,
userAge : res.data.profile.userAge,
contact : res.data.profile.contact,
doctorType : null,
patientInfo : res.data.info,
});
}).catch(err => console.log(err));
} catch(e) {
console.log(e);
}
};
const onInitialize = () => {
setInfo({
infoType : 'DOCTOR',
userNm : doctorInfo.doctorNm,
doctorType : doctorInfo.doctorType,
contact : doctorInfo.contact,
userAge : null,
patientInfo : '',
});
setFilteringPatientList([]);
setSearchPatientKeyword('');
setPatientDetail(null);
};
useEffect(() => {
if(!token || !token.length) {
props.history.push('/login');
} else fetchData();
}, []);
useEffect(() => {
setFilteringPatientList(searchPatientKeyword === '' ? [] :
patientList.filter((patient : any) =>
patient.contact.includes(searchPatientKeyword)
|| patient.userNm.includes(searchPatientKeyword)
|| patient.userId.includes(searchPatientKeyword)
)
);
}, [searchPatientKeyword]);
return (
<DoctorMenuPresenter
info = {info}
searchPatientKeyword = {searchPatientKeyword}
onSetKeyword = {onSetKeyword}
filteringPatientList = {filteringPatientList}
patientDetail = {patientDetail}
onFetchPatientDetail = {onFetchPatientDetail}
onInitialize = {onInitialize}
editModal = {editModal}
setEditModal = {setEditModal}
newPatientRegisterModal = {newPatientRegisterModal}
setNewPatientRegisterModal = {setNewPatientRegisterModal}
/>
);
};
export default DoctorMenuContainer;
\ No newline at end of file
import React from 'react';
import * as styled from './DoctorMenuStyled';
interface DoctorMenuProps {
info : {
infoType : string;
userNm : string;
doctorType : string | null;
contact : string;
userAge : number | null;
patientInfo : string;
};
searchPatientKeyword : string;
onSetKeyword : React.ChangeEventHandler<HTMLInputElement>;
filteringPatientList : any[];
patientDetail : any;
onFetchPatientDetail : (arg0 : string) => void;
onInitialize : () => void;
editModal : boolean;
setEditModal : any;
newPatientRegisterModal : boolean;
setNewPatientRegisterModal : any;
}
const DoctorMenuPresenter = (props : DoctorMenuProps) => {
return (
<styled.Container>
{
props.editModal ?
<styled.ModalContainer>
<styled.ModalClsButtonWrapper>
<styled.ModalClsButton
onClick = {() => props.setEditModal(false)}
>
<styled.ModalClsButtonImg />
<styled.ModalClsButtonText>닫기</styled.ModalClsButtonText>
</styled.ModalClsButton>
</styled.ModalClsButtonWrapper>
<styled.ModalContentWrapper>
<styled.ModalContent>
<styled.NewPatientRegisterTitle>새 환자 등록</styled.NewPatientRegisterTitle>
<styled.NewPatientSearchWrapper>
<styled.NewPatientSearchInput
placeholder = '환자 이메일을 입력하세요.'
/>
<styled.NewPatientSearchButton>
<styled.NewPatientSearchButtonImg />
</styled.NewPatientSearchButton>
</styled.NewPatientSearchWrapper>
<styled.NewPatientSearchResultWrapper>
🤔검색 결과가 없습니다.
</styled.NewPatientSearchResultWrapper>
<styled.NewPatientRegisterButtonWrapper>
<styled.NewPatientRegisterButton>
확인
</styled.NewPatientRegisterButton>
<styled.NewPatientRegisterButton>
취소
</styled.NewPatientRegisterButton>
</styled.NewPatientRegisterButtonWrapper>
</styled.ModalContent>
</styled.ModalContentWrapper>
<styled.ModalClsButtonWrapper/>
</styled.ModalContainer> : null
}
<styled.InfoAndSearchWrapper>
<styled.InfoWrapper>
{
props.info.infoType === 'DOCTOR' ?
<styled.InfoSquare>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>분야</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.doctorType}</styled.InfoEachText>
</styled.InfoEachWrapper>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>이름</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.userNm}</styled.InfoEachText>
</styled.InfoEachWrapper>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>연락처</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.contact}</styled.InfoEachText>
</styled.InfoEachWrapper>
</styled.InfoSquare> :
<styled.InfoSquare>
<styled.EditPatientInfoButton>
<styled.EditPatientInfoButtonImg />
<styled.EditPatientInfoButtonText>수정</styled.EditPatientInfoButtonText>
</styled.EditPatientInfoButton>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>이름</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.userNm}</styled.InfoEachText>
</styled.InfoEachWrapper>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>생년월일</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.userAge}세</styled.InfoEachText>
</styled.InfoEachWrapper>
<styled.InfoEachWrapper>
<styled.InfoEachTopic>연락처</styled.InfoEachTopic>
<styled.InfoEachText>{props.info.contact}</styled.InfoEachText>
</styled.InfoEachWrapper>
<styled.InfoEachWrapper
style = {{margin : '10px 0 0 0'}}
>
<styled.InfoEachTopic>환자 기록</styled.InfoEachTopic>
<styled.PatientInfo>
{
props.info.patientInfo.split('\n\n').map((patientInfoText : string) => {
return (
<div key = {patientInfoText}>
{patientInfoText}<br/><br/>
</div>
)
})
}
</styled.PatientInfo>
</styled.InfoEachWrapper>
</styled.InfoSquare>
}
<styled.NewPatientButton
onClick = {() => props.setEditModal(true)}
>
새 환자 등록
</styled.NewPatientButton>
</styled.InfoWrapper>
<styled.SearchAndDetailWrapper>
<styled.SearchBarWrapper>
<styled.SearchBar
placeholder = '환자 정보(이름, 이메일, 휴대폰 번호)'
value = {props.searchPatientKeyword}
onChange = {props.onSetKeyword}
/>
<styled.SearchButton>
검색
</styled.SearchButton>
<styled.SearchButton
onClick = {props.onInitialize}
>
초기화
</styled.SearchButton>
</styled.SearchBarWrapper>
<styled.SearchResultWrapper>
<styled.SearchResultInfo>
<styled.SearchResultInfoEach isLast = {false}>이름</styled.SearchResultInfoEach>
<styled.SearchResultInfoEach isLast = {false}>생년월일</styled.SearchResultInfoEach>
<styled.SearchResultInfoEach isLast = {true}>연락처</styled.SearchResultInfoEach>
</styled.SearchResultInfo>
{
props.filteringPatientList.length ?
props.filteringPatientList.map(patient => {
return (
<styled.SearchResultEach
key = {patient._id}
onClick = {() => props.onFetchPatientDetail(patient.userId)}
>
<styled.SearchResultEachText isLast = {false}>{patient.userNm}</styled.SearchResultEachText>
<styled.SearchResultEachText isLast = {false}>{patient.userAge}세</styled.SearchResultEachText>
<styled.SearchResultEachText isLast = {true}>{patient.contact}</styled.SearchResultEachText>
</styled.SearchResultEach>
)
}) :
<styled.NothingWrapper>
🤔검색 결과가 없습니다.
</styled.NothingWrapper>
}
</styled.SearchResultWrapper>
</styled.SearchAndDetailWrapper>
</styled.InfoAndSearchWrapper>
<styled.BottleListWrapper>
{
props.patientDetail && props.patientDetail.bottleList ?
props.patientDetail.bottleList.map((bottle : any) => {
return (
<styled.EachBottleWrapper
key = {bottle._id}
>
{
bottle.bottleId
}
</styled.EachBottleWrapper>
)
}) :
<styled.NothingWrapper>
🤔먼저 환자를 선택하세요.
</styled.NothingWrapper>
}
</styled.BottleListWrapper>
</styled.Container>
)
};
export default DoctorMenuPresenter;
\ No newline at end of file
import styled from 'styled-components';
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;
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 : 25px;
width : 25px;
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 : 600px;
height : 400px;
background-color : #fff;
border : 1.2px solid #337DFF;
border-radius : 5px;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
`;
export const NewPatientRegisterTitle = styled.div `
font-size : 20px;
font-weight : 700;
color : #337DFF;
letter-spacing : 1px;
`;
export const NewPatientSearchWrapper = styled.div `
margin : 20px 0 0 0;
border : none;
border-bottom : 1px solid #ddd;
width : 80%;
padding : 0 10px 5px 10px;
display : flex;
flex-direction : row;
justify-content : space-between;
`;
export const NewPatientSearchInput = styled.input `
border : none;
width : 80%;
`;
export const NewPatientSearchButton = styled.button `
border : none;
background-color : transparent;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const NewPatientSearchButtonImg = styled.img `
height : 20px;
width : 20px;
`;
export const NewPatientSearchResultWrapper = styled.div `
border : 1px solid #337DFF;
margin : 10px 0 0 0;
width : 80%;
padding : 10px;
height : 100px;
display : flex;
justify-content : center;
align-items : center;
font-size : 14px;
color : #a0a0a0;
`;
export const NewPatientRegisterButtonWrapper = styled.div `
display : flex;
flex-direction : row;
justify-content : center;
align-items :center;
margin : 20px 0 0 0;
`;
export const NewPatientRegisterButton = 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;
flex-direction : row;
margin : 0 0 10px 0;
`;
export const InfoWrapper = styled.div `
flex : 2;
display : flex;
flex-direction : column;
padding : 10px;
`;
export const InfoSquare = styled.div `
overflow : scroll;
border : 1px solid #ddd;
border-radius : 5px;
background-color : transparent;
height : 300px;
margin : 0 0 20px 0;
box-shadow: 0px 0px 5px #a0a0a0;
padding : 20px;
display : flex;
flex-direction : column;
align-items : center;
&::-webkit-scrollbar {
width : 3px;
background-color : transparent;
height : 1px;
}
&::-webkit-scrollbar-thumb {
background-color : #337DFF;
}
`;
export const EditPatientInfoButton = styled.button `
display : flex;
flex-direction : row;
align-self : flex-end;
justify-content : center;
align-items : center;
border : none;
background-color : transparent;
cursor : pointer;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const EditPatientInfoButtonImg = styled.img `
height : 15px;
width : 15px;
margin : 0 5px 0 0;
`;
export const EditPatientInfoButtonText = styled.div `
font-size : 12px;
font-weight : 600;
`;
export const InfoEachWrapper = styled.div `
display : flex;
flex-direction : column;
justify-content : flex-start;
align-items : flex-start;
width : 100%;
border : none;
margin : 0 0 20px 0;
`;
export const InfoEachTopic = styled.div `
margin : 0 0 5px 0;
font-size : 14px;
font-weight : 700;
color : #337DFF;
`;
export const InfoEachText = styled.div `
font-size : 18px;
font-weight : bold;
border : none;
border-bottom : 2px solid #337DFF;
padding : 0px 10px 2px 10px;
`;
export const PatientInfo = styled.div `
font-size : 15px;
`;
export const NewPatientButton = styled.button `
flex : 1;
border : 1px solid #ddd;
border-radius : 3px;
background-color : #fff;
color : #337DFF;
padding : 10px 30px;
transition : .25s all;
font-size : 18px;
font-weight : 700;
cursor : pointer;
&:hover {
background-color : #337DFF;
color : #fff;
}
`;
export const SearchAndDetailWrapper = styled.div `
flex : 5;
display : flex;
flex-direction : column;
padding : 10px;
`;
export const SearchBarWrapper = styled.div `
flex : 1;
border : 1px solid #ddd;
border-radius : 3px;
background-color : transparent;
display : flex;
flex-direction : row;
padding : 10px;
align-items : center;
justify-content : space-around;
margin : 0 0 10px 0;
`;
export const SearchBar = styled.input `
border : none;
border-bottom : 2px solid #ddd;
width : 80%;
margin : 0 10px 0 20px;
padding : 10px 0px;
`;
export const SearchButton = styled.button `
border : 1px solid #ddd;
background-color : transparent;
height : 50px;
width : 50px;
transition : .25s all;
cursor : pointer;
&:hover {
color : #fff;
background-color : #343434;
}
`;
export const SearchResultWrapper = styled.div `
flex : 5;
border : 1px solid #ddd;
border-radius : 3px;
background-color : transparent;
`;
export const SearchResultInfo = styled.div `
display : flex;
flex-direction : row;
border : none;
border-bottom : 2px solid #ddd;
padding : 5px 20px;
`;
export const SearchResultInfoEach = styled.div<{isLast : boolean}> `
flex : 1;
text-align : center;
font-size : 18px;
font-weight : 600;
border : none;
border-right : ${props => props.isLast ? 'none' : '1px solid #ddd'};
`;
export const SearchResultEach = styled.div `
display : flex;
flex-direction : row;
border : none;
border-bottom : 1px solid #ddd;
align-items : center;
background-color : transparent;
color : #337DFF;
padding : 10px 20px;
cursor : pointer;
transition : .25s all;
&:hover {
background-color : #337DFF;
color : #fff;
}
`;
export const SearchResultEachText = styled.div<{isLast : boolean}> `
flex : 1;
text-align : center;
border : none;
border-right : ${props => props.isLast ? 'none' : '1px solid #ddd'};
`;
export const BottleListWrapper = styled.div `
overflow : scroll;
flex : 2;
display : flex;
flex-direction : row;
border : 1px solid #ddd;
border-radius : 3px;
padding : 20px;
margin : 0 0 10px 0;
box-shadow: 0px 2px 5px 0px #a0a0a0;
&::-webkit-scrollbar {
width : 0px;
background-color : transparent;
height : 3px;
}
&::-webkit-scrollbar-thumb {
background-color : #337DFF;
}
`;
export const EachBottleWrapper = styled.div `
height : 100%;
min-width : 200px;
border : 1px solid #ddd;
border-radius : 3px;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
margin : 0 20px 0 0;
cursor : pointer;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const NothingWrapper = styled.div `
height : 100%;
width : 100%;
display : flex;
justify-content : center;
align-items : center;
color : #a0a0a0;
`;
\ No newline at end of file
import DoctorMenuContainer from './DoctorMenuContainer';
export default DoctorMenuContainer;
\ No newline at end of file
import React, { useState, useEffect } from "react";
import { RouteComponentProps} from 'react-router-dom';
import { useRecoilValue } from "recoil";
import * as recoilUtil from '../../../util/recoilUtil';
import ManagerMenuPresenter from "./ManagerMenuPresenter";
type ManagerMenuProps = RouteComponentProps;
const ManagerMenuContainer = (props : ManagerMenuProps) => {
return (
<ManagerMenuPresenter
/>
);
};
export default ManagerMenuContainer;
\ No newline at end of file
import React from 'react';
import * as styled from './ManagerMenuStyled';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ManagerMenuProps {}
const ManagerMenuPresenter = (props : ManagerMenuProps) => {
return (
<styled.Container>
관리자 메뉴
</styled.Container>
)
};
export default ManagerMenuPresenter;
\ No newline at end of file
import styled from 'styled-components';
export const Container = styled.div `
`;
\ No newline at end of file
import ManagerMenuContainer from "./ManagerMenuContainer";
export default ManagerMenuContainer;
\ No newline at end of file