From 304fae8e82d63262b037bbd08019689ccea94896 Mon Sep 17 00:00:00 2001 From: geon-2 Date: Tue, 21 Apr 2026 22:46:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EA=B8=B0=EC=97=85/=EC=A7=81?= =?UTF-8?q?=EB=AC=B4=20input=20field=20placeholder=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A7=81=EB=AC=B4=EB=AA=85=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=99=84=EC=84=B1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../company/layouts/CompanySection.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/input-page/company/layouts/CompanySection.jsx b/src/pages/input-page/company/layouts/CompanySection.jsx index 915eebc..f35a2e3 100644 --- a/src/pages/input-page/company/layouts/CompanySection.jsx +++ b/src/pages/input-page/company/layouts/CompanySection.jsx @@ -3,7 +3,10 @@ import { useNavigate } from "react-router-dom"; import EntrySection from "../components/EntrySection"; import Button from "../../components/Button"; import TempSaveModal from "../../components/TempSaveModal"; -import { useFetchCompanies, useFetchPositions } from "api/setupApi"; +import { + useFetchCompanies, + // useFetchPositions +} from "api/setupApi"; function CompanySection() { const navigate = useNavigate(); @@ -11,10 +14,10 @@ function CompanySection() { // API 자동완성 데이터 const { data: companiesData } = useFetchCompanies(); - const { data: positionsData } = useFetchPositions(); + // const { data: positionsData } = useFetchPositions(); const companiesList = useMemo(() => companiesData?.data?.list ?? [], [companiesData]); - const positionsList = useMemo(() => positionsData?.data?.list ?? [], [positionsData]); + // const positionsList = useMemo(() => positionsData?.data?.list ?? [], [positionsData]); // 1. 상태 정의 const [companyName, setCompanyName] = useState(() => sessionStorage.getItem('company_companyName') || ''); @@ -48,7 +51,6 @@ function CompanySection() { caption="지원 회사명" value={companyName} onChange={setCompanyName} - placeholder="pertineo" width={530} required={true} autocompleteResults={companyResults} @@ -58,11 +60,10 @@ function CompanySection() { caption="지원 직무" value={jobTitle} onChange={setJobTitle} - placeholder="소프트웨어 엔지니어" width={530} required={true} - autocompleteResults={positionsList} - selectOnly={true} + // autocompleteResults={positionsList} + // selectOnly={true} /> @@ -70,7 +71,6 @@ function CompanySection() { caption="지원 공고 사이트 URL" value={noticeUrl} onChange={setNoticeUrl} - placeholder="https://pertineo.khu.ac.kr/" width={1080} /> From 6f334b5d5b2773e718bd9bbb1576de478981ecdd Mon Sep 17 00:00:00 2001 From: sam_ryong Date: Wed, 22 Apr 2026 02:33:43 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat=20:=20=ED=95=99=EC=A0=90=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=ED=98=95=EC=8B=9D=20=EC=A0=9C=ED=95=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=EC=9E=90=EC=86=8C=EC=84=9C=2010=EB=AC=B8=ED=95=AD?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EB=B3=80=EA=B2=BD,=20=EC=A0=9C3=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=9D=98=EC=84=9C=20=ED=95=84=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../input-page/auth/components/Agreement.jsx | 4 +- .../resume/layouts/ResumeSection.jsx | 73 +++++++++++++++++-- .../layouts/SelfIntroSection.jsx | 2 +- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/pages/input-page/auth/components/Agreement.jsx b/src/pages/input-page/auth/components/Agreement.jsx index b63aac4..08af65f 100644 --- a/src/pages/input-page/auth/components/Agreement.jsx +++ b/src/pages/input-page/auth/components/Agreement.jsx @@ -29,14 +29,14 @@ const AGREEMENT_ITEMS = [ }, { id: "thirdParty", - type: "선택", + type: "필수", label: "개인정보 제3자 제공에 동의합니다.", modalTitle: "Pertineo 개인정보 제3자 제공 동의서", url: "https://d2qlxukzyb0szn.cloudfront.net/terms-of-service/v1/third-party-data-sharing.html", }, ]; -const REQUIRED_IDS = ["terms", "privacy", "policy"]; +const REQUIRED_IDS = ["terms", "privacy", "policy", "thirdParty"]; const AGREEMENT_CHECKED_KEY = "agreementChecked"; function Agreement({ isEmailVerified = false, email = "" }) { diff --git a/src/pages/input-page/resume/layouts/ResumeSection.jsx b/src/pages/input-page/resume/layouts/ResumeSection.jsx index b447d9e..449faac 100644 --- a/src/pages/input-page/resume/layouts/ResumeSection.jsx +++ b/src/pages/input-page/resume/layouts/ResumeSection.jsx @@ -144,6 +144,49 @@ function ResumeSection() { ); }; + // GPA 범위 검증 함수 + const validateGPA = (gpa) => { + if (!gpa) return null; + const gpaNum = parseFloat(gpa); + if (isNaN(gpaNum)) return "범위가 벗어났습니다"; + if (gpaNum < 0.0 || gpaNum > 4.3) return "범위가 벗어났습니다"; + return null; + }; + + // 각 education 행의 GPA 에러 상태 + const educationGPAErrors = education.map((row) => validateGPA(row.gpa)); + + // Education 변경 핸들러 (GPA 필터링 포함) + const handleEducationChange = (newEducation) => { + const filteredEducation = newEducation.map((row) => { + let gpa = row.gpa; + + // 숫자와 첫 번째 점 이외의 모든 것 제거 + let numericPart = ''; + let hasDot = false; + + for (let char of gpa) { + if (char === '.' && !hasDot) { + numericPart += '.'; + hasDot = true; + } else if (/[0-9]/.test(char)) { + numericPart += char; + } + } + + // 점으로 시작하는 경우만 제거 (끝나는 경우는 허용) + if (numericPart.startsWith('.')) { + numericPart = numericPart.slice(1); + } + + return { + ...row, + gpa: numericPart + }; + }); + setEducation(filteredEducation); + }; + // 행별 자동완성 결과 동적 계산 const eduAutocomplete = useMemo(() => { return education.map((row) => ({ @@ -168,10 +211,17 @@ function ResumeSection() { // 학력사항(required)의 필수 필드가 모두 입력된 경우에만 다음 버튼 활성화 const canProceed = education.every( - (row) => - row.university?.trim() !== "" && - row.major?.trim() !== "" && - row.gpa?.trim() !== "", + (row) => { + const gpa = parseFloat(row.gpa); + return ( + row.university?.trim() !== "" && + row.major?.trim() !== "" && + row.gpa?.trim() !== "" && + !isNaN(gpa) && + gpa >= 0.0 && + gpa <= 4.3 + ); + } ); return ( @@ -183,7 +233,7 @@ function ResumeSection() { + + {/* GPA 에러 메시지 */} + {educationGPAErrors.some((err) => err !== null) && ( +
+ {educationGPAErrors.map((error, idx) => + error ? ( +
+ {error} +
+ ) : null + )} +
+ )} {/* 경력사항 */} [{ id: 0, question: "", content: "" }];