@@ -34,19 +63,54 @@ export default function MatchingSameMajorSection({
CC를 방지할 수 있어요.
- {/* 옵션 전용 가격 뱃지 */}
-
-
-
- 1
-
-
+ {/* 옵션 전용 가격 뱃지 / 선택 완료 */}
+ {isExcluded ? (
+
+ ) : (
+
+
+
+ 1
+
+
+ )}
);
}
diff --git a/app/matching/_components/ScreenMatching.tsx b/app/matching/_components/ScreenMatching.tsx
index a28a669..1c1ecf1 100644
--- a/app/matching/_components/ScreenMatching.tsx
+++ b/app/matching/_components/ScreenMatching.tsx
@@ -38,9 +38,11 @@ const frequencyMapping: Record
= {
};
import { useItems } from "@/hooks/useItems";
+import { useMatching } from "@/hooks/useMatching";
const ScreenMatching = () => {
const { data: itemData } = useItems();
+ const { mutate: match, isPending } = useMatching();
const [selectedMBTI, setSelectedMBTI] = useState("");
const [selectedAgeGroup, setSelectedAgeGroup] = useState("");
const [selectedFrequency, setSelectedFrequency] = useState("");
@@ -130,8 +132,7 @@ const ScreenMatching = () => {
maxAgeOffset: ageInfo.max,
};
- console.log("Matching Payload:", payload);
- alert("매칭을 시작합니다!");
+ match(payload);
};
return (
@@ -163,6 +164,12 @@ const ScreenMatching = () => {
setImportantOption(option)}
selectedOption={importantOption}
+ selections={{
+ MBTI: selectedMBTI || "",
+ AGE: selectedAgeGroup || "",
+ HOBBY: selectedHobbyCategory || "",
+ CONTACT: selectedFrequency || "",
+ }}
/>
{
diff --git a/app/profile-builder/_components/ProfileButton.tsx b/app/profile-builder/_components/ProfileButton.tsx
index 9960729..2c6b8a6 100644
--- a/app/profile-builder/_components/ProfileButton.tsx
+++ b/app/profile-builder/_components/ProfileButton.tsx
@@ -20,8 +20,8 @@ export default function ProfileButton({
className={cn(
"typo-20-700 flex h-12 flex-1 items-center justify-center rounded-full transition-colors",
selected
- ? "bg-pink-gradient border border-pink-700 text-pink-700"
- : "bg-[#FFFFFF4D] text-gray-300",
+ ? "bg-pink-gradient border-color-pink-700 text-color-pink-700 border"
+ : "bg-color-gray-0-a30 text-color-gray-300",
)}
onClick={onClick}
>
diff --git a/hooks/useMatching.ts b/hooks/useMatching.ts
new file mode 100644
index 0000000..ead5cbc
--- /dev/null
+++ b/hooks/useMatching.ts
@@ -0,0 +1,18 @@
+import { useMutation } from "@tanstack/react-query";
+import { postMatchingAction } from "@/lib/actions/matchingAction";
+
+/**
+ * 매칭 실행 Mutation 훅
+ * 성공 시 매칭된 유저 정보를 반환합니다.
+ */
+export const useMatching = () => {
+ return useMutation({
+ mutationFn: postMatchingAction,
+ onSuccess: (data) => {
+ console.log("✅ 매칭 성공:", data);
+ },
+ onError: (error) => {
+ console.error("❌ 매칭 실패:", (error as Error).message);
+ },
+ });
+};
diff --git a/lib/actions/matchingAction.ts b/lib/actions/matchingAction.ts
new file mode 100644
index 0000000..601b2c1
--- /dev/null
+++ b/lib/actions/matchingAction.ts
@@ -0,0 +1,40 @@
+"use server";
+
+import { serverApi } from "@/lib/server-api";
+import {
+ MatchingRequest,
+ MatchingResult,
+ ApiResponse,
+} from "@/lib/types/matching";
+import { isAxiosError } from "@/lib/server-api";
+
+/**
+ * 매칭 실행 Server Action
+ * 백엔드 API를 호출하여 매칭을 진행합니다.
+ */
+export async function postMatchingAction(
+ payload: MatchingRequest,
+): Promise {
+ try {
+ const response = await serverApi.post({
+ path: "/api/matching",
+ body: payload,
+ });
+
+ return response.data;
+ } catch (error) {
+ if (isAxiosError(error)) {
+ const message =
+ error.response?.data?.message || "매칭 시스템 오류가 발생했습니다.";
+ console.error("[postMatchingAction] API Error:", {
+ status: error.response?.status,
+ message,
+ payload,
+ });
+ throw new Error(message);
+ }
+
+ console.error("[postMatchingAction] Unexpected Error:", error);
+ throw new Error("알 수 없는 오류가 발생했습니다.");
+ }
+}
diff --git a/lib/types/matching.ts b/lib/types/matching.ts
index 263909b..017fb5f 100644
--- a/lib/types/matching.ts
+++ b/lib/types/matching.ts
@@ -1,4 +1,4 @@
-import { ContactFrequency } from "./profile";
+import { ContactFrequency, Hobby, Gender, MBTI, SocialType } from "./profile";
export type AgeOption = "OLDER" | "YOUNGER" | "EQUAL";
@@ -22,3 +22,25 @@ export interface MatchingRequest {
minAgeOffset?: number | null;
maxAgeOffset?: number | null;
}
+
+export interface MatchingResult {
+ memberId: number;
+ gender: Gender;
+ age: number;
+ mbti: MBTI;
+ major: string;
+ intro: string;
+ nickname: string;
+ profileImageUrl: string;
+ socialType: SocialType;
+ socialAccountId: string;
+ hobbies: Hobby[];
+ tags: { tag: string }[];
+}
+
+export interface ApiResponse {
+ code: string;
+ status: number;
+ message: string;
+ data: T;
+}