evOo-local/apps/mobile/components/bot-member-picker.tsx
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

45 lines
1.5 KiB
TypeScript

import { GROUP_MEMBER_MAX } from "@rakazo/contracts";
import { StyleSheet, Switch, Text, View } from "react-native";
import type { MobileBot } from "../lib/api";
import { useMobileTokens } from "../lib/native";
import { BotAvatar } from "./bot-avatar";
export function BotMemberPicker({
bots,
selected,
onChange,
disabled = false,
}: {
bots: MobileBot[];
selected: string[];
onChange: (botIds: string[]) => void;
disabled?: boolean;
}) {
const tokens = useMobileTokens();
return bots.map((bot) => {
const checked = selected.includes(bot.id);
return (
<View key={bot.id} style={styles.row}>
<BotAvatar color={bot.color} identity={bot.id} size={34} status={bot.status} />
<Text style={[styles.name, { color: tokens.foreground }]}>{bot.name}</Text>
<Switch
accessibilityLabel={bot.name}
value={checked}
disabled={disabled || (!checked && selected.length >= GROUP_MEMBER_MAX)}
trackColor={{ false: tokens.border, true: tokens.primary }}
thumbColor={checked ? tokens.primaryForeground : tokens.foreground}
onValueChange={(next) => {
if (next && selected.length >= GROUP_MEMBER_MAX) return;
onChange(next ? [...selected, bot.id] : selected.filter((id) => id !== bot.id));
}}
/>
</View>
);
});
}
const styles = StyleSheet.create({
row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 12 },
name: { flex: 1, fontSize: 16 },
});