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
5 changes: 5 additions & 0 deletions app/mypage/pinpoints/address/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AddresWidgets } from "@/src/widgets/onboardingSection/ui/address/addressSection";

export default function MypagePinpointsAddressPage() {
return <AddresWidgets />;
}
50 changes: 50 additions & 0 deletions app/mypage/pinpoints/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";

import { MapPin } from "@/src/assets/icons/onboarding";
import { useAddressStore } from "@/src/entities/address";
import { AddressSearch } from "@/src/features/addressSearch";
import { useAddPinpoint } from "@/src/features/mypage/hooks/useAddPinpoint";
import { Button } from "@/src/shared/lib/headlessUi";
import { useRouter } from "next/navigation";

const MypagePinpointsPage = () => {
const title = "핀포인트 설정";
const description = "나만의 핀포인트를 찍고\n원하는 거리 안의 임재주택을 찾아보세요!";
const image = <MapPin />;
const { address, pinPoint } = useAddressStore();
const router = useRouter();
const { addPinpoint, isLoading, isError, error } = useAddPinpoint({
onSuccess: () => {
router.push("/mypage/settings"); // 주소 선택 후 이전 화면으로
// 또는 목록 새로고침 등
},
onError: err => {
// 토스트 등 에러 처리
},
});
return (
<div className="p-5">
<div className="mb-3 flex flex-[1] flex-col items-center justify-start text-center">
<div className="inline-flex sm:min-w-[200px] sm:max-w-[250px] md:min-w-[250px] md:max-w-[300px] lg:min-w-[280px] lg:max-w-[340px]">
{image}
</div>
{title && <h2 className="text-lg font-bold">{title}</h2>}
<p className="mt-1 whitespace-pre-line text-center text-sm text-gray-500">{description}</p>
<div className="mt-5 w-full">
<AddressSearch />
</div>
</div>
{address ? (
<Button
size={"md"}
variant={"solid"}
onClick={() => addPinpoint({ address, name: pinPoint || "핀 포인트", first: true })}
>
핀포인트 추가
</Button>
) : null}
</div>
);
};

export default MypagePinpointsPage;
9 changes: 6 additions & 3 deletions src/features/addressSearch/ui/addressButton.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { SearchLine } from "@/src/assets/icons/home";
import { useAddressStore } from "@/src/entities/address";
import { PageTransition } from "@/src/shared/ui/animation";
import { IconButton } from "@/src/shared/ui/button/iconButton";
import { useParams } from "next/navigation";
import { useParams, usePathname } from "next/navigation";
import { useRouter } from "next/navigation";

