@ateam-ai-mobile/ui 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai-mobile/ui",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Prebuilt ADAS chat experience for React Native \u2014 full-screen chat, chips, widget views. Built on @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,8 +9,8 @@
9
9
  "build": "tsup"
10
10
  },
11
11
  "dependencies": {
12
- "@ateam-ai-mobile/core": "0.1.1",
13
- "@ateam-ai-mobile/plugin-runtime": "0.1.1",
12
+ "@ateam-ai-mobile/core": "0.1.2",
13
+ "@ateam-ai-mobile/plugin-runtime": "0.1.2",
14
14
  "zustand": "^5.0.0"
15
15
  },
16
16
  "peerDependencies": {
@@ -1,28 +1,35 @@
1
1
  /**
2
- * TenantPicker — optional prebuilt team switcher.
2
+ * TenantPicker — prebuilt team switcher, fully SDK-driven.
3
3
  *
4
- * Lists the user's REAL tenant memberships via core's listMyTenants() and
5
- * calls onSelect when one is tapped. The host owns what "switching" means
6
- * (mint a new tenant-scoped JWT, then re-init) — this component only picks.
7
- * Single-tenant hosts simply never render it.
4
+ * Lists the user's REAL memberships via core's listMyTenants() and, on tap,
5
+ * re-scopes the whole session with core's switchTenant() (which mints the new
6
+ * tenant JWT, persists it through config.onSession, and reconnects chat). The
7
+ * host only reacts via onSwitched (e.g. navigate home). Single-tenant hosts
8
+ * simply never render it.
9
+ *
10
+ * For custom flows, pass `onSelect` to intercept the tap instead of switching.
8
11
  */
9
12
  import { useEffect, useState } from 'react';
10
13
  import { View, Text, Pressable, ActivityIndicator, StyleSheet, Platform } from 'react-native';
11
- import { ada, fontSize, borderRadius, listMyTenants, getTenant } from '@ateam-ai-mobile/core';
12
- import type { TenantMembership } from '@ateam-ai-mobile/core';
14
+ import { ada, fontSize, borderRadius, listMyTenants, switchTenant, getTenant } from '@ateam-ai-mobile/core';
15
+ import type { TenantMembership, AdasSession } from '@ateam-ai-mobile/core';
13
16
 
14
17
  const fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;
15
18
 
16
19
  export interface TenantPickerProps {
17
- /** Called with the picked tenant. Host mints a JWT for it and re-inits. */
18
- onSelect: (tenant: TenantMembership) => void;
20
+ /** Called after a successful SDK-driven switch (host navigates/refreshes). */
21
+ onSwitched?: (session: AdasSession) => void;
22
+ /** Intercept the tap instead of switching — for fully custom host flows.
23
+ * When provided, the SDK does NOT call switchTenant(). */
24
+ onSelect?: (tenant: TenantMembership) => void;
19
25
  /** Highlight the active tenant. Defaults to the SDK config's tenant. */
20
26
  currentTenantId?: string;
21
27
  }
22
28
 
23
- export default function TenantPicker({ onSelect, currentTenantId }: TenantPickerProps) {
29
+ export default function TenantPicker({ onSwitched, onSelect, currentTenantId }: TenantPickerProps) {
24
30
  const [tenants, setTenants] = useState<TenantMembership[] | null>(null);
25
31
  const [error, setError] = useState<string | null>(null);
32
+ const [switching, setSwitching] = useState<string | null>(null);
26
33
  const active = currentTenantId ?? getTenant();
27
34
 
28
35
  useEffect(() => {
@@ -33,6 +40,21 @@ export default function TenantPicker({ onSelect, currentTenantId }: TenantPicker
33
40
  return () => { cancelled = true; };
34
41
  }, []);
35
42
 
43
+ const handlePress = async (t: TenantMembership) => {
44
+ if (t.id === active || switching) return;
45
+ if (onSelect) { onSelect(t); return; }
46
+ setError(null);
47
+ setSwitching(t.id);
48
+ try {
49
+ const session = await switchTenant(t.id);
50
+ onSwitched?.(session);
51
+ } catch (e: any) {
52
+ setError(e?.message || 'Could not switch team');
53
+ } finally {
54
+ setSwitching(null);
55
+ }
56
+ };
57
+
36
58
  if (error) return <Text style={styles.error}>{error}</Text>;
37
59
  if (!tenants) {
38
60
  return (
@@ -47,12 +69,14 @@ export default function TenantPicker({ onSelect, currentTenantId }: TenantPicker
47
69
  <View style={styles.list}>
48
70
  {tenants.map(t => {
49
71
  const isActive = t.id === active;
72
+ const isSwitching = switching === t.id;
50
73
  return (
51
74
  <Pressable
52
75
  key={t.id}
53
76
  accessibilityRole="button"
54
77
  accessibilityLabel={`Team ${t.name}${isActive ? ', current' : ''}`}
55
- onPress={() => onSelect(t)}
78
+ disabled={!!switching}
79
+ onPress={() => handlePress(t)}
56
80
  style={[styles.row, isActive && styles.rowActive]}
57
81
  >
58
82
  <View style={styles.dot} />
@@ -60,7 +84,7 @@ export default function TenantPicker({ onSelect, currentTenantId }: TenantPicker
60
84
  <Text style={styles.name}>{t.name}</Text>
61
85
  <Text style={styles.slug}>{t.id}</Text>
62
86
  </View>
63
- {isActive && <Text style={styles.check}>✓</Text>}
87
+ {isSwitching ? <ActivityIndicator color={ada.orange} /> : isActive ? <Text style={styles.check}>✓</Text> : null}
64
88
  </Pressable>
65
89
  );
66
90
  })}