improvement for the backend api

This commit is contained in:
ivannoskov
2025-11-19 12:56:04 +03:00
parent b0a9934220
commit d4672ea32b
40 changed files with 2383 additions and 3313 deletions

View File

@@ -17,7 +17,7 @@ import {
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { externalChannelsApi } from "@/lib/api";
import { externalChannelsApi, channelsApi } from "@/lib/api";
import {
formatNumber,
formatMetric,
@@ -74,10 +74,24 @@ export default function ExternalChannelsPage() {
const loadChannels = async () => {
try {
setLoading(true);
const response = await externalChannelsApi.list();
setChannels(response.data);
// Сначала загружаем target channels
const targetChannelsRes = await channelsApi.list();
if (targetChannelsRes.target_channels.length === 0) {
setError("Добавьте сначала целевой канал");
setLoading(false);
return;
}
// Загружаем external channels для первого target channel
const firstTargetChannel = targetChannelsRes.target_channels[0];
const response = await externalChannelsApi.list(firstTargetChannel.id);
setChannels(response.external_channels);
} catch (err: any) {
setError(err?.error?.message || "Ошибка загрузки каналов");
const errorMsg =
typeof err?.detail === "string"
? err.detail
: err?.error?.message || "Ошибка загрузки каналов";
setError(errorMsg);
} finally {
setLoading(false);
}
@@ -86,15 +100,23 @@ export default function ExternalChannelsPage() {
const handleCreate = async () => {
try {
setIsCreating(true);
// Получаем первый доступный target channel
const targetChannelsRes = await channelsApi.list();
if (targetChannelsRes.target_channels.length === 0) {
alert("Добавьте сначала целевой канал");
setIsCreating(false);
return;
}
await externalChannelsApi.create({
telegram_id: 0, // Временно, пока не получим реальный ID
title: formData.title,
username: formData.username || undefined,
link: formData.link,
username: formData.username || null,
subscribers_count: formData.subscribers_count
? parseInt(formData.subscribers_count)
: undefined,
description: formData.description || undefined,
target_channel_ids: [], // По умолчанию не привязываем
: null,
description: formData.description || null,
target_channel_ids: [targetChannelsRes.target_channels[0].id],
});
setIsCreateDialogOpen(false);
setFormData({
@@ -106,7 +128,11 @@ export default function ExternalChannelsPage() {
});
loadChannels();
} catch (err: any) {
alert(err?.error?.message || "Ошибка создания канала");
const errorMsg =
typeof err?.detail === "string"
? err.detail
: err?.error?.message || "Ошибка создания канала";
alert(errorMsg);
} finally {
setIsCreating(false);
}
@@ -317,7 +343,7 @@ export default function ExternalChannelsPage() {
<CardDescription className="truncate mt-1">
{channel.username ? (
<a
href={channel.link}
href={`https://t.me/${channel.username}`}
target="_blank"
rel="noopener noreferrer"
className="hover:underline"
@@ -325,14 +351,9 @@ export default function ExternalChannelsPage() {
{formatUsername(channel.username)}
</a>
) : (
<a
href={channel.link}
target="_blank"
rel="noopener noreferrer"
className="hover:underline text-xs"
>
{channel.link}
</a>
<span className="text-xs">
ID: {channel.telegram_id}
</span>
)}
</CardDescription>
</div>
@@ -345,8 +366,8 @@ export default function ExternalChannelsPage() {
</p>
)}
<div className="grid grid-cols-3 gap-2 text-center">
<div className="rounded-lg border bg-muted/50 p-2">
<div className="flex items-center gap-2">
<div className="flex-1 rounded-lg border bg-muted/50 p-2">
<div className="flex items-center justify-center gap-1">
<Users className="h-3 w-3 text-muted-foreground" />
<div className="text-sm font-medium">
@@ -355,44 +376,29 @@ export default function ExternalChannelsPage() {
: "—"}
</div>
</div>
<div className="text-xs text-muted-foreground">
<div className="text-xs text-muted-foreground text-center">
Подписчики
</div>
</div>
<div className="rounded-lg border bg-muted/50 p-2">
<div className="flex-1 rounded-lg border bg-muted/50 p-2 text-center">
<div className="text-sm font-medium">
{formatNumber(channel.total_purchases)}
ID: {channel.telegram_id}
</div>
<div className="text-xs text-muted-foreground">
Закупов
Telegram ID
</div>
</div>
<div className="rounded-lg border bg-muted/50 p-2">
<div className="text-sm font-medium">
{formatMetric(channel.avg_cpf)}
</div>
<div className="text-xs text-muted-foreground">CPF</div>
</div>
</div>
<div className="flex gap-2 pt-2">
<Button
asChild
variant="default"
variant="destructive"
size="sm"
className="flex-1"
>
<Link href={`/external-channels/${channel.id}`}>
<Eye className="mr-2 h-4 w-4" />
Подробнее
</Link>
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => handleDelete(channel.id, channel.title)}
>
<Trash2 className="h-4 w-4" />
<Trash2 className="mr-2 h-4 w-4" />
Удалить
</Button>
</div>
</CardContent>