import { useState, useEffect } from 'react'; import { useLocation } from 'react-router'; import type { MarketingPlan, ChannelStrategyCard, CalendarData, ContentStrategyData } from '../types/plan'; import { fetchReportById, fetchActiveContentPlan, supabase } from '../lib/supabase'; import { transformReportToPlan } from '../lib/transformPlan'; import { mockPlan } from '../data/mockPlan'; interface UseMarketingPlanResult { data: MarketingPlan | null; isLoading: boolean; error: string | null; } interface LocationState { report?: Record; metadata?: Record; reportId?: string; clinicId?: string; } /** * Build a MarketingPlan from content_plans DB row. * content_plans stores AI-generated strategy in JSONB columns. */ function buildPlanFromContentPlans( row: Record, clinicName: string, clinicNameEn: string, targetUrl: string, ): MarketingPlan { const channelStrategies = (row.channel_strategies || []) as ChannelStrategyCard[]; const contentStrategy = (row.content_strategy || {}) as ContentStrategyData; const calendar = (row.calendar || { weeks: [], monthlySummary: [] }) as CalendarData; return { id: row.id as string, reportId: (row.run_id as string) || (row.id as string), clinicName, clinicNameEn, createdAt: (row.created_at as string) || new Date().toISOString(), targetUrl, brandGuide: (row.brand_guide as MarketingPlan['brandGuide']) || { colors: [], fonts: [], logoRules: [], toneOfVoice: { personality: ['전문적', '친근한', '신뢰할 수 있는'], communicationStyle: '의료 전문 지식을 쉽고 친근하게 전달', doExamples: [], dontExamples: [], }, channelBranding: [], brandInconsistencies: [], }, channelStrategies, contentStrategy: { pillars: contentStrategy.pillars || [], typeMatrix: contentStrategy.typeMatrix || [], workflow: contentStrategy.workflow || [ { step: 1, name: '기획', description: 'AI 콘텐츠 주제 선정', owner: 'INFINITH AI', duration: '자동' }, { step: 2, name: '제작', description: 'AI 초안 생성 + 의료진 감수', owner: 'INFINITH AI', duration: '1시간' }, { step: 3, name: '편집', description: '영상/이미지 편집', owner: 'INFINITH Studio', duration: '30분' }, { step: 4, name: '배포', description: '채널별 최적화 배포', owner: 'INFINITH Distribution', duration: '자동' }, { step: 5, name: '분석', description: '성과 데이터 수집 + 전략 조정', owner: 'INFINITH Analytics', duration: '자동' }, ], repurposingSource: contentStrategy.repurposingSource || '1개 롱폼 영상', repurposingOutputs: contentStrategy.repurposingOutputs || [], }, calendar, assetCollection: { assets: [], youtubeRepurpose: [] }, }; } export function useMarketingPlan(id: string | undefined): UseMarketingPlanResult { const [data, setData] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const location = useLocation(); useEffect(() => { if (!id) { setError('No plan ID provided'); setIsLoading(false); return; } const state = location.state as LocationState | undefined; async function loadPlan() { try { // ─── Dev / Demo: return mock data immediately ─── if (id === 'demo' || id === 'view-clinic') { setData(mockPlan); setIsLoading(false); return; } // ─── Source 1: Try content_plans table (AI-generated strategy) ─── // First, resolve clinicId from navigation state or analysis_runs let clinicId = state?.clinicId || null; let clinicName = ''; let clinicNameEn = ''; let targetUrl = ''; if (!clinicId) { // Try to find clinicId from analysis_runs by run/report ID const { data: run } = await supabase .from('analysis_runs') .select('clinic_id') .eq('id', id) .single(); if (run) clinicId = run.clinic_id; } if (clinicId) { // Fetch clinic info for plan metadata const { data: clinic } = await supabase .from('clinics') .select('name, name_en, url') .eq('id', clinicId) .single(); if (clinic) { clinicName = clinic.name || ''; clinicNameEn = clinic.name_en || ''; targetUrl = clinic.url || ''; } // Try fetching active content plan const contentPlan = await fetchActiveContentPlan(clinicId); if (contentPlan) { const plan = buildPlanFromContentPlans( contentPlan, clinicName, clinicNameEn, targetUrl, ); setData(plan); setIsLoading(false); return; } } // ─── Source 2: Report data from navigation state (fallback) ─── if (state?.report && state?.metadata) { const plan = transformReportToPlan({ id: (state.reportId || id), url: (state.metadata.url as string) || '', clinic_name: (state.metadata.clinicName as string) || '', report: state.report, created_at: (state.metadata.generatedAt as string) || new Date().toISOString(), }); setData(plan); setIsLoading(false); return; } // ─── Source 3: Fetch report from Supabase and transform (fallback) ─── const row = await fetchReportById(id); const plan = transformReportToPlan(row); setData(plan); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to fetch marketing plan'); } finally { setIsLoading(false); } } loadPlan(); }, [id, location.state]); return { data, isLoading, error }; }