|
1 | | -import { useState, useMemo, useCallback, useRef } from 'react'; |
| 1 | +import { useState, useMemo, useCallback, useRef, useEffect } from 'react'; |
2 | 2 | import { |
3 | 3 | Text, |
4 | 4 | View, |
|
9 | 9 | TouchableOpacity, |
10 | 10 | FlatList, |
11 | 11 | Modal, |
| 12 | + Clipboard, |
12 | 13 | } from 'react-native'; |
13 | 14 | import { |
14 | 15 | SQLiteSyncProvider, |
@@ -83,7 +84,7 @@ registerBackgroundSyncCallback( |
83 | 84 | * - Always uses writeDb (for atomic write operations) |
84 | 85 | * - Triggers reactive queries when transaction commits |
85 | 86 | */ |
86 | | -function TestApp() { |
| 87 | +function TestApp({ deviceToken }: { deviceToken: string | null }) { |
87 | 88 | const { writeDb, initError } = useSqliteDb(); |
88 | 89 | const { isSyncReady, isSyncing, lastSyncTime, syncError } = useSyncStatus(); |
89 | 90 | const [searchText, setSearchText] = useState(''); |
@@ -177,6 +178,18 @@ function TestApp() { |
177 | 178 | <View style={styles.fixedHeader}> |
178 | 179 | <Text style={styles.title}>SQLite Sync Demo</Text> |
179 | 180 |
|
| 181 | + {deviceToken && ( |
| 182 | + <TouchableOpacity |
| 183 | + style={styles.tokenBanner} |
| 184 | + onPress={() => Clipboard.setString(deviceToken)} |
| 185 | + > |
| 186 | + <Text style={styles.tokenLabel}>Device Token (tap to copy):</Text> |
| 187 | + <Text style={styles.tokenText} numberOfLines={2}> |
| 188 | + {deviceToken} |
| 189 | + </Text> |
| 190 | + </TouchableOpacity> |
| 191 | + )} |
| 192 | + |
180 | 193 | {/* Status Section */} |
181 | 194 | <View style={styles.statusSection}> |
182 | 195 | <Text style={styles.status}> |
@@ -344,6 +357,13 @@ function PermissionDialog({ |
344 | 357 | export default function App() { |
345 | 358 | const [showPermissionDialog, setShowPermissionDialog] = useState(false); |
346 | 359 | const permissionResolverRef = useRef<((value: boolean) => void) | null>(null); |
| 360 | + const [deviceToken, setDeviceToken] = useState<string | null>(null); |
| 361 | + |
| 362 | + useEffect(() => { |
| 363 | + Notifications.getExpoPushTokenAsync() |
| 364 | + .then((token) => setDeviceToken(token.data as string)) |
| 365 | + .catch(() => setDeviceToken('Failed to get token')); |
| 366 | + }, []); |
347 | 367 |
|
348 | 368 | // Callback to show custom UI before system permission request |
349 | 369 | const handleBeforePushPermissionRequest = useCallback(async () => { |
@@ -412,7 +432,7 @@ export default function App() { |
412 | 432 | apiKey={SQLITE_CLOUD_API_KEY} |
413 | 433 | debug={true} |
414 | 434 | > |
415 | | - <TestApp /> |
| 435 | + <TestApp deviceToken={deviceToken} /> |
416 | 436 | </SQLiteSyncProvider> |
417 | 437 | </> |
418 | 438 | ); |
@@ -697,4 +717,25 @@ const styles = StyleSheet.create({ |
697 | 717 | color: '#666', |
698 | 718 | fontSize: 16, |
699 | 719 | }, |
| 720 | + tokenBanner: { |
| 721 | + backgroundColor: '#E8F5E9', |
| 722 | + padding: 12, |
| 723 | + marginHorizontal: 16, |
| 724 | + marginTop: 0, |
| 725 | + marginBottom: 8, |
| 726 | + borderRadius: 8, |
| 727 | + borderWidth: 1, |
| 728 | + borderColor: '#A5D6A7', |
| 729 | + }, |
| 730 | + tokenLabel: { |
| 731 | + fontSize: 12, |
| 732 | + fontWeight: '600', |
| 733 | + color: '#2E7D32', |
| 734 | + marginBottom: 4, |
| 735 | + }, |
| 736 | + tokenText: { |
| 737 | + fontSize: 11, |
| 738 | + color: '#333', |
| 739 | + fontFamily: 'monospace', |
| 740 | + }, |
700 | 741 | }); |
0 commit comments