1import React, { useState, useEffect, useRef } from "react";
2import {
3 View,
4 Text,
5 Button,
6 Alert,
7 ScrollView,
8 Linking,
9 StyleSheet,
10 AppRegistry,
11} from "react-native";
12import {
13 AgentforceService,
14 isEmployeeAgentAuthSupported,
15 hasEmployeeAgentSession,
16 loginForEmployeeAgent,
17 logoutEmployeeAgent,
18 getEmployeeAgentCredentials,
19 AuthCredentials,
20 FeatureFlags,
21 LogLevel,
22 NavigationRequest,
23 ViewProviderComponentData,
24} from "@salesforce/react-native-agentforce";
25
26// Custom View Component
27function CustomAgentforceView({ componentData }: { componentData: ViewProviderComponentData }) {
28 return (
29 <View style={{ padding: 8, backgroundColor: "#e8f0fe", borderRadius: 6, margin: 4 }}>
30 <Text style={{ fontWeight: "bold" }}>[Custom] {componentData.definition}</Text>
31 <Text>{JSON.stringify(componentData.properties, null, 2)}</Text>
32 </View>
33 );
34}
35
36AppRegistry.registerComponent("CustomAgentforceView", () => CustomAgentforceView);
37
38// Config
39const SERVICE_CONFIG = {
40 type: "service" as const,
41 serviceApiURL: "https://mycompany-support.my.salesforce-scrt.com",
42 organizationId: "00Dxx0000001234EAA",
43 esDeveloperName: "My_Service_Agent",
44};
45
46export default function HomeScreen() {
47 // State
48 const [configured, setConfigured] = useState(false);
49 const [mode, setMode] = useState<"service" | "employee" | null>(null);
50 const [authSupported, setAuthSupported] = useState(false);
51 const [loggedIn, setLoggedIn] = useState(false);
52 const [credentials, setCredentials] = useState<AuthCredentials | null>(null);
53 const [flags, setFlags] = useState<FeatureFlags | null>(null);
54 const logCount = useRef(0);
55
56 // Initialize
57 useEffect(() => {
58 initializeApp();
59 return () => {
60 AgentforceService.clearLoggerDelegate();
61 AgentforceService.clearNavigationDelegate();
62 };
63 }, []);
64
65 const initializeApp = async () => {
66 // Set up delegates first
67 setupDelegates();
68
69 // Check current state
70 const info = await AgentforceService.getConfigurationInfo();
71 setConfigured(info.configured);
72 setMode(info.mode);
73
74 const storedFlags = await AgentforceService.getFeatureFlags();
75 setFlags(storedFlags);
76
77 // Check Employee Agent auth
78 const supported = await isEmployeeAgentAuthSupported();
79 setAuthSupported(supported);
80 if (supported) {
81 const session = await hasEmployeeAgentSession();
82 setLoggedIn(session);
83 if (session) {
84 setCredentials(await getEmployeeAgentCredentials());
85 }
86 }
87 };
88
89 const setupDelegates = () => {
90 // Logger
91 AgentforceService.setLoggerDelegate({
92 onLog(level: LogLevel, message: string, error?: string) {
93 logCount.current++;
94 if (level === "error") {
95 console.error(`[SDK ERROR] ${message}`, error || "");
96 }
97 },
98 });
99
100 // Navigation
101 AgentforceService.setNavigationDelegate({
102 onNavigate(request: NavigationRequest) {
103 switch (request.type) {
104 case "link":
105 if (request.uri) Linking.openURL(request.uri as string);
106 break;
107 case "record":
108 Alert.alert("Record", `${request.objectType}: ${request.recordId}`);
109 break;
110 default:
111 console.log("Navigation:", request.type, request);
112 }
113 },
114 });
115
116 // View Provider
117 AgentforceService.setViewProviderDelegate({
118 componentMap: {
119 "copilot/richText": "CustomAgentforceView",
120 },
121 }).catch(console.error);
122 };
123
124 // Service Agent
125 const handleConfigureService = async () => {
126 try {
127 await AgentforceService.configure({
128 ...SERVICE_CONFIG,
129 featureFlags: flags || undefined,
130 });
131 setConfigured(true);
132 setMode("service");
133 Alert.alert("Configured", "Service Agent ready");
134 } catch (error) {
135 Alert.alert("Error", String(error));
136 }
137 };
138
139 // Employee Agent
140 const handleLogin = async () => {
141 try {
142 const creds = await loginForEmployeeAgent();
143 setCredentials(creds);
144 setLoggedIn(true);
145 } catch (error) {
146 Alert.alert("Login Failed", String(error));
147 }
148 };
149
150 const handleConfigureEmployee = async () => {
151 if (!credentials) {
152 Alert.alert("Error", "Login first");
153 return;
154 }
155 try {
156 const agentId = await AgentforceService.getEmployeeAgentId();
157 await AgentforceService.configure({
158 type: "employee",
159 instanceUrl: credentials.instanceUrl,
160 organizationId: credentials.organizationId,
161 userId: credentials.userId,
162 agentId: agentId || undefined,
163 accessToken: credentials.accessToken,
164 featureFlags: flags || undefined,
165 });
166 setConfigured(true);
167 setMode("employee");
168 Alert.alert("Configured", "Employee Agent ready");
169 } catch (error) {
170 Alert.alert("Error", String(error));
171 }
172 };
173
174 // Conversations
175 const handleLaunch = async () => {
176 try {
177 await AgentforceService.launchConversation();
178 } catch (error) {
179 Alert.alert("Launch Error", String(error));
180 }
181 };
182
183 const handleNewConversation = async () => {
184 try {
185 await AgentforceService.startNewConversation();
186 } catch (error) {
187 Alert.alert("Error", String(error));
188 }
189 };
190
191 const handleSetContext = async () => {
192 try {
193 await AgentforceService.setAdditionalContext({
194 variables: [
195 { name: "screen", type: "Text", value: "HomeScreen" },
196 { name: "timestamp", type: "DateTime", value: new Date().toISOString() },
197 { name: "userAgent", type: "Text", value: "react-native-agentforce-example" },
198 ],
199 });
200 Alert.alert("Context Set", "3 variables sent to the agent");
201 } catch (error) {
202 Alert.alert("Error", String(error));
203 }
204 };
205
206 // Cleanup
207 const handleReset = async () => {
208 if (loggedIn) {
209 await logoutEmployeeAgent();
210 }
211 await AgentforceService.resetSettings();
212 setConfigured(false);
213 setMode(null);
214 setLoggedIn(false);
215 setCredentials(null);
216 Alert.alert("Reset", "All settings cleared");
217 };
218
219 return (
220 <ScrollView style={styles.container} contentContainerStyle={styles.content}>
221 <Text style={styles.title}>Agentforce Demo</Text>
222
223 {/* Status */}
224 <View style={styles.section}>
225 <Text style={styles.sectionTitle}>Status</Text>
226 <Text>Configured: {configured ? "Yes" : "No"}</Text>
227 <Text>Mode: {mode || "None"}</Text>
228 <Text>Log messages received: {logCount.current}</Text>
229 </View>
230
231 {/* Service Agent */}
232 <View style={styles.section}>
233 <Text style={styles.sectionTitle}>Service Agent</Text>
234 <Button title="Configure Service Agent" onPress={handleConfigureService} />
235 </View>
236
237 {/* Employee Agent */}
238 {authSupported && (
239 <View style={styles.section}>
240 <Text style={styles.sectionTitle}>Employee Agent</Text>
241 <Text>Logged in: {loggedIn ? "Yes" : "No"}</Text>
242 {!loggedIn ? (
243 <Button title="Login" onPress={handleLogin} />
244 ) : (
245 <Button title="Configure Employee Agent" onPress={handleConfigureEmployee} />
246 )}
247 </View>
248 )}
249
250 {/* Conversation Actions */}
251 {configured && (
252 <View style={styles.section}>
253 <Text style={styles.sectionTitle}>Conversation</Text>
254 <Button title="Launch Conversation" onPress={handleLaunch} />
255 <View style={styles.spacer} />
256 <Button title="New Conversation" onPress={handleNewConversation} />
257 <View style={styles.spacer} />
258 <Button title="Set Context Variables" onPress={handleSetContext} />
259 </View>
260 )}
261
262 {/* Reset */}
263 <View style={styles.section}>
264 <Button title="Reset Everything" onPress={handleReset} color="red" />
265 </View>
266 </ScrollView>
267 );
268}
269
270const styles = StyleSheet.create({
271 container: { flex: 1 },
272 content: { padding: 16, paddingBottom: 48 },
273 title: { fontSize: 28, fontWeight: "bold", marginBottom: 24 },
274 section: { marginBottom: 24 },
275 sectionTitle: { fontSize: 18, fontWeight: "600", marginBottom: 8 },
276 spacer: { height: 8 },
277});