Skip to content

Commit 190b682

Browse files
authored
feat: RecruitSubmit,Result,Check 페이지 추가 + Banner 컴포넌트 추가 + 기존 UI 컴포넌트 폰트 수정
* feat: RecruitSubmit,Result,Check 페이지 추가 + Banner 컴포넌트 추가 + 기존 UI 컴포넌트 폰트 수정
1 parent 75038bb commit 190b682

File tree

8 files changed

+314
-50
lines changed

8 files changed

+314
-50
lines changed

src/components/UI/RecruitUI.tsx

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,94 @@
11
import React from 'react'
22

3-
43
interface RecruitHeaderProps {
54
title: string;
65
}
76

87
export const RecruitHeader: React.FC<RecruitHeaderProps> = ({ title }) => {
98
return (
10-
<div className=" w-full max-w-[375px] bg-[#00B493] text-white font-bold text-[11px] p-1 pl-2 ml-2.5">
9+
<div className=" w-full max-w-[375px] bg-[#00B493] text-white font-pretendardBold text-[13px] p-1 pl-2 ml-2.5 mt-16">
1110
{title}
1211
</div>
1312
)
1413
}
1514

1615

1716
export const RecruitUI: React.FC = () => {
18-
return (
19-
<div className=" text-gray-300 flex flex-col items-start max-w-[375px] h-[250px] shadow-[0px_2px_3px_rgba(255,255,255,0.2)] bg-#17171B] gap-2 ml-2.5">
20-
<p className=" text-[10px] font-bold pl-2 pt-2">
21-
다솜에서 개발자로서 성장해갈 <span className="text-yellow-400 font-bold">34기 멤버분들</span>을 찾습니다!
17+
return (
18+
<div className="text-white font-pretendardRegular flex flex-col text-[12px] items-start max-w-[375px] shadow-[0px_2px_3px_rgba(255,255,255,0.2)] bg-#17171B] gap-2 ml-2.5">
19+
<p className="pl-2 pt-2">
20+
<span className='font-pretendardBold'>다솜</span>에서 개발자로서 성장해갈 <span className="text-yellow-400 font-pretendardBold">34기 멤버분들</span>을 찾습니다!
21+
</p>
22+
<div className="mt-2 pl-2">
23+
<p className="text-green-400 font-pretendardSemiBold">📅 모집 일정 :</p>
24+
<p>모집 폼 제출 : 2/25(화) ~ 3/14(금)</p>
25+
<p>대면 면접 : 3/19(수) ~ 3/21(금)</p>
26+
<p>최종 합격자 발표 : 3/24(월)</p>
27+
</div>
28+
29+
<div className="mt-2 pl-2 flex items-center">
30+
<p className="text-green-400 font-pretendardSemiBold">📝 모집 대상 :</p>
31+
<span className="text-white pl-1">25년도 1학기부터 다솜과 함께할 예비 다솜 멤버</span>
32+
</div>
33+
34+
<div className="mt-2 pl-2 flex items-center">
35+
<p className="text-green-400 font-pretendardSemiBold">🌿 신청 조건 :</p>
36+
<span className="text-white pl-1 ">컴퓨터소프트웨어공학과 학생</span>
37+
</div>
38+
39+
<div className="mt-2 pl-2">
40+
<p className="text-green-400 font-pretendardSemiBold inline">🍀 회비 :</p>
41+
<span className="text-white pl-1 inline">20,000원</span>
42+
<p className="text-white mt-1">
43+
회비는 동아리 운영자금 및 프로젝트 서버비용 지원 등에 사용됩니다.
2244
</p>
23-
<div className="mt-2 text-[10px] pl-2">
24-
<p className="text-green-400 font-semibold">📅 모집 일정 :</p>
25-
<p>모집 폼 제출 : 2/25(화) ~ 3/14(금)</p>
26-
<p>대면 면접 : 3/19(수) ~ 3/21(금)</p>
27-
<p>최종 합격자 발표 : 3/24(월)</p>
28-
</div>
29-
30-
<div className="mt-2 text-[10px] pl-2">
31-
<p className="text-green-400 font-semibold">📝 모집 대상 :
32-
<span className="text-gray-300 pl-1">25년도 1학기부터 다솜과 함께할 예비 다솜 멤버</span>
33-
</p>
34-
</div>
35-
36-
<div className="mt-2 text-[10px] pl-2 ">
37-
<p className="text-green-400 font-semibold">🌿 신청 조건 :
38-
<span className="text-gray-300 pl-1">컴퓨터소프트웨어공학과 학생</span>
39-
</p>
40-
</div>
41-
42-
<div className="mt-2 text-[10px] pl-2">
43-
<p className="text-green-400 font-semibold">💰 회비 :
44-
<span className="text-gray-300 pl-1">20,000원 </span>
45-
</p>
46-
<p> 회비는 동아리 운영자금 및 프로젝트 서버비용 지원 등에 사용됩니다. </p>
47-
</div>
48-
49-
<p className="mt-2 text-[10px] pl-2">👀 의지가 있으며 교류를 중시하는 분을 기다립니다.</p>
5045
</div>
51-
)
46+
<p className="pl-2 mb-4 ">👀 의지가 있으며 교류를 중시하는 분을 기다립니다.</p>
47+
</div>
48+
)
5249
}
50+
51+
52+
53+
54+
export const RecruitUI_SUB: React.FC = () => {
55+
return (
56+
<div className=" text-gray-300 flex flex-col items-start max-w-[375px] h-[auto] shadow-[0px_2px_3px_rgba(255,255,255,0.2)] bg-#17171B] gap-2 ml-2.5">
57+
58+
{/* 1차 서류 합격 안내 */}
59+
<p className="text-[15px] font-bold text-yellow-300 pt-3">
60+
🎊 1차 서류 합격을 진심으로 축하드립니다!
61+
</p>
62+
<p className="text-[12px] p-1">
63+
2차 면접이 진행될 예정입니다. 아래에서 <span className="text-green-400 font-semibold">편하신 날짜와 시간을 선택하여 예약</span>해주세요.
64+
</p>
65+
66+
{/* 면접 일정 */}
67+
68+
<p className="text-green-400 font-semibold text-sm">📅 면접 일정</p>
69+
<p className="text-xs">✔ 3월 19일(수) ~ 3월 21일(금)</p>
70+
71+
72+
{/* 면접 장소 */}
73+
74+
<p className="text-green-400 font-semibold text-sm">🕒 면접 장소</p>
75+
<p className="text-xs">✔ 개별 안내 예정</p>
76+
77+
78+
{/* 추가 안내 사항 */}
79+
80+
<p className="text-yellow-300 font-semibold text-sm">📌 면접 안내 사항</p>
81+
<p className="text-xs">✅ 면접은 <span className="text-white">개별 면접</span>으로 진행됩니다.</p>
82+
<p className="text-xs"><span className="text-white">예약 변경은 불가</span>하므로 신중히 선택해주세요.</p>
83+
<p className="text-xs">✅ 선착순 마감으로 <span className="text-white">일부 시간대는 예약이 어려울 수 있습니다.</span></p>
84+
85+
86+
<p className="mt-4 text-[12px] text-gray-300 mb-3">
87+
🔔 면접 당일 <span className="text-yellow-300 font-semibold">지각 없이 참석</span> 부탁드립니다.
88+
<p>💡 면접 일정은 선착순으로 마감되므로 빠른 예약을 권장드립니다! 😊</p>
89+
</p>
90+
91+
</div>
92+
)
93+
}
94+

