UNPKG

@trycourier/courier-react-native

Version:

Inbox, Push Notifications, and Preferences for React Native

1,069 lines (1,068 loc) 39.7 kB
import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ActivityIndicator, Platform, FlatList, TouchableOpacity, TextInput, Modal, Button, Switch, TouchableWithoutFeedback, Keyboard } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import Courier, { CourierClient } from '@trycourier/courier-react-native'; import Env from '../Env'; import { ExampleServer, Utils } from '../Utils'; let savedClient = undefined; const IntegrationTests = { createClient: async (params) => { const token = params.jwt ?? await ExampleServer.generateJwt({ authKey: Env.authKey, userId: params.userId, }); savedClient = new CourierClient({ userId: params.userId, showLogs: params.showLogs, jwt: token, clientKey: params.clientKey, tenantId: params.tenantId, connectionId: params.connectionId, }); return { id: savedClient.clientId, options: savedClient.options, }; }, removeClient: async (params) => { let id = params.clientId; if (savedClient) { id = savedClient.clientId; savedClient.remove(); savedClient = undefined; } return { clientId: id, }; }, testPutToken: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } await savedClient.tokens.putUserToken({ provider: params.provider, token: params.token, }); return { token: params.token, provider: params.provider }; }, testDeleteToken: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } await savedClient.tokens.deleteUserToken({ token: params.token }); }, testGetBrands: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const brand = await savedClient.brands.getBrand({ brandId: params.brandId }); return brand; }, testMessages: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } return await savedClient.inbox.getMessages({ paginationLimit: params.paginationLimit, startCursor: params.startCursor, }); }, testUnreadCount: async () => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const count = await savedClient.inbox.getUnreadMessageCount(); console.log('Unread Count:', count); return count; }, testArchivedMessages: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } return await savedClient.inbox.getArchivedMessages({ paginationLimit: params.paginationLimit, startCursor: params.startCursor, }); }, testMessageById: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); return await savedClient.inbox.getMessageById({ messageId: messageId, }); }, openMessage: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await savedClient.inbox.open({ messageId: messageId, }); return { messageId: messageId }; }, clickMessage: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await savedClient.inbox.click({ messageId: messageId, trackingId: params.trackingId ?? 'test-tracking-id', }); return { messageId: messageId }; }, readMessage: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await savedClient.inbox.read({ messageId: messageId, }); return { messageId: messageId }; }, unreadMessage: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await savedClient.inbox.unread({ messageId: messageId, }); return { messageId: messageId }; }, archiveMessage: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: savedClient.options.userId, channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await savedClient.inbox.archive({ messageId: messageId, }); return { messageId: messageId }; }, readAllMessages: async () => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } await savedClient.inbox.readAll(); }, testGetPreferences: async () => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } return await savedClient.preferences.getUserPreferences(); }, testUpdatePreferences: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } await savedClient.preferences.putUserPreferenceTopic({ topicId: params.topicId, status: params.status, hasCustomRouting: params.hasCustomRouting, customRouting: params.customRouting.split(',').map(channel => channel.trim()), }); }, testGetPreferenceTopics: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } return await savedClient.preferences.getUserPreferenceTopic({ topicId: params.topicId }); }, testPostTrackingUrl: async (params) => { if (!savedClient) { throw new Error("Client not initialized. Run createClient first."); } return await savedClient.tracking.postTrackingUrl({ url: params.trackingUrl, event: params.event, }); }, testSignIn: async (params) => { const token = params.accessToken ?? await ExampleServer.generateJwt({ authKey: Env.authKey, userId: params.userId, }); await Courier.shared.signIn({ userId: params.userId, accessToken: token, clientKey: params.clientKey, tenantId: params.tenantId, showLogs: params.showLogs, }); const client = await Courier.shared.getClient(); return client?.options; }, testGetUserId: async () => { return await Courier.shared.getUserId(); }, testGetTenantId: async () => { return await Courier.shared.getTenantId(); }, testGetIsUserSignedIn: async () => { return await Courier.shared.isUserSignedIn(); }, testAuthenticationListener: async () => { const listener = await Courier.shared.addAuthenticationListener({ onUserChanged: (userId) => { console.log('User changed:', userId); }, }); listener.remove(); return listener.listenerId; }, testRemoveAllAuthenticationListeners: async () => { return Courier.shared.removeAllAuthenticationListeners(); }, testSignOut: async () => { await Courier.shared.signOut(); }, testGetClient: async () => { const client = await Courier.shared.getClient(); return { clientId: client?.clientId, options: client?.options, }; }, testGetAllTokens: async () => { const tokens = await Courier.shared.getAllTokens(); const tokenObject = {}; tokens.forEach((value, key) => { tokenObject[key] = value; }); return tokenObject; }, testGetToken: async (params) => { return await Courier.shared.getToken({ key: params.provider }); }, testSetToken: async (params) => { return await Courier.shared.setToken({ key: params.provider, token: params.token }); }, testAddPushNotificationListener: async () => { const listener = Courier.shared.addPushNotificationListener({ onPushNotificationClicked: (push) => { console.log('Push notification clicked:', push); }, }); listener.remove(); return listener.listenerId; }, testRemoveAllPushNotificationListeners: async () => { return Courier.shared.removeAllPushNotificationListeners(); }, testSetInboxPaginationLimit: async (params) => { await Courier.shared.setInboxPaginationLimit(params.limit); }, testGetInboxPaginationLimit: async () => { return await Courier.shared.getInboxPaginationLimit(); }, testOpenMessage: async (params) => { const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: await Courier.shared.getUserId() ?? '', channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await Courier.shared.openMessage({ messageId: messageId }); return { messageId: messageId }; }, testClickMessage: async (params) => { const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: await Courier.shared.getUserId() ?? '', channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await Courier.shared.clickMessage({ messageId: messageId }); return { messageId: messageId }; }, testReadMessage: async (params) => { const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: await Courier.shared.getUserId() ?? '', channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await Courier.shared.readMessage({ messageId: messageId }); return { messageId: messageId }; }, testUnreadMessage: async (params) => { const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: await Courier.shared.getUserId() ?? '', channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await Courier.shared.unreadMessage({ messageId: messageId }); return { messageId: messageId }; }, testArchiveMessage: async (params) => { const messageId = params.messageId ?? await new Promise(async (resolve) => { const result = await ExampleServer.sendTest({ authKey: Env.authKey, userId: await Courier.shared.getUserId() ?? '', channel: 'inbox', }); setTimeout(() => resolve(result), 5000); }); await Courier.shared.archiveMessage({ messageId: messageId }); return { messageId: messageId }; }, testReadAllInboxMessages: async () => { return await Courier.shared.readAllInboxMessages(); }, testAddInboxListener: async () => { const listener = await Courier.shared.addInboxListener({ onInitialLoad: () => { console.log('Inbox initial load'); }, onError: (error) => { console.log('Inbox error:', error); }, onFeedChanged: (messageSet) => { console.log('Inbox messages changed:', messageSet); }, }); await listener.remove(); return listener; }, testRemoveAllInboxListeners: async () => { return Courier.shared.removeAllInboxListeners(); }, testRefreshInbox: async () => { return await Courier.shared.refreshInbox(); }, testFetchNextPageOfMessages: async () => { return await Courier.shared.fetchNextPageOfMessages({ inboxMessageFeed: 'feed' }); }, testRequestPushNotificationPermission: async () => { return await Courier.requestNotificationPermission(); }, testGetPushNotificationPermissionStatus: async () => { return await Courier.getNotificationPermissionStatus(); }, testSetIOSForegroundPresentationOptions: async (params) => { return Courier.setIOSForegroundPresentationOptions({ options: params.options }); }, testOpenSettingsForApp: async () => { return Courier.openSettingsForApp(); }, testSendInboxMessage: async (params) => { const messageId = await ExampleServer.sendTest({ authKey: Env.authKey, userId: params.userId, channel: 'inbox', title: params.title ?? 'Test', body: params.body ?? 'Body', }); return { messageId: messageId }; }, testSendApnMessage: async (params) => { const messageId = await ExampleServer.sendTest({ authKey: Env.authKey, userId: params.userId, channel: 'apn', title: params.title ?? 'Test', body: params.body ?? 'Body', }); return { messageId: messageId }; }, testSendFcmMessage: async (params) => { const messageId = await ExampleServer.sendTest({ authKey: Env.authKey, userId: params.userId, channel: 'firebase-fcm', title: params.title ?? 'Test', body: params.body ?? 'Body', }); return { messageId: messageId }; }, }; const getTestSections = async () => [ { title: 'Client Management', tests: [ { name: 'Create Client', testId: 'createClient', defaultParams: { userId: Utils.generateUUID(), clientKey: Env.clientKey, showLogs: true, tenantId: undefined, connectionId: undefined }, runOrder: 'normal' }, { name: 'Remove Client', testId: 'removeClient', defaultParams: { clientId: savedClient?.clientId }, runOrder: 'skip' }, ] }, { title: 'Tokens', tests: [ { name: 'Put Token', testId: 'testPutToken', defaultParams: { token: 'test-token', provider: 'test-provider' }, runOrder: 'normal' }, { name: 'Delete Token', testId: 'testDeleteToken', defaultParams: { token: 'test-token' }, runOrder: 'normal' }, ] }, { title: 'Brands', tests: [ { name: 'Get Brand', testId: 'testGetBrands', defaultParams: { brandId: Env.brandId }, runOrder: 'normal' }, ] }, { title: 'Inbox', tests: [ { name: 'Get Messages', testId: 'testMessages', defaultParams: { paginationLimit: 10, paginationCursor: undefined }, runOrder: 'normal' }, { name: 'Get Unread Count', testId: 'testUnreadCount', defaultParams: {}, runOrder: 'normal' }, { name: 'Get Archived Messages', testId: 'testArchivedMessages', defaultParams: { paginationLimit: 10, paginationCursor: undefined }, runOrder: 'normal' }, { name: 'Get Message By ID', testId: 'testMessageById', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Open Message', testId: 'openMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Click Message', testId: 'clickMessage', defaultParams: { messageId: undefined, trackingId: undefined }, runOrder: 'normal' }, { name: 'Read Message', testId: 'readMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Unread Message', testId: 'unreadMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Archive Message', testId: 'archiveMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Read All Messages', testId: 'readAllMessages', defaultParams: {}, runOrder: 'normal' }, ] }, { title: 'Preferences', tests: [ { name: 'Get Preferences', testId: 'testGetPreferences', defaultParams: { paginationCursor: undefined }, runOrder: 'normal' }, { name: 'Update Preferences', testId: 'testUpdatePreferences', defaultParams: { topicId: Env.topicId, status: 'OPTED_IN', hasCustomRouting: true, customRouting: 'push,sms,email' }, runOrder: 'normal' }, { name: 'Get Preference Topics', testId: 'testGetPreferenceTopics', defaultParams: { topicId: Env.topicId }, runOrder: 'normal' }, ] }, { title: 'Tracking', tests: [ { name: 'Post Tracking Url', testId: 'testPostTrackingUrl', defaultParams: { trackingUrl: 'https://af6303be-0e1e-40b5-bb80-e1d9299cccff.ct0.app/t/tzgspbr4jcmcy1qkhw96m0034bvy', event: 'delivered' }, runOrder: 'normal' }, ] }, { title: 'Shared Authentication', tests: [ { name: 'Sign In', testId: 'testSignIn', defaultParams: { userId: Utils.generateUUID(), accessToken: undefined, clientKey: Env.clientKey, tenantId: undefined, showLogs: true }, runOrder: 'normal' }, { name: 'Get User ID', testId: 'testGetUserId', defaultParams: {}, runOrder: 'normal' }, { name: 'Get Tenant ID', testId: 'testGetTenantId', defaultParams: {}, runOrder: 'normal' }, { name: 'Get Is User Signed In', testId: 'testGetIsUserSignedIn', defaultParams: {}, runOrder: 'normal' }, { name: 'Add Authentication Listener', testId: 'testAuthenticationListener', defaultParams: {}, runOrder: 'normal' }, { name: 'Remove All Authentication Listeners', testId: 'testRemoveAllAuthenticationListeners', defaultParams: {}, runOrder: 'normal' }, { name: 'Sign Out', testId: 'testSignOut', defaultParams: {}, runOrder: 'skip' } ] }, { title: 'Shared Client', tests: [ { name: 'Get Client', testId: 'testGetClient', defaultParams: {}, runOrder: 'normal' } ] }, { title: 'Shared Push', tests: [ { name: 'Set Token', testId: 'testSetToken', defaultParams: { provider: 'expo', token: 'test-token' }, runOrder: 'normal' }, { name: 'Get Token', testId: 'testGetToken', defaultParams: { provider: 'expo' }, runOrder: 'normal' }, { name: 'Get All Tokens', testId: 'testGetAllTokens', defaultParams: {}, runOrder: 'normal' }, { name: 'Add Push Notification Listener', testId: 'testAddPushNotificationListener', defaultParams: {}, runOrder: 'normal' }, { name: 'Remove All Push Notification Listeners', testId: 'testRemoveAllPushNotificationListeners', defaultParams: {}, runOrder: 'skip' } ] }, { title: 'Shared Inbox', tests: [ { name: 'Set Inbox Pagination Limit', testId: 'testSetInboxPaginationLimit', defaultParams: { limit: 20 }, runOrder: 'normal' }, { name: 'Get Inbox Pagination Limit', testId: 'testGetInboxPaginationLimit', defaultParams: {}, runOrder: 'normal' }, { name: 'Open Message', testId: 'testOpenMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Click Message', testId: 'testClickMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Read Message', testId: 'testReadMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Unread Message', testId: 'testUnreadMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Archive Message', testId: 'testArchiveMessage', defaultParams: { messageId: undefined }, runOrder: 'normal' }, { name: 'Read All Inbox Messages', testId: 'testReadAllInboxMessages', defaultParams: {}, runOrder: 'normal' }, { name: 'Add Inbox Listener', testId: 'testAddInboxListener', defaultParams: {}, runOrder: 'normal' }, { name: 'Remove All Inbox Listeners', testId: 'testRemoveAllInboxListeners', defaultParams: {}, runOrder: 'skip' }, { name: 'Refresh Inbox', testId: 'testRefreshInbox', defaultParams: {}, runOrder: 'normal' }, { name: 'Fetch Next Page of Messages', testId: 'testFetchNextPageOfMessages', defaultParams: {}, runOrder: 'normal' } ] }, { title: 'System', tests: [ { name: 'Request Push Notification Permission', testId: 'testRequestPushNotificationPermission', defaultParams: {}, runOrder: 'normal' }, { name: 'Get Push Notification Permission Status', testId: 'testGetPushNotificationPermissionStatus', defaultParams: {}, runOrder: 'normal' }, { name: 'Set iOS Foreground Presentation Options', testId: 'testSetIOSForegroundPresentationOptions', defaultParams: { options: 'badge,sound,list,banner' }, runOrder: 'normal' }, { name: 'Open Settings for App', testId: 'testOpenSettingsForApp', defaultParams: {}, runOrder: 'normal' }, ] }, { title: 'Send', tests: [ { name: 'Send Inbox Message', testId: 'testSendInboxMessage', defaultParams: { userId: await Courier.shared.getUserId() ?? savedClient?.options.userId, title: 'Test', body: 'Body' }, runOrder: 'normal' }, { name: 'Send APN Message', testId: 'testSendApnMessage', defaultParams: { userId: await Courier.shared.getUserId() ?? savedClient?.options.userId, title: 'Test', body: 'Body' }, runOrder: 'normal' }, { name: 'Send FCM Message', testId: 'testSendFcmMessage', defaultParams: { userId: await Courier.shared.getUserId() ?? savedClient?.options.userId, title: 'Test', body: 'Body' }, runOrder: 'normal' } ] } ]; const TestItem = ({ item, onPress }) => (React.createElement(TouchableOpacity, { onPress: onPress }, React.createElement(View, { style: [styles.testItem, item.status === 'running' && styles.runningTestItem] }, React.createElement(View, { style: styles.testItemContent }, React.createElement(Text, { style: styles.testItemTitle }, item.name), item.status !== undefined && item.status !== 'running' && (React.createElement(Text, { style: styles.testItemResult }, item.result !== undefined ? (typeof item.result === 'number' ? item.result.toString() : JSON.stringify(item.result, null, 2)) : 'No Response'))), React.createElement(View, { style: styles.testItemStatus }, item.status === undefined ? (React.createElement(Text, { style: styles.statusEmoji }, "\uD83E\uDDEA")) : item.status === 'running' ? (React.createElement(ActivityIndicator, { size: "small" })) : item.status === 'skipped' ? (React.createElement(Text, { style: styles.statusEmoji }, "\u26A0\uFE0F")) : (React.createElement(Text, { style: styles.statusEmoji }, item.status === 'success' ? '✅' : '❌')))))); const SectionHeader = ({ title }) => (React.createElement(View, { style: styles.sectionHeader }, React.createElement(Text, { style: styles.sectionHeaderText }, title))); const Tests = () => { const navigation = useNavigation(); const [testSections, setTestSections] = useState([]); const [testResults, setTestResults] = useState([]); const [isRunning, setIsRunning] = useState(false); const [currentTestIndex, setCurrentTestIndex] = useState(0); const [totalTests, setTotalTests] = useState(0); useEffect(() => { const loadTests = async () => { const sections = await getTestSections(); setTestSections(sections); setTestResults(sections.flatMap(section => section.tests.map(test => ({ name: test.name, runOrder: test.runOrder })))); setTotalTests(sections.flatMap(section => section.tests).length); }; loadTests(); }, []); useEffect(() => { navigation.setOptions({ headerRight: () => (React.createElement(TouchableOpacity, { onPress: runAllTests, disabled: isRunning, style: { marginRight: 22 } }, isRunning ? (React.createElement(ActivityIndicator, { size: "small" })) : (React.createElement(Text, { style: [styles.runTestsButton, isRunning && styles.disabledButton] }, "Run Tests")))), headerTitle: isRunning ? `Running Test ${currentTestIndex + 1}/${totalTests}` : 'Tests', }); }, [isRunning, currentTestIndex]); const handleTestError = (error) => { let errorMessage = 'An unknown error occurred'; let errorDetails = {}; if (error instanceof Error) { errorMessage = error.message; errorDetails = { name: error.name, }; } else if (typeof error === 'object' && error !== null) { errorMessage = String(error); errorDetails = { ...error }; } else if (typeof error === 'string') { errorMessage = error; } return { errorMessage, errorDetails }; }; const runAllTests = async () => { if (isRunning) return; setTestResults(prev => prev.map(item => ({ ...item, status: undefined, result: undefined }))); setIsRunning(true); setCurrentTestIndex(0); const normalTests = testSections.flatMap(section => section.tests.filter(test => test.runOrder === 'normal')); const endTests = testSections.flatMap(section => section.tests.filter(test => test.runOrder === 'run at end')); const skipTests = testSections.flatMap(section => section.tests.filter(test => test.runOrder === 'skip')); for (let i = 0; i < normalTests.length; i++) { setCurrentTestIndex(i); await runSingleTest(normalTests[i]); } for (let i = 0; i < endTests.length; i++) { setCurrentTestIndex(normalTests.length + i); await runSingleTest(endTests[i]); } for (const test of skipTests) { setTestResults(prev => prev.map(t => t.name === test.name ? { ...t, status: 'skipped' } : t)); } setIsRunning(false); setCurrentTestIndex(0); }; const runSingleTest = async (test) => { setTestResults(prev => prev.map(t => t.name === test.name ? { ...t, status: 'running', result: undefined } : t)); setModalVisible(false); // Close the modal when the test starts try { const testFunction = IntegrationTests[test.testId]; if (typeof testFunction === 'function') { const result = await testFunction(test.defaultParams); setTestResults(prev => prev.map(t => t.name === test.name ? { ...t, result, status: 'success' } : t)); } else { throw new Error(`Test function '${test.testId}' not found`); } } catch (error) { const { errorMessage, errorDetails } = handleTestError(error); console.log('Test failed:', { testName: test.name, errorMessage, errorDetails, }); setTestResults(prev => prev.map(t => t.name === test.name ? { ...t, result: { errorMessage, errorDetails, }, status: 'failure' } : t)); } }; const [modalVisible, setModalVisible] = useState(false); const [selectedTest, setSelectedTest] = useState(null); const [testParams, setTestParams] = useState({}); const onTestItemPress = (item) => { if (isRunning) return; setSelectedTest(item); setTestParams({ ...item.defaultParams }); setModalVisible(true); }; const handleParamChange = (key, value) => { setTestParams(prev => ({ ...prev, [key]: value })); }; const handleRunTest = async () => { if (selectedTest) { const testToRun = { ...selectedTest, defaultParams: testParams }; await runSingleTest(testToRun); } setModalVisible(false); }; const handleModalClose = () => { setModalVisible(false); setSelectedTest(null); setTestParams({}); }; return (React.createElement(View, { style: styles.container }, React.createElement(FlatList, { data: testSections, renderItem: ({ item: section }) => (React.createElement(React.Fragment, null, React.createElement(SectionHeader, { title: section.title }), section.tests.map((test) => (React.createElement(TestItem, { key: test.name, item: testResults.find(r => r.name === test.name) || { name: test.name, runOrder: test.runOrder }, onPress: () => onTestItemPress(test) }))))), keyExtractor: (item) => item.title }), React.createElement(Modal, { visible: modalVisible, animationType: "slide", transparent: true }, React.createElement(TouchableWithoutFeedback, { onPress: Keyboard.dismiss }, React.createElement(View, { style: styles.modalContainer }, React.createElement(View, { style: styles.modalContent }, React.createElement(Text, null, "Run Test: ", selectedTest?.name), Object.entries(testParams).map(([key, value]) => (React.createElement(View, { key: key, style: styles.inputContainer }, React.createElement(Text, { style: styles.inputLabel }, key, ":"), typeof value === 'boolean' ? (React.createElement(Switch, { value: value, onValueChange: (newValue) => handleParamChange(key, newValue) })) : typeof value === 'number' ? (React.createElement(TextInput, { style: styles.input, value: value !== undefined ? String(value) : '', onChangeText: (text) => { const numValue = Number(text); handleParamChange(key, isNaN(numValue) ? undefined : numValue); }, keyboardType: "numeric", autoCapitalize: "none", autoCorrect: false })) : (React.createElement(TextInput, { style: styles.input, value: value !== undefined ? String(value) : '', onChangeText: (text) => handleParamChange(key, text || undefined), autoCapitalize: "none", autoCorrect: false }))))), React.createElement(Button, { title: "Run", onPress: handleRunTest }), React.createElement(Button, { title: "Cancel", onPress: handleModalClose }))))))); }; const styles = StyleSheet.create({ container: { flex: 1, }, testItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', padding: 20, borderBottomWidth: 1, borderBottomColor: '#ccc', }, runningTestItem: { backgroundColor: '#e6f3ff', }, testItemContent: { flex: 1, marginRight: 10, }, testItemTitle: { fontFamily: Platform.select({ ios: 'Courier', android: 'monospace', default: 'monospace', }), fontSize: 16, fontWeight: 'bold', marginBottom: 8, }, testItemStatus: { width: 24, alignItems: 'center', justifyContent: 'center', }, testItemResult: { fontFamily: Platform.select({ ios: 'Courier', android: 'monospace', default: 'monospace', }), fontSize: 14, }, statusEmoji: { fontSize: 16, lineHeight: 24, }, runTestsButton: { fontSize: 16, }, disabledButton: { opacity: 0.5, }, sectionHeader: { backgroundColor: '#f0f0f0', padding: 20, }, sectionHeaderText: { fontFamily: Platform.select({ ios: 'Courier', android: 'monospace', default: 'monospace', }), fontWeight: 'bold', fontSize: 24, paddingTop: 20, }, modalContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.5)', }, modalContent: { backgroundColor: 'white', padding: 20, borderRadius: 10, width: '80%', }, inputContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 10, }, inputLabel: { width: 100, marginRight: 10, }, input: { flex: 1, borderWidth: 1, borderColor: '#ccc', padding: 5, }, }); export default Tests;