Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2021-1-capstone-design1
/
RIT_Project1
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
1
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
박권수
2021-08-21 18:13:40 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
49de8694ead526ba3df7edf131d7f6ad24bc065f
49de8694
1 parent
f194d32d
feat. Register View
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
461 additions
and
6 deletions
web/package-lock.json
web/package.json
web/src/components/Header/index.tsx
web/src/views/bottleInfo/BottleInfoStyled.tsx
web/src/views/register/RegisterContainer.tsx
web/src/views/register/RegisterPresenter.tsx
web/src/views/register/RegisterStyled.tsx
web/yarn.lock
web/package-lock.json
View file @
49de869
...
...
@@ -17,6 +17,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"
,
...
...
@@ -24,12 +25,15 @@
"recoil"
:
"^0.4.0"
,
"recoil-persist"
:
"^3.0.0"
,
"styled-components"
:
"^5.3.0"
,
"sweetalert2"
:
"^11.1.3"
,
"typescript"
:
"^4.1.2"
,
"validator"
:
"^13.6.0"
,
"web-vitals"
:
"^1.0.1"
},
"devDependencies"
:
{
"@types/react-router-dom"
:
"^5.1.8"
,
"@types/styled-components"
:
"^5.1.12"
,
"@types/validator"
:
"^13.6.3"
,
"@typescript-eslint/eslint-plugin"
:
"^4.29.1"
,
"@typescript-eslint/parser"
:
"^4.29.1"
,
"eslint"
:
"^7.32.0"
,
...
...
@@ -2631,6 +2635,12 @@
"source-map"
:
"^0.6.1"
}
},
"node_modules/@types/validator"
:
{
"version"
:
"13.6.3"
,
"resolved"
:
"https://registry.npmjs.org/@types/validator/-/validator-13.6.3.tgz"
,
"integrity"
:
"sha512-fWG42pMJOL4jKsDDZZREnXLjc3UE0R8LOJfARWYg6U966rxDT7TYejYzLnUF5cvSObGg34nd0+H2wHHU5Omdfw=="
,
"dev"
:
true
},
"node_modules/@types/webpack"
:
{
"version"
:
"4.41.26"
,
"resolved"
:
"https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz"
,
...
...
@@ -11693,6 +11703,14 @@
"mkdirp"
:
"bin/cmd.js"
}
},
"node_modules/moment"
:
{
"version"
:
"2.29.1"
,
"resolved"
:
"https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
,
"integrity"
:
"sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
,
"engines"
:
{
"node"
:
"*"
}
},
"node_modules/move-concurrently"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz"
,
...
...
@@ -16885,6 +16903,14 @@
"url"
:
"https://github.com/sponsors/ljharb"
}
},
"node_modules/sweetalert2"
:
{
"version"
:
"11.1.4"
,
"resolved"
:
"https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.1.4.tgz"
,
"integrity"
:
"sha512-CTNLviF6w1wyh1ou2UY8RpZasV2RiXbO6489v+a1Swz4jrUyuFDDjMZ9tMMVFnxTMdiUGfYiJoFUniZbHSEnHw=="
,
"funding"
:
{
"url"
:
"https://sweetalert2.github.io/#donations"
}
},
"node_modules/symbol-tree"
:
{
"version"
:
"3.2.4"
,
"resolved"
:
"https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
,
...
...
@@ -17811,6 +17837,14 @@
"spdx-expression-parse"
:
"^3.0.0"
}
},
"node_modules/validator"
:
{
"version"
:
"13.6.0"
,
"resolved"
:
"https://registry.npmjs.org/validator/-/validator-13.6.0.tgz"
,
"integrity"
:
"sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
,
"engines"
:
{
"node"
:
">= 0.10"
}
},
"node_modules/value-equal"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
,
...
...
@@ -21123,6 +21157,12 @@
"source-map"
:
"^0.6.1"
}
},
"@types/validator"
:
{
"version"
:
"13.6.3"
,
"resolved"
:
"https://registry.npmjs.org/@types/validator/-/validator-13.6.3.tgz"
,
"integrity"
:
"sha512-fWG42pMJOL4jKsDDZZREnXLjc3UE0R8LOJfARWYg6U966rxDT7TYejYzLnUF5cvSObGg34nd0+H2wHHU5Omdfw=="
,
"dev"
:
true
},
"@types/webpack"
:
{
"version"
:
"4.41.26"
,
"resolved"
:
"https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz"
,
...
...
@@ -28254,6 +28294,11 @@
"minimist"
:
"^1.2.5"
}
},
"moment"
:
{
"version"
:
"2.29.1"
,
"resolved"
:
"https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
,
"integrity"
:
"sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz"
,
...
...
@@ -32338,6 +32383,11 @@
}
}
},
"sweetalert2"
:
{
"version"
:
"11.1.4"
,
"resolved"
:
"https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.1.4.tgz"
,
"integrity"
:
"sha512-CTNLviF6w1wyh1ou2UY8RpZasV2RiXbO6489v+a1Swz4jrUyuFDDjMZ9tMMVFnxTMdiUGfYiJoFUniZbHSEnHw=="
},
"symbol-tree"
:
{
"version"
:
"3.2.4"
,
"resolved"
:
"https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
,
...
...
@@ -33054,6 +33104,11 @@
"spdx-expression-parse"
:
"^3.0.0"
}
},
"validator"
:
{
"version"
:
"13.6.0"
,
"resolved"
:
"https://registry.npmjs.org/validator/-/validator-13.6.0.tgz"
,
"integrity"
:
"sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
},
"value-equal"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
,
...
...
web/package.json
View file @
49de869
...
...
@@ -23,6 +23,7 @@
"styled-components"
:
"^5.3.0"
,
"sweetalert2"
:
"^11.1.3"
,
"typescript"
:
"^4.1.2"
,
"validator"
:
"^13.6.0"
,
"web-vitals"
:
"^1.0.1"
},
"scripts"
:
{
...
...
@@ -52,6 +53,7 @@
"devDependencies"
:
{
"@types/react-router-dom"
:
"^5.1.8"
,
"@types/styled-components"
:
"^5.1.12"
,
"@types/validator"
:
"^13.6.3"
,
"@typescript-eslint/eslint-plugin"
:
"^4.29.1"
,
"@typescript-eslint/parser"
:
"^4.29.1"
,
"eslint"
:
"^7.32.0"
,
...
...
web/src/components/Header/index.tsx
View file @
49de869
...
...
@@ -63,7 +63,7 @@ const Header = (props : HeaderProps) => {
<styled.Container>
<styled.HeaderLeftWrapper>
{
(token && token.length && props.location.pathname !== '/')
|| props.location.pathname === '/register'
?
(token && token.length && props.location.pathname !== '/') ?
<styled.Backbutton
onClick = {onGoBack}
>
...
...
web/src/views/bottleInfo/BottleInfoStyled.tsx
View file @
49de869
...
...
@@ -146,7 +146,7 @@ export const MedicineInfoWrapper = styled.div `
width : 100%;
overflow : scroll;
border :
1px solid
;
border :
none
;
display : flex;
flex-direction : column;
...
...
web/src/views/register/RegisterContainer.tsx
View file @
49de869
import React, { useState, useEffect } from "react";
import { RouteComponentProps } from 'react-router-dom';
import { useRecoilValue
, useRecoilState
} from "recoil";
import { useRecoilValue } from "recoil";
import * as recoilUtil from '../../util/recoilUtil';
import validator from 'validator';
import * as Alert from '../../util/alertMessage';
import Header from '../../components/Header';
import RegisterPresenter from "./RegisterPresenter";
import { authApi } from '../../api';
import { resourceLimits } from "worker_threads";
// eslint-disable-next-line @typescript-eslint/no-empty-interface
...
...
@@ -15,7 +19,26 @@ interface RegisterProps extends RouteComponentProps {}
const RegisterContainer = (props : RegisterProps) => {
const [token, setToken] = useRecoilState(recoilUtil.token);
const token = useRecoilValue(recoilUtil.token);
const [registerForm, setRegisterForm] = useState<any>({
userId : '',
password : '',
passwordCheck : '',
info : {
doctorLicense : '',
hospitalNm : '',
hospitalAddr : '',
contact : '',
doctorType : '',
doctorNm : '',
},
});
const [page, setPage] = useState<number>(1);
const [error, setError] = useState<string | null>(null);
const fetchData = async() => {
if(token && token.length) {
...
...
@@ -26,8 +49,167 @@ const RegisterContainer = (props : RegisterProps) => {
}
};
const onCancleRegister = () => {
Alert.onCheck('회원가입을 취소하시겠습니까?',
() => props.history.push('/login'),
() => null);
};
const onGoBackPage = () => {
if(page > 1) {
setPage(page - 1);
}
};
const validateRegisterForm = () => {
if(page === 1) {
if (!validator.isEmail(registerForm.userId)) {
setError('회원 가입 ID는 이메일이어야 합니다.');
} else if(registerForm.password === registerForm.password.toLowerCase()
|| !/\d/.test(registerForm.password)
) {
setError('비밀번호는 최소 8자 이상이어야 하고, 대문자 및 숫자를 1개 이상 포함하고 있어야 합니다.');
} else if(registerForm.password !== registerForm.passwordCheck) {
setError('비밀번호가 일치하지 않습니다.')
} else setError(null);
} else if(page === 2) {
if(!registerForm.info.doctorLicense.length &&
!validator.isAlphanumeric(registerForm.info.doctorLicense)) {
setError('의사 자격 번호를 입력해야 합니다.');
} else if(registerForm.info.doctorNm.length < 2) {
setError('의사 이름을 올바르게 입력해야 합니다.');
} else if(!registerForm.info.contact) {
setError('연락처를 입력해주세요.');
} else setError(null);
} else if(page === 3) {
if(!registerForm.info.doctorType.length) {
setError('전문 분야를 입력해주세요.');
} else if(!registerForm.info.hospitalNm || !registerForm.info.hospitalAddr) {
setError('올바른 병원 정보를 입력해주세요');
} else setError(null);
}
};
const onSetUserId = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
userId : e.target.value,
});
};
const onSetPassword = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
password : e.target.value,
});
};
const onSetPasswordCheck = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
passwordCheck : e.target.value,
});
};
const onSetDoctorLicense = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
doctorLicense : e.target.value,
},
});
};
const onSetHospitalNm = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalNm : e.target.value,
},
});
};
const onSetHospitalAddr = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalAddr : e.target.value,
},
});
};
const onSetContact = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
contact : e.target.value,
},
});
};
const onSetDoctorType = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
doctorType : e.target.value,
},
});
};
const onSetDoctorNm = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
doctorNm : e.target.value,
},
});
};
const onSubmitButton = () => {
if(error) {
Alert.onError(error, () => null);
return;
}
if(page === 1) {
setPage(2);
} else if(page === 2) {
setPage(3);
} else if(page === 3) {
const onRegisterDoctor = async () => {
try {
const result = await authApi.registerDoctor(registerForm);
if(result.data === 'Created') {
Alert.onSuccess('회원가입 성공, 관리자의 승인을 대기하세요.', () => props.history.push('/login'));
}
} catch(e) {
Alert.onError(e.response.data, () => null);
}
};
Alert.onCheck('입력하신 정보로 회원가입을 진행하시겠습니까?', onRegisterDoctor, () => null);
}
};
useEffect(() => {
validateRegisterForm();
}, [registerForm, page]);
useEffect(() => {
fetchData();
validateRegisterForm();
}, []);
...
...
@@ -35,7 +217,23 @@ const RegisterContainer = (props : RegisterProps) => {
<>
<Header {...props}/>
<RegisterPresenter
registerForm = {registerForm}
page = {page}
error = {error}
onGoBackPage = {onGoBackPage}
onCancleRegister = {onCancleRegister}
onSetUserId = {onSetUserId}
onSetPassword = {onSetPassword}
onSetPasswordCheck = {onSetPasswordCheck}
onSetDoctorLicense = {onSetDoctorLicense}
onSetHospitalNm = {onSetHospitalNm}
onSetHospitalAddr = {onSetHospitalAddr}
onSetContact = {onSetContact}
onSetDoctorType = {onSetDoctorType}
onSetDoctorNm = {onSetDoctorNm}
onSubmitButton = {onSubmitButton}
/>
</>
)
...
...
web/src/views/register/RegisterPresenter.tsx
View file @
49de869
...
...
@@ -3,31 +3,155 @@ import React from 'react';
import * as styled from './RegisterStyled';
const RegisterPresenter = () => {
interface RegisterProps {
registerForm : {
userId : string;
password : string;
passwordCheck : string;
info : {
doctorLicense : string;
hospitalNm : string;
hospitalAddr : string;
contact : string;
doctorType : string;
doctorNm : string;
},
};
page : number;
error : string | null;
onGoBackPage : () => void;
onCancleRegister : () => void;
onSetUserId : React.ChangeEventHandler<HTMLInputElement>;
onSetPassword : React.ChangeEventHandler<HTMLInputElement>;
onSetPasswordCheck : React.ChangeEventHandler<HTMLInputElement>;
onSetDoctorLicense : React.ChangeEventHandler<HTMLInputElement>;
onSetHospitalNm : React.ChangeEventHandler<HTMLInputElement>;
onSetHospitalAddr : React.ChangeEventHandler<HTMLInputElement>;
onSetContact : React.ChangeEventHandler<HTMLInputElement>;
onSetDoctorType : React.ChangeEventHandler<HTMLInputElement>;
onSetDoctorNm : React.ChangeEventHandler<HTMLInputElement>;
onSubmitButton : () => void;
}
const RegisterPresenter = (props : RegisterProps) => {
return (
<styled.Container>
<styled.RegisterWrapper>
<styled.RegisterBackButtonWrapper>
<styled.RegisterBackButton
onClick = {props.onCancleRegister}
>
회원가입 취소
</styled.RegisterBackButton>
{
props.page > 1 ?
<styled.RegisterBackButton
onClick = {props.onGoBackPage}
>
이전
</styled.RegisterBackButton> : null
}
</styled.RegisterBackButtonWrapper>
<styled.RegisterTitle>회원 가입</styled.RegisterTitle>
<styled.RegisterInfo>* 의사만 회원가입이 가능합니다.</styled.RegisterInfo>
<styled.RegisterInfo style = {{fontSize : 10,}}>의사 인증을 위한 정보가 요구됩니다. 해당 정보는 인증을 위한 용도로만 사용됩니다.</styled.RegisterInfo>
{
props.page === 1 ?
<>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>이메일</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Email'
value = {props.registerForm.userId}
onChange = {props.onSetUserId}
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>비밀번호</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Password'
value = {props.registerForm.password}
onChange = {props.onSetPassword}
type = 'password'
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>비밀번호 확인</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Password Again'
value = {props.registerForm.passwordCheck}
onChange = {props.onSetPasswordCheck}
type = 'password'
/>
</styled.RegisterInputWrapper>
</> :
props.page === 2 ?
<>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>의사 자격증 번호</styled.RegisterInputText>
<styled.RegisterInput
placeholder = "Doctor's License"
value = {props.registerForm.info.doctorLicense}
onChange = {props.onSetDoctorLicense}
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>이름</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Name'
value = {props.registerForm.info.doctorNm}
onChange = {props.onSetDoctorNm}
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>연락처</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Contact'
value = {props.registerForm.info.contact}
onChange = {props.onSetContact}
/>
</styled.RegisterInputWrapper>
</> :
props.page === 3 ?
<>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>전문 분야</styled.RegisterInputText>
<styled.RegisterInput
placeholder = "Doctor's Type"
value = {props.registerForm.info.doctorType}
onChange = {props.onSetDoctorType}
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>병원 이름</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Hospital'
value = {props.registerForm.info.hospitalNm}
onChange = {props.onSetHospitalNm}
/>
</styled.RegisterInputWrapper>
<styled.RegisterInputWrapper>
<styled.RegisterInputText>병원 주소</styled.RegisterInputText>
<styled.RegisterInput
placeholder = 'Address'
value = {props.registerForm.info.hospitalAddr}
onChange = {props.onSetHospitalAddr}
/>
</styled.RegisterInputWrapper>
</> : null
}
<styled.RegisterButtonWrapper>
<styled.RegisterButton
onClick = {props.onSubmitButton}
>
{
props.page < 3 ? '다음' : '회원 가입'
}
</styled.RegisterButton>
</styled.RegisterButtonWrapper>
</styled.RegisterWrapper>
</styled.Container>
)
...
...
web/src/views/register/RegisterStyled.tsx
View file @
49de869
import styled from 'styled-components';
export const Container = styled.div `
width : 100%;
height : 80vh;
...
...
@@ -24,6 +25,44 @@ export const RegisterWrapper = styled.div `
box-shadow: 0px 0px 10px #a0a0a0;
`;
export const RegisterBackButtonWrapper = styled.div `
width : 100%;
border : none;
display : flex;
flex-direction : row-reverse;
align-items : center;
justify-content : space-between;
margin : 0 0 10px 0;
`;
export const RegisterBackButton = styled.div `
border : none;
border-bottom : 1px solid;
background-color : transparent;
color : #a0a0a0;
cursor : pointer;
font-size : 12px;
font-weight : 500;
letter-spacing : 1px;
padding : 1px 3px;
margin : 0px 20px;
transition : .25s all;
&:hover {
opacity : .7;
}
`;
export const RegisterTitle = styled.div `
...
...
@@ -60,11 +99,48 @@ export const RegisterInputText = styled.div `
export const RegisterInput = styled.input `
width : 80%;
padding :
0 0 5px 0
;
padding :
5px 10px
;
border : none;
border-bottom : 1px solid #ddd;
font-size : 14px;
letter-spacing : 1px;
&::placeholder {
color : #ddd;
}
`;
export const RegisterButtonWrapper = styled.div `
margin : 20px 0 0 0;
width : 100%;
border : none;
display : flex;
justify-content : center;
align-items : center;
`;
export const RegisterButton = styled.button `
padding : 10px 30px;
width : 80%;
cursor : pointer;
background-color : transparent;
border : 1.2px solid;
border-radius : 3px;
color : #343434;
transition : .25s all;
&:hover {
color : #fff;
border : 1.2px solid #343434;
background-color : #343434;
}
`;
\ No newline at end of file
...
...
web/yarn.lock
View file @
49de869
This diff could not be displayed because it is too large.
Please
register
or
login
to post a comment