src/components/UI/Recruit_Button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ interface ButtonProps {
99
export const Button: React.FC<ButtonProps> = ({ text, className }) => {
1010
return (
1111
<div className='w-full max-w-[395px] h-[50px] flex justify-center'>
12-
<button
13-
className={`bg-[#00B493] max-w-[395px] h-[22px] text-white font-bold px-4 text-[10px] transition-all hover:bg-[#00937A] active:scale-95 ${className}`}
12+
<button type="submit"
13+
className={`bg-[#00B493] max-w-[395px] h-[22px] text-white font-bold px-4 text-[12px] transition-all hover:bg-[#00937A] active:scale-95 ${className}`}
1414
>
1515
{text}
1616
</button>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react'
2+
3+
interface Recruit_InfoBannerProps {
4+
message: string;
5+
date: string;
6+
}
7+
8+
// 📌 Recruit 공지 컴포넌트
9+
export const Recruit_InfoBanner: React.FC<Recruit_InfoBannerProps> = ({ message, date }) => {
10+
return (
11+
<div className="w-full max-w-[395px] p-2 mt-3 text-white text-center text-[10px] font-bold">
12+
<div className='max-w[355px] bg-[#00B493] p-1'>
13+
<p>{message}</p>
14+
<p>
15+
{date.includes('이메일') ? (
16+
date.split('이메일').map((part, index) => (
17+
index === 0 ? (
18+
<span key={index}>
19+
{part}
20+
<span className="text-red-600 ">이메일</span>
21+
</span>
22+
) : (
23+
<span key={index}>{part}</span>
24+
)
25+
))
26+
) : (
27+
date
28+
)}
29+
</p>
30+
</div>
31+
</div>
32+
)
33+
}

src/components/UI/Recruit_InputField.tsx

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// import React, { useRef } from 'react'
12
import React from 'react'
23

34
interface InputFieldProps {
@@ -8,6 +9,7 @@ interface InputFieldProps {
89
required?: boolean;
910
options?: { value: string; label: string }[];
1011
checkboxLabel?: string;
12+
phoneNumber?: boolean;
1113
}
1214

1315
export const InputField: React.FC<InputFieldProps> = ({
@@ -18,7 +20,30 @@ export const InputField: React.FC<InputFieldProps> = ({
1820
required = false,
1921
options = [],
2022
checkboxLabel = '확인했습니다.',
23+
phoneNumber = false,
2124
}) => {
25+
26+
// const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null)
27+
28+
// const handleKeyDown = (e: React.KeyboardEvent) => {
29+
// if (e.key === 'Enter' && type !== 'textarea') {
30+
// e.preventDefault() // 기본 엔터 동작(폼 제출) 방지
31+
32+
// const inputElement = e.currentTarget as HTMLInputElement // 🔹 타입 단언 추가
33+
// const form = inputElement.form // 🔹 이제 form 속성 사용 가능
34+
35+
// if (!form) return
36+
37+
// const index = Array.from(form.elements).indexOf(inputElement)
38+
// const nextElement = form.elements[index + 1] as HTMLElement
39+
40+
// if (nextElement) {
41+
// nextElement.focus() // 다음 input으로 포커스 이동
42+
// }
43+
// }
44+
// }
45+
46+
2247

2348
// 📌 공통 스타일 변수
2449
const containerStyles = 'mb-4 p-3 shadow-[0px_2px_3px_rgba(255,255,255,0.2)] text-white'
@@ -28,18 +53,32 @@ export const InputField: React.FC<InputFieldProps> = ({
2853
return (
2954
<div className={containerStyles}>
3055
<label className="block text-white text-[10px] font-bold mb-1">
31-
{label.split('대면으로').map((part, index) => (
32-
<span key={index}>
56+
{label.split(/(| 4)/).map((part, index) => (
57+
<span key={index} className={part === '대면으로' ? 'text-red-500' : part === '전화번호 마지막 4자리' ? 'text-[#00B493]' : ''}>
3358
{part}
34-
{index !== label.split('대면으로').length - 1 && (
35-
<span className="text-red-500">대면으로</span>
36-
)}
3759
</span>
3860
))}
3961
{type !== 'checkbox' && type !== 'test' && required && <span className="text-red-500 pl-1">*</span>}
4062
</label>
4163

42-
{subLabel && <p className=" font-bold text-[10px] mb-3">{subLabel}</p>}
64+
{subLabel && (
65+
<p className="font-bold text-[10px]">
66+
{subLabel.split(/(ex\)|\d{4})/).map((part, index, array) => (
67+
<span
68+
key={index}
69+
className={
70+
part === 'ex)'
71+
? 'text-[#A5A5A5]'
72+
: index === array.length - 2 && /\d{4}/.test(part)
73+
? 'text-[#00B493]'
74+
: ''
75+
}
76+
>
77+
{part}
78+
</span>
79+
))}
80+
</p>
81+
)}
4382

4483
{type === 'select' ? (
4584
<select className={baseInputStyles}>
@@ -55,7 +94,7 @@ export const InputField: React.FC<InputFieldProps> = ({
5594
) : type === 'checkbox' ? (
5695
<div className="flex items-center space-x-2">
5796
<input type="checkbox" className={inputStyles} required={required} />
58-
97+
5998
<span className="text-white text-[10px]">{checkboxLabel}</span>
6099
</div>
61100

src/pages/Recruit.tsx

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,84 @@
1-
import React from 'react'
1+
import React, { useState } from 'react'
22
import MobileLayout from '../components/layout/MobileLayout'
3+
import { useNavigate } from 'react-router-dom'
34
import { Header } from '../components/UI/Header'
45
import { RecruitUI, RecruitHeader } from '../components/UI/RecruitUI'
56
import { InputField } from '../components/UI/Recruit_InputField'
67
import { Button } from '../components/UI/Recruit_Button'
78

89
const Recruit: React.FC = () => {
10+
11+
const navigate = useNavigate()
12+
13+
14+
const [formData, setFormData] = useState({
15+
name: '',
16+
studentNo: '',
17+
contact: '',
18+
email: '',
19+
grade: '',
20+
reasonForApply: '',
21+
activityWish: '',
22+
isPrivacyPolicyAgreed: false, // 개인정보 동의 체크
23+
isOverwriteConfirmed: false, // 중복 지원 여부 체크
24+
})
25+
26+
27+
// 📌 입력값 변경 핸들러
28+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
29+
const { name, value, type } = e.target
30+
const newValue = type === 'checkbox' ? (e.target as HTMLInputElement).checked : value
31+
32+
setFormData((prevData) => ({
33+
...prevData,
34+
[name]: newValue,
35+
}))
36+
}
37+
38+
// 📌 API 요청 보내기 (POST)
39+
const handleSubmit = async (e: React.FormEvent) => {
40+
e.preventDefault()
41+
42+
// 유효성 검사 (예: 모든 필수 값 입력 확인)
43+
if (!formData.name || !formData.studentNo || !formData.contact || !formData.email || !formData.reasonForApply) {
44+
alert('모든 필수 정보를 입력해주세요.')
45+
return
46+
}
47+
48+
try {
49+
const response = await fetch('http://dmu-dasom/or.kr/api/recruit/apply', {
50+
method: 'POST',
51+
headers: {
52+
'Content-Type': 'application/json',
53+
},
54+
body: JSON.stringify(formData),
55+
})
56+
57+
if (response.ok) {
58+
alert('지원이 성공적으로 제출되었습니다!')
59+
navigate('/recruit-submit') // ✅ 제출 후 페이지 이동
60+
} else {
61+
const errorData = await response.json()
62+
alert(`오류 발생: ${errorData.message}`)
63+
}
64+
} catch (error) {
65+
console.error('API 요청 중 오류 발생:', error)
66+
alert('지원 제출 중 오류가 발생했습니다.')
67+
}
68+
}
69+
70+
71+
// const handleSubmit = (e: React.FormEvent) => {
72+
// e.preventDefault()
73+
// navigate('/recruit-submit')
74+
// }
75+
976
return (
1077
<MobileLayout>
1178
<RecruitHeader title="컴퓨터 소프트웨어 공학과 전공 동아리 다솜 34기 모집 폼" />
1279
<RecruitUI />
13-
<div className=" flex flex-col items-center gap-6">
14-
<form className="mt-3 bg-mainBlack w-full px-2">
80+
<div className=" flex flex-col items-center gap-6 ">
81+
<form className="mt-3 bg-mainBlack w-full px-2" onSubmit={handleSubmit}>
1582
<InputField label="이름" required />
1683
<InputField label="학번" required />
1784
<InputField label="연락처" placeholder="ex) 010-0000-0000" required />
@@ -41,12 +108,10 @@ const Recruit: React.FC = () => {
41108
type='checkbox'
42109
required
43110
/>
111+
<Button text="폼 제출하기" />
44112
</form>
45-
46-
47-
48113
</div>
49-
<Button text="폼 제출하기" />
114+
50115
</MobileLayout>
51116
)
52117
}

0 commit comments

Comments
 (0)