@onairos/react-native 1.0.0 → 1.0.1

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.
Files changed (32) hide show
  1. package/lib/commonjs/components/OnairosButton.js +6 -415
  2. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  3. package/lib/commonjs/components/Overlay.js +0 -549
  4. package/lib/commonjs/components/PinInput.js +160 -0
  5. package/lib/commonjs/components/PinInput.js.map +1 -0
  6. package/lib/commonjs/components/PlatformList.js +137 -0
  7. package/lib/commonjs/components/PlatformList.js.map +1 -0
  8. package/lib/commonjs/components/TrainingModal.js +130 -0
  9. package/lib/commonjs/components/TrainingModal.js.map +1 -0
  10. package/lib/commonjs/index.js +12 -276
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/module/components/OnairosButton.js +121 -514
  13. package/lib/module/components/OnairosButton.js.map +1 -1
  14. package/lib/module/components/Overlay.js +0 -565
  15. package/lib/module/components/PinInput.js +151 -0
  16. package/lib/module/components/PinInput.js.map +1 -0
  17. package/lib/module/components/PlatformList.js +129 -0
  18. package/lib/module/components/PlatformList.js.map +1 -0
  19. package/lib/module/components/TrainingModal.js +122 -0
  20. package/lib/module/components/TrainingModal.js.map +1 -0
  21. package/package.json +5 -4
  22. package/src/components/OnairosButton.tsx +5 -5
  23. package/src/components/PinInput.tsx +189 -0
  24. package/src/components/PlatformList.tsx +145 -0
  25. package/src/components/TrainingModal.tsx +132 -0
  26. package/lib/commonjs/components/Notification.js +0 -106
  27. package/lib/commonjs/components/Notification.js.map +0 -1
  28. package/lib/module/components/Notification.js +0 -99
  29. package/lib/module/components/Notification.js.map +0 -1
  30. package/src/components/Notification.js +0 -101
  31. package/src/components/OnairosButton.js +0 -604
  32. package/src/components/Overlay.js +0 -854
