123 lines
5.0 KiB
TypeScript
123 lines
5.0 KiB
TypeScript
import { useState } from "react";
|
|
import ChannelYoutubeIcon from "@/assets/icons/channel-youtube.svg?react";
|
|
import { Pill } from "@/components/atoms/Pill";
|
|
import { Surface } from "@/components/atoms/Surface";
|
|
import { SegmentTabButton } from "@/features/plan/ui/SegmentTabButton";
|
|
import type { AssetCollectionData } from "@/features/plan/types/marketingPlan";
|
|
import {
|
|
ASSET_COLLECTION_FILTER_TABS,
|
|
type AssetCollectionFilterKey,
|
|
} from "@/features/plan/ui/assetCollection/assetCollectionFilterTabs";
|
|
import {
|
|
assetSourceBadgeClass,
|
|
assetStatusConfig,
|
|
assetTypeBadgeClass,
|
|
assetTypeDisplayLabel,
|
|
formatYoutubeViews,
|
|
} from "@/features/plan/ui/assetCollection/assetCollectionBadgeClasses";
|
|
|
|
type AssetCollectionPanelProps = {
|
|
data: AssetCollectionData;
|
|
};
|
|
|
|
export function AssetCollectionPanel({ data }: AssetCollectionPanelProps) {
|
|
const [activeFilter, setActiveFilter] = useState<AssetCollectionFilterKey>("all");
|
|
|
|
const filteredAssets =
|
|
activeFilter === "all" ? data.assets : data.assets.filter((a) => a.source === activeFilter);
|
|
|
|
return (
|
|
<div>
|
|
<div className="flex flex-wrap gap-2 mb-8" role="tablist" aria-label="에셋 출처 필터">
|
|
{ASSET_COLLECTION_FILTER_TABS.map((tab) => {
|
|
const isActive = activeFilter === tab.key;
|
|
return (
|
|
<SegmentTabButton
|
|
key={tab.key}
|
|
role="tab"
|
|
aria-selected={isActive}
|
|
active={isActive}
|
|
onClick={() => setActiveFilter(tab.key)}
|
|
>
|
|
{tab.label}
|
|
</SegmentTabButton>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-12">
|
|
{filteredAssets.map((asset) => {
|
|
const statusInfo = assetStatusConfig(asset.status);
|
|
return (
|
|
<Surface key={asset.id}>
|
|
<div className="flex items-center gap-2 mb-3 flex-wrap">
|
|
<Pill className={`shrink-0 ${assetSourceBadgeClass(asset.source)}`}>{asset.sourceLabel}</Pill>
|
|
<Pill className={`shrink-0 ${assetTypeBadgeClass(asset.type)}`}>{assetTypeDisplayLabel(asset.type)}</Pill>
|
|
<Pill className={`ml-auto shrink-0 ${statusInfo.className}`}>{statusInfo.label}</Pill>
|
|
</div>
|
|
|
|
<h4 className="title-14 text-navy-900 mb-1 break-keep">{asset.title}</h4>
|
|
<p className="body-14 text-neutral-70 mb-3 break-keep">{asset.description}</p>
|
|
|
|
{asset.repurposingSuggestions.length > 0 ? (
|
|
<div>
|
|
<p className="label-12 font-semibold text-neutral-60 uppercase mb-2 break-keep">
|
|
Repurposing →
|
|
</p>
|
|
<div className="flex flex-wrap gap-2">
|
|
{asset.repurposingSuggestions.map((suggestion, j) => (
|
|
<Pill key={j} size="sm" className="shrink-0 bg-lavender-100 text-violet-700">
|
|
{suggestion}
|
|
</Pill>
|
|
))}
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</Surface>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{data.youtubeRepurpose.length > 0 ? (
|
|
<div>
|
|
<h3 className="font-serif headline-24 text-navy-900 mb-4 break-keep">
|
|
YouTube Top Videos for Repurposing
|
|
</h3>
|
|
<div className="flex overflow-x-auto gap-4 pb-4 scrollbar-hide">
|
|
{data.youtubeRepurpose.map((video) => (
|
|
<Surface key={video.title} className="min-w-[280px] shrink-0">
|
|
<div className="flex items-start gap-2 mb-3 min-w-0">
|
|
<ChannelYoutubeIcon width={18} height={18} className="text-[var(--color-status-critical-dot)] shrink-0 mt-1" aria-hidden />
|
|
<h4 className="title-14 text-navy-900 break-keep min-w-0">{video.title}</h4>
|
|
</div>
|
|
<div className="flex items-center gap-2 mb-3 flex-wrap">
|
|
<Pill className="shrink-0 bg-neutral-10 text-neutral-80">
|
|
{formatYoutubeViews(video.views)} views
|
|
</Pill>
|
|
<Pill
|
|
className={
|
|
video.type === "Short"
|
|
? "shrink-0 bg-lavender-100 text-violet-700 border border-lavender-300"
|
|
: "shrink-0 bg-[var(--color-status-info-bg)] text-[var(--color-status-info-text)] border border-[var(--color-status-info-border)]"
|
|
}
|
|
>
|
|
{video.type}
|
|
</Pill>
|
|
</div>
|
|
<p className="label-12 font-semibold text-neutral-60 uppercase mb-2 break-keep">Repurpose As:</p>
|
|
<div className="flex flex-wrap gap-2">
|
|
{video.repurposeAs.map((suggestion, j) => (
|
|
<Pill key={j} size="sm" className="shrink-0 bg-lavender-100 text-violet-700">
|
|
{suggestion}
|
|
</Pill>
|
|
))}
|
|
</div>
|
|
</Surface>
|
|
))}
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|