BangSo/apps/mobile/app/new.tsx

143 lines
4.3 KiB
TypeScript
Raw Normal View History

2026-09-01 16:51:19 +00:00
import {
BOT_DESCRIPTION_MAX_LENGTH,
BOT_NAME_MAX_LENGTH,
BOT_TITLE_MAX_LENGTH,
type ComputerMode,
normalizeCreateBotProfile,
} from "@rakazo/contracts";
import { Stack, useRouter } from "expo-router";
import { useState } from "react";
import { Pressable, ScrollView, Text, TextInput } from "react-native";
import { ComputerModePicker } from "../components/computer-mode-picker";
import { type MobileBot, rpc } from "../lib/api";
export default function NewBot() {
const router = useRouter();
const [name, setName] = useState("");
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [computerMode, setComputerMode] = useState<ComputerMode>("team");
const [error, setError] = useState<string | null>(null);
const [pending, setPending] = useState(false);
function close() {
if (router.canDismiss()) {
router.dismiss();
return;
}
if (router.canGoBack()) {
router.back();
return;
}
router.replace("/");
}
async function create() {
if (!name.trim() || pending) return;
setPending(true);
setError(null);
try {
const bot = await rpc<MobileBot>("bots/create", {
...normalizeCreateBotProfile({ name, title, description }),
notifyOnFinish: true,
computerMode,
});
router.replace({ pathname: "/thread", params: { botId: bot.id, name: bot.name } });
} catch (err) {
setError(err instanceof Error ? err.message : "Could not create bot");
} finally {
setPending(false);
}
}
return (
<>
<Stack.Screen
options={{
headerLeft: () => (
<Pressable
onPress={close}
hitSlop={12}
accessibilityRole="button"
accessibilityLabel="Cancel"
>
<Text style={{ color: "#0A84FF", fontSize: 17 }}>Cancel</Text>
</Pressable>
),
}}
/>
<ScrollView
style={{ flex: 1, backgroundColor: "#050506" }}
contentContainerStyle={{ padding: 24 }}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag"
>
<Text style={{ color: "#85858A", fontSize: 14 }}>Name</Text>
<TextInput
value={name}
maxLength={BOT_NAME_MAX_LENGTH}
onChangeText={setName}
placeholder="Name this bot"
placeholderTextColor="#6C6C70"
style={{
marginTop: 8,
backgroundColor: "#1A1A1D",
borderRadius: 11,
padding: 16,
color: "#ECECEE",
}}
/>
<Text style={{ color: "#85858A", marginTop: 16, fontSize: 14 }}>Title</Text>
<TextInput
value={title}
maxLength={BOT_TITLE_MAX_LENGTH}
onChangeText={setTitle}
placeholder="Describe what this bot does"
placeholderTextColor="#6C6C70"
style={{
marginTop: 8,
backgroundColor: "#1A1A1D",
borderRadius: 11,
padding: 16,
color: "#ECECEE",
}}
/>
<Text style={{ color: "#85858A", marginTop: 16, fontSize: 14 }}>Description</Text>
<TextInput
value={description}
maxLength={BOT_DESCRIPTION_MAX_LENGTH}
onChangeText={setDescription}
placeholder="What this bot is for"
placeholderTextColor="#6C6C70"
multiline
style={{
marginTop: 8,
backgroundColor: "#1A1A1D",
borderRadius: 11,
padding: 16,
color: "#ECECEE",
minHeight: 120,
textAlignVertical: "top",
}}
/>
<ComputerModePicker value={computerMode} onChange={setComputerMode} />
{error ? <Text style={{ color: "#E65707", marginTop: 16 }}>{error}</Text> : null}
<Pressable
onPress={() => void create()}
disabled={!name.trim() || pending}
style={{
marginTop: 24,
backgroundColor: "#F1F1EF",
borderRadius: 11,
padding: 16,
alignItems: "center",
opacity: !name.trim() || pending ? 0.4 : 1,
}}
>
<Text style={{ color: "#17171A", fontSize: 16 }}>{pending ? "Creating…" : "Create"}</Text>
</Pressable>
</ScrollView>
</>
);
}