Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
425d047
feat: useHouseData 훅 추가 및 상태 관리 로직 구현
Dobbymin Aug 22, 2025
498526a
feat: 위험도 분석 타입 수정 및 리팩토링
Dobbymin Aug 22, 2025
8d760c1
feat: 진단 API 요청 및 응답 타입 수정
Dobbymin Aug 22, 2025
493ccce
feat: HOUSE_TYPE_OPTIONS에서 'APARTMENT' 값을 'APT'로 변경
Dobbymin Aug 22, 2025
4355502
feat: 위험 요소 타입을 RiskFactor에서 Factor로 변경
Dobbymin Aug 22, 2025
4173a3c
feat: 진단 폼에서 데이터 전송 성공 시 상태 관리 로직 추가
Dobbymin Aug 22, 2025
1e19a62
feat: GradeBox 컴포넌트에 gradeData prop 추가 및 기본 데이터 처리 로직 수정
Dobbymin Aug 22, 2025
1c1aa47
feat: MultiHouseBox 컴포넌트에 multiHouseData prop 추가 및 기본 데이터 처리 로직 수정
Dobbymin Aug 22, 2025
29e2d07
feat: ReasonBox 컴포넌트에서 RELIABILITY_REASONS를 data 변수로 변경하여 가독성 향상
Dobbymin Aug 22, 2025
3deb57a
feat: 위험 분석 데이터에 grade 필드 추가
Dobbymin Aug 22, 2025
03d1e80
feat: SubrogationPaymentBox 컴포넌트에 subrogationData prop 추가 및 데이터 처리 로직 수정
Dobbymin Aug 22, 2025
10ed2c6
feat: useMapAddress 상태 관리에 devtools 미들웨어 추가
Dobbymin Aug 22, 2025
9c40c43
feat: LandlordReliabilitySection 컴포넌트에 데이터 로딩 및 오류 처리 추가, 진단 데이터 기반으로…
Dobbymin Aug 22, 2025
12ae641
feat: RiskAnalysisSummarySection 컴포넌트에 데이터 로딩 및 오류 처리 추가, 진단 데이터 기반으로…
Dobbymin Aug 22, 2025
80c3b86
feat: useHouseData 상태 관리에서 resetState 메서드 수정, 로딩 및 오류 상태 초기화 추가
Dobbymin Aug 22, 2025
d4be253
fix: RiskAnalysisSummarySection 컴포넌트에서 데이터 구조 검증 로직 수정, score가 null인 …
Dobbymin Aug 22, 2025
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
10 changes: 3 additions & 7 deletions src/entities/chart/types/risk-analysis.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
* 위험도 분석 관련 entities
*/