export const AddressButton = () => {
const { address } = useAddressStore();
const { type } = useParams();
const router = useRouter();

const pathname = usePathname();
const openEmbed = () => {
if (pathname?.startsWith("/mypage/pinpoints")) {
router.push("/mypage/pinpoints/address");
return;
}
if (type === "agent") router.push(`${type}/address`);
return;
};
Expand Down
3 changes: 1 addition & 2 deletions src/features/addressSearch/ui/addressSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ declare global {

export const AddressSearch = () => {
const { address, setPinPoint } = useAddressStore();

const onPinPointChange = (e: ChangeEvent<HTMLInputElement>) => {
setPinPoint(e.target.value);
};
Expand All @@ -26,7 +25,7 @@ export const AddressSearch = () => {
<Input
size={"default"}
variant={"default"}
placeholder="핀포인트 1"
placeholder="핀포인트"
onChange={onPinPointChange}
className="text-sm placeholder:text-sm placeholder:font-medium placeholder:text-gray-400"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/features/addressSearch/ui/embedAddress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const EmbedAddress = () => {
<IconButton size={"lg"} variant={"ghost"}>
<div className="flex w-full items-center gap-3" onClick={openEmbed}>
<SearchLine />
<span className="text-text-tertiary">
<span className={address ? "text-text-primary" : "text-text-tertiary"}>
<p className="text-sm">{address === "" ? "주소를 입력해주세요" : address}</p>
</span>
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/features/eligibility/model/eligibilityContentMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ELIGIBILITY_GROUP_IDS = {
PERSONAL_INFO: "personalInfo", // 개인정보
IDENTITY_INFO: "identityInfo", // 신분정보
ASSET_INFO: "assetInfo", // 자산정보
DIAGNOSIS_END: "diagnosisEnd", // 진단종료
} as const;

// 결정트리에서 path 정보 생성 (하위 호환성 유지)
Expand Down Expand Up @@ -47,4 +48,8 @@ export const ELIGIBILITY_STEPS: EligibilityStep[] = [
id: ELIGIBILITY_GROUP_IDS.ASSET_INFO,
label: "자산정보",
},
] as const;
{
id: ELIGIBILITY_GROUP_IDS.DIAGNOSIS_END,
label: "진단종료",
},
];
11 changes: 2 additions & 9 deletions src/features/eligibility/model/eligibilityDecisionTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ export const eligibilityDecisionTree: StepConfig[] = [
// diagnosisEnd
{
id: "diagnosisEnd",
groupId: "personalInfo",
groupId: "diagnosisEnd",
components: [
{
type: "statusBanner",
Expand All @@ -1800,15 +1800,8 @@ export const eligibilityDecisionTree: StepConfig[] = [
description: "",
},
},
{
type: "infoButton",
props: {
text: "홈으로 이동",
action: "home",
},
},
],
validation: () => "진단종료",
validation: () => null,
getNextStep: () => null,
},
];
Expand Down
3 changes: 2 additions & 1 deletion src/features/eligibility/ui/common/eligibilityStepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ export const EligibilityStepper = ({
return (
<div className={cn("aligin-center flex justify-center", className)}>
{steps.map((step, index) => {
if (index === steps.length - 1) return null;
const status = getStepStatus(index);
const isLast = index === steps.length - 1;
const isLast = index === steps.length - 2;

return (
<div key={step.id} className="flex items-center">
Expand Down
8 changes: 6 additions & 2 deletions src/features/eligibility/ui/eligibilityNextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ export const EligibilityNextButton = () => {
}
return;
}

// diagnosisEnd에서 다음 클릭 시 홈으로 이동
if (currentStepId === "diagnosisEnd" && isLastStep) {
router.push("/home");
return;
}
// 마지막 단계인 경우 진단종료 페이지로 이동
if (isLastStep) {
router.push("/eligibility?step=diagnosisEnd");
Expand All @@ -91,7 +95,7 @@ export const EligibilityNextButton = () => {
onClick={handleClick}
disabled={isDisabled}
>
다음
{currentStepId === "diagnosisEnd" ? "홈으로 이동하기" : "다음"}
</Button>
);
};
4 changes: 4 additions & 0 deletions src/features/home/ui/components/homeFullSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export const HomeSheet = () => {
closeSheet();
};

const handleSetPinpoint = () => {
router.push("/mypage/pinpoints");
};
return (
<AnimatePresence>
{open && (
Expand Down Expand Up @@ -70,6 +73,7 @@ export const HomeSheet = () => {
)}
variant="outline"
radius="sm"
onClick={handleSetPinpoint}
>
핀포인트 설정
</Button>
Expand Down
8 changes: 6 additions & 2 deletions src/features/home/ui/homeActionCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ export const ActionCardList = () => {
router.push("/listings");
};

const onEligibilityPageMove = () => {
router.push("/eligibility");
};
return (
<div className="mb-4 flex gap-4">
<div
className="flex min-h-[88px] flex-1 flex-col justify-between rounded-lg bg-primary-blue-300 px-4 py-3"
className="flex min-h-[88px] flex-1 cursor-pointer flex-col justify-between rounded-lg bg-primary-blue-300 px-4 py-3"
onClick={onListingsPageMove}
>
<div className="flex items-center justify-between text-white">
Expand All @@ -29,8 +32,9 @@ export const ActionCardList = () => {
</div>

<div
className="flex min-h-[88px] flex-1 flex-col justify-between rounded-lg px-4 py-3"
className="flex min-h-[88px] flex-1 cursor-pointer flex-col justify-between rounded-lg px-4 py-3"
style={{ background: "#FFBA18" }}
onClick={onEligibilityPageMove}
>
<div className="flex items-center justify-between text-white">
<p className="text-sm font-bold leading-tight opacity-[0.7]">자격진단 기준</p>
Expand Down
6 changes: 5 additions & 1 deletion src/features/home/ui/homePersonalShortcutList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HomeScreenHomeIcon } from "@/src/assets/icons/home/home";
import { HomeScreenTask } from "@/src/assets/icons/home/homeScreenTask";
import { useEffect, useState } from "react";
import { useOAuthStore } from "../../login/model";
import { useRouter } from "next/navigation";

const PERSONAL_SHORTCUTS = [
{
Expand All @@ -13,6 +14,7 @@ const PERSONAL_SHORTCUTS = [
icon: <HomeScreenHomeIcon />,
button: <LeftButton width={25} />,
message: "임대주택 탐색이 처음이라면?",
path: "/listings",
},
{
id: "save-condition",
Expand All @@ -21,6 +23,7 @@ const PERSONAL_SHORTCUTS = [
icon: <HomeScreenTask />,
button: <LeftButton width={25} />,
message: "나의 공공 임대주택 지원자격을 알고싶다면?",
path: "/eligibility",
},
] as const;

Expand All @@ -37,8 +40,8 @@ const ShortcutMessage = ({ text }: { text: string }) => {
};

const messageSeenKey = (userId: string) => `home-shortcut-msg-seen:${userId ?? "anon"}`;

export const PersonalShortcutList = () => {
const router = useRouter();
const { userName } = useOAuthStore(); // 실제로 쓰는 user 식별자 넣기
const [showMessage, setShowMessage] = useState(false);

Expand All @@ -60,6 +63,7 @@ export const PersonalShortcutList = () => {
<button
className="shadow- flex w-full items-center gap-2 rounded-2xl border border-greyscale-grey-50 bg-white p-4 text-left"
type="button"
onClick={() => router.push(item.path)}
>
<div>{item.icon}</div>

Expand Down
39 changes: 39 additions & 0 deletions src/features/mypage/hooks/useAddPinpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";

import { useMutation } from "@tanstack/react-query";
import { requestSetPinpoint } from "@/src/entities/address/api";

export interface IPinpointData {
address: string;
name: string;
first: boolean;
}

interface IUseAddPinpointParams {
onSuccess?: () => void;
onError?: (error: unknown) => void;
}

/**
* 핀포인트만 추가하는 커스텀 훅 (마이페이지 등에서 사용)
*/
export const useAddPinpoint = ({ onSuccess, onError }: IUseAddPinpointParams = {}) => {
const mutation = useMutation({
mutationFn: (data: IPinpointData) => requestSetPinpoint(data),
onSuccess: () => {
onSuccess?.();
},
onError: error => {
console.error("핀포인트 추가 실패:", error);
onError?.(error);
},
});

return {
addPinpoint: mutation.mutateAsync,
addPinpointMutate: mutation.mutate,
isLoading: mutation.isPending,
isError: mutation.isError,
error: mutation.error,
};
};
2 changes: 0 additions & 2 deletions src/features/onboarding/hooks/useOnboardingFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ export const useOnboardingFlow = ({
mutationFn: (data: IOnboardingCompleteRequest) => completeOnboarding(data),
onSuccess: async success => {
if (success) {
console.log("온보딩 완료 성공");
// 핀포인트 설정은 onSuccess에서 처리 (쿠키 설정 후)
if (pinpointData) {
try {
await requestSetPinpoint(pinpointData);
console.log("핀포인트 설정 성공");
} catch (error) {
console.error("핀포인트 설정 실패:", error);
}
Expand Down
2 changes: 1 addition & 1 deletion src/features/onboarding/ui/onBoardingNextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const OnboardingNextButton = () => {
pinpointData: isLastStep
? {
address,
name: pinPoint,
name: pinPoint || "핀 포인트",
first: false,
}
: undefined,
Expand Down
13 changes: 13 additions & 0 deletions src/widgets/onboardingSection/ui/address/addressSection.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
"use client";
import { useAddressStore } from "@/src/entities/address";
import { EmbedAddress, EmbedAddressClose } from "@/src/features/addressSearch";
import { Button } from "@/src/shared/lib/headlessUi";
import { PageTransition } from "@/src/shared/ui/animation";
import { useRouter } from "next/navigation";
import Script from "next/script";

export const AddresWidgets = () => {
const { address } = useAddressStore();
const router = useRouter();
const handleSetAddress = () => {
router.back();
};
return (
<section className="flex h-full w-full flex-col justify-between overflow-hidden px-5 py-5">
<PageTransition>
Expand All @@ -14,6 +22,11 @@ export const AddresWidgets = () => {
/>
<EmbedAddressClose />
<EmbedAddress />
{address ? (
<Button size={"md"} variant={"solid"} onClick={handleSetAddress}>
선택한 주소로 설정
</Button>
) : null}
</div>
</PageTransition>
</section>
Expand Down
Loading