mirror of
https://github.com/ktds-dg0501/kt-event-marketing-fe.git
synced 2025-12-06 08:56:23 +00:00
- RecommendationStep 컴포넌트 확장 및 기능 개선 - 이벤트 API 및 AI API 연동 강화 - 인증 관련 훅 기능 확장 - 타입 정의 및 에러 처리 개선 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
190 lines
5.5 KiB
TypeScript
190 lines
5.5 KiB
TypeScript
'use client';
|
|
|
|
import { useFunnel } from '@use-funnel/browser';
|
|
import { useRouter } from 'next/navigation';
|
|
import ObjectiveStep from './steps/ObjectiveStep';
|
|
import RecommendationStep from './steps/RecommendationStep';
|
|
import ContentPreviewStep from './steps/ContentPreviewStep';
|
|
import ContentEditStep from './steps/ContentEditStep';
|
|
import ChannelStep from './steps/ChannelStep';
|
|
import ApprovalStep from './steps/ApprovalStep';
|
|
|
|
// 이벤트 생성 데이터 타입
|
|
export type EventObjective = 'new_customer' | 'revisit' | 'sales' | 'awareness';
|
|
export type BudgetLevel = 'low' | 'medium' | 'high';
|
|
export type EventMethod = 'online' | 'offline';
|
|
|
|
export interface EventData {
|
|
eventDraftId?: number;
|
|
eventId?: string;
|
|
objective?: EventObjective;
|
|
recommendation?: {
|
|
recommendation: {
|
|
optionNumber: number;
|
|
concept: string;
|
|
title: string;
|
|
description: string;
|
|
targetAudience: string;
|
|
duration: {
|
|
recommendedDays: number;
|
|
recommendedPeriod?: string;
|
|
};
|
|
mechanics: {
|
|
type: 'DISCOUNT' | 'GIFT' | 'STAMP' | 'EXPERIENCE' | 'LOTTERY' | 'COMBO';
|
|
details: string;
|
|
};
|
|
promotionChannels: string[];
|
|
estimatedCost: {
|
|
min: number;
|
|
max: number;
|
|
breakdown?: {
|
|
material?: number;
|
|
promotion?: number;
|
|
discount?: number;
|
|
};
|
|
};
|
|
expectedMetrics: {
|
|
newCustomers: { min: number; max: number };
|
|
repeatVisits?: { min: number; max: number };
|
|
revenueIncrease: { min: number; max: number };
|
|
roi: { min: number; max: number };
|
|
socialEngagement?: {
|
|
estimatedPosts: number;
|
|
estimatedReach: number;
|
|
};
|
|
};
|
|
differentiator: string;
|
|
};
|
|
eventId: string;
|
|
};
|
|
contentPreview?: {
|
|
imageStyle: string;
|
|
images?: any[];
|
|
};
|
|
contentEdit?: {
|
|
title: string;
|
|
prize: string;
|
|
guide: string;
|
|
};
|
|
channels?: string[];
|
|
}
|
|
|
|
export default function EventCreatePage() {
|
|
const router = useRouter();
|
|
|
|
const funnel = useFunnel<{
|
|
objective: EventData;
|
|
recommendation: EventData;
|
|
contentPreview: EventData;
|
|
contentEdit: EventData;
|
|
channel: EventData;
|
|
approval: EventData;
|
|
}>({
|
|
id: 'event-creation',
|
|
initial: {
|
|
step: 'objective',
|
|
context: {},
|
|
},
|
|
});
|
|
|
|
const handleComplete = () => {
|
|
// 이벤트 생성 완료 후 대시보드로 이동
|
|
router.push('/');
|
|
};
|
|
|
|
return (
|
|
<funnel.Render
|
|
objective={({ history }) => (
|
|
<ObjectiveStep
|
|
onNext={({ objective, eventId }) => {
|
|
history.push('recommendation', { objective, eventId });
|
|
}}
|
|
/>
|
|
)}
|
|
recommendation={({ context, history }) => (
|
|
<RecommendationStep
|
|
eventId={context.eventId}
|
|
objective={context.objective}
|
|
onNext={(recommendation) => {
|
|
history.push('channel', { ...context, recommendation });
|
|
}}
|
|
onBack={() => {
|
|
history.go(-1);
|
|
}}
|
|
/>
|
|
)}
|
|
channel={({ context, history }) => (
|
|
<ChannelStep
|
|
onNext={(channels) => {
|
|
// 우리동네TV, 지니TV, SNS 중 하나라도 포함되어 있으면 contentPreview로
|
|
const needsContent = channels.some((ch) =>
|
|
['uriTV', 'genieTV', 'sns'].includes(ch)
|
|
);
|
|
|
|
if (needsContent) {
|
|
// localStorage에 이벤트 정보 저장
|
|
const eventData = {
|
|
eventDraftId: context.recommendation?.eventId || String(Date.now()), // eventId 사용
|
|
eventTitle: context.recommendation?.recommendation.title || '',
|
|
eventDescription: context.recommendation?.recommendation.description || '',
|
|
industry: '',
|
|
location: '',
|
|
trends: context.recommendation?.recommendation.promotionChannels || [],
|
|
prize: '',
|
|
};
|
|
localStorage.setItem('eventCreationData', JSON.stringify(eventData));
|
|
|
|
history.push('contentPreview', { ...context, channels });
|
|
} else {
|
|
history.push('approval', { ...context, channels });
|
|
}
|
|
}}
|
|
onBack={() => {
|
|
history.go(-1);
|
|
}}
|
|
/>
|
|
)}
|
|
contentPreview={({ context, history }) => (
|
|
<ContentPreviewStep
|
|
eventId={context.recommendation?.eventId}
|
|
eventTitle={context.recommendation?.recommendation.title}
|
|
eventDescription={context.recommendation?.recommendation.description}
|
|
onNext={(imageStyle, images) => {
|
|
history.push('contentEdit', {
|
|
...context,
|
|
contentPreview: { imageStyle, images },
|
|
});
|
|
}}
|
|
onSkip={() => {
|
|
history.push('approval', context);
|
|
}}
|
|
onBack={() => {
|
|
history.go(-1);
|
|
}}
|
|
/>
|
|
)}
|
|
contentEdit={({ context, history }) => (
|
|
<ContentEditStep
|
|
initialTitle={context.recommendation?.recommendation.title || ''}
|
|
initialPrize={''}
|
|
onNext={(contentEdit) => {
|
|
history.push('approval', { ...context, contentEdit });
|
|
}}
|
|
onBack={() => {
|
|
history.go(-1);
|
|
}}
|
|
/>
|
|
)}
|
|
approval={({ context, history }) => (
|
|
<ApprovalStep
|
|
eventData={context}
|
|
onApprove={handleComplete}
|
|
onBack={() => {
|
|
history.go(-1);
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
);
|
|
}
|