feat: add header channel selector & adding channel modal menu
This commit is contained in:
@@ -42,11 +42,12 @@ import {
|
||||
Copy,
|
||||
Check,
|
||||
} from "lucide-react";
|
||||
import type { TargetChannel, ExternalChannel, Creative } from "@/lib/types/api";
|
||||
import type { ExternalChannel, Creative } from "@/lib/types/api";
|
||||
import { useTargetChannel } from "@/components/providers/target-channel-provider";
|
||||
|
||||
export default function CreatePurchasePage() {
|
||||
const router = useRouter();
|
||||
const [channels, setChannels] = useState<TargetChannel[]>([]);
|
||||
const { selectedChannel } = useTargetChannel();
|
||||
const [externalChannels, setExternalChannels] = useState<ExternalChannel[]>(
|
||||
[]
|
||||
);
|
||||
@@ -57,7 +58,6 @@ export default function CreatePurchasePage() {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
target_channel_id: "",
|
||||
external_channel_id: "",
|
||||
creative_id: "",
|
||||
placement_date: "",
|
||||
@@ -68,41 +68,28 @@ export default function CreatePurchasePage() {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, []);
|
||||
if (selectedChannel) {
|
||||
loadData();
|
||||
}
|
||||
}, [selectedChannel]);
|
||||
|
||||
const loadData = async () => {
|
||||
try {
|
||||
const channelsRes = await channelsApi.list();
|
||||
setChannels(channelsRes.target_channels.filter((c) => c.is_active));
|
||||
if (!selectedChannel) return;
|
||||
|
||||
// Загружаем внешние каналы для первого доступного target channel
|
||||
if (channelsRes.target_channels.length > 0) {
|
||||
const firstTargetChannel = channelsRes.target_channels[0];
|
||||
const [externalChannelsRes, creativesRes] = await Promise.all([
|
||||
externalChannelsApi.list(firstTargetChannel.id),
|
||||
creativesApi.list(),
|
||||
]);
|
||||
setExternalChannels(externalChannelsRes.external_channels);
|
||||
setCreatives(
|
||||
creativesRes.creatives.filter((c) => c.status === "active")
|
||||
);
|
||||
} else {
|
||||
setCreatives([]);
|
||||
setExternalChannels([]);
|
||||
}
|
||||
try {
|
||||
const [externalChannelsRes, creativesRes] = await Promise.all([
|
||||
externalChannelsApi.list(selectedChannel.id),
|
||||
creativesApi.list({ target_channel_id: selectedChannel.id }),
|
||||
]);
|
||||
setExternalChannels(externalChannelsRes.external_channels);
|
||||
setCreatives(
|
||||
creativesRes.creatives.filter((c) => c.status === "active")
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Error loading data:", err);
|
||||
}
|
||||
};
|
||||
|
||||
// Фильтр креативов по выбранному целевому каналу
|
||||
const filteredCreatives = formData.target_channel_id
|
||||
? creatives.filter(
|
||||
(c) => c.target_channel_id === formData.target_channel_id
|
||||
)
|
||||
: creatives;
|
||||
|
||||
const selectedCreative = creatives.find((c) => c.id === formData.creative_id);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@@ -110,8 +97,8 @@ export default function CreatePurchasePage() {
|
||||
setError(null);
|
||||
|
||||
// Validation
|
||||
if (!formData.target_channel_id) {
|
||||
setError("Выберите целевой канал");
|
||||
if (!selectedChannel) {
|
||||
setError("Выберите целевой канал в верхнем меню");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,7 +125,7 @@ export default function CreatePurchasePage() {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const result = await purchasesApi.create({
|
||||
target_channel_id: formData.target_channel_id,
|
||||
target_channel_id: selectedChannel.id,
|
||||
external_channel_id: formData.external_channel_id,
|
||||
creative_id: formData.creative_id,
|
||||
placement_date: formData.placement_date,
|
||||
@@ -253,7 +240,6 @@ export default function CreatePurchasePage() {
|
||||
onClick={() => {
|
||||
setInviteLink("");
|
||||
setFormData({
|
||||
target_channel_id: "",
|
||||
external_channel_id: "",
|
||||
creative_id: "",
|
||||
placement_date: "",
|
||||
@@ -315,42 +301,29 @@ export default function CreatePurchasePage() {
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="target_channel_id">Целевой канал *</Label>
|
||||
<Select
|
||||
value={formData.target_channel_id}
|
||||
onValueChange={(value) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
target_channel_id: value,
|
||||
creative_id: "", // Сбросить креатив при смене канала
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите канал" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{channels.map((channel) => (
|
||||
<SelectItem key={channel.id} value={channel.id}>
|
||||
{channel.title}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{selectedChannel && (
|
||||
<Alert>
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
Размещение будет создано для канала: <strong>{selectedChannel.title}</strong>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="external_channel_id">Внешний канал *</Label>
|
||||
<Select
|
||||
value={formData.external_channel_id}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, external_channel_id: value })
|
||||
setFormData({
|
||||
...formData,
|
||||
external_channel_id: value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите канал" />
|
||||
<SelectValue placeholder="Выберите внешний канал" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{externalChannels.map((channel) => (
|
||||
@@ -361,34 +334,27 @@ export default function CreatePurchasePage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="creative_id">Креатив *</Label>
|
||||
<Select
|
||||
value={formData.creative_id}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, creative_id: value })
|
||||
}
|
||||
disabled={!formData.target_channel_id}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="creative_id">Креатив *</Label>
|
||||
<Select
|
||||
value={formData.creative_id}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, creative_id: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={
|
||||
formData.target_channel_id
|
||||
? "Выберите креатив"
|
||||
: "Сначала выберите целевой канал"
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{filteredCreatives.map((creative) => (
|
||||
<SelectItem key={creative.id} value={creative.id}>
|
||||
{creative.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите креатив" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{creatives.map((creative) => (
|
||||
<SelectItem key={creative.id} value={creative.id}>
|
||||
{creative.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user