99 lines
3.1 KiB
TypeScript
99 lines
3.1 KiB
TypeScript
/**
|
|
* @file features/layout/hooks/use-market-indices.ts
|
|
* @description 시장 지수 데이터를 가져오고 상태를 관리하는 커스텀 훅
|
|
*
|
|
* @description [주요 책임]
|
|
* - `useMarketIndicesStore`와 연동하여 상태(지수, 로딩, 에러)를 제공
|
|
* - KIS 검증 세션이 있을 때 `/api/kis/domestic/indices` API를 인증 헤더와 함께 호출
|
|
* - API 호출 로직을 `useCallback`으로 메모이제이션하여 성능을 최적화
|
|
*/
|
|
import { useCallback } from "react";
|
|
import {
|
|
buildKisRequestHeaders,
|
|
resolveKisApiErrorMessage,
|
|
type KisApiErrorPayload,
|
|
} from "@/features/settings/apis/kis-api-utils";
|
|
import { useKisRuntimeStore } from "@/features/settings/store/use-kis-runtime-store";
|
|
import { useMarketIndicesStore } from "@/features/layout/stores/market-indices-store";
|
|
import type { DomesticMarketIndexResult } from "@/lib/kis/dashboard";
|
|
import type { DashboardIndicesResponse } from "@/features/dashboard/types/dashboard.types";
|
|
|
|
interface LegacyMarketIndicesResponse {
|
|
indices: DomesticMarketIndexResult[];
|
|
fetchedAt: string;
|
|
}
|
|
|
|
export function useMarketIndices() {
|
|
const verifiedCredentials = useKisRuntimeStore((state) => state.verifiedCredentials);
|
|
const isKisVerified = useKisRuntimeStore((state) => state.isKisVerified);
|
|
|
|
const {
|
|
indices,
|
|
isLoading,
|
|
error,
|
|
fetchedAt,
|
|
setIndices,
|
|
setLoading,
|
|
setError,
|
|
} = useMarketIndicesStore();
|
|
|
|
const fetchIndices = useCallback(async () => {
|
|
// [Step 1] KIS 검증이 안 된 상태에서는 지수 API를 호출하지 않습니다.
|
|
if (!isKisVerified || !verifiedCredentials) {
|
|
setLoading(false);
|
|
setError(null);
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
// [Step 2] 인증 헤더를 포함한 신규 지수 API를 호출합니다.
|
|
const response = await fetch("/api/kis/domestic/indices", {
|
|
method: "GET",
|
|
headers: buildKisRequestHeaders(verifiedCredentials, {
|
|
includeSessionOverride: true,
|
|
}),
|
|
cache: "no-store",
|
|
});
|
|
|
|
const payload = (await response.json()) as
|
|
| DashboardIndicesResponse
|
|
| LegacyMarketIndicesResponse
|
|
| KisApiErrorPayload;
|
|
|
|
if (!response.ok) {
|
|
throw new Error(resolveKisApiErrorMessage(payload, "지수 조회 중 오류가 발생했습니다."));
|
|
}
|
|
|
|
// [Step 3] 신규/레거시 응답 형식을 모두 수용해 스토어에 반영합니다.
|
|
if ("items" in payload) {
|
|
setIndices({
|
|
indices: payload.items,
|
|
fetchedAt: payload.fetchedAt,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if ("indices" in payload && "fetchedAt" in payload) {
|
|
setIndices({
|
|
indices: payload.indices,
|
|
fetchedAt: payload.fetchedAt,
|
|
});
|
|
return;
|
|
}
|
|
|
|
throw new Error("지수 응답 형식이 올바르지 않습니다.");
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e : new Error("An unknown error occurred"));
|
|
}
|
|
}, [isKisVerified, setError, setIndices, setLoading, verifiedCredentials]);
|
|
|
|
return {
|
|
indices,
|
|
isLoading,
|
|
error,
|
|
fetchedAt,
|
|
fetchIndices,
|
|
};
|
|
}
|