From 311f9e697a0cf9c1439070d9c2cba84509d00a9a Mon Sep 17 00:00:00 2001 From: dasosann Date: Fri, 13 Mar 2026 17:56:55 +0900 Subject: [PATCH 1/5] fix:card --- app/main/_components/ProfileCard.tsx | 13 +++++++--- app/main/_components/ProfileSlider.tsx | 34 +++++++++++++++++++++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/app/main/_components/ProfileCard.tsx b/app/main/_components/ProfileCard.tsx index 923c1da..4dd4973 100644 --- a/app/main/_components/ProfileCard.tsx +++ b/app/main/_components/ProfileCard.tsx @@ -200,16 +200,21 @@ const SocialIdDisplay = ({ profile }: { profile: ProfileData }) => { /* ── 메인 프로필 카드 컴포넌트 ── */ interface ProfileCardProps { profile: ProfileData; + isExpanded: boolean; + onToggleExpanded: () => void; } -const ProfileCard = ({ profile }: ProfileCardProps) => { - const [isExpanded, setIsExpanded] = React.useState(false); +const ProfileCard = ({ + profile, + isExpanded, + onToggleExpanded, +}: ProfileCardProps) => { const touchStartTime = useRef(0); const handleCardClick = () => { const touchDuration = Date.now() - touchStartTime.current; if (touchDuration < 200) { - setIsExpanded(!isExpanded); + onToggleExpanded(); } }; @@ -227,7 +232,7 @@ const ProfileCard = ({ profile }: ProfileCardProps) => { onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); - setIsExpanded(!isExpanded); + onToggleExpanded(); } }} className="flex w-full cursor-pointer flex-col items-center justify-start gap-3 p-4" diff --git a/app/main/_components/ProfileSlider.tsx b/app/main/_components/ProfileSlider.tsx index 19592d1..c324c79 100644 --- a/app/main/_components/ProfileSlider.tsx +++ b/app/main/_components/ProfileSlider.tsx @@ -1,7 +1,7 @@ "use client"; import { ProfileData } from "@/lib/types/profile"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import ProfileCard from "./ProfileCard"; /* ── 프로필 슬라이더 (스와이프 + 인디케이터) ── */ @@ -9,22 +9,31 @@ interface ProfileSliderProps { profiles: ProfileData[]; } +const PEEK_WIDTH = 28; // 다음 카드가 살짝 보이는 너비 (px) + const ProfileSlider = ({ profiles }: ProfileSliderProps) => { const [activeIndex, setActiveIndex] = useState(0); + const [isExpanded, setIsExpanded] = useState(false); const scrollRef = useRef(null); + const toggleExpanded = useCallback(() => { + setIsExpanded((prev) => !prev); + }, []); + useEffect(() => { const el = scrollRef.current; if (!el) return; const handleScroll = () => { - const index = Math.round(el.scrollLeft / el.clientWidth); + const cardWidth = + profiles.length > 1 ? el.clientWidth - PEEK_WIDTH : el.clientWidth; + const index = Math.round(el.scrollLeft / cardWidth); setActiveIndex(index); }; el.addEventListener("scroll", handleScroll); return () => el.removeEventListener("scroll", handleScroll); - }, []); + }, [profiles.length]); if (!profiles || profiles.length === 0) return null; @@ -34,10 +43,23 @@ const ProfileSlider = ({ profiles }: ProfileSliderProps) => {
- {profiles.map((profile) => ( -
- + {profiles.map((profile, i) => ( +
1 ? PEEK_WIDTH : 0}px)`, + paddingLeft: i === 0 ? 0 : undefined, + marginRight: i < profiles.length - 1 ? 0 : `${PEEK_WIDTH}px`, + }} + > +
))}
From 2d0d417a4937061eb2dac5bf8d2ead9fd1e0e0c4 Mon Sep 17 00:00:00 2001 From: dasosann Date: Fri, 13 Mar 2026 17:59:15 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20=EA=B0=84=EA=B2=A9=20=EB=B0=8F=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main/_components/ProfileSlider.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/main/_components/ProfileSlider.tsx b/app/main/_components/ProfileSlider.tsx index c324c79..c7569c1 100644 --- a/app/main/_components/ProfileSlider.tsx +++ b/app/main/_components/ProfileSlider.tsx @@ -9,7 +9,8 @@ interface ProfileSliderProps { profiles: ProfileData[]; } -const PEEK_WIDTH = 28; // 다음 카드가 살짝 보이는 너비 (px) +const PEEK_WIDTH = 16; // 다음 카드가 살짝 보이는 너비 (px) +const CARD_GAP = 8; // 카드 사이 간격 (px) const ProfileSlider = ({ profiles }: ProfileSliderProps) => { const [activeIndex, setActiveIndex] = useState(0); @@ -26,7 +27,9 @@ const ProfileSlider = ({ profiles }: ProfileSliderProps) => { const handleScroll = () => { const cardWidth = - profiles.length > 1 ? el.clientWidth - PEEK_WIDTH : el.clientWidth; + profiles.length > 1 + ? el.clientWidth - PEEK_WIDTH + CARD_GAP + : el.clientWidth; const index = Math.round(el.scrollLeft / cardWidth); setActiveIndex(index); }; @@ -43,16 +46,16 @@ const ProfileSlider = ({ profiles }: ProfileSliderProps) => {
{profiles.map((profile, i) => (
1 ? PEEK_WIDTH : 0}px)`, - paddingLeft: i === 0 ? 0 : undefined, - marginRight: i < profiles.length - 1 ? 0 : `${PEEK_WIDTH}px`, + width: `calc(100% - ${profiles.length > 1 ? PEEK_WIDTH + CARD_GAP : 0}px)`, + marginRight: + i === profiles.length - 1 ? `${PEEK_WIDTH}px` : undefined, }} > Date: Mon, 16 Mar 2026 11:21:39 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main/_components/ProfileSlider.tsx | 10 +-- app/main/_components/ScreenMainPage.tsx | 45 +++++++++++-- .../_components/ScreenProfileBuilder.tsx | 66 +++++++++++-------- 3 files changed, 82 insertions(+), 39 deletions(-) diff --git a/app/main/_components/ProfileSlider.tsx b/app/main/_components/ProfileSlider.tsx index c7569c1..00b7acc 100644 --- a/app/main/_components/ProfileSlider.tsx +++ b/app/main/_components/ProfileSlider.tsx @@ -14,11 +14,11 @@ const CARD_GAP = 8; // 카드 사이 간격 (px) const ProfileSlider = ({ profiles }: ProfileSliderProps) => { const [activeIndex, setActiveIndex] = useState(0); - const [isExpanded, setIsExpanded] = useState(false); + const [expandedCardId, setExpandedCardId] = useState(null); const scrollRef = useRef(null); - const toggleExpanded = useCallback(() => { - setIsExpanded((prev) => !prev); + const toggleExpanded = useCallback((id: number) => { + setExpandedCardId((prev) => (prev === id ? null : id)); }, []); useEffect(() => { @@ -60,8 +60,8 @@ const ProfileSlider = ({ profiles }: ProfileSliderProps) => { > toggleExpanded(profile.memberId)} />
))} diff --git a/app/main/_components/ScreenMainPage.tsx b/app/main/_components/ScreenMainPage.tsx index 9355ffa..daa4520 100644 --- a/app/main/_components/ScreenMainPage.tsx +++ b/app/main/_components/ScreenMainPage.tsx @@ -50,7 +50,11 @@ const ScreenMainPage = () => { major: "정보통신전자공학부", mbti: "ENTP", contactFrequency: "NORMAL", - hobbies: [{ name: "🎸 인디음악", category: "음악" }], + hobbies: [ + { name: "🎸 인디음악", category: "음악" }, + { name: "📸 사진찍기", category: "문화" }, + ], + advantages: ["친절함", "경청하는 태도"], profileImageUrl: "/main/cat.png", socialAccountId: "winterizcoming_", }, @@ -61,7 +65,12 @@ const ScreenMainPage = () => { major: "컴퓨터정보공학부", mbti: "INFJ", contactFrequency: "FREQUENT", - hobbies: [{ name: "🎬 영화감상", category: "문화" }], + hobbies: [ + { name: "🎬 영화감상", category: "문화" }, + { name: "📖 독서", category: "문화" }, + { name: "🏊 수영", category: "스포츠" }, + ], + advantages: ["긍정적인 에너지", "솔직함", "유머러스함"], profileImageUrl: "/main/dog.png", socialType: "INSTAGRAM", socialAccountId: "comatching_king", @@ -73,7 +82,12 @@ const ScreenMainPage = () => { major: "경영학과", mbti: "ENFP", contactFrequency: "NORMAL", - hobbies: [{ name: "☕ 카페투어", category: "일상" }], + hobbies: [ + { name: "☕ 카페투어", category: "일상" }, + { name: "🍳 요리", category: "문화" }, + { name: "🍰 베이킹", category: "문화" }, + ], + advantages: ["공감 능력이 좋음"], profileImageUrl: "/main/cat.png", socialType: "KAKAO", socialAccountId: "kakao_kim", @@ -85,7 +99,11 @@ const ScreenMainPage = () => { major: "산업디자인학과", mbti: "ISFP", contactFrequency: "RARE", - hobbies: [{ name: "🎨 그림그리기", category: "예술" }], + hobbies: [ + { name: "🎨 그림그리기", category: "예술" }, + { name: "🧶 뜨개질", category: "예술" }, + ], + advantages: ["꼼꼼함", "배려심", "예술적 감각", "성실함"], profileImageUrl: "/main/cat.png", socialAccountId: "", }, @@ -96,7 +114,12 @@ const ScreenMainPage = () => { major: "천문학과", mbti: "INTP", contactFrequency: "NORMAL", - hobbies: [{ name: "🔭 별보기", category: "자연" }], + hobbies: [ + { name: "🔭 별보기", category: "자연" }, + { name: "🧩 퍼즐", category: "문화" }, + { name: "♟️ 보드게임", category: "놀이" }, + ], + advantages: ["지적인 대화", "차분함"], profileImageUrl: "/main/dog.png", socialType: "INSTAGRAM", socialAccountId: "nightsky_star", @@ -108,7 +131,11 @@ const ScreenMainPage = () => { major: "체육교육과", mbti: "ESTP", contactFrequency: "FREQUENT", - hobbies: [{ name: "⚽ 축구", category: "스포츠" }], + hobbies: [ + { name: "⚽ 축구", category: "스포츠" }, + { name: "🧗 클라이밍", category: "스포츠" }, + ], + advantages: ["건강한 정신", "추진력", "밝은 웃음"], profileImageUrl: "/main/cat.png", socialAccountId: "", }, @@ -119,7 +146,11 @@ const ScreenMainPage = () => { major: "국어국문학과", mbti: "ISTJ", contactFrequency: "RARE", - hobbies: [{ name: "📚 독서", category: "문화" }], + hobbies: [ + { name: "📚 독서", category: "문화" }, + { name: "✍️ 글쓰기", category: "문화" }, + ], + advantages: ["진중함", "학구열"], profileImageUrl: "/main/dog.png", socialType: "INSTAGRAM", socialAccountId: "bookworm_kr", diff --git a/app/profile-builder/_components/ScreenProfileBuilder.tsx b/app/profile-builder/_components/ScreenProfileBuilder.tsx index 9bfa035..4667efe 100644 --- a/app/profile-builder/_components/ScreenProfileBuilder.tsx +++ b/app/profile-builder/_components/ScreenProfileBuilder.tsx @@ -78,35 +78,47 @@ export const ScreenProfileBuilder = () => { initialValues.frequency, ); - const [currentStep, setCurrentStep] = useState(allFilled ? 4 : 1); - const [selectedBirthYear, setSelectedBirthYear] = useState( - initialValues.birthYear || "", - ); - const [selectedUniversity, setSelectedUniversity] = useState( - initialValues.university || "", - ); - const [selectedDepartment, setSelectedDepartment] = useState( - initialValues.department || "", - ); - const [selectedMajor, setSelectedMajor] = useState( - initialValues.major || "", - ); - const [selectedGender, setSelectedGender] = useState( - initialValues.gender || "", - ); - const [selectedMBTI, setSelectedMBTI] = useState( - initialValues.mbti || "", - ); - const [selectedFrequency, setSelectedFrequency] = useState( - initialValues.frequency || "", - ); + const [currentStep, setCurrentStep] = useState(1); + const [selectedBirthYear, setSelectedBirthYear] = useState(""); + const [selectedUniversity, setSelectedUniversity] = useState(""); + const [selectedDepartment, setSelectedDepartment] = useState(""); + const [selectedMajor, setSelectedMajor] = useState(""); + const [selectedGender, setSelectedGender] = useState(""); + const [selectedMBTI, setSelectedMBTI] = useState(""); + const [selectedFrequency, setSelectedFrequency] = useState(""); - // isReady ref — kept to avoid re-running on profile change during session - const initializedRef = useRef(false); useEffect(() => { - if (!isReady || initializedRef.current) return; - initializedRef.current = true; - // Values are already set via lazy init above; nothing extra needed here + if (!isReady) return; + + const initialValues = getInitialValues(); + const allFilled = Boolean( + initialValues.birthYear && + initialValues.university && + initialValues.department && + initialValues.major && + initialValues.gender && + initialValues.mbti && + initialValues.frequency, + ); + + // 컴포넌트 마운트 후 및 isReady 시점에 비동기로 상태 업데이트 (Hydration mismatch 및 cascading render 방지) + const timeoutId = setTimeout(() => { + if (initialValues.birthYear) + setSelectedBirthYear(initialValues.birthYear); + if (initialValues.university) + setSelectedUniversity(initialValues.university); + if (initialValues.department) + setSelectedDepartment(initialValues.department); + if (initialValues.major) setSelectedMajor(initialValues.major); + if (initialValues.gender) setSelectedGender(initialValues.gender); + if (initialValues.mbti) setSelectedMBTI(initialValues.mbti); + if (initialValues.frequency) + setSelectedFrequency(initialValues.frequency); + + if (allFilled) setCurrentStep(4); + }, 0); + + return () => clearTimeout(timeoutId); }, [isReady]); const yearOptions = getYearOptions(); From 1c992ba54e0b298f522d586b9c252081d1ad4b9f Mon Sep 17 00:00:00 2001 From: dasosann Date: Mon, 16 Mar 2026 11:31:14 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=EB=AC=B8=EB=B2=95=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/profile-builder/_components/ScreenProfileBuilder.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/profile-builder/_components/ScreenProfileBuilder.tsx b/app/profile-builder/_components/ScreenProfileBuilder.tsx index 4667efe..54ea3eb 100644 --- a/app/profile-builder/_components/ScreenProfileBuilder.tsx +++ b/app/profile-builder/_components/ScreenProfileBuilder.tsx @@ -256,3 +256,5 @@ export const ScreenProfileBuilder = () => {
); }; + +export default ScreenProfileBuilder; From 2e900e8c8a566449f10781f5f507c869c72c7eb1 Mon Sep 17 00:00:00 2001 From: dasosann Date: Mon, 16 Mar 2026 11:44:16 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20lint=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/ScreenProfileBuilder.tsx | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/app/profile-builder/_components/ScreenProfileBuilder.tsx b/app/profile-builder/_components/ScreenProfileBuilder.tsx index 3ce964c..5d46d8c 100644 --- a/app/profile-builder/_components/ScreenProfileBuilder.tsx +++ b/app/profile-builder/_components/ScreenProfileBuilder.tsx @@ -62,9 +62,8 @@ const LEGACY_PROFILE_STORAGE_KEY = "profileBuilder"; export const ScreenProfileBuilder = () => { const router = useRouter(); - const { profile, updateProfile } = useProfile(); + const { profile, updateProfile, isReady } = useProfile(); - // Derive initial values from profile or localStorage synchronously const [currentStep, setCurrentStep] = useState(1); const [selectedBirthYear, setSelectedBirthYear] = useState(""); const [selectedUniversity, setSelectedUniversity] = useState(""); @@ -125,18 +124,6 @@ export const ScreenProfileBuilder = () => { return {}; }; - useEffect(() => { - const initialValues = getInitialValues(); - - const [currentStep, setCurrentStep] = useState(1); - const [selectedBirthYear, setSelectedBirthYear] = useState(""); - const [selectedUniversity, setSelectedUniversity] = useState(""); - const [selectedDepartment, setSelectedDepartment] = useState(""); - const [selectedMajor, setSelectedMajor] = useState(""); - const [selectedGender, setSelectedGender] = useState(""); - const [selectedMBTI, setSelectedMBTI] = useState(""); - const [selectedFrequency, setSelectedFrequency] = useState(""); - useEffect(() => { if (!isReady) return; @@ -151,7 +138,6 @@ export const ScreenProfileBuilder = () => { initialValues.frequency, ); - // 컴포넌트 마운트 후 및 isReady 시점에 비동기로 상태 업데이트 (Hydration mismatch 및 cascading render 방지) const timeoutId = setTimeout(() => { if (initialValues.birthYear) setSelectedBirthYear(initialValues.birthYear); @@ -160,10 +146,18 @@ export const ScreenProfileBuilder = () => { if (initialValues.department) setSelectedDepartment(initialValues.department); if (initialValues.major) setSelectedMajor(initialValues.major); - if (initialValues.gender) setSelectedGender(initialValues.gender); - if (initialValues.mbti) setSelectedMBTI(initialValues.mbti); - if (initialValues.frequency) + if (initialValues.gender) { + setSelectedGender(initialValues.gender); + setHasSelectedGender(true); + } + if (initialValues.mbti) { + setSelectedMBTI(initialValues.mbti); + setHasSelectedMBTI(true); + } + if (initialValues.frequency) { setSelectedFrequency(initialValues.frequency); + setHasSelectedFrequency(true); + } if (allFilled) setCurrentStep(4); }, 0); @@ -192,7 +186,6 @@ export const ScreenProfileBuilder = () => { const handleComplete = () => { const normalizedMBTI = selectedMBTI.toUpperCase(); - // Context 업데이트용 데이터 변환 const profileData: Partial = { birthDate: selectedBirthYear ? `${selectedBirthYear}-01-01` : undefined, university: selectedUniversity, @@ -203,10 +196,7 @@ export const ScreenProfileBuilder = () => { contactFrequency: contactFrequencyMap[selectedFrequency], }; - // Context 업데이트 updateProfile(profileData); - - // 다음 페이지로 이동 router.push("/hobby-select"); }; @@ -225,7 +215,6 @@ export const ScreenProfileBuilder = () => { setHasSelectedFrequency(true); }; - // 단계별 유효성 검사 const isStepValid = (() => { switch (currentStep) { case 1: @@ -248,7 +237,6 @@ export const ScreenProfileBuilder = () => { return (
- {/* 헤더 영역 */}

@@ -261,9 +249,7 @@ export const ScreenProfileBuilder = () => {

- {/* 폼 영역 */}
- {/* Step 4: Contact Frequency */} {currentStep >= 4 && ( { /> )} - {/* Step 3: MBTI */} {currentStep >= 3 && ( { /> )} - {/* Step 2: Gender */} {currentStep >= 2 && ( { /> )} - {/* Step 1: Basic */} { />
- {/* 하단 고정 버튼 */}