fix: 제거된 파일 (channel 수정)
parent
327a50bd41
commit
2fd78f48b5
|
|
@ -1,19 +1,16 @@
|
||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState } from 'react';
|
||||||
import { useVerifyChannels } from '@/shared/api/generated/channels/channels';
|
|
||||||
import { mergeEnrichment, type EnrichmentData } from '@/features/report/lib/transformReport';
|
|
||||||
import type { MarketingReport } from '@/features/report/types/report';
|
import type { MarketingReport } from '@/features/report/types/report';
|
||||||
|
|
||||||
// TODO(migration): 기존 enrichChannels Edge Function 은 백엔드의 /api/channels/verify 로 통합.
|
// 신규 백엔드 파이프라인에서는 channel enrichment 가 startAnalysis 단계에 통합됨.
|
||||||
// 응답 스펙이 약간 다르므로 데이터 정합 시점에 추가 매핑 필요.
|
// 기존 /api/channels/verify 엔드포인트는 제거되어 별도 호출 불필요.
|
||||||
|
// 본 훅은 호출부 호환을 위해 인터페이스만 유지하고 no-op 으로 동작.
|
||||||
|
|
||||||
type EnrichmentStatus = 'idle' | 'loading' | 'success' | 'error';
|
type EnrichmentStatus = 'idle' | 'loading' | 'success' | 'error';
|
||||||
|
|
||||||
interface UseEnrichmentResult {
|
interface UseEnrichmentResult {
|
||||||
status: EnrichmentStatus;
|
status: EnrichmentStatus;
|
||||||
enrichedReport: MarketingReport | null;
|
enrichedReport: MarketingReport | null;
|
||||||
/** 재시도 시도 횟수 */
|
|
||||||
retryCount: number;
|
retryCount: number;
|
||||||
/** enrichment를 재시도할 때 호출 (최대 2회 재시도) */
|
|
||||||
retry: () => void;
|
retry: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,68 +24,15 @@ interface EnrichmentParams {
|
||||||
address?: string;
|
address?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_RETRIES = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Phase 1 리포트 렌더링 후 백그라운드 채널 enrichment를 트리거.
|
|
||||||
* 한 번만 실행되며, 백엔드 verify 엔드포인트 완료(~27초)까지 대기한 후
|
|
||||||
* 병합된 리포트를 반환. 최대 2회까지 수동 재시도 지원.
|
|
||||||
*/
|
|
||||||
export function useEnrichment(
|
export function useEnrichment(
|
||||||
baseReport: MarketingReport | null,
|
_baseReport: MarketingReport | null,
|
||||||
params: EnrichmentParams | null,
|
_params: EnrichmentParams | null,
|
||||||
): UseEnrichmentResult {
|
): UseEnrichmentResult {
|
||||||
const [status, setStatus] = useState<EnrichmentStatus>('idle');
|
const [retryCount] = useState(0);
|
||||||
const [enrichedReport, setEnrichedReport] = useState<MarketingReport | null>(null);
|
|
||||||
const [retryCount, setRetryCount] = useState(0);
|
|
||||||
const hasTriggered = useRef(false);
|
|
||||||
const { mutateAsync: verifyChannelsAsync } = useVerifyChannels();
|
|
||||||
|
|
||||||
const doEnrich = useCallback(async () => {
|
|
||||||
if (!baseReport || !params?.reportId) return;
|
|
||||||
|
|
||||||
setStatus('loading');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await verifyChannelsAsync({
|
|
||||||
// TODO(migration): backend ChannelVerifyRequest 스키마와 정확한 필드 매핑 확인 필요
|
|
||||||
data: {
|
|
||||||
instagram: params.instagramHandle ? { handle: params.instagramHandle } : undefined,
|
|
||||||
youtube: params.youtubeChannelId ? { channel_id: params.youtubeChannelId } : undefined,
|
|
||||||
facebook: params.facebookHandle ? { handle: params.facebookHandle } : undefined,
|
|
||||||
} as unknown as Parameters<typeof verifyChannelsAsync>[0]['data'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result.status === 200 && result.data) {
|
|
||||||
const merged = mergeEnrichment(baseReport, result.data as unknown as EnrichmentData);
|
|
||||||
setEnrichedReport(merged);
|
|
||||||
setStatus('success');
|
|
||||||
} else {
|
|
||||||
setStatus('error');
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setStatus('error');
|
|
||||||
}
|
|
||||||
}, [baseReport, params, verifyChannelsAsync]);
|
|
||||||
|
|
||||||
// 초기 트리거
|
|
||||||
useEffect(() => {
|
|
||||||
if (!baseReport || !params?.reportId || hasTriggered.current) return;
|
|
||||||
hasTriggered.current = true;
|
|
||||||
doEnrich();
|
|
||||||
}, [baseReport, params, doEnrich]);
|
|
||||||
|
|
||||||
// 수동 재시도
|
|
||||||
const retry = useCallback(() => {
|
|
||||||
if (retryCount >= MAX_RETRIES) return;
|
|
||||||
setRetryCount(prev => prev + 1);
|
|
||||||
doEnrich();
|
|
||||||
}, [retryCount, doEnrich]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status,
|
status: 'idle',
|
||||||
enrichedReport,
|
enrichedReport: null,
|
||||||
retryCount,
|
retryCount,
|
||||||
retry,
|
retry: () => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,16 @@
|
||||||
*/
|
*/
|
||||||
import ky, { type KyInstance } from 'ky'
|
import ky, { type KyInstance } from 'ky'
|
||||||
|
|
||||||
const API_KEY = import.meta.env.VITE_API_KEY as string | undefined;
|
// Vite 가 빌드 시 치환하는 환경변수 (개발 서버에서도 동일).
|
||||||
|
// import.meta 를 모듈 최상단에서 읽으면 일부 번들러가 cjs 변환 시 경고를 내므로
|
||||||
|
// 함수 내부에서 lazy 하게 접근.
|
||||||
|
function getApiKey(): string | undefined {
|
||||||
|
try {
|
||||||
|
return (import.meta as { env?: { VITE_API_KEY?: string } }).env?.VITE_API_KEY;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const kyInstance: KyInstance = ky.create({
|
export const kyInstance: KyInstance = ky.create({
|
||||||
timeout: 10_000,
|
timeout: 10_000,
|
||||||
|
|
@ -18,7 +27,8 @@ export const kyInstance: KyInstance = ky.create({
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeRequest: [
|
beforeRequest: [
|
||||||
(request) => {
|
(request) => {
|
||||||
if (API_KEY) request.headers.set('x-api-key', API_KEY);
|
const apiKey = getApiKey();
|
||||||
|
if (apiKey) request.headers.set('x-api-key', apiKey);
|
||||||
},
|
},
|
||||||
// TODO: 인증 토큰 주입
|
// TODO: 인증 토큰 주입
|
||||||
// request => {
|
// request => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue