어드민 회원 가입신청 기능 추가
This commit is contained in:
@@ -73,7 +73,7 @@ const App = () => {
|
|||||||
>
|
>
|
||||||
<Routes>
|
<Routes>
|
||||||
{/* 1. 로그인 여부와 관계없이 항상 독립적으로 표시되는 페이지 */}
|
{/* 1. 로그인 여부와 관계없이 항상 독립적으로 표시되는 페이지 */}
|
||||||
<Route path="/register" element={<Register />} />
|
<Route path="/admin/member/register" element={<Register />} />
|
||||||
<Route path="/404" element={<Page404 />} />
|
<Route path="/404" element={<Page404 />} />
|
||||||
<Route path="/500" element={<Page500 />} />
|
<Route path="/500" element={<Page500 />} />
|
||||||
|
|
||||||
|
|||||||
@@ -62,3 +62,9 @@ export const deleteAdminMember = async (memberSeq: number): Promise<AdminMemberR
|
|||||||
const response = await axios.post<AdminMemberResponse>('/admin/member/delete', { memberSeq });
|
const response = await axios.post<AdminMemberResponse>('/admin/member/delete', { memberSeq });
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 회원 가입 (비로그인 상태에서 회원가입)
|
||||||
|
export const registerAdminMember = async (member: Partial<AdminMember>): Promise<AdminMemberResponse> => {
|
||||||
|
const response = await axios.post<AdminMemberResponse>('/admin/member/register', member);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ const Login = () => {
|
|||||||
setError('쿠키에서 accessToken을 찾을 수 없습니다.');
|
setError('쿠키에서 accessToken을 찾을 수 없습니다.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setError(response.resultMessage || '로그인에 실패했습니다.');
|
let errorMsg = response.resultMessage || '로그인에 실패했습니다.'
|
||||||
|
if (response.resultData && typeof response.resultData === 'string') {
|
||||||
|
errorMsg += `\n${response.resultData}`
|
||||||
|
}
|
||||||
|
setError(errorMsg)
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(err.response?.data?.message || '로그인 중 오류가 발생했습니다.');
|
setError(err.response?.data?.message || '로그인 중 오류가 발생했습니다.');
|
||||||
@@ -65,16 +69,16 @@ const Login = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
||||||
<CContainer>
|
<CContainer fluid>
|
||||||
<CRow className="justify-content-center">
|
<CRow className="justify-content-center">
|
||||||
<CCol md={8}>
|
<CCol md={8}>
|
||||||
<CCardGroup>
|
<CCardGroup style={{ minWidth: '300px' }}>
|
||||||
<CCard className="p-4">
|
<CCard className="p-4">
|
||||||
<CCardBody>
|
<CCardBody>
|
||||||
<CForm onSubmit={handleSubmit}>
|
<CForm onSubmit={handleSubmit}>
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<p className="text-body-secondary">Sign In to your account</p>
|
<p className="text-body-secondary">Sign In to your account</p>
|
||||||
{error && <div className="text-danger mb-3">{error}</div>}
|
{error && <div className="text-danger mb-3" style={{ whiteSpace: 'pre-line' }}>{error}</div>}
|
||||||
<CInputGroup className="mb-3">
|
<CInputGroup className="mb-3">
|
||||||
<CInputGroupText>
|
<CInputGroupText>
|
||||||
<CIcon icon={cilUser} />
|
<CIcon icon={cilUser} />
|
||||||
@@ -108,16 +112,19 @@ const Login = () => {
|
|||||||
</CForm>
|
</CForm>
|
||||||
</CCardBody>
|
</CCardBody>
|
||||||
</CCard>
|
</CCard>
|
||||||
<CCard className="text-white bg-primary py-5">
|
<CCard className="text-white bg-primary py-5" style={{ minWidth: '300px' }}>
|
||||||
<CCardBody className="text-center">
|
<CCardBody className="text-center">
|
||||||
<div>
|
<div>
|
||||||
<h2>Sign up</h2>
|
<h2>가입신청</h2>
|
||||||
|
<br/>
|
||||||
<p>
|
<p>
|
||||||
신규 사용자의 경우, 가입신청 후 권한을 부여받아야 접속 가능합니다.
|
신규 어드민 회원은<br/>
|
||||||
|
가입신청 후 권한을 부여받아야<br/>
|
||||||
|
접속 가능합니다.
|
||||||
</p>
|
</p>
|
||||||
<Link to="/register">
|
<Link to="/admin/member/register">
|
||||||
<CButton color="primary" className="mt-3" active tabIndex={-1}>
|
<CButton color="primary" className="mt-3" active tabIndex={-1}>
|
||||||
Register Now!
|
어드민 회원가입 신청
|
||||||
</CButton>
|
</CButton>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { useNavigate, Link } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
CButton,
|
CButton,
|
||||||
CCard,
|
CCard,
|
||||||
@@ -7,14 +8,79 @@ import {
|
|||||||
CContainer,
|
CContainer,
|
||||||
CForm,
|
CForm,
|
||||||
CFormInput,
|
CFormInput,
|
||||||
CInputGroup,
|
CFormLabel,
|
||||||
CInputGroupText,
|
|
||||||
CRow,
|
CRow,
|
||||||
|
CSpinner,
|
||||||
} from '@coreui/react'
|
} from '@coreui/react'
|
||||||
import CIcon from '@coreui/icons-react'
|
import { registerAdminMember } from 'src/services/adminMemberService'
|
||||||
import { cilLockLocked, cilUser } from '@coreui/icons'
|
import { logout } from 'src/axios/authService'
|
||||||
|
|
||||||
const Register = () => {
|
const Register = () => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
// 회원가입 페이지 진입 시 기존 토큰 제거
|
||||||
|
useEffect(() => {
|
||||||
|
logout()
|
||||||
|
}, [])
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
memberId: '',
|
||||||
|
memberName: '',
|
||||||
|
password: '',
|
||||||
|
passwordConfirm: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const { name, value } = e.target
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[name]: value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
// 유효성 검사
|
||||||
|
if (!formData.memberId.trim()) {
|
||||||
|
alert('어드민 회원 ID를 입력해주세요.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.memberName.trim()) {
|
||||||
|
alert('이름을 입력해주세요.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.password) {
|
||||||
|
alert('비밀번호를 입력해주세요.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (formData.password !== formData.passwordConfirm) {
|
||||||
|
alert('비밀번호가 일치하지 않습니다.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const response = await registerAdminMember({
|
||||||
|
memberId: formData.memberId,
|
||||||
|
memberName: formData.memberName,
|
||||||
|
password: formData.password,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.resultCode === '200') {
|
||||||
|
alert('회원가입이 완료되었습니다. 관리자 승인 후 로그인이 가능합니다.')
|
||||||
|
navigate('/login')
|
||||||
|
} else {
|
||||||
|
alert(response.resultMessage || '회원가입에 실패했습니다.')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('회원가입 실패:', error)
|
||||||
|
alert('회원가입에 실패했습니다.')
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
||||||
<CContainer>
|
<CContainer>
|
||||||
@@ -22,41 +88,78 @@ const Register = () => {
|
|||||||
<CCol md={9} lg={7} xl={6}>
|
<CCol md={9} lg={7} xl={6}>
|
||||||
<CCard className="mx-4">
|
<CCard className="mx-4">
|
||||||
<CCardBody className="p-4">
|
<CCardBody className="p-4">
|
||||||
<CForm>
|
<CForm onSubmit={handleSubmit}>
|
||||||
<h1>Register</h1>
|
<h1>어드민 회원가입</h1>
|
||||||
<p className="text-body-secondary">Create your account</p>
|
<p className="text-body-secondary">어드민 계정을 생성합니다</p>
|
||||||
<CInputGroup className="mb-3">
|
|
||||||
<CInputGroupText>
|
<div className="mb-3">
|
||||||
<CIcon icon={cilUser} />
|
<CFormLabel htmlFor="memberId">어드민 회원 ID *</CFormLabel>
|
||||||
</CInputGroupText>
|
<CFormInput
|
||||||
<CFormInput placeholder="Username" autoComplete="username" />
|
type="text"
|
||||||
</CInputGroup>
|
id="memberId"
|
||||||
<CInputGroup className="mb-3">
|
name="memberId"
|
||||||
<CInputGroupText>@</CInputGroupText>
|
value={formData.memberId}
|
||||||
<CFormInput placeholder="Email" autoComplete="email" />
|
onChange={handleInputChange}
|
||||||
</CInputGroup>
|
placeholder="어드민 회원 ID를 입력하세요"
|
||||||
<CInputGroup className="mb-3">
|
autoComplete="username"
|
||||||
<CInputGroupText>
|
/>
|
||||||
<CIcon icon={cilLockLocked} />
|
</div>
|
||||||
</CInputGroupText>
|
|
||||||
|
<div className="mb-3">
|
||||||
|
<CFormLabel htmlFor="memberName">이름 *</CFormLabel>
|
||||||
|
<CFormInput
|
||||||
|
type="text"
|
||||||
|
id="memberName"
|
||||||
|
name="memberName"
|
||||||
|
value={formData.memberName}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="이름을 입력하세요"
|
||||||
|
autoComplete="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-3">
|
||||||
|
<CFormLabel htmlFor="password">비밀번호 *</CFormLabel>
|
||||||
<CFormInput
|
<CFormInput
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Password"
|
id="password"
|
||||||
|
name="password"
|
||||||
|
value={formData.password}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="비밀번호를 입력하세요"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</CInputGroup>
|
</div>
|
||||||
<CInputGroup className="mb-4">
|
|
||||||
<CInputGroupText>
|
<div className="mb-3">
|
||||||
<CIcon icon={cilLockLocked} />
|
<CFormLabel htmlFor="passwordConfirm">비밀번호 확인 *</CFormLabel>
|
||||||
</CInputGroupText>
|
|
||||||
<CFormInput
|
<CFormInput
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Repeat password"
|
id="passwordConfirm"
|
||||||
|
name="passwordConfirm"
|
||||||
|
value={formData.passwordConfirm}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="비밀번호를 다시 입력하세요"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</CInputGroup>
|
</div>
|
||||||
|
|
||||||
<div className="d-grid">
|
<div className="d-grid">
|
||||||
<CButton color="success">Create Account</CButton>
|
<CButton color="success" type="submit" disabled={loading}>
|
||||||
|
{loading ? (
|
||||||
|
<>
|
||||||
|
<CSpinner size="sm" className="me-2" />
|
||||||
|
가입 중...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
'회원가입'
|
||||||
|
)}
|
||||||
|
</CButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center mt-3">
|
||||||
|
<span className="text-body-secondary">이미 계정이 있으신가요? </span>
|
||||||
|
<Link to="/login">로그인</Link>
|
||||||
</div>
|
</div>
|
||||||
</CForm>
|
</CForm>
|
||||||
</CCardBody>
|
</CCardBody>
|
||||||
|
|||||||
Reference in New Issue
Block a user