Skip to content

Commit

Permalink
Xquare 회원가입 페이지 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaisqls committed Mar 9, 2024
1 parent fa6d490 commit 25b12d2
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ProjectApprove } from './manage/ProjectApprove';
import { ProjectList } from './manage/ProjectList';
import reportWebVitals from './reportWebVitals';
import Login from './manage/Login';
import SignUp from "./signup/SignUp";
import {SignUpDone} from "./signup/SignUpDone";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
Expand All @@ -19,6 +21,8 @@ root.render(
<Route path="/admin/approve" element={<ProjectApprove/>}></Route>
<Route path="/admin/list" element={<ProjectList/>}></Route>
<Route path="/admin" element={<Login/>}></Route>
<Route path="/signup" element={<SignUp/>}></Route>
<Route path="/signup/done" element={<SignUpDone/>}></Route>
</Routes>
</BrowserRouter>
</React.StrictMode>
Expand Down
197 changes: 197 additions & 0 deletions src/signup/SignUp.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function InputField({ label, type, value, onChange, error }) {
return (
<label className="block mb-2 text-sm text-gray-700">
{label}
<input
className={`w-full px-3 py-2 mt-1 text-sm leading-tight text-gray-700 border rounded shadow appearance-none focus:outline-none focus:shadow-outline ${error ? 'border-red-500' : ''}`}
type={type}
value={value}
onChange={onChange}
/>
{error && <p className="text-red-500 text-sm mt-1">{error}</p>}
</label>
);
}

function useInput(initialValue, validation) {
const [value, setValue] = useState(initialValue);
const [error, setError] = useState('');
function handleChange(event) {
const inputValue = event.target.value;
setValue(inputValue);
setError(inputValue === '' ? '필수 항목입니다.' : validation(inputValue));
}
return { value, setValue, onChange: handleChange, error, setError };
}

export const SignUp = () => {
const nameInput = useInput('', (value) => (/^[가-힣]+$/.test(value) ? '' : '올바른 이름을 입력해주세요.'));
const studentNumberInput = useInput('', (value) => (1100 < value && value < 1500 ? '' : '올바른 학번을 입력해주세요.'))
const birthdayInput = useInput('', (value) => (/^\d{4}-\d{2}-\d{2}$/.test(value) ? '' : '올바른 형식으로 입력해주세요.'));
const accountIdInput = useInput('', (value) => (/^[a-zA-Z0-9\s]+$/.test(value) ? '' : '영어 대소문자, 숫자만 사용할 수 있습니다.'));
const passwordInput = useInput('', (value) => (/(?=.*[a-z])(?=.*[0-9])(?=.*[!#$%&'()*+,./:;<=>?@\^_`{|}~])[a-zA-Z0-9!#$%&'()*+,./:;<=>?@\^_`{|}~]{8,30}$/.test(value) ? '' : '비밀번호는 영어, 숫자, 특수문자가 포함된 8~30자여야 합니다.'));
const passwordCheckInput = useInput('', (value) => (value === passwordInput.value ? '' : '비밀번호가 일치하지 않습니다.'))

const [studentNumberDuplicateCheck, setStudentNumberDuplicateCheck] = useState(false);
const [accountIdDuplicateCheck, setAccountIdDuplicateCheck] = useState(false);

useEffect(() => {
setStudentNumberDuplicateCheck(false)
}, [studentNumberInput.value]);

const baseurl = 'https://prod-server.xquare.app/dsm-login'
async function checkStudentNumberAvailability(value) {
try {
if (!studentNumberInput.error || studentNumberInput.error === '중복체크를 완료해주세요.') {
await axios.get(baseurl + '/user/class-number-check/' + value)
.then((res) => {
if (res.data.duplicated) {
studentNumberInput.setError('이미 존재하는 학번입니다.')
} else {
setStudentNumberDuplicateCheck(true)
studentNumberInput.setError('')
}
})
}
} catch (error) {
console.error(error);
}
}

useEffect(() => {
setAccountIdDuplicateCheck(false)
}, [accountIdInput.value]);

async function checkAccountIdAvailability(value) {
try {
if (!accountIdInput.error || accountIdInput.error === '중복체크를 완료해주세요.') {
await axios.get(baseurl + '/user/account-id-check/' + value)
.then((res) => {
if (res.data.duplicated) {
accountIdInput.setError('이미 존재하는 아이디입니다.')
} else {
setAccountIdDuplicateCheck(true)
accountIdInput.setError('')
}
})
}
} catch (error) {
console.error(error);
}
}

async function handleSubmit(e) {
e.preventDefault();

let check = true;
if (!studentNumberDuplicateCheck) { studentNumberInput.setError('중복체크를 완료해주세요.'); check = false; }
if (!accountIdDuplicateCheck) { studentNumberInput.setError('중복체크를 완료해주세요.'); check = false; }

if (!nameInput.value) { nameInput.setError('필수 항목입니다.'); check = false; }
if (!birthdayInput.value) { birthdayInput.setError('필수 항목입니다.'); check = false; }
if (!studentNumberInput.value) { studentNumberInput.setError('필수 항목입니다.'); check = false; }
if (!accountIdInput.value) { accountIdInput.setError('필수 항목입니다.'); check = false; }
if (!passwordInput.value) { passwordInput.setError('필수 항목입니다.'); check = false; }
if (!passwordCheckInput.value) { passwordCheckInput.setError('비밀번호를 다시 한 번 입력해주세요.'); check = false; }

// 모든 입력 필드의 유효성 검사 확인
if (
check &&
!nameInput.error &&
!birthdayInput.error &&
!studentNumberInput.error &&
!accountIdInput.error &&
!passwordInput.error &&
!passwordCheckInput.error
) {
const dataToSubmit = {
name: nameInput.value,
birthday: birthdayInput.value,
birth_day: birthdayInput.value,
class_number: studentNumberInput.value,
account_id: accountIdInput.value,
password: passwordInput.value,
password_check: passwordInput.value
};
// Axios 요청 보내기
axios.post(baseurl + '/user/signup', dataToSubmit)
.then((res) => {console.log(res); window.location.href = '/signup/done'})
.catch((err) => console.error(err));
}
}

return (
<div className="my-[10px] flex flex-col items-center justify-center h-screen bg-gray-200">
<form className="p-6 flex flex-col gap-[15px] bg-white rounded w-[500px]" onSubmit={handleSubmit}>
<img className="my-0 mx-auto h-16" src="https://github.com/rlaisqls/TIL/assets/81006587/4492b702-5cb6-40af-821d-e264cd82549b"/>
<p>안녕하세요. Xquare 회원가입 페이지입니다 :)<br/>자신의 정보를 입력하여 회원가입 해주세요!</p>
<InputField
label="이름"
type="text"
{...nameInput}
required
/>
<InputField
label="생일 (ex. 2006-12-14)"
type="text"
{...birthdayInput}
required
/>
<div className="flex flex-row gap-[10px]">
<InputField
label="학번"
type="number"
{...studentNumberInput}
required
/>
{!studentNumberDuplicateCheck ? (
<div
className="px-4 py-2 mt-[27.5px] w-fit h-fit outline outline-2 outline-slate-900 rounded-md hover:outline-slate-600 hover:text-slate-600"
onClick={async () => checkStudentNumberAvailability(studentNumberInput.value)}>중복체크</div>
) : (
<div
className="px-4 py-2 mt-[27.5px] w-fit h-fit outline outline-2 outline-slate-500 text-slate-500 rounded-md bg-slate-200">사용가능</div>
)}
</div>
<div className="flex flex-row gap-[10px]">
<InputField
label="아이디"
type="text"
{...accountIdInput}
required
/>
{!accountIdDuplicateCheck ? (
<div
className="px-4 py-2 mt-[27.5px] w-fit h-fit outline outline-2 outline-slate-900 rounded-md hover:outline-slate-600 hover:text-slate-600"
onClick={async () => checkAccountIdAvailability(accountIdInput.value)}>중복체크</div>
) : (
<div
className="px-4 py-2 mt-[27.5px] w-fit h-fit outline outline-2 outline-slate-500 text-slate-500 rounded-md bg-slate-200">사용가능</div>
)}
</div>
<InputField
label="비밀번호"
type="password"
{...passwordInput}
/>
<InputField
label="비밀번호 확인"
type="password"
{...passwordCheckInput}
/>

<button
className="w-full px-4 py-2 mt-6 text-white bg-[#9650FA] rounded-md hover:bg-[#8640FA] focus:outline-none focus:shadow-outline"
type="submit"
>
제출하기
</button>
</form>
</div>
);
}

export default SignUp;
37 changes: 37 additions & 0 deletions src/signup/SignUpDone.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useEffect, useState } from 'react';

export const SignUpDone = () => {

const [projectName, setProjectName] = useState('');

useEffect(() => {
const currentURL = new URL(window.location.href);
const searchParams = currentURL.searchParams;
setProjectName(searchParams.get('projectname'))
}, []);

return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-200">
<img className="my-0 mx-auto h-16"
src="https://github.com/rlaisqls/TIL/assets/81006587/4492b702-5cb6-40af-821d-e264cd82549b"/>

<img className="h-[300px] my-4"
src="https://github.com/rlaisqls/rlaisqls/assets/81006587/416ba6e7-193d-43a2-89ec-284a86e72e86"
alt="Thankyou"/>
<p className="text-[20px] text-center leading-loose">
감사합니다! Xquare 회원가입이 완료되었습니다 :)<br/>
곧 공개될 학교 프로젝트들을 기대해주세요!<br/>
심심한 1학년이라면 아래 링크를 한 번 눌러보세용
</p>

<a href="https://scratched-aries-15e.notion.site/DSM-1-d314aa7ba06642cd999c6b01c7a35cc8?pvs=4">
<button
className="w-[230px] px-4 py-2 mt-6 text-white bg-[#9650FA] rounded-md hover:bg-[#8640FA] focus:outline-none focus:shadow-outline"
type="button"
>
선배들이 준비한 신입생 로드맵
</button>
</a>
</div>
);
}

0 comments on commit 25b12d2

Please sign in to comment.