// 위험 요인
export type RiskFactor = {
export type Factor = {
name: string;
percent: number;
};

// 위험도 요약
export type RiskSummary = {
score: number;
factors: RiskFactor[];
grade: string;
factors: Factor[];
};

// 임대인 정보
export type Landlord = {
landlordId: number;
name: string;
Expand All @@ -25,7 +23,6 @@ export type Landlord = {
updatedAt: string;
};

// 임대인 신뢰도
export type LandlordTrust = {
trustScore: number;
subrogationCount: number;
Expand All @@ -35,7 +32,6 @@ export type LandlordTrust = {
grade: string;
};

// 임대인 소유 매물
export type LandlordPlace = {
placeId: number;
label: string;
Expand Down
12 changes: 10 additions & 2 deletions src/features/main/apis/diagnosis.api.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import type { Landlord, LandlordPlace, LandlordTrust, RiskSummary } from '@/entities';
import { fetchInstance } from '@/shared';

import type { HouseType } from '../types';

export const DIAGNOSIS_API_PATH = '/api/diagnosis';

interface DiagnosisApiResponse {
interface DiagnosisApiRequest {
address: string;
addressDetail: string;
houseType: HouseType;
deposit: number;
}

interface DiagnosisApiResponse {
riskSummary: RiskSummary;
landlord: Landlord;
landlordTrust: LandlordTrust;
landlordPlaces: LandlordPlace[];
}

export const diagnosisApi = async ({
address,
addressDetail,
houseType,
deposit,
}: DiagnosisApiResponse) => {
}: DiagnosisApiRequest) => {
const response = await fetchInstance.post<DiagnosisApiResponse>(DIAGNOSIS_API_PATH, {
address,
addressDetail,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { RiskFactor } from '@/entities';
import type { Factor } from '@/entities';

type Props = {
riskFactors: RiskFactor[];
riskFactors: Factor[];
};

export const RiskFactorsBox = ({ riskFactors }: Props) => {
Expand Down
6 changes: 6 additions & 0 deletions src/features/main/components/features/form/DiagnosticForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Button, Form } from '@/shared';

import { diagnosisApi } from '../../../apis';
import { type SearchAddressType, searchAddressSchema } from '../../../model';
import { useHouseData } from '../../../store';
import type { HouseType } from '../../../types';
import {
AddressField,
Expand All @@ -17,6 +18,8 @@ import {
} from '../../common';

export const DiagnosticForm = () => {
const { setDiagnosisData } = useHouseData();

const form = useForm<SearchAddressType>({
resolver: zodResolver(searchAddressSchema),
defaultValues: {
Expand All @@ -35,6 +38,9 @@ export const DiagnosticForm = () => {
houseType: data.houseType as HouseType,
deposit: data.deposit,
}),
onSuccess: (data) => {
setDiagnosisData(data);
},
});

const onSubmit = (data: SearchAddressType) => {
Expand Down
17 changes: 13 additions & 4 deletions src/features/main/components/features/reliability/GradeBox.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import type { LandlordTrust } from '@/entities';
import { getTrustGradeColorClass } from '@/shared';

import { LANDLORD_TRUST_DATA } from '../../../mock';

export const GradeBox = () => {
type Props = {
gradeData: LandlordTrust;
};

export const GradeBox = ({ gradeData }: Props) => {
const data = gradeData || LANDLORD_TRUST_DATA;

return (
<div className='flex flex-col gap-2'>
<h1 className='text-3xl font-bold'>임대인 신뢰도 등급</h1>
<span className='text-md flex gap-2 font-semibold'>
<span className='text-black'>위험점수 :</span>
<span className='text-chart-green'>{LANDLORD_TRUST_DATA.trustScore}</span>
<span className='text-chart-green'>{data.trustScore}</span>
<span className='text-black'>점</span>
</span>
<div className='flex w-full items-center justify-center'>
<span
className={`text-landlord-reliability font-semibold ${getTrustGradeColorClass(LANDLORD_TRUST_DATA.grade)}`}
className={`text-landlord-reliability font-semibold ${getTrustGradeColorClass(
data.grade,
)}`}
>
{LANDLORD_TRUST_DATA.grade}
{data.grade}
</span>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import type { LandlordTrust } from '@/entities';

import { LANDLORD_TRUST_DATA } from '../../../mock';

export const MultiHouseBox = () => {
type Props = {
multiHouseData: LandlordTrust;
};

export const MultiHouseBox = ({ multiHouseData }: Props) => {
const data = multiHouseData || LANDLORD_TRUST_DATA;

return (
<div>
<h1 className='text-3xl font-bold'>다주택자</h1>
<div className='flex w-full items-end justify-center'>
<span className='text-landlord-reliability font-bold text-blue-500'>
{LANDLORD_TRUST_DATA.ownedUnsoldCount}
{data.ownedUnsoldCount}
</span>
<span className='mb-25 text-5xl font-semibold text-black'>채</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { RELIABILITY_REASONS } from '../../../mock';

export const ReasonBox = () => {
const data = RELIABILITY_REASONS;

return (
<div className='flex w-full flex-col gap-2 pb-3'>
<h1 className='text-3xl font-bold'>임대인 신뢰도 등급 사유</h1>
{RELIABILITY_REASONS.map((reason, index) => (
{data.map((reason, index) => (
<div
key={`${reason.name}-${reason.percent}-${index}`}
className='flex items-center gap-5 py-3 text-center font-semibold'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import { getSubrogationColorClass } from '@/shared';

import { LANDLORD_TRUST_DATA } from '../../../mock';

export const SubrogationPaymentBox = () => {
type Props = {
subrogationData: number;
};

export const SubrogationPaymentBox = ({ subrogationData }: Props) => {
const data = subrogationData || LANDLORD_TRUST_DATA.subrogationCount;

return (
<div>
<h1 className='text-3xl font-bold'>대위변제 이력</h1>
<div className='flex w-full items-end justify-center'>
<span
className={`text-landlord-reliability font-bold ${getSubrogationColorClass(LANDLORD_TRUST_DATA.subrogationCount)}`}
>
{LANDLORD_TRUST_DATA.subrogationCount}
<span className={`text-landlord-reliability font-bold ${getSubrogationColorClass(data)}`}>
{data}
</span>
<span className='mb-25 text-5xl font-semibold text-black'>회</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/features/main/constants/house-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export const HOUSE_TYPE_OPTIONS = [
{ value: 'ONE_ROOM', label: '원룸' },
{ value: 'TWO_ROOM', label: '투룸' },
{ value: 'OFFICETEL', label: '오피스텔' },
{ value: 'APARTMENT', label: '아파트' },
{ value: 'APT', label: '아파트' },
{ value: 'ETC', label: '기타' },
] as const;
1 change: 1 addition & 0 deletions src/features/main/mock/risk-analysis.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const TEMP_RISK_ANALYSIS_DATA: RiskAnalysisResponse[] = [
data: {
riskSummary: {
score: 50,
grade: 'B',
factors: [
{ name: '전세가율', percent: 12 },
{ name: '가격하락', percent: 10 },
Expand Down
1 change: 1 addition & 0 deletions src/features/main/store/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './useMapAddress';
export * from './useHouseData';
71 changes: 71 additions & 0 deletions src/features/main/store/useHouseData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

import type { Landlord, LandlordPlace, LandlordTrust, RiskSummary } from '@/entities';

export type HouseDiagnosisData = {
riskSummary: RiskSummary;
landlord: Landlord;
landlordTrust: LandlordTrust;
landlordPlaces: LandlordPlace[];
};

// API 응답 형태
export type ApiResponse = {
data: HouseDiagnosisData;
status: string;
serverDateTime: string;
errorCode: string | null;
errorMessage: string | null;
};

type HouseDataState = {
// 상태
diagnosisData: HouseDiagnosisData | null;
isLoading: boolean;
error: string | null;

// 액션
setDiagnosisData: (data: HouseDiagnosisData | ApiResponse) => void;
clearDiagnosisData: () => void;
resetState: () => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
};

export const useHouseData = create<HouseDataState>()(
devtools(
(set) => ({
// 초기 상태
diagnosisData: null,
isLoading: false,
error: null,

// 액션들
setDiagnosisData: (data: HouseDiagnosisData | ApiResponse) => {
// API 응답 형태인지 확인하고 적절히 처리
const processedData = 'data' in data ? data.data : data;
set({ diagnosisData: processedData });
},

clearDiagnosisData: () => {
set({ diagnosisData: null });
},

resetState: () => {
set({ diagnosisData: null, isLoading: false, error: null });
},

setLoading: (loading: boolean) => {
set({ isLoading: loading });
},

setError: (error: string | null) => {
set({ error });
},
}),
{
name: 'house-data-store',
},
),
);
82 changes: 45 additions & 37 deletions src/features/main/store/useMapAddress.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

import type { MapAddress } from '@/entities';

Expand All @@ -11,40 +12,47 @@ type MapAddressState = {
updateAddress: (address: string) => void;
};

export const useMapAddress = create<MapAddressState>()((set, get) => ({
mapAddress: null,

setMapAddress: (address: MapAddress) => {
set({ mapAddress: address });
},

clearMapAddress: () => {
set({ mapAddress: null });
},

updateCoordinates: (latitude: number, longitude: number) => {
const currentAddress = get().mapAddress;
if (currentAddress) {
set({
mapAddress: {
...currentAddress,
latitude,
longitude,
},
});
}
},

updateAddress: (address: string) => {
const currentAddress = get().mapAddress;

if (currentAddress) {
set({
mapAddress: {
...currentAddress,
address,
},
});
}
},
}));
export const useMapAddress = create<MapAddressState>()(
devtools(
(set, get) => ({
mapAddress: null,

setMapAddress: (address: MapAddress) => {
set({ mapAddress: address });
},

clearMapAddress: () => {
set({ mapAddress: null });
},

updateCoordinates: (latitude: number, longitude: number) => {
const currentAddress = get().mapAddress;
if (currentAddress) {
set({
mapAddress: {
...currentAddress,
latitude,
longitude,
},
});
}
},

updateAddress: (address: string) => {
const currentAddress = get().mapAddress;

if (currentAddress) {
set({
mapAddress: {
...currentAddress,
address,
},
});
}
},
}),
{
name: 'map-address-store', // Redux DevTools에서 표시될 이름
},
),
);
Loading
Loading