Files
moreminimore-vibe/src/components/CreateAppDialog.tsx
Will Chen b0f08eaf15 Neon / portal template support (#713)
TODOs:
- [x] Do restart when checkout / restore if there is a DB
- [x] List all branches (branch id, name, date)
- [x] Allow checking out versions with no DB
- [x] safeguard to never delete main branches
- [x] create app hook for neon template
- [x] weird UX with connector on configure panel
- [x] tiny neon logo in connector
- [x] deploy to vercel
- [x] build forgot password page
- [x] what about email setup
- [x] lots of imgix errors
- [x] edit file - db snapshot
- [x] DYAD_DISABLE_DB_PUSH
- [ ] update portal doc
- [x] switch preview branch to be read-only endpoint
- [x] disable supabase sys prompt if neon is enabled
- [ ] https://payloadcms.com/docs/upload/storage-adapters
- [x] need to use main branch...

Phase 2?
- [x] generate DB migrations
2025-08-04 16:36:09 -07:00

138 lines
4.0 KiB
TypeScript

import React, { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { useCreateApp } from "@/hooks/useCreateApp";
import { useCheckName } from "@/hooks/useCheckName";
import { useSetAtom } from "jotai";
import { selectedAppIdAtom } from "@/atoms/appAtoms";
import { NEON_TEMPLATE_IDS, Template } from "@/shared/templates";
import { useRouter } from "@tanstack/react-router";
import { Loader2 } from "lucide-react";
import { neonTemplateHook } from "@/client_logic/template_hook";
import { showError } from "@/lib/toast";
interface CreateAppDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
template: Template | undefined;
}
export function CreateAppDialog({
open,
onOpenChange,
template,
}: CreateAppDialogProps) {
const setSelectedAppId = useSetAtom(selectedAppIdAtom);
const [appName, setAppName] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const { createApp } = useCreateApp();
const { data: nameCheckResult } = useCheckName(appName);
const router = useRouter();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!appName.trim()) {
return;
}
if (nameCheckResult?.exists) {
return;
}
setIsSubmitting(true);
try {
const result = await createApp({ name: appName.trim() });
if (template && NEON_TEMPLATE_IDS.has(template.id)) {
await neonTemplateHook({
appId: result.app.id,
appName: result.app.name,
});
}
setSelectedAppId(result.app.id);
// Navigate to the new app's first chat
router.navigate({
to: "/chat",
search: { id: result.chatId },
});
setAppName("");
onOpenChange(false);
} catch (error) {
showError(error as any);
// Error is already handled by createApp hook or shown above
console.error("Error creating app:", error);
} finally {
setIsSubmitting(false);
}
};
const isNameValid = appName.trim().length > 0;
const nameExists = nameCheckResult?.exists;
const canSubmit = isNameValid && !nameExists && !isSubmitting;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Create New App</DialogTitle>
<DialogDescription>
{`Create a new app using the ${template?.title} template.`}
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit}>
<div className="grid gap-4 py-4">
<div className="grid gap-2">
<Label htmlFor="appName">App Name</Label>
<Input
id="appName"
value={appName}
onChange={(e) => setAppName(e.target.value)}
placeholder="Enter app name..."
className={nameExists ? "border-red-500" : ""}
disabled={isSubmitting}
/>
{nameExists && (
<p className="text-sm text-red-500">
An app with this name already exists
</p>
)}
</div>
</div>
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
disabled={isSubmitting}
>
Cancel
</Button>
<Button
type="submit"
disabled={!canSubmit}
className="bg-indigo-600 hover:bg-indigo-700"
>
{isSubmitting && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
{isSubmitting ? "Creating..." : "Create App"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}