@@ -1,854 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import {
3
- View,
4
- Text,
5
- TouchableOpacity,
6
- ScrollView,
7
- StyleSheet,
8
- ActivityIndicator,
9
- Image,
10
- Dimensions,
11
- TextInput,
12
- KeyboardAvoidingView,
13
- Platform
14
- } from 'react-native';
15
- import Modal from 'react-native-modal';
16
- import Icon from 'react-native-vector-icons/MaterialIcons';
17
- import { Othent } from '@othent/kms-react-native';
18
- import { sha256 } from 'react-native-crypto-js';
19
- import { getPin } from '../utils/auth';
20
- import AsyncStorage from '@react-native-async-storage/async-storage';
21
- import axios from 'axios';
22
-
23
- const { width, height } = Dimensions.get('window');
24
- const API_URL = 'https://api2.onairos.uk';
25
-
26
- const Overlay = ({
27
- setOthentConnected,
28
- dataRequester,
29
- NoAccount,
30
- NoModel,
31
- accountInfo,
32
- activeModels,
33
- avatar,
34
- traits,
35
- requestData,
36
- handleConnectionSelection,
37
- changeGranted,
38
- granted,
39
- allowSubmit,
40
- rejectDataRequest,
41
- sendDataRequest,
42
- isAuthenticated,
43
- onLoginSuccess,
44
- onClose,
45
- setOthentUser,
46
- setHashedOthentSub,
47
- setEncryptedPin
48
- }) => {
49
- const [currentStep, setCurrentStep] = useState(
50
- NoAccount.current ? 'onboarding' : NoModel.current ? 'createModel' : 'dataRequest'
51
- );
52
- const [isLoading, setIsLoading] = useState(false);
53
- const [selectedConnections, setSelectedConnections] = useState([]);
54
- const [pin, setPin] = useState('');
55
- const [confirmPin, setConfirmPin] = useState('');
56
- const [pinError, setPinError] = useState('');
57
- const [selectedSocialAccounts, setSelectedSocialAccounts] = useState([]);
58
- const [isTraining, setIsTraining] = useState(false);
59
- const [trainingProgress, setTrainingProgress] = useState(0);
60
- const [username, setUsername] = useState('');
61
- const [password, setPassword] = useState('');
62
- const [loginError, setLoginError] = useState('');
63
- const [email, setEmail] = useState('');
64
-
65
- // Social media platforms for onboarding
66
- const socialPlatforms = [
67
- { id: 'reddit', name: 'Reddit', icon: 'https://onairos.sirv.com/Images/reddit-icon.png' },
68
- { id: 'instagram', name: 'Instagram', icon: 'https://onairos.sirv.com/Images/instagram-icon.png' },
69
- { id: 'pinterest', name: 'Pinterest', icon: 'https://onairos.sirv.com/Images/pinterest-icon.png' },
70
- { id: 'twitter', name: 'Twitter', icon: 'https://onairos.sirv.com/Images/twitter-icon.png' },
71
- { id: 'facebook', name: 'Facebook', icon: 'https://onairos.sirv.com/Images/facebook-icon.png' }
72
- ];
73
-
74
- // Toggle data request selection
75
- const toggleDataRequest = (dataRequester, key, index, type, reward) => {
76
- const isSelected = !selectedConnections.some(
77
- conn => conn.dataRequester === dataRequester && conn.key === key && conn.index === index
78
- );
79
-
80
- if (isSelected) {
81
- setSelectedConnections([
82
- ...selectedConnections,
83
- { dataRequester, key, index, type, reward }
84
- ]);
85
- } else {
86
- setSelectedConnections(
87
- selectedConnections.filter(
88
- conn => !(conn.dataRequester === dataRequester && conn.key === key && conn.index === index)
89
- )
90
- );
91
- }
92
-
93
- handleConnectionSelection(dataRequester, key, index, type, reward, isSelected);
94
- changeGranted(isSelected ? 1 : -1);
95
- };
96
-
97
- // Handle social account selection
98
- const toggleSocialAccount = (id) => {
99
- if (selectedSocialAccounts.includes(id)) {
100
- setSelectedSocialAccounts(selectedSocialAccounts.filter(item => item !== id));
101
- } else {
102
- setSelectedSocialAccounts([...selectedSocialAccounts, id]);
103
- }
104
- };
105
-
106
- // Start model training
107
- const startTraining = () => {
108
- if (selectedSocialAccounts.length === 0) {
109
- // Show error - need at least one account
110
- return;
111
- }
112
-
113
- setIsTraining(true);
114
- setTrainingProgress(0);
115
-
116
- // Simulate training progress
117
- const interval = setInterval(() => {
118
- setTrainingProgress(prev => {
119
- const newProgress = prev + 5;
120
- if (newProgress >= 100) {
121
- clearInterval(interval);
122
- setTimeout(() => {
123
- setIsTraining(false);
124
- setCurrentStep('createPin');
125
- }, 500);
126
- return 100;
127
- }
128
- return newProgress;
129
- });
130
- }, 300);
131
- };
132
-
133
- // Handle PIN creation
134
- const handleCreatePin = () => {
135
- if (pin.length < 4) {
136
- setPinError('PIN must be at least 4 digits');
137
- return;
138
- }
139
-
140
- if (pin !== confirmPin) {
141
- setPinError('PINs do not match');
142
- return;
143
- }
144
-
145
- setPinError('');
146
- completeOnboarding();
147
- };
148
-
149
- // Complete the onboarding process
150
- const completeOnboarding = async () => {
151
- setIsLoading(true);
152
-
153
- try {
154
- // Connect with Othent
155
- const appInfo = {
156
- name: 'Onairos',
157
- version: '1.0.0',
158
- env: 'production',
159
- };
160
- const othent = new Othent({ appInfo, throwErrors: false });
161
- const userDetails = await othent.connect();
162
-
163
- // Hash the user's sub
164
- const hashedSub = sha256(userDetails.sub).toString();
165
- setHashedOthentSub(hashedSub);
166
- setOthentUser(true);
167
-
168
- // Create account on Onairos server with the selected social accounts
169
- const response = await axios.post(`${API_URL}/createAccount`, {
170
- othentSub: hashedSub,
171
- pin: pin,
172
- socialAccounts: selectedSocialAccounts,
173
- email: userDetails.email
174
- });
175
-
176
- if (response.status === 200) {
177
- // Store the token
178
- await AsyncStorage.setItem('onairosToken', response.data.token);
179
- await AsyncStorage.setItem('username', response.data.username);
180
-
181
- // Get the encrypted pin from the server
182
- const userOnairosDetails = await getPin(hashedSub);
183
- setEncryptedPin(userOnairosDetails.result);
184
-
185
- setOthentConnected(true);
186
-
187
- // Move to data request step
188
- setCurrentStep('dataRequest');
189
- } else {
190
- throw new Error('Failed to create account');
191
- }
192
- } catch (error) {
193
- console.error('Onboarding failed:', error);
194
- } finally {
195
- setIsLoading(false);
196
- }
197
- };
198
-
199
- // Handle Othent login
200
- const handleOthentLogin = async () => {
201
- setIsLoading(true);
202
-
203
- try {
204
- const appInfo = {
205
- name: 'Onairos',
206
- version: '1.0.0',
207
- env: 'production',
208
- };
209
- const othent = new Othent({ appInfo, throwErrors: false });
210
- const userDetails = await othent.connect();
211
-
212
- // Hash the user's sub
213
- const hashedSub = sha256(userDetails.sub).toString();
214
- setHashedOthentSub(hashedSub);
215
-
216
- // Get the encrypted pin from the server
217
- const userOnairosDetails = await getPin(hashedSub);
218
-
219
- if (userOnairosDetails.result === "No user account") {
220
- // No account found, move to onboarding
221
- NoAccount.current = true;
222
- setCurrentStep('onboarding');
223
- } else {
224
- // Account found, store the encrypted pin
225
- setEncryptedPin(userOnairosDetails.result);
226
- setOthentUser(true);
227
- setOthentConnected(true);
228
-
229
- // Store the token
230
- await AsyncStorage.setItem('onairosToken', userOnairosDetails.token);
231
-
232
- // Fetch account info
233
- await onLoginSuccess(userDetails.email, true);
234
- }
235
- } catch (error) {
236
- console.error('Othent login failed:', error);
237
- setLoginError('Authentication failed. Please try again.');
238
- } finally {
239
- setIsLoading(false);
240
- }
241
- };
242
-
243
- // Handle username/password login
244
- const handleUsernameLogin = async () => {
245
- if (!username || !password) {
246
- setLoginError('Please enter both username and password');
247
- return;
248
- }
249
-
250
- setIsLoading(true);
251
- setLoginError('');
252
-
253
- try {
254
- const response = await axios.post(`${API_URL}/login`, {
255
- username,
256
- password
257
- });
258
-
259
- if (response.status === 200) {
260
- // Store the token
261
- await AsyncStorage.setItem('onairosToken', response.data.token);
262
- await AsyncStorage.setItem('username', username);
263
-
264
- // Update authentication state
265
- await onLoginSuccess(username, false);
266
- } else {
267
- setLoginError('Invalid username or password');
268
- }
269
- } catch (error) {
270
- console.error('Login failed:', error);
271
- setLoginError('Login failed. Please check your credentials.');
272
- } finally {
273
- setIsLoading(false);
274
- }
275
- };
276
-
277
- // Render login form
278
- const renderLoginForm = () => (
279
- <View style={styles.loginContainer}>
280
- <Text style={styles.loginTitle}>Sign in to Onairos</Text>
281
-
282
- {loginError ? <Text style={styles.errorText}>{loginError}</Text> : null}
283
-
284
- <View style={styles.inputContainer}>
285
- <Text style={styles.inputLabel}>Username</Text>
286
- <TextInput
287
- style={styles.input}
288
- value={username}
289
- onChangeText={setUsername}
290
- placeholder="Enter your username"
291
- autoCapitalize="none"
292
- />
293
- </View>
294
-
295
- <View style={styles.inputContainer}>
296
- <Text style={styles.inputLabel}>Password</Text>
297
- <TextInput
298
- style={styles.input}
299
- value={password}
300
- onChangeText={setPassword}
301
- placeholder="Enter your password"
302
- secureTextEntry
303
- />
304
- </View>
305
-
306
- <TouchableOpacity
307
- style={styles.loginButton}
308
- onPress={handleUsernameLogin}
309
- disabled={isLoading}
310
- >
311
- {isLoading ? (
312
- <ActivityIndicator color="#fff" size="small" />
313
- ) : (
314
- <Text style={styles.loginButtonText}>Sign In</Text>
315
- )}
316
- </TouchableOpacity>
317
-
318
- <View style={styles.divider}>
319
- <View style={styles.dividerLine} />
320
- <Text style={styles.dividerText}>OR</Text>
321
- <View style={styles.dividerLine} />
322
- </View>
323
-
324
- <TouchableOpacity
325
- style={styles.othentButton}
326
- onPress={handleOthentLogin}
327
- disabled={isLoading}
328
- >
329
- <Image
330
- source={{ uri: 'https://onairos.sirv.com/Images/othent-logo.png' }}
331
- style={styles.othentLogo}
332
- />
333
- <Text style={styles.othentButtonText}>Continue with Othent</Text>
334
- </TouchableOpacity>
335
- </View>
336
- );
337
-
338
- // Render onboarding step
339
- const renderOnboarding = () => (
340
- <View style={styles.onboardingContainer}>
341
- <Text style={styles.onboardingTitle}>Connect Your Accounts</Text>
342
- <Text style={styles.onboardingSubtitle}>
343
- Select the social media accounts you want to connect to Onairos
344
- </Text>
345
-
346
- <View style={styles.socialAccountsContainer}>
347
- {socialPlatforms.map(platform => (
348
- <TouchableOpacity
349
- key={platform.id}
350
- style={[
351
- styles.socialAccount,
352
- selectedSocialAccounts.includes(platform.id) && styles.selectedSocialAccount
353
- ]}
354
- onPress={() => toggleSocialAccount(platform.id)}
355
- >
356
- <Image source={{ uri: platform.icon }} style={styles.socialIcon} />
357
- <Text style={styles.socialName}>{platform.name}</Text>
358
- {selectedSocialAccounts.includes(platform.id) && (
359
- <Icon name="check-circle" size={24} color="#4CAF50" style={styles.checkIcon} />
360
- )}
361
- </TouchableOpacity>
362
- ))}
363
- </View>
364
-
365
- <TouchableOpacity
366
- style={[
367
- styles.nextButton,
368
- selectedSocialAccounts.length === 0 && styles.disabledButton
369
- ]}
370
- onPress={startTraining}
371
- disabled={selectedSocialAccounts.length === 0 || isTraining}
372
- >
373
- {isTraining ? (
374
- <ActivityIndicator color="#fff" size="small" />
375
- ) : (
376
- <Text style={styles.nextButtonText}>Continue</Text>
377
- )}
378
- </TouchableOpacity>
379
- </View>
380
- );
381
-
382
- // Render training progress
383
- const renderTraining = () => (
384
- <View style={styles.trainingContainer}>
385
- <Text style={styles.trainingTitle}>Training Your Model</Text>
386
- <Text style={styles.trainingSubtitle}>
387
- Please wait while we train your personalized AI model
388
- </Text>
389
-
390
- <View style={styles.progressBarContainer}>
391
- <View style={[styles.progressBar, { width: `${trainingProgress}%` }]} />
392
- </View>
393
-
394
- <Text style={styles.progressText}>{trainingProgress}% Complete</Text>
395
- </View>
396
- );
397
-
398
- // Render PIN creation step
399
- const renderCreatePin = () => (
400
- <View style={styles.pinContainer}>
401
- <Text style={styles.pinTitle}>Create Your PIN</Text>
402
- <Text style={styles.pinSubtitle}>
403
- This PIN will be used to secure your data
404
- </Text>
405
-
406
- {pinError ? <Text style={styles.errorText}>{pinError}</Text> : null}
407
-
408
- <View style={styles.inputContainer}>
409
- <Text style={styles.inputLabel}>PIN</Text>
410
- <TextInput
411
- style={styles.input}
412
- value={pin}
413
- onChangeText={setPin}
414
- placeholder="Enter a 4-digit PIN"
415
- keyboardType="numeric"
416
- secureTextEntry
417
- maxLength={4}
418
- />
419
- </View>
420
-
421
- <View style={styles.inputContainer}>
422
- <Text style={styles.inputLabel}>Confirm PIN</Text>
423
- <TextInput
424
- style={styles.input}
425
- value={confirmPin}
426
- onChangeText={setConfirmPin}
427
- placeholder="Confirm your PIN"
428
- keyboardType="numeric"
429
- secureTextEntry
430
- maxLength={4}
431
- />
432
- </View>
433
-
434
- <TouchableOpacity
435
- style={styles.nextButton}
436
- onPress={handleCreatePin}
437
- disabled={isLoading}
438
- >
439
- {isLoading ? (
440
- <ActivityIndicator color="#fff" size="small" />
441
- ) : (
442
- <Text style={styles.nextButtonText}>Complete Setup</Text>
443
- )}
444
- </TouchableOpacity>
445
- </View>
446
- );
447
-
448
- // Render data request step
449
- const renderDataRequest = () => (
450
- <View style={styles.dataRequestContainer}>
451
- <Text style={styles.dataRequestTitle}>
452
- {dataRequester} is requesting access to your data
453
- </Text>
454
-
455
- <ScrollView style={styles.requestsScrollView}>
456
- {Object.keys(requestData).map((key) => (
457
- <View key={key} style={styles.requestSection}>
458
- <Text style={styles.requestSectionTitle}>{key} Data Request</Text>
459
- <Text style={styles.requestDescription}>{requestData[key].descriptions}</Text>
460
-
461
- <TouchableOpacity
462
- style={[
463
- styles.requestToggle,
464
- selectedConnections.some(
465
- conn => conn.key === key && conn.dataRequester === dataRequester
466
- ) && styles.requestToggleSelected
467
- ]}
468
- onPress={() => toggleDataRequest(
469
- dataRequester,
470
- key,
471
- 0,
472
- requestData[key].type,
473
- requestData[key].reward
474
- )}
475
- >
476
- <Text style={styles.requestToggleText}>
477
- {selectedConnections.some(
478
- conn => conn.key === key && conn.dataRequester === dataRequester
479
- )
480
- ? 'Selected'
481
- : 'Select'}
482
- </Text>
483
- </TouchableOpacity>
484
- </View>
485
- ))}
486
- </ScrollView>
487
-
488
- <View style={styles.actionButtonsContainer}>
489
- <TouchableOpacity
490
- style={styles.rejectButton}
491
- onPress={rejectDataRequest}
492
- >
493
- <Text style={styles.rejectButtonText}>Reject</Text>
494
- </TouchableOpacity>
495
-
496
- <TouchableOpacity
497
- style={[
498
- styles.approveButton,
499
- !allowSubmit && styles.disabledButton
500
- ]}
501
- onPress={sendDataRequest}
502
- disabled={!allowSubmit || isLoading}
503
- >
504
- {isLoading ? (
505
- <ActivityIndicator color="#fff" size="small" />
506
- ) : (
507
- <Text style={styles.approveButtonText}>Approve</Text>
508
- )}
509
- </TouchableOpacity>
510
- </View>
511
- </View>
512
- );
513
-
514
- // Render content based on current step
515
- const renderContent = () => {
516
- if (!isAuthenticated && currentStep !== 'onboarding') {
517
- return renderLoginForm();
518
- }
519
-
520
- switch (currentStep) {
521
- case 'onboarding':
522
- return renderOnboarding();
523
- case 'training':
524
- return renderTraining();
525
- case 'createPin':
526
- return renderCreatePin();
527
- case 'dataRequest':
528
- return renderDataRequest();
529
- default:
530
- return renderDataRequest();
531
- }
532
- };
533
-
534
- return (
535
- <Modal
536
- isVisible={true}
537
- onBackdropPress={onClose}
538
- onBackButtonPress={onClose}
539
- style={styles.modal}
540
- swipeDirection="down"
541
- onSwipeComplete={onClose}
542
- propagateSwipe
543
- avoidKeyboard
544
- >
545
- <KeyboardAvoidingView
546
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
547
- style={styles.keyboardAvoidingView}
548
- >
549
- <View style={styles.modalContent}>
550
- <View style={styles.modalHeader}>
551
- <View style={styles.dragIndicator} />
552
- <TouchableOpacity style={styles.closeButton} onPress={onClose}>
553
- <Icon name="close" size={24} color="#333" />
554
- </TouchableOpacity>
555
- </View>
556
-
557
- {renderContent()}
558
- </View>
559
- </KeyboardAvoidingView>
560
- </Modal>
561
- );
562
- };
563
-
564
- const styles = StyleSheet.create({
565
- modal: {
566
- justifyContent: 'flex-end',
567
- margin: 0,
568
- },
569
- keyboardAvoidingView: {
570
- width: '100%',
571
- },
572
- modalContent: {
573
- backgroundColor: 'white',
574
- borderTopLeftRadius: 20,
575
- borderTopRightRadius: 20,
576
- paddingHorizontal: 20,
577
- paddingBottom: 20,
578
- maxHeight: height * 0.8,
579
- },
580
- modalHeader: {
581
- flexDirection: 'row',
582
- justifyContent: 'center',
583
- alignItems: 'center',
584
- paddingVertical: 10,
585
- position: 'relative',
586
- },
587
- dragIndicator: {
588
- width: 40,
589
- height: 5,
590
- backgroundColor: '#ccc',
591
- borderRadius: 3,
592
- },
593
- closeButton: {
594
- position: 'absolute',
595
- right: 0,
596
- top: 10,
597
- },
598
-
599
- // Login styles
600
- loginContainer: {
601
- padding: 16,
602
- },
603
- loginTitle: {
604
- fontSize: 24,
605
- fontWeight: 'bold',
606
- marginBottom: 20,
607
- textAlign: 'center',
608
- },
609
- inputContainer: {
610
- marginBottom: 16,
611
- },
612
- inputLabel: {
613
- fontSize: 16,
614
- marginBottom: 8,
615
- color: '#333',
616
- },
617
- input: {
618
- borderWidth: 1,
619
- borderColor: '#ccc',
620
- borderRadius: 8,
621
- padding: 12,
622
- fontSize: 16,
623
- },
624
- loginButton: {
625
- backgroundColor: '#2196F3',
626
- borderRadius: 8,
627
- padding: 16,
628
- alignItems: 'center',
629
- marginTop: 8,
630
- },
631
- loginButtonText: {
632
- color: 'white',
633
- fontSize: 16,
634
- fontWeight: 'bold',
635
- },
636
- divider: {
637
- flexDirection: 'row',
638
- alignItems: 'center',
639
- marginVertical: 20,
640
- },
641
- dividerLine: {
642
- flex: 1,
643
- height: 1,
644
- backgroundColor: '#ccc',
645
- },
646
- dividerText: {
647
- marginHorizontal: 10,
648
- color: '#666',
649
- },
650
- othentButton: {
651
- flexDirection: 'row',
652
- alignItems: 'center',
653
- justifyContent: 'center',
654
- backgroundColor: '#f5f5f5',
655
- borderRadius: 8,
656
- padding: 16,
657
- borderWidth: 1,
658
- borderColor: '#ddd',
659
- },
660
- othentLogo: {
661
- width: 24,
662
- height: 24,
663
- marginRight: 10,
664
- },
665
- othentButtonText: {
666
- fontSize: 16,
667
- color: '#333',
668
- },
669
-
670
- // Onboarding styles
671
- onboardingContainer: {
672
- padding: 16,
673
- },
674
- onboardingTitle: {
675
- fontSize: 24,
676
- fontWeight: 'bold',
677
- marginBottom: 8,
678
- },
679
- onboardingSubtitle: {
680
- fontSize: 16,
681
- color: '#666',
682
- marginBottom: 20,
683
- },
684
- socialAccountsContainer: {
685
- marginBottom: 20,
686
- },
687
- socialAccount: {
688
- flexDirection: 'row',
689
- alignItems: 'center',
690
- padding: 16,
691
- borderWidth: 1,
692
- borderColor: '#ddd',
693
- borderRadius: 8,
694
- marginBottom: 10,
695
- },
696
- selectedSocialAccount: {
697
- borderColor: '#4CAF50',
698
- backgroundColor: 'rgba(76, 175, 80, 0.1)',
699
- },
700
- socialIcon: {
701
- width: 24,
702
- height: 24,
703
- marginRight: 16,
704
- },
705
- socialName: {
706
- fontSize: 16,
707
- flex: 1,
708
- },
709
- checkIcon: {
710
- marginLeft: 8,
711
- },
712
- nextButton: {
713
- backgroundColor: '#4CAF50',
714
- borderRadius: 8,
715
- padding: 16,
716
- alignItems: 'center',
717
- },
718
- nextButtonText: {
719
- color: 'white',
720
- fontSize: 16,
721
- fontWeight: 'bold',
722
- },
723
- disabledButton: {
724
- backgroundColor: '#ccc',
725
- },
726
-
727
- // Training styles
728
- trainingContainer: {
729
- padding: 16,
730
- alignItems: 'center',
731
- },
732
- trainingTitle: {
733
- fontSize: 24,
734
- fontWeight: 'bold',
735
- marginBottom: 8,
736
- },
737
- trainingSubtitle: {
738
- fontSize: 16,
739
- color: '#666',
740
- marginBottom: 30,
741
- textAlign: 'center',
742
- },
743
- progressBarContainer: {
744
- width: '100%',
745
- height: 12,
746
- backgroundColor: '#e0e0e0',
747
- borderRadius: 6,
748
- overflow: 'hidden',
749
- marginBottom: 16,
750
- },
751
- progressBar: {
752
- height: '100%',
753
- backgroundColor: '#4CAF50',
754
- },
755
- progressText: {
756
- fontSize: 16,
757
- fontWeight: 'bold',
758
- color: '#4CAF50',
759
- },
760
-
761
- // PIN styles
762
- pinContainer: {
763
- padding: 16,
764
- },
765
- pinTitle: {
766
- fontSize: 24,
767
- fontWeight: 'bold',
768
- marginBottom: 8,
769
- },
770
- pinSubtitle: {
771
- fontSize: 16,
772
- color: '#666',
773
- marginBottom: 20,
774
- },
775
- errorText: {
776
- color: 'red',
777
- marginBottom: 16,
778
- },
779
-
780
- // Data request styles
781
- dataRequestContainer: {
782
- padding: 16,
783
- },
784
- dataRequestTitle: {
785
- fontSize: 20,
786
- fontWeight: 'bold',
787
- marginBottom: 16,
788
- },
789
- requestsScrollView: {
790
- maxHeight: 300,
791
- },
792
- requestSection: {
793
- marginBottom: 20,
794
- padding: 16,
795
- borderWidth: 1,
796
- borderColor: '#ddd',
797
- borderRadius: 8,
798
- },
799
- requestSectionTitle: {
800
- fontSize: 18,
801
- fontWeight: 'bold',
802
- marginBottom: 8,
803
- },
804
- requestDescription: {
805
- fontSize: 14,
806
- color: '#666',
807
- marginBottom: 16,
808
- },
809
- requestToggle: {
810
- backgroundColor: '#f5f5f5',
811
- padding: 12,
812
- borderRadius: 8,
813
- alignItems: 'center',
814
- },
815
- requestToggleSelected: {
816
- backgroundColor: '#4CAF50',
817
- },
818
- requestToggleText: {
819
- fontWeight: 'bold',
820
- },
821
- actionButtonsContainer: {
822
- flexDirection: 'row',
823
- justifyContent: 'space-between',
824
- marginTop: 20,
825
- },
826
- rejectButton: {
827
- flex: 1,
828
- backgroundColor: '#f5f5f5',
829
- borderRadius: 8,
830
- padding: 16,
831
- alignItems: 'center',
832
- marginRight: 8,
833
- },
834
- rejectButtonText: {
835
- color: '#333',
836
- fontSize: 16,
837
- fontWeight: 'bold',
838
- },
839
- approveButton: {
840
- flex: 1,
841
- backgroundColor: '#4CAF50',
842
- borderRadius: 8,
843
- padding: 16,
844
- alignItems: 'center',
845
- marginLeft: 8,
846
- },
847
- approveButtonText: {
848
- color: 'white',
849
- fontSize: 16,
850
- fontWeight: 'bold',
851
- },
852
- });
853
-
854
- export default Overlay;