import { useNavigate, useSearch } from "@tanstack/react-router"; import { useAtom, useSetAtom } from "jotai"; import { homeChatInputValueAtom } from "../atoms/chatAtoms"; import { selectedAppIdAtom } from "@/atoms/appAtoms"; import { IpcClient } from "@/ipc/ipc_client"; import { generateCuteAppName } from "@/lib/utils"; import { useLoadApps } from "@/hooks/useLoadApps"; import { useSettings } from "@/hooks/useSettings"; import { SetupBanner } from "@/components/SetupBanner"; import { isPreviewOpenAtom } from "@/atoms/viewAtoms"; import { useState, useEffect, useCallback } from "react"; import { useStreamChat } from "@/hooks/useStreamChat"; import { HomeChatInput } from "@/components/chat/HomeChatInput"; import { usePostHog } from "posthog-js/react"; import { PrivacyBanner } from "@/components/TelemetryBanner"; import { INSPIRATION_PROMPTS } from "@/prompts/inspiration_prompts"; import { useAppVersion } from "@/hooks/useAppVersion"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { useTheme } from "@/contexts/ThemeContext"; import { Button } from "@/components/ui/button"; import { ExternalLink } from "lucide-react"; import { ImportAppButton } from "@/components/ImportAppButton"; import { showError } from "@/lib/toast"; // Adding an export for attachments export interface HomeSubmitOptions { attachments?: File[]; } export default function HomePage() { const [inputValue, setInputValue] = useAtom(homeChatInputValueAtom); const navigate = useNavigate(); const search = useSearch({ from: "/" }); const setSelectedAppId = useSetAtom(selectedAppIdAtom); const { refreshApps } = useLoadApps(); const { settings, updateSettings } = useSettings(); const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom); const [isLoading, setIsLoading] = useState(false); const { streamMessage } = useStreamChat({ hasChatId: false }); const posthog = usePostHog(); const appVersion = useAppVersion(); const [releaseNotesOpen, setReleaseNotesOpen] = useState(false); const [releaseUrl, setReleaseUrl] = useState(""); const { theme } = useTheme(); useEffect(() => { const updateLastVersionLaunched = async () => { if ( appVersion && appVersion.match(/^\d+\.\d+\.\d+$/) && settings && settings.lastShownReleaseNotesVersion !== appVersion ) { await updateSettings({ lastShownReleaseNotesVersion: appVersion, }); try { const result = await IpcClient.getInstance().doesReleaseNoteExist({ version: appVersion, }); if (result.exists && result.url) { setReleaseUrl(result.url + "?hideHeader=true&theme=" + theme); setReleaseNotesOpen(true); } } catch (err) { console.warn( "Unable to check if release note exists for: " + appVersion, err, ); } } }; updateLastVersionLaunched(); }, [appVersion, settings, updateSettings, theme]); // Get the appId from search params const appId = search.appId ? Number(search.appId) : null; // State for random prompts const [randomPrompts, setRandomPrompts] = useState< typeof INSPIRATION_PROMPTS >([]); // Function to get random prompts const getRandomPrompts = useCallback(() => { const shuffled = [...INSPIRATION_PROMPTS].sort(() => 0.5 - Math.random()); return shuffled.slice(0, 5); }, []); // Initialize random prompts useEffect(() => { setRandomPrompts(getRandomPrompts()); }, [getRandomPrompts]); // Redirect to app details page if appId is present useEffect(() => { if (appId) { navigate({ to: "/app-details", search: { appId } }); } }, [appId, navigate]); const handleSubmit = async (options?: HomeSubmitOptions) => { const attachments = options?.attachments || []; if (!inputValue.trim() && attachments.length === 0) return; try { setIsLoading(true); // Create the chat and navigate const result = await IpcClient.getInstance().createApp({ name: generateCuteAppName(), }); // Stream the message with attachments streamMessage({ prompt: inputValue, chatId: result.chatId, attachments, }); await new Promise((resolve) => setTimeout(resolve, settings?.isTestMode ? 0 : 2000), ); setInputValue(""); setSelectedAppId(result.app.id); setIsPreviewOpen(false); await refreshApps(); // Ensure refreshApps is awaited if it's async posthog.capture("home:chat-submit"); navigate({ to: "/chat", search: { id: result.chatId } }); } catch (error) { console.error("Failed to create chat:", error); showError("Failed to create app. " + (error as any).toString()); setIsLoading(false); // Ensure loading state is reset on error } // No finally block needed for setIsLoading(false) here if navigation happens on success }; // Loading overlay for app creation if (isLoading) { return (
We're setting up your app with AI magic.
This might take a moment...