o2o-infinith-demo/src/components/plan/ChannelStrategy.tsx

122 lines
4.6 KiB
TypeScript

import { type ComponentType } from 'react';
import { motion } from 'motion/react';
import {
YoutubeFilled,
InstagramFilled,
FacebookFilled,
GlobeFilled,
VideoFilled,
MessageFilled,
CalendarFilled,
TiktokFilled,
} from '../icons/FilledIcons';
import { SectionWrapper } from '../report/ui/SectionWrapper';
import type { ChannelStrategyCard } from '../../types/plan';
interface ChannelStrategyProps {
channels: ChannelStrategyCard[];
}
const channelIconMap: Record<string, ComponentType<{ size?: number; className?: string }>> = {
youtube: YoutubeFilled,
instagram: InstagramFilled,
facebook: FacebookFilled,
globe: GlobeFilled,
video: VideoFilled,
messagesquare: MessageFilled,
tiktok: TiktokFilled,
};
function getChannelIcon(icon: string) {
return channelIconMap[icon.toLowerCase()] ?? GlobeFilled;
}
const priorityStyle: Record<string, string> = {
P0: 'bg-[#FFF0F0] text-[#7C3A4B] border border-[#F5D5DC] shadow-[2px_3px_8px_rgba(212,136,154,0.15)]',
P1: 'bg-[#FFF6ED] text-[#7C5C3A] border border-[#F5E0C5] shadow-[2px_3px_8px_rgba(212,168,114,0.15)]',
P2: 'bg-[#F3F0FF] text-[#4A3A7C] border border-[#D5CDF5] shadow-[2px_3px_8px_rgba(155,138,212,0.15)]',
};
export default function ChannelStrategy({ channels }: ChannelStrategyProps) {
return (
<SectionWrapper
id="channel-strategy"
title="Channel Strategy"
subtitle="채널별 커뮤니케이션 전략"
dark
>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{channels.map((ch, index) => {
const Icon = getChannelIcon(ch.icon);
return (
<motion.div
key={ch.channelId}
className="bg-white rounded-2xl p-6 shadow-[3px_4px_12px_rgba(0,0,0,0.06)] hover:shadow-[4px_6px_16px_rgba(0,0,0,0.09)] transition-shadow"
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
{/* Header */}
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 rounded-xl bg-[#F3F0FF] flex items-center justify-center">
<Icon size={20} className="text-[#9B8AD4]" />
</div>
<h4 className="text-lg font-bold text-[#0A1128] flex-1">{ch.channelName}</h4>
<span
className={`text-xs font-semibold px-3 py-1 rounded-full ${
priorityStyle[ch.priority] ?? 'bg-slate-100 text-slate-600'
}`}
>
{ch.priority}
</span>
</div>
{/* Current → Target */}
<div className="flex items-center gap-2 mb-4 flex-wrap">
<span className="bg-[#FFF0F0] text-[#7C3A4B] rounded-full px-3 py-1 text-xs font-medium border border-[#F5D5DC] shadow-[2px_3px_6px_rgba(212,136,154,0.12)]">
{ch.currentStatus}
</span>
<span className="text-slate-400 text-sm">&rarr;</span>
<span className="bg-[#F3F0FF] text-[#4A3A7C] rounded-full px-3 py-1 text-xs font-medium border border-[#D5CDF5] shadow-[2px_3px_6px_rgba(155,138,212,0.12)]">
{ch.targetGoal}
</span>
</div>
{/* Content Types */}
<div className="flex flex-wrap gap-2 mb-4">
{ch.contentTypes.map((type) => (
<span
key={type}
className="bg-slate-50 border border-slate-100 rounded-full px-3 py-1 text-xs text-slate-600 font-medium shadow-[2px_3px_6px_rgba(0,0,0,0.04)]"
>
{type}
</span>
))}
</div>
{/* Posting Frequency */}
<div className="flex items-center gap-2 mb-3">
<CalendarFilled size={14} className="text-[#9B8AD4] shrink-0" />
<p className="text-sm text-slate-600">{ch.postingFrequency}</p>
</div>
{/* Tone */}
<p className="text-sm italic text-[#6C5CE7]/70 mb-4">{ch.tone}</p>
{/* Format Guidelines */}
<ul className="space-y-2">
{ch.formatGuidelines.map((guideline, i) => (
<li key={i} className="flex items-start gap-2">
<span className="shrink-0 w-2 h-2 rounded-full bg-[#6C5CE7] mt-2" />
<span className="text-sm text-slate-700">{guideline}</span>
</li>
))}
</ul>
</motion.div>
);
})}
</div>
</SectionWrapper>
);
}