import { GROUP_MEMBER_MAX, GROUP_MEMBER_MIN } from "@rakazo/contracts"; import { Stack, useLocalSearchParams, useRouter } from "expo-router"; import { useEffect, useState } from "react"; import { Alert, Pressable, ScrollView, Text, TextInput } from "react-native"; import { BotMemberPicker } from "../components/bot-member-picker"; import { type MobileBot, type MobileGroup, type MobileSpace, type MobileSpaceNavigation, rpc, } from "../lib/api"; import { useI18n } from "../lib/i18n"; import { canDeleteInboxSpace, removeInboxSpace } from "../lib/inbox-spaces"; import { useMobileTokens } from "../lib/native"; export default function GroupSettingsScreen() { const { t } = useI18n(); const tokens = useMobileTokens(); const router = useRouter(); const { groupId } = useLocalSearchParams<{ groupId: string }>(); const [group, setGroup] = useState(null); const [projectSpace, setProjectSpace] = useState(null); const [bots, setBots] = useState([]); const [name, setName] = useState(""); const [selected, setSelected] = useState([]); const [error, setError] = useState(null); const [pending, setPending] = useState(false); const isMainConversation = group?.kind === "main"; const isProjectMain = isMainConversation && projectSpace !== null && !projectSpace.isDefault; useEffect(() => { if (!groupId) return; void Promise.all([ rpc("groups/list").then( (groups) => groups.find((row) => row.id === groupId) ?? null, ), rpc("bots/list"), rpc("spaces/list").catch(() => null), ]) .then(([nextGroup, nextBots, navigation]) => { if (!nextGroup) throw new Error(t("Group not found")); setGroup(nextGroup); const space = navigation?.spaces.find( (item) => item.id === nextGroup.spaceId || item.id === navigation.current.id, ) ?? null; setProjectSpace(space); setName( nextGroup.kind === "main" && space && !space.isDefault ? space.name : nextGroup.name, ); setSelected(nextGroup.members.map((member) => member.botId)); setBots(nextBots.filter((bot) => !bot.archivedAt)); }) .catch((err) => setError(err instanceof Error ? err.message : t("Could not load group"))); }, [groupId]); async function save() { if (!groupId || !group || pending) return; setPending(true); setError(null); try { const trimmed = name.trim(); if (isProjectMain && projectSpace) { if (trimmed && trimmed !== projectSpace.name) { await rpc("spaces/update", { spaceId: projectSpace.id, name: trimmed }); } router.back(); return; } const input: { groupId: string; name?: string; botIds?: string[] } = { groupId }; if (trimmed !== group.name) input.name = trimmed; if (!isMainConversation) { const memberIds = group.members.map((member) => member.botId).join(","); if (selected.join(",") !== memberIds) input.botIds = selected; } if (input.name || input.botIds) await rpc("groups/update", input); router.back(); } catch (err) { setError(err instanceof Error ? err.message : t("Could not save group")); } finally { setPending(false); } } function remove() { if (!groupId || !group) return; if (isProjectMain && projectSpace) { Alert.alert( t("Delete {name}?", { name: projectSpace.name }), t("This removes the empty space for everyone."), [ { text: t("Cancel"), style: "cancel" }, { text: t("Delete"), style: "destructive", onPress: () => void removeInboxSpace(projectSpace.id, async () => {}) .then(() => router.replace("/")) .catch((err) => Alert.alert( t("Could not delete space"), err instanceof Error ? err.message : t("Try again."), ), ), }, ], ); return; } Alert.alert(group.name, t("Delete this group? Bots and their solo threads are kept."), [ { text: t("Cancel"), style: "cancel" }, { text: t("Delete"), style: "destructive", onPress: () => void rpc("groups/remove", { groupId }) .then(() => router.replace("/")) .catch((err) => Alert.alert( t("Could not delete group"), err instanceof Error ? err.message : t("Try again."), ), ), }, ]); } const saveDisabled = !name.trim() || pending || (!isMainConversation && (selected.length < GROUP_MEMBER_MIN || selected.length > GROUP_MEMBER_MAX)); return ( <> {t("Name")} {!isMainConversation ? ( <> {t("Members")} ) : null} {error ? {error} : null} void save()} disabled={saveDisabled} style={{ marginTop: 24, backgroundColor: tokens.primary, opacity: saveDisabled ? 0.5 : 1, borderRadius: 11, padding: 14, alignItems: "center", }} > {pending ? t("Saving…") : t("Save")} {isProjectMain && projectSpace && canDeleteInboxSpace(projectSpace) ? ( {t("Delete space")} ) : !isMainConversation ? ( {t("Delete group")} ) : null} ); }