fix mini app bot father
This commit is contained in:
171
apps/frontend/app/mini-apps/bot-father/content.tsx
Normal file
171
apps/frontend/app/mini-apps/bot-father/content.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Bot, ChevronRight, Loader2, Plus } from 'lucide-react';
|
||||
import { usePublicSettings } from '@/components/id/public-settings-provider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { BotCreateMiniAppContent } from '@/app/mini-apps/bot-create/content';
|
||||
import { BotManageMiniAppContent } from '@/app/mini-apps/bot-manage/content';
|
||||
import { useMiniAppAuth } from '@/hooks/use-mini-app-auth';
|
||||
import { fetchMyBots, getApiErrorMessage, type ManagedBot } from '@/lib/api';
|
||||
import { useToast } from '@/components/id/toast-provider';
|
||||
|
||||
type View = 'list' | 'create' | 'manage';
|
||||
|
||||
export function BotFatherMiniAppContent() {
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const { projectName } = usePublicSettings();
|
||||
const { showToast } = useToast();
|
||||
const { effectiveToken, canUse, authReady, waitingForBridge, isLoading } = useMiniAppAuth();
|
||||
|
||||
const initialBotId = searchParams.get('botId');
|
||||
const initialMode = searchParams.get('mode');
|
||||
|
||||
const [view, setView] = useState<View>(() => {
|
||||
if (initialBotId) return 'manage';
|
||||
if (initialMode === 'create') return 'create';
|
||||
return 'list';
|
||||
});
|
||||
const [selectedBotId, setSelectedBotId] = useState<string | null>(initialBotId);
|
||||
const [bots, setBots] = useState<ManagedBot[]>([]);
|
||||
const [loadingBots, setLoadingBots] = useState(false);
|
||||
|
||||
const syncUrl = useCallback(
|
||||
(nextView: View, botId?: string | null) => {
|
||||
const params = new URLSearchParams();
|
||||
if (nextView === 'create') params.set('mode', 'create');
|
||||
if (nextView === 'manage' && botId) params.set('botId', botId);
|
||||
const query = params.toString();
|
||||
router.replace(query ? `/mini-apps/bot-father?${query}` : '/mini-apps/bot-father');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const loadBots = useCallback(async () => {
|
||||
if (!effectiveToken) return;
|
||||
setLoadingBots(true);
|
||||
try {
|
||||
const response = await fetchMyBots(effectiveToken);
|
||||
setBots((response.bots ?? []).filter((bot) => !bot.isSystemBot));
|
||||
} catch (error) {
|
||||
showToast(getApiErrorMessage(error, 'Не удалось загрузить список ботов') ?? 'Ошибка');
|
||||
} finally {
|
||||
setLoadingBots(false);
|
||||
}
|
||||
}, [effectiveToken, showToast]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canUse) return;
|
||||
if (view === 'list') void loadBots();
|
||||
}, [canUse, loadBots, view]);
|
||||
|
||||
const selectedBot = useMemo(
|
||||
() => bots.find((bot) => bot.id === selectedBotId) ?? null,
|
||||
[bots, selectedBotId]
|
||||
);
|
||||
|
||||
function openManage(botId: string) {
|
||||
setSelectedBotId(botId);
|
||||
setView('manage');
|
||||
syncUrl('manage', botId);
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
setView('create');
|
||||
syncUrl('create');
|
||||
}
|
||||
|
||||
function backToList() {
|
||||
setSelectedBotId(null);
|
||||
setView('list');
|
||||
syncUrl('list');
|
||||
void loadBots();
|
||||
}
|
||||
|
||||
if ((isLoading || waitingForBridge || !authReady) && !effectiveToken) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center p-6 text-center text-sm text-[#667085]">
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Загрузка...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center p-6 text-center text-sm text-[#667085]">
|
||||
Войдите в {projectName}, чтобы управлять ботами
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (view === 'create') {
|
||||
return (
|
||||
<BotCreateMiniAppContent
|
||||
onBack={backToList}
|
||||
onCreated={(botId) => openManage(botId)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (view === 'manage' && selectedBotId) {
|
||||
return <BotManageMiniAppContent botId={selectedBotId} onBack={backToList} botHint={selectedBot?.username} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#17212b] p-4 text-white">
|
||||
<div className="mx-auto max-w-md space-y-4">
|
||||
<div className="rounded-[24px] bg-[#242f3d] p-5 shadow-xl">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-[#3390ec]/20 text-[#3390ec]">
|
||||
<Bot className="h-6 w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold">BotFather</h1>
|
||||
<p className="text-sm text-[#8b93a7]">Создание и настройка ваших ботов</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button className="h-12 w-full rounded-xl text-base" onClick={openCreate}>
|
||||
<Plus className="mr-2 h-5 w-5" />
|
||||
Создать нового бота
|
||||
</Button>
|
||||
|
||||
<div className="rounded-[24px] bg-[#242f3d] p-4 shadow-xl">
|
||||
<p className="mb-3 text-sm font-medium text-[#c5cad3]">Мои боты</p>
|
||||
{loadingBots ? (
|
||||
<div className="flex items-center justify-center gap-2 py-8 text-sm text-[#8b93a7]">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
Загрузка...
|
||||
</div>
|
||||
) : bots.length === 0 ? (
|
||||
<p className="py-6 text-center text-sm text-[#8b93a7]">У вас пока нет ботов</p>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{bots.map((bot) => (
|
||||
<button
|
||||
key={bot.id}
|
||||
type="button"
|
||||
onClick={() => openManage(bot.id)}
|
||||
className="flex w-full items-center gap-3 rounded-2xl bg-[#17212b] px-4 py-3 text-left transition hover:bg-[#1c2733]"
|
||||
>
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-[#3390ec]/15 text-[#3390ec]">
|
||||
<Bot className="h-5 w-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate font-medium">{bot.name}</p>
|
||||
<p className="truncate text-sm text-[#8b93a7]">@{bot.username}</p>
|
||||
</div>
|
||||
<ChevronRight className="h-5 w-5 shrink-0 text-[#667085]" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user