diff --git a/.DS_Store b/.DS_Store index 8563691..b4ce137 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1f09b9a..21891da 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,19 +9,19 @@ "version": "0.1.0", "dependencies": { "@heroicons/react": "^2.2.0", - "next": "15.1.7", + "next": "^15.2.3", "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@types/node": "20.17.19", - "@types/react": "19.0.10", - "@types/react-dom": "^19", - "autoprefixer": "^10.4.20", + "@types/node": "^20.17.24", + "@types/react": "^19.0.12", + "@types/react-dom": "^19.0.4", + "autoprefixer": "^10.4.21", "eslint": "^9", "eslint-config-next": "15.1.7", - "postcss": "^8.4.31", + "postcss": "^8.5.3", "tailwindcss": "^3.4.17", "typescript": "5.7.3" } @@ -695,9 +695,9 @@ } }, "node_modules/@next/env": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.7.tgz", - "integrity": "sha512-d9jnRrkuOH7Mhi+LHav2XW91HOgTAWHxjMPkXMGBc9B2b7614P7kjt8tAplRvJpbSt4nbO1lugcT/kAaWzjlLQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.4.tgz", + "integrity": "sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -711,9 +711,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.7.tgz", - "integrity": "sha512-hPFwzPJDpA8FGj7IKV3Yf1web3oz2YsR8du4amKw8d+jAOHfYHYFpMkoF6vgSY4W6vB29RtZEklK9ayinGiCmQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz", + "integrity": "sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==", "cpu": [ "arm64" ], @@ -727,9 +727,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.7.tgz", - "integrity": "sha512-2qoas+fO3OQKkU0PBUfwTiw/EYpN+kdAx62cePRyY1LqKtP09Vp5UcUntfZYajop5fDFTjSxCHfZVRxzi+9FYQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz", + "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==", "cpu": [ "x64" ], @@ -743,9 +743,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.7.tgz", - "integrity": "sha512-sKLLwDX709mPdzxMnRIXLIT9zaX2w0GUlkLYQnKGoXeWUhcvpCrK+yevcwCJPdTdxZEUA0mOXGLdPsGkudGdnA==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz", + "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==", "cpu": [ "arm64" ], @@ -759,9 +759,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.7.tgz", - "integrity": "sha512-zblK1OQbQWdC8fxdX4fpsHDw+VSpBPGEUX4PhSE9hkaWPrWoeIJn+baX53vbsbDRaDKd7bBNcXRovY1hEhFd7w==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz", + "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==", "cpu": [ "arm64" ], @@ -775,9 +775,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.7.tgz", - "integrity": "sha512-GOzXutxuLvLHFDAPsMP2zDBMl1vfUHHpdNpFGhxu90jEzH6nNIgmtw/s1MDwpTOiM+MT5V8+I1hmVFeAUhkbgQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz", + "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==", "cpu": [ "x64" ], @@ -791,9 +791,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.7.tgz", - "integrity": "sha512-WrZ7jBhR7ATW1z5iEQ0ZJfE2twCNSXbpCSaAunF3BKcVeHFADSI/AW1y5Xt3DzTqPF1FzQlwQTewqetAABhZRQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz", + "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==", "cpu": [ "x64" ], @@ -807,9 +807,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.7.tgz", - "integrity": "sha512-LDnj1f3OVbou1BqvvXVqouJZKcwq++mV2F+oFHptToZtScIEnhNRJAhJzqAtTE2dB31qDYL45xJwrc+bLeKM2Q==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz", + "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==", "cpu": [ "arm64" ], @@ -823,9 +823,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.7.tgz", - "integrity": "sha512-dC01f1quuf97viOfW05/K8XYv2iuBgAxJZl7mbCKEjMgdQl5JjAKJ0D2qMKZCgPWDeFbFT0Q0nYWwytEW0DWTQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz", + "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==", "cpu": [ "x64" ], @@ -948,9 +948,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.17.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", - "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", + "version": "20.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.24.tgz", + "integrity": "sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==", "dev": true, "license": "MIT", "dependencies": { @@ -958,9 +958,9 @@ } }, "node_modules/@types/react": { - "version": "19.0.10", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", - "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", + "version": "19.0.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", + "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", "dev": true, "license": "MIT", "dependencies": { @@ -4069,12 +4069,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.7.tgz", - "integrity": "sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz", + "integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==", "license": "MIT", "dependencies": { - "@next/env": "15.1.7", + "@next/env": "15.2.4", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -4089,14 +4089,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.7", - "@next/swc-darwin-x64": "15.1.7", - "@next/swc-linux-arm64-gnu": "15.1.7", - "@next/swc-linux-arm64-musl": "15.1.7", - "@next/swc-linux-x64-gnu": "15.1.7", - "@next/swc-linux-x64-musl": "15.1.7", - "@next/swc-win32-arm64-msvc": "15.1.7", - "@next/swc-win32-x64-msvc": "15.1.7", + "@next/swc-darwin-arm64": "15.2.4", + "@next/swc-darwin-x64": "15.2.4", + "@next/swc-linux-arm64-gnu": "15.2.4", + "@next/swc-linux-arm64-musl": "15.2.4", + "@next/swc-linux-x64-gnu": "15.2.4", + "@next/swc-linux-x64-musl": "15.2.4", + "@next/swc-win32-arm64-msvc": "15.2.4", + "@next/swc-win32-x64-msvc": "15.2.4", "sharp": "^0.33.5" }, "peerDependencies": { diff --git a/frontend/package.json b/frontend/package.json index 96a07ec..76b6c3c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,19 +10,19 @@ }, "dependencies": { "@heroicons/react": "^2.2.0", - "next": "15.1.7", + "next": "^15.2.3", "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@types/node": "20.17.19", - "@types/react": "19.0.10", - "@types/react-dom": "^19", - "autoprefixer": "^10.4.20", + "@types/node": "^20.17.24", + "@types/react": "^19.0.12", + "@types/react-dom": "^19.0.4", + "autoprefixer": "^10.4.21", "eslint": "^9", "eslint-config-next": "15.1.7", - "postcss": "^8.4.31", + "postcss": "^8.5.3", "tailwindcss": "^3.4.17", "typescript": "5.7.3" } diff --git a/frontend/src/app/estimate/view/[id]/EstimateViewClient.tsx b/frontend/src/app/estimate/view/[id]/EstimateViewClient.tsx new file mode 100644 index 0000000..f1de2d1 --- /dev/null +++ b/frontend/src/app/estimate/view/[id]/EstimateViewClient.tsx @@ -0,0 +1,117 @@ +// src/app/estimate/view/[id]/EstimateViewClient.tsx +'use client'; + +import React, { useEffect, useState } from 'react'; +import Title from '@/components/Title'; + +// 견적서 데이터 타입 정의 +interface EstimateDetail { + id: number; + title: string; + content: string; + date: string; + author: string; +} + +export default function EstimateViewClient({ id }: { id: string }) { + const [estimateData, setEstimateData] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // 실제로는 API 호출로 대체할 부분 + // 임시 데이터를 사용하여 해당 ID의 견적서 데이터를 가져옴 + const fetchEstimateData = () => { + setLoading(true); + + // 임시 데이터 (실제로는 API 호출로 대체) + const mockData = [ + { + id: 1, + title: '안녕하세요 이번에 문의드릴게 있어서요', + content: '우편발송 수량 / 3개\n택배포장 수량 / 5개\n우편발송 할 내용물 종류 / 서류, 카탈로그\n택배포장할 내용물 종류 / 전자제품, 부품', + date: '2024/02/29 10:30', + author: 'hellosy76 (박세영)' + }, + { + id: 2, + title: '빔프로젝트 설치 견적 문의드립니다', + content: '우편발송 수량 / 2개\n택배포장 수량 / 4개\n우편발송 할 내용물 종류 / 문서\n택배포장할 내용물 종류 / 빔프로젝터, 액세서리', + date: '2024/02/28 15:20', + author: 'projector123 (김영수)' + }, + { + id: 3, + title: '방문 설치 문의드립니다. 가능할까요?', + content: '방문 설치 가능 여부 확인 부탁드립니다.\n설치 요청 장소: 서울시 강남구\n설치 요청 일자: 2024년 3월 10일\n설치 물품: 스크린, 스피커 시스템', + date: '2024/02/27 09:15', + author: 'user567 (이지원)' + } + ]; + + // 파라미터로 받은 ID와 일치하는 견적서 찾기 + const foundEstimate = mockData.find(item => item.id === parseInt(id)); + + setEstimateData(foundEstimate || null); + setLoading(false); + }; + + fetchEstimateData(); + }, [id]); + + if (loading) { + return ( +
+ + <div className="flex justify-center items-center h-screen"> + <p>로딩 중...</p> + </div> + </main> + ); + } + + if (!estimateData) { + return ( + <main className="flex flex-col min-h-screen"> + <Title pageTitle="견적서 상세" /> + <div className="flex justify-center items-center h-screen"> + <p>견적서를 찾을 수 없습니다.</p> + </div> + </main> + ); + } + + return ( + <main className="flex flex-col min-h-screen"> + {/* 고정된 요소들 - Title */} + <Title pageTitle="견적서 상세" /> + + <div className="relative px-5 pt-[164px] pb-10 w-full"> + {/* 견적 내용 라벨과 날짜 */} + <div className="flex justify-between items-center mb-2 mt-[12px]"> + <h2 className="font-inter font-bold text-[17px] leading-[21px] text-black"> + 견적내용 + </h2> + <span className="font-inter font-normal text-[15px] leading-[20px] text-[rgba(0,0,0,0.3)]"> + {estimateData.date} + </span> + </div> + + {/* 견적 내용 표시 박스 - 읽기 전용 */} + <div className="w-full mx-auto"> + <div + className="box-border w-full h-[232px] p-[10px] text-[13px] leading-[20px] font-inter font-normal border border-solid border-[rgba(53,51,155,0.9)] rounded-[5px] overflow-auto whitespace-pre-wrap" + > + {estimateData.content} + </div> + </div> + + {/* 작성자 정보 - 왼쪽 정렬 */} + <div className="mt-2"> + <p className="font-inter font-normal text-[10px] leading-[12px] text-black"> + 작성자: {estimateData.author} + </p> + </div> + </div> + </main> + ); +} \ No newline at end of file diff --git a/frontend/src/app/estimate/view/[id]/page.tsx b/frontend/src/app/estimate/view/[id]/page.tsx index 5e2722b..cbdd6c4 100644 --- a/frontend/src/app/estimate/view/[id]/page.tsx +++ b/frontend/src/app/estimate/view/[id]/page.tsx @@ -1,117 +1,13 @@ -// app/estimate/view/[id]/page.tsx -'use client'; +import { notFound } from 'next/navigation'; +import EstimateViewClient from './EstimateViewClient'; -import React, { useEffect, useState } from 'react'; -import Title from '@/components/Title'; +export default async function EstimateViewPage({ params }: { params: Promise<{ id: string }> }) { + const resolvedParams = await params; // params가 Promise이면 풀어서 사용 -// 견적서 데이터 타입 정의 -interface EstimateDetail { - id: number; - title: string; - content: string; - date: string; - author: string; -} - -export default function EstimateViewPage({ params }: { params: { id: string } }) { - const [estimateData, setEstimateData] = useState<EstimateDetail | null>(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - // 실제로는 API 호출로 대체할 부분 - // 임시 데이터를 사용하여 해당 ID의 견적서 데이터를 가져옴 - const fetchEstimateData = () => { - setLoading(true); - - // 임시 데이터 (실제로는 API 호출로 대체) - const mockData = [ - { - id: 1, - title: '안녕하세요 이번에 문의드릴게 있어서요', - content: '우편발송 수량 / 3개\n택배포장 수량 / 5개\n우편발송 할 내용물 종류 / 서류, 카탈로그\n택배포장할 내용물 종류 / 전자제품, 부품', - date: '2024/02/29 10:30', - author: 'hellosy76 (박세영)' - }, - { - id: 2, - title: '빔프로젝트 설치 견적 문의드립니다', - content: '우편발송 수량 / 2개\n택배포장 수량 / 4개\n우편발송 할 내용물 종류 / 문서\n택배포장할 내용물 종류 / 빔프로젝터, 액세서리', - date: '2024/02/28 15:20', - author: 'projector123 (김영수)' - }, - { - id: 3, - title: '방문 설치 문의드립니다. 가능할까요?', - content: '방문 설치 가능 여부 확인 부탁드립니다.\n설치 요청 장소: 서울시 강남구\n설치 요청 일자: 2024년 3월 10일\n설치 물품: 스크린, 스피커 시스템', - date: '2024/02/27 09:15', - author: 'user567 (이지원)' - } - ]; - - // 파라미터로 받은 ID와 일치하는 견적서 찾기 - const foundEstimate = mockData.find(item => item.id === parseInt(params.id)); - - setEstimateData(foundEstimate || null); - setLoading(false); - }; - - fetchEstimateData(); - }, [params.id]); - - if (loading) { - return ( - <main className="flex flex-col min-h-screen"> - <Title pageTitle="견적서 상세" /> - <div className="flex justify-center items-center h-screen"> - <p>로딩 중...</p> - </div> - </main> - ); - } - - if (!estimateData) { - return ( - <main className="flex flex-col min-h-screen"> - <Title pageTitle="견적서 상세" /> - <div className="flex justify-center items-center h-screen"> - <p>견적서를 찾을 수 없습니다.</p> - </div> - </main> - ); + const validIds = ['1', '2', '3']; + if (!validIds.includes(resolvedParams.id)) { + notFound(); } - return ( - <main className="flex flex-col min-h-screen"> - {/* 고정된 요소들 - Title */} - <Title pageTitle="견적서 상세" /> - - <div className="relative px-5 pt-[164px] pb-10 w-full"> - {/* 견적 내용 라벨과 날짜 */} - <div className="flex justify-between items-center mb-2 mt-[12px]"> - <h2 className="font-inter font-bold text-[17px] leading-[21px] text-black"> - 견적내용 - </h2> - <span className="font-inter font-normal text-[15px] leading-[20px] text-[rgba(0,0,0,0.3)]"> - {estimateData.date} - </span> - </div> - - {/* 견적 내용 표시 박스 - 읽기 전용 */} - <div className="w-full mx-auto"> - <div - className="box-border w-full h-[232px] p-[10px] text-[13px] leading-[20px] font-inter font-normal border border-solid border-[rgba(53,51,155,0.9)] rounded-[5px] overflow-auto whitespace-pre-wrap" - > - {estimateData.content} - </div> - </div> - - {/* 작성자 정보 - 왼쪽 정렬 */} - <div className="mt-2"> - <p className="font-inter font-normal text-[10px] leading-[12px] text-black"> - 작성자: {estimateData.author} - </p> - </div> - </div> - </main> - ); -} \ No newline at end of file + return <EstimateViewClient id={resolvedParams.id} />; +} diff --git a/frontend/src/app/find/page.tsx b/frontend/src/app/find/page.tsx index fe5307e..f050db8 100644 --- a/frontend/src/app/find/page.tsx +++ b/frontend/src/app/find/page.tsx @@ -1,27 +1,38 @@ "use client"; -import { useRouter, useSearchParams } from "next/navigation"; -import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { useState, useEffect } from "react"; import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid"; import PrimaryButton from "@/components/find/PrimaryButton"; import InputField from "@/components/find/InputField"; const FindPage = () => { const router = useRouter(); - const searchParams = useSearchParams(); - const tab = searchParams.get("tab") || "id"; - + + // ✅ URL에서 직접 `tab`을 가져오지 않고, useState로 관리 + const [tab, setTab] = useState<"id" | "password">("id"); const [foundId, setFoundId] = useState<string | null>(null); const [showVerification, setShowVerification] = useState(false); const [isVerified, setIsVerified] = useState(false); const [verificationCode, setVerificationCode] = useState(""); const [verificationError, setVerificationError] = useState(false); const [showPasswordReset, setShowPasswordReset] = useState(false); - const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); - const handleTabChange = (newTab: string) => { + // ✅ useEffect로 URL 쿼리 파라미터를 `tab` 상태로 반영 + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const currentTab = urlParams.get("tab"); + if (currentTab === "password") { + setTab("password"); + } else { + setTab("id"); + } + }, []); + + const handleTabChange = (newTab: "id" | "password") => { + setTab(newTab); router.push(`/find?tab=${newTab}`); setFoundId(null); setShowVerification(false); @@ -31,30 +42,6 @@ const FindPage = () => { setShowPasswordReset(false); }; - const handleFindId = () => { - // 추후 연동 필요 - setFoundId("ekdm*******"); - }; - - const handleVerifyEmail = () => { - setShowVerification(true); - }; - - const handleConfirmVerification = () => { - if (verificationCode === "1234") { - // 추후 연동 필요, 우선 인증코드가 1234면 통과 - setIsVerified(true); - setVerificationError(false); - } else { - setIsVerified(false); - setVerificationError(true); - } - }; - - const handlePasswordReset = () => { - setShowPasswordReset(true); - }; - return ( <div className="flex flex-col items-center w-[390px] h-[844px] mx-auto p-6"> <div className="w-full h-16 border-b border-gray-400 flex items-center justify-center text-gray-500"> @@ -92,25 +79,15 @@ const FindPage = () => { 고객님과 일치하는 아이디입니다. </p> <p className="text-xl font-semibold mt-2"> ID : {foundId}</p> - <PrimaryButton - text="로그인" - onClick={() => router.push("/login")} - /> - <button - className="w-full text-sm underline mt-4" - onClick={() => handleTabChange("password")} - > + <PrimaryButton text="로그인" onClick={() => router.push("/login")} /> + <button className="w-full text-sm underline mt-4" onClick={() => handleTabChange("password")}> 비밀번호 찾기 </button> </div> ) : ( <div> - <InputField - label="이메일" - type="email" - placeholder="이메일 주소 입력" - /> - <PrimaryButton text="아이디 확인하기" onClick={handleFindId} /> + <InputField label="이메일" type="email" placeholder="이메일 주소 입력" /> + <PrimaryButton text="아이디 확인하기" onClick={() => setFoundId("ekdm*******")} /> </div> ) ) : showPasswordReset ? ( @@ -123,7 +100,6 @@ const FindPage = () => { onChange={(e) => setNewPassword(e.target.value)} helperText="*영문 + 숫자 + 특수문자 8자 이상" /> - <InputField label="변경 비밀번호 재확인" type="password" @@ -137,15 +113,8 @@ const FindPage = () => { <div> <InputField label="아이디" type="text" placeholder="아이디 입력" /> <div className="w-full flex items-center"> - <InputField - label="이메일" - type="email" - placeholder="이메일 주소 입력" - > - <button - className="font-bold px-4 py-2 bg-primary text-white rounded-md text-sm whitespace-nowrap" - onClick={handleVerifyEmail} - > + <InputField label="이메일" type="email" placeholder="이메일 주소 입력"> + <button className="font-bold px-4 py-2 bg-primary text-white rounded-md text-sm whitespace-nowrap" onClick={() => setShowVerification(true)}> 인증 </button> </InputField> @@ -165,31 +134,27 @@ const FindPage = () => { verificationError ? "border-red-500" : "border-gray-600" }`} /> - {isVerified && ( - <CheckCircleIcon className="w-6 h-6 text-green-500 flex-shrink-0 ml-2" /> - )} - {verificationError && ( - <XCircleIcon className="w-6 h-6 text-red-500 flex-shrink-0 ml-2" /> - )} + {isVerified && <CheckCircleIcon className="w-6 h-6 text-green-500 flex-shrink-0 ml-2" />} + {verificationError && <XCircleIcon className="w-6 h-6 text-red-500 flex-shrink-0 ml-2" />} <button className="ml-2 font-bold px-4 py-2 bg-primary text-white rounded-md text-sm whitespace-nowrap" - onClick={handleConfirmVerification} + onClick={() => { + if (verificationCode === "1234") { + setIsVerified(true); + setVerificationError(false); + } else { + setIsVerified(false); + setVerificationError(true); + } + }} > 확인 </button> </div> - {verificationError && ( - <p className="text-red-500 font-semibold text-sm mt-1"> - * 인증번호를 다시 확인해주세요. - </p> - )} + {verificationError && <p className="text-red-500 font-semibold text-sm mt-1">* 인증번호를 다시 확인해주세요.</p>} </div> )} - <PrimaryButton - text="비밀번호 재설정" - onClick={handlePasswordReset} - disabled={!isVerified} - /> + <PrimaryButton text="비밀번호 재설정" onClick={() => setShowPasswordReset(true)} disabled={!isVerified} /> </div> )} </div> diff --git a/frontend/src/components/AboutNavigation.tsx b/frontend/src/components/AboutNavigation.tsx index c909258..80cda7f 100644 --- a/frontend/src/components/AboutNavigation.tsx +++ b/frontend/src/components/AboutNavigation.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useMemo } from 'react'; import React from 'react'; interface NavItem { @@ -11,12 +11,13 @@ interface NavItem { const AboutNavigation = () => { const [activeSection, setActiveSection] = useState<string>('company'); - const navItems: NavItem[] = [ + // Wrap navItems in useMemo to prevent recreation on each render + const navItems = useMemo<NavItem[]>(() => [ { id: 'company', label: '회사 소개' }, { id: 'service', label: '서비스 소개' }, { id: 'location', label: '위치/교통' }, { id: 'support', label: '고객지원' } - ]; + ], []); // 현재 보이는 섹션 감지 함수 const handleScroll = useCallback(() => {