From ddf0951e0caaa284fc6a810a35cfece4d16bc390 Mon Sep 17 00:00:00 2001
From: HYEON <74049556+dohy-eon@users.noreply.github.com>
Date: Fri, 4 Apr 2025 13:32:36 +0900
Subject: [PATCH 1/9] =?UTF-8?q?hotfix:=20=ED=95=99=EC=88=A0=ED=8C=80?=
=?UTF-8?q?=EC=9E=A5=20=EA=B9=83=ED=97=88=EB=B8=8C=20=EC=A3=BC=EC=86=8C?=
=?UTF-8?q?=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/CoreMembers.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/pages/CoreMembers.tsx b/src/pages/CoreMembers.tsx
index f816405..cbf5ce7 100644
--- a/src/pages/CoreMembers.tsx
+++ b/src/pages/CoreMembers.tsx
@@ -14,7 +14,7 @@ const profiles: Profile[] = [
{ id: 1, name: '윤도훈', roll: '회장', github_username: 'hodoon' },
{ id: 2, name: '공석', roll: '부회장', github_username: '' },
{ id: 3, name: '유승완', roll: '기술팀장', github_username: 'ysw789' },
- { id: 4, name: '최도현', roll: '학술팀장', github_username: 'titeotty' },
+ { id: 4, name: '최도현', roll: '학술팀장', github_username: 'dohy-eon' },
{ id: 5, name: '공석', roll: '학술차장', github_username: '' },
{ id: 6, name: '김수현', roll: '홍보팀장', github_username: 'sooh329' },
{ id: 7, name: '임성환', roll: '서기', github_username: 'limtjdghks' },
@@ -127,4 +127,4 @@ const CoreMembers: React.FC = () => {
)
}
-export default CoreMembers
\ No newline at end of file
+export default CoreMembers
From c4887b75d08f00dcef7e0b7bc050065b69cc1940 Mon Sep 17 00:00:00 2001
From: sooh329
Date: Wed, 9 Apr 2025 16:20:26 +0900
Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=EC=86=9C=EC=BB=A4=ED=86=A4=20?=
=?UTF-8?q?=EB=AA=A8=EC=A7=91=20=ED=8F=BC=20=EA=B5=AC=ED=98=84=EC=99=84?=
=?UTF-8?q?=EB=A3=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.tsx | 4 +
src/components/UI/RecruitUI.tsx | 34 ++++++
src/pages/SomkathonRecruit.tsx | 183 ++++++++++++++++++++++++++++++++
src/pages/SomkathonSubmit.tsx | 21 ++++
4 files changed, 242 insertions(+)
create mode 100644 src/pages/SomkathonRecruit.tsx
create mode 100644 src/pages/SomkathonSubmit.tsx
diff --git a/src/App.tsx b/src/App.tsx
index e24ee21..7dbbf55 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -24,6 +24,8 @@ import FAQ from './pages/FAQ'
import { RecruitSubmit } from './pages/RecruitSubmit'
import RecruitCheck from './pages/RecruitCheck'
import RecruitCheckFinal from './pages/RecruitCheckFinal'
+import SomkathonRecruit from './pages/SomkathonRecruit'
+import SomkathonSubmit from './pages/SomkathonSubmit'
import ProtectedRoute from './components/layout/ProtectRoute'
function App() {
@@ -59,6 +61,8 @@ function AppContent() {
} />
} />
} />
+ } />
+ } />
{/* 관리자 페이지 */}
} />
diff --git a/src/components/UI/RecruitUI.tsx b/src/components/UI/RecruitUI.tsx
index 88b3209..500b044 100644
--- a/src/components/UI/RecruitUI.tsx
+++ b/src/components/UI/RecruitUI.tsx
@@ -188,4 +188,38 @@ export const RecruitUI_FINAL2: React.FC = ({ name }) => {
)
+}
+
+export const SomRecruitUI: React.FC = () => {
+ return(
+
+
+ 솜커톤에서 멋진 프로젝트를 만들어주실 학우 여러분들을 모집합니다!
+
+
+
📅 모집 일정 :
+
4월 11일 (금) ~ 4월 16일 (수)
+
+
+
+
📝 모집 대상 :
+
25년도 1학기 솜커톤에 참가하는 학우 여러분
+
+
+
+
🌿 신청 조건 :
+
컴퓨터공학부 학생, 시각디자인과 동아리 구미래 부원
+
+
+
+
🍀 참가비 :
+
10,000원
+
+ 참가비는 솜커톤 행사 운영 자금으로 사용됩니다.
+ 납부 방법은 추후 안내드리겠습니다.
+
+
+
👀 의지가 있으며 교류를 중시하는 분을 기다립니다.
+
+ )
}
\ No newline at end of file
diff --git a/src/pages/SomkathonRecruit.tsx b/src/pages/SomkathonRecruit.tsx
new file mode 100644
index 0000000..be8b2bb
--- /dev/null
+++ b/src/pages/SomkathonRecruit.tsx
@@ -0,0 +1,183 @@
+import React, { useState, useEffect, useRef } from 'react'
+import axios from 'axios'
+import MobileLayout from '../components/layout/MobileLayout'
+import { useNavigate } from 'react-router-dom'
+import { SomRecruitUI, RecruitHeader } from '../components/UI/RecruitUI'
+import { InputField } from '../components/UI/Recruit_InputField'
+import { Button } from '../components/UI/Recruit_Button'
+
+
+const SomkathonRecruit: React.FC = () => {
+ const navigate = useNavigate()
+ const [contact, setContact] = useState('')
+ const [isRecruiting, setIsRecruiting] = useState(null)
+ const alertShown = useRef(false)
+
+ const [formData, setFormData] = useState({
+ participantName: '',
+ studentId: '',
+ department: '',
+ grade: '',
+ contact: '',
+ email: '',
+ })
+
+ useEffect(() => {
+ const checkRecruitmentPeriod = async () => {
+ const startDate = new Date('2025-04-08T00:00:00')
+ const endDate = new Date('2025-04-17T00:00:00')
+ const now = new Date()
+
+ if (now >= startDate && now <= endDate) {
+ setIsRecruiting(true)
+ } else {
+ setIsRecruiting(false)
+ if (!alertShown.current) {
+ alertShown.current = true
+ alert('현재 모집 기간이 아닙니다.')
+ navigate('/')
+ }
+ }
+ }
+
+ checkRecruitmentPeriod()
+ }, [navigate])
+
+ if (isRecruiting === false) return null
+
+ // 입력값들 제약조건 설정
+ const handleInputChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target
+ let newValue = value
+
+ if (name === 'contact') {
+ let formattedValue = value.replace(/[^0-9]/g, '')
+
+
+ if (formattedValue.length > 11) {
+ formattedValue = formattedValue.slice(0, 11)
+ }
+
+ if (formattedValue.length === 10) {
+ formattedValue = formattedValue.replace(/^(\d{3})(\d{3})(\d{4})$/, '$1-$2-$3')
+ } else if (formattedValue.length === 11) {
+ formattedValue = formattedValue.replace(/^(\d{3})(\d{4})(\d{4})$/, '$1-$2-$3')
+ }
+
+ setContact(formattedValue)
+ setFormData((prevData) => ({
+ ...prevData,
+ contact: formattedValue
+ }))
+ }
+ else if (name === 'participantName') {
+ if (value.length <= 16) {
+ setFormData((prevData) => ({
+ ...prevData,
+ participantName: value
+ }))
+ }
+ } else if (name === 'studentId') {
+ let formattedValue = value.replace(/[^0-9]/g, '')
+ formattedValue = formattedValue.slice(0, 8)
+
+ setFormData((prevData) => ({
+ ...prevData,
+ studentId: formattedValue
+ }))
+ } else {
+ setFormData((prevData) => ({
+ ...prevData,
+ [name]: newValue
+ }))
+ }
+ }
+
+ const handleKeyPress = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ e.preventDefault()
+
+ const form = e.currentTarget.form
+ if (!form) return
+
+ const elements = Array.from(form.elements) as HTMLElement[]
+ const index = elements.indexOf(e.currentTarget)
+
+
+ for (let i = index + 1; i < elements.length; i++) {
+ const nextElement = elements[i]
+ if (nextElement instanceof HTMLInputElement || nextElement instanceof HTMLTextAreaElement || nextElement instanceof HTMLSelectElement) {
+ nextElement.focus()
+ break
+ }
+ }
+ }
+ }
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault()
+ console.log(formData)
+ if (!formData.participantName || !formData.studentId || !formData.contact || !formData.email || !formData.department) {
+ alert('모든 필수 정보를 입력해주세요.')
+ return
+ }
+
+ try {
+ await axios.post('https://dmu-dasom-api.or.kr/api/somkathon/participants/create', formData, {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ })
+
+ navigate('/somkathon/result')
+ } catch (error: any) {
+ if (error.response) {
+ const errorData = error.response.data
+
+ if (error.response.status === 400 && errorData.code === 'C001') {
+ alert('입력 정보를 다시 확인해주세요.')
+ } else if (error.response.status === 400 && errorData.code === 'C002'){
+ alert('이미 등록된 학번입니다.')
+ }
+ } else {
+ console.error('API 요청 중 오류 발생:', error)
+ alert('네트워크 오류가 발생했습니다.')
+ }
+ }
+ }
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export default SomkathonRecruit
\ No newline at end of file
diff --git a/src/pages/SomkathonSubmit.tsx b/src/pages/SomkathonSubmit.tsx
new file mode 100644
index 0000000..aa7e0a9
--- /dev/null
+++ b/src/pages/SomkathonSubmit.tsx
@@ -0,0 +1,21 @@
+import React from 'react'
+import MobileLayout from '../components/layout/MobileLayout'
+import { Header } from '../components/UI/Header'
+import { SomRecruitUI, RecruitHeader } from '../components/UI/RecruitUI'
+import { Recruit_InfoBanner } from '../components/UI/Recruit_InfoBanner'
+
+const SomkathonSubmit: React.FC = () => {
+ return(
+
+
+
+
+
+
+ )
+}
+
+export default SomkathonSubmit
\ No newline at end of file
From 8ea202201a4d155a828036b1555ac7434b670cf7 Mon Sep 17 00:00:00 2001
From: sooh329
Date: Wed, 9 Apr 2025 16:40:28 +0900
Subject: [PATCH 3/9] =?UTF-8?q?feat:=20header=20=EC=86=9C=EC=BB=A4?=
=?UTF-8?q?=ED=86=A4=20=EC=A7=80=EC=9B=90=ED=95=98=EA=B8=B0=20=EC=B6=94?=
=?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/UI/Header.tsx | 32 +++++++++-----------------------
1 file changed, 9 insertions(+), 23 deletions(-)
diff --git a/src/components/UI/Header.tsx b/src/components/UI/Header.tsx
index 2a90c35..c7eb173 100644
--- a/src/components/UI/Header.tsx
+++ b/src/components/UI/Header.tsx
@@ -132,29 +132,15 @@ export const Header = (): JSX.Element => {
>
FAQ
-
- {/* 모집 기간에 따라 버튼 다르게 표시 */}
- {isRecruiting ? (
- {
- navigate('/recruit')
- toggleMenu()
- }}
- >
- 34기 지원하기
-
- ) : (
- {
- navigate('/recruit/result')
- toggleMenu()
- }}
- >
- 34기 합격여부 확인하기
-
- )}
+ {
+ navigate('/somkathon')
+ toggleMenu()
+ }}
+ >
+ 솜커톤 지원하기
+
)}
From bbd437cd238334d90eb26b6e55414468bc95f261 Mon Sep 17 00:00:00 2001
From: sooh329
Date: Wed, 9 Apr 2025 17:47:31 +0900
Subject: [PATCH 4/9] =?UTF-8?q?fix:=20navigate=EC=A3=BC=EC=86=8C=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=98=A4=EB=A5=98=EC=B2=98?=
=?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/UI/RecruitUI.tsx | 4 ++--
src/pages/SomkathonRecruit.tsx | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/UI/RecruitUI.tsx b/src/components/UI/RecruitUI.tsx
index 500b044..add893e 100644
--- a/src/components/UI/RecruitUI.tsx
+++ b/src/components/UI/RecruitUI.tsx
@@ -194,7 +194,7 @@ export const SomRecruitUI: React.FC = () => {
return(
- 솜커톤에서 멋진 프로젝트를 만들어주실 학우 여러분들을 모집합니다!
+ 솜커톤에서 멋진 프로젝트를 만들어 주실 학우 여러분들을 모집합니다!
📅 모집 일정 :
@@ -208,7 +208,7 @@ export const SomRecruitUI: React.FC = () => {
🌿 신청 조건 :
-
컴퓨터공학부 학생, 시각디자인과 동아리 구미래 부원
+
컴퓨터공학부 학생
diff --git a/src/pages/SomkathonRecruit.tsx b/src/pages/SomkathonRecruit.tsx
index be8b2bb..94fa10f 100644
--- a/src/pages/SomkathonRecruit.tsx
+++ b/src/pages/SomkathonRecruit.tsx
@@ -17,7 +17,7 @@ const SomkathonRecruit: React.FC = () => {
participantName: '',
studentId: '',
department: '',
- grade: '',
+ grade: '1',
contact: '',
email: '',
})
@@ -130,14 +130,14 @@ const SomkathonRecruit: React.FC = () => {
}
})
- navigate('/somkathon/result')
+ navigate('/somkathon/submit')
} catch (error: any) {
if (error.response) {
const errorData = error.response.data
- if (error.response.status === 400 && errorData.code === 'C001') {
+ if (error.response.status === 400 && errorData.code === 'C001' || errorData.code === 'C007') {
alert('입력 정보를 다시 확인해주세요.')
- } else if (error.response.status === 400 && errorData.code === 'C002'){
+ } else if (error.response.status === 400 && errorData.code === 'C013'){
alert('이미 등록된 학번입니다.')
}
} else {
From 77f11f535a0cd06ff6d2440a954b001e868f3f24 Mon Sep 17 00:00:00 2001
From: sooh329
Date: Wed, 9 Apr 2025 18:07:01 +0900
Subject: [PATCH 5/9] =?UTF-8?q?fix:=20console.log=20=EC=82=AD=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/SomkathonRecruit.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/pages/SomkathonRecruit.tsx b/src/pages/SomkathonRecruit.tsx
index 94fa10f..d9484fa 100644
--- a/src/pages/SomkathonRecruit.tsx
+++ b/src/pages/SomkathonRecruit.tsx
@@ -116,7 +116,6 @@ const SomkathonRecruit: React.FC = () => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
- console.log(formData)
if (!formData.participantName || !formData.studentId || !formData.contact || !formData.email || !formData.department) {
alert('모든 필수 정보를 입력해주세요.')
return
From 0d26c16333bb02ebfbe0550a21b8d7be4ac3759b Mon Sep 17 00:00:00 2001
From: sooh329
Date: Wed, 9 Apr 2025 18:10:27 +0900
Subject: [PATCH 6/9] =?UTF-8?q?fix:=20placeholder=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/SomkathonRecruit.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/SomkathonRecruit.tsx b/src/pages/SomkathonRecruit.tsx
index d9484fa..8c514d4 100644
--- a/src/pages/SomkathonRecruit.tsx
+++ b/src/pages/SomkathonRecruit.tsx
@@ -156,7 +156,7 @@ const SomkathonRecruit: React.FC = () => {
required minLength={1} maxLength={16} />
-
+
Date: Wed, 9 Apr 2025 22:31:30 +0900
Subject: [PATCH 7/9] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 64c1a33..2deccb0 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
| **분야** | **이름** | **포지션** |
| --- | --- | --- |
-| PM | 최도현 | **프론트엔드 리드**, 프론트 인프라 구축 & 서버 연동 및 배포, 화면 UI 구현,
UI/UX, GUI 디자인, 백엔드 API 및 DB 구축 |
+| PM | 최도현 | **프론트엔드 리드**, 프론트 인프라 구축 & 서버 연동 및 배포, 화면 UI 구현,
UI/UX, GUI 디자인, 백엔드 API 및 DB 구축 |
| 백엔드 | 유승완 | **백엔드 리드**, 백엔드 인프라 구축 & 서버 연동 및 배포, API 및 DB 구축 |
| 백엔드 | 윤도훈 | **백엔드**, API 및 DB 구축 |
| 프론트엔드 | 김수현 | **프론트엔드**, 화면 UI 구현, API 연동 |
From 6062408d52f8d58cbce42b8d0c72d95ae8cb0c62 Mon Sep 17 00:00:00 2001
From: limtjdghks
Date: Thu, 10 Apr 2025 12:35:43 +0900
Subject: [PATCH 8/9] =?UTF-8?q?feat:=20=EC=86=9C=EC=BB=A4=ED=86=A4=20?=
=?UTF-8?q?=EC=9D=B8=EC=9B=90=20=EA=B4=80=EB=A6=AC=20=ED=8E=98=EC=9D=B4?=
=?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/App.tsx b/src/App.tsx
index e24ee21..cd79844 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -25,6 +25,7 @@ import { RecruitSubmit } from './pages/RecruitSubmit'
import RecruitCheck from './pages/RecruitCheck'
import RecruitCheckFinal from './pages/RecruitCheckFinal'
import ProtectedRoute from './components/layout/ProtectRoute'
+import SomkatonApplicants from './pages/admin/SomkatonApplicants'
function App() {
return (
@@ -69,6 +70,7 @@ function AppContent() {
} />
} />
} />
+ }/>
>
)
From f76d540a4d3f58162c905b2498953a5b2d765d02 Mon Sep 17 00:00:00 2001
From: limtjdghks
Date: Thu, 10 Apr 2025 12:36:04 +0900
Subject: [PATCH 9/9] =?UTF-8?q?feat:=20=EC=86=9C=EC=BB=A4=ED=86=A4=20?=
=?UTF-8?q?=EC=9D=B8=EC=9B=90=20=EA=B4=80=EB=A6=AC=20=ED=8E=98=EC=9D=B4?=
=?UTF-8?q?=EC=A7=80=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/admin/AdminMain.tsx | 1 +
src/pages/admin/SomkatonApplicants.tsx | 132 +++++++++++++++++++++++++
2 files changed, 133 insertions(+)
create mode 100644 src/pages/admin/SomkatonApplicants.tsx
diff --git a/src/pages/admin/AdminMain.tsx b/src/pages/admin/AdminMain.tsx
index aa32bdc..819976d 100644
--- a/src/pages/admin/AdminMain.tsx
+++ b/src/pages/admin/AdminMain.tsx
@@ -42,6 +42,7 @@ const AdminMain: React.FC = () => {
+
{
+ const [applicants, setApplicants] = useState
([])
+ const [detailInfo, setDetailInfo] = useState(null)
+ const [selectedId, setSelectedId] = useState (null)
+ const [count, setCount] = useState(0)
+ const accessToken = localStorage.getItem('accessToken')
+
+ // 지원자 전체 조회
+ const getData = async () => {
+ try {
+ if(!accessToken) {
+ alert('로그인이 필요합니다.')
+ return
+ }
+ const response = await axios.get('https://dmu-dasom-api.or.kr/api/somkathon/participants')
+ console.log(response.data)
+ setApplicants(response.data)
+ setCount(response.data.length)
+ } catch (e:any) {
+ alert('지원자 목록 불러오기 실패')
+ console.log(e)
+ }
+ }
+
+ useEffect(() => {
+ getData()
+ },[])
+
+ // 지원자 상세 조회
+ const toggleDetail = async (id:number) => {
+ if(selectedId === id) {
+ setSelectedId(null)
+ setDetailInfo(null)
+ return
+ }
+
+ try {
+ const response = await axios.get(`https://dmu-dasom-api.or.kr/api/somkathon/participants/${id}`)
+ setDetailInfo(response.data)
+ setSelectedId(id)
+ } catch (e:any) {
+ console.log(e)
+ alert('지원자 상세정보 불러오기 실패')
+ }
+ }
+
+ const handleDelete = async (id:number) => {
+ try {
+ await axios.delete(`https://dmu-dasom-api.or.kr/api/somkathon/participants/${id}`)
+ setDetailInfo(null)
+ getData()
+ } catch (e:any) {
+ console.log(e)
+ alert('지원자 삭제 실패')
+ }
+ }
+
+ const ApplicantInfo = ({applicant} : {applicant:any}) => {
+ return(
+
+ | {applicant.id} |
+ {applicant.participantName} |
+ {applicant.studentId} |
+
+
+
+ {selectedId === applicant.id && ( )}
+
+ |
+
+ )
+ }
+
+ const DetailItem = ({label, value} : {label:string, value:string}) => {
+ return (
+
+ )
+ }
+
+ const ApplicantDetailInfo = ({applicant} : {applicant:any}) => {
+ if(!applicant) return null
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ | ID |
+ 이름 |
+ 학번 |
+ 상세정보 |
+
+
+
+ {applicants.map((applicant) => (
+
+ ))}
+
+
+
+ )
+}
+
+export default SomkatonApplicants
\ No newline at end of file