Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions app/main/_components/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { Hobby, ProfileData } from "@/lib/types/profile";

Check warning on line 3 in app/main/_components/ProfileCard.tsx

View workflow job for this annotation

GitHub Actions / lint

'Hobby' is defined but never used
import Image from "next/image";
import { Send } from "lucide-react";
import React, { useRef } from "react";
Expand Down Expand Up @@ -200,16 +200,21 @@
/* ── 메인 프로필 카드 컴포넌트 ── */
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<number>(0);

const handleCardClick = () => {
const touchDuration = Date.now() - touchStartTime.current;
if (touchDuration < 200) {
setIsExpanded(!isExpanded);
onToggleExpanded();
}
};

Expand All @@ -227,7 +232,7 @@
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"
Expand Down
37 changes: 31 additions & 6 deletions app/main/_components/ProfileSlider.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
"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";

/* ── 프로필 슬라이더 (스와이프 + 인디케이터) ── */
interface ProfileSliderProps {
profiles: ProfileData[];
}

const PEEK_WIDTH = 16; // 다음 카드가 살짝 보이는 너비 (px)
const CARD_GAP = 8; // 카드 사이 간격 (px)

const ProfileSlider = ({ profiles }: ProfileSliderProps) => {
const [activeIndex, setActiveIndex] = useState(0);
const [expandedCardId, setExpandedCardId] = useState<number | null>(null);
const scrollRef = useRef<HTMLDivElement>(null);

const toggleExpanded = useCallback((id: number) => {
setExpandedCardId((prev) => (prev === id ? null : id));
}, []);

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 + CARD_GAP
: 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;

Expand All @@ -34,10 +46,23 @@ const ProfileSlider = ({ profiles }: ProfileSliderProps) => {
<div
ref={scrollRef}
className="scrollbar-hide flex w-full snap-x snap-mandatory overflow-x-auto"
style={{ gap: `${CARD_GAP}px` }}
>
{profiles.map((profile) => (
<div key={profile.memberId} className="w-full shrink-0 snap-center">
<ProfileCard profile={profile} />
{profiles.map((profile, i) => (
<div
key={profile.memberId}
className="shrink-0 snap-start"
style={{
width: `calc(100% - ${profiles.length > 1 ? PEEK_WIDTH + CARD_GAP : 0}px)`,
marginRight:
i === profiles.length - 1 ? `${PEEK_WIDTH}px` : undefined,
}}
>
<ProfileCard
profile={profile}
isExpanded={expandedCardId === profile.memberId}
onToggleExpanded={() => toggleExpanded(profile.memberId)}
/>
</div>
))}
</div>
Expand Down
45 changes: 38 additions & 7 deletions app/main/_components/ScreenMainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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_",
},
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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: "",
},
Expand All @@ -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",
Expand All @@ -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: "",
},
Expand All @@ -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",
Expand Down
53 changes: 22 additions & 31 deletions app/profile-builder/_components/ScreenProfileBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@

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("");
Expand Down Expand Up @@ -126,9 +125,20 @@
};

useEffect(() => {
const initialValues = getInitialValues();
if (!isReady) return;

Promise.resolve().then(() => {
const initialValues = getInitialValues();
const allFilled = Boolean(
initialValues.birthYear &&
initialValues.university &&
initialValues.department &&
initialValues.major &&
initialValues.gender &&
initialValues.mbti &&
initialValues.frequency,
);

const timeoutId = setTimeout(() => {
if (initialValues.birthYear)
setSelectedBirthYear(initialValues.birthYear);
if (initialValues.university)
Expand All @@ -141,28 +151,19 @@
setHasSelectedGender(true);
}
if (initialValues.mbti) {
const mbti = initialValues.mbti.toUpperCase();
setSelectedMBTI(mbti);
if (isValidMBTI(mbti)) setHasSelectedMBTI(true);
setSelectedMBTI(initialValues.mbti);
setHasSelectedMBTI(true);
}
if (initialValues.frequency) {
setSelectedFrequency(initialValues.frequency);
setHasSelectedFrequency(true);
}

const allFilled = Boolean(
initialValues.birthYear &&
initialValues.university &&
initialValues.department &&
initialValues.major &&
initialValues.gender &&
isValidMBTI(initialValues.mbti) &&
initialValues.frequency,
);

if (allFilled) setCurrentStep(4);
});
}, [profile]);
}, 0);

return () => clearTimeout(timeoutId);
}, [isReady]);

Check warning on line 166 in app/profile-builder/_components/ScreenProfileBuilder.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'getInitialValues'. Either include it or remove the dependency array

const yearOptions = getYearOptions();
const universityOptions = getUniversityOptions(universities);
Expand All @@ -185,7 +186,6 @@
const handleComplete = () => {
const normalizedMBTI = selectedMBTI.toUpperCase();

// Context 업데이트용 데이터 변환
const profileData: Partial<ProfileData> = {
birthDate: selectedBirthYear ? `${selectedBirthYear}-01-01` : undefined,
university: selectedUniversity,
Expand All @@ -196,10 +196,7 @@
contactFrequency: contactFrequencyMap[selectedFrequency],
};

// Context 업데이트
updateProfile(profileData);

// 다음 페이지로 이동
router.push("/hobby-select");
};

Expand All @@ -218,7 +215,6 @@
setHasSelectedFrequency(true);
};

// 단계별 유효성 검사
const isStepValid = (() => {
switch (currentStep) {
case 1:
Expand All @@ -241,7 +237,6 @@

return (
<div className="relative flex min-h-screen flex-col px-4 pb-32">
{/* 헤더 영역 */}
<ProgressStepBar currentStep={1} totalSteps={3} />
<div className="mt-8 mb-10 text-center">
<h1 className="typo-24-700 text-color-gray-900 mb-2">
Expand All @@ -254,33 +249,28 @@
</p>
</div>

{/* 폼 영역 */}
<div className="flex flex-col gap-6">
{/* Step 4: Contact Frequency */}
{currentStep >= 4 && (
<Step4ContactFrequency
onFrequencySelect={handleFrequencySelect}
defaultValue={selectedFrequency}
/>
)}

{/* Step 3: MBTI */}
{currentStep >= 3 && (
<Step3MBTI
onMBTISelect={handleMBTISelect}
defaultValue={selectedMBTI}
/>
)}

{/* Step 2: Gender */}
{currentStep >= 2 && (
<Step2Gender
onGenderSelect={handleGenderSelect}
defaultValue={selectedGender}
/>
)}

{/* Step 1: Basic */}
<Step1Basic
yearOptions={yearOptions}
universityOptions={universityOptions}
Expand All @@ -300,7 +290,6 @@
/>
</div>

{/* 하단 고정 버튼 */}
<Button
type="button"
fixed
Expand All @@ -316,3 +305,5 @@
</div>
);
};

export default ScreenProfileBuilder;
Loading