Skip to content

Commit abd5e6f

Browse files
committed
Add react-native-barebones app
1 parent 15e0def commit abd5e6f

51 files changed

Lines changed: 4169 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
BUNDLE_PATH: "vendor/bundle"
2+
BUNDLE_FORCE_RUBY_PLATFORM: 1
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# OSX
2+
#
3+
.DS_Store
4+
5+
# Xcode
6+
#
7+
build/
8+
*.pbxuser
9+
!default.pbxuser
10+
*.mode1v3
11+
!default.mode1v3
12+
*.mode2v3
13+
!default.mode2v3
14+
*.perspectivev3
15+
!default.perspectivev3
16+
xcuserdata
17+
*.xccheckout
18+
*.moved-aside
19+
DerivedData
20+
*.hmap
21+
*.ipa
22+
*.xcuserstate
23+
**/.xcode.env.local
24+
25+
# Android/IntelliJ
26+
#
27+
build/
28+
.idea
29+
.gradle
30+
local.properties
31+
*.iml
32+
*.hprof
33+
.cxx/
34+
*.keystore
35+
!debug.keystore
36+
.kotlin/
37+
38+
# node.js
39+
#
40+
node_modules/
41+
npm-debug.log
42+
yarn-error.log
43+
44+
# fastlane
45+
#
46+
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47+
# screenshots whenever they are needed.
48+
# For more information about the recommended setup visit:
49+
# https://docs.fastlane.tools/best-practices/source-control/
50+
51+
**/fastlane/report.xml
52+
**/fastlane/Preview.html
53+
**/fastlane/screenshots
54+
**/fastlane/test_output
55+
56+
# Bundle artifact
57+
*.jsbundle
58+
59+
# Ruby / CocoaPods
60+
**/Pods/
61+
/vendor/bundle/
62+
63+
# Temporary files created by Metro to check the health of the file watcher
64+
.metro-health-check*
65+
66+
# testing
67+
/coverage
68+
69+
# Yarn
70+
.yarn/*
71+
!.yarn/patches
72+
!.yarn/plugins
73+
!.yarn/releases
74+
!.yarn/sdks
75+
!.yarn/versions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
import React, { useEffect, useState, useCallback } from 'react';
2+
import {
3+
ScrollView,
4+
StatusBar,
5+
StyleSheet,
6+
Text,
7+
useColorScheme,
8+
View,
9+
TouchableOpacity,
10+
ActivityIndicator
11+
} from 'react-native';
12+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
13+
import {
14+
column,
15+
Table,
16+
Schema,
17+
type PowerSyncBackendConnector,
18+
PowerSyncDatabase,
19+
createConsoleLogger,
20+
LogLevels
21+
} from '@powersync/react-native';
22+
23+
const Colors = {
24+
primary: '#0a7ea4',
25+
white: '#ffffff',
26+
black: '#000000',
27+
light: '#f5f5f5',
28+
dark: '#333333',
29+
lighter: '#f3f4f6',
30+
darker: '#1a1a1a'
31+
};
32+
33+
const RANDOM_NAMES = ['Alex', 'Jordan', 'Sam', 'Casey', 'Riley', 'Morgan', 'Quinn', 'Avery', 'Taylor', 'Jamie'];
34+
35+
/**
36+
* A placeholder connector which doesn't do anything but used to confirm connect can run.
37+
*/
38+
class DummyConnector implements PowerSyncBackendConnector {
39+
async fetchCredentials() {
40+
return {
41+
endpoint: '',
42+
token: ''
43+
};
44+
}
45+
46+
async uploadData() {}
47+
}
48+
49+
const customersTable = new Table({ name: column.text });
50+
const schema = new Schema({ customers: customersTable });
51+
52+
let powerSync: PowerSyncDatabase | null = null;
53+
54+
const setupDatabase = async (): Promise<PowerSyncDatabase> => {
55+
if (powerSync) return powerSync;
56+
57+
powerSync = new PowerSyncDatabase({
58+
schema,
59+
database: {
60+
dbFilename: 'powersync.db'
61+
},
62+
logger: createConsoleLogger({ minLevel: LogLevels.debug })
63+
});
64+
65+
await powerSync.init();
66+
return powerSync;
67+
};
68+
69+
type Customer = { id: string; name: string };
70+
71+
function App(): React.JSX.Element {
72+
const isDarkMode = useColorScheme() === 'dark';
73+
const [customers, setCustomers] = useState<Customer[]>([]);
74+
const [loading, setLoading] = useState(true);
75+
const [adding, setAdding] = useState(false);
76+
const [deletingId, setDeletingId] = useState<string | null>(null);
77+
78+
const backgroundStyle = {
79+
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter
80+
};
81+
const cardBg = isDarkMode ? Colors.darker : Colors.white;
82+
const textColor = isDarkMode ? Colors.white : Colors.black;
83+
const mutedColor = isDarkMode ? Colors.light : Colors.dark;
84+
85+
const loadCustomers = useCallback(async () => {
86+
if (!powerSync) return;
87+
try {
88+
const result = await powerSync.getAll<Customer>('SELECT id, name FROM customers ORDER BY name');
89+
setCustomers(Array.isArray(result) ? result : []);
90+
} catch (e) {
91+
console.error('Failed to load customers:', e);
92+
}
93+
}, []);
94+
95+
useEffect(() => {
96+
let mounted = true;
97+
98+
const init = async () => {
99+
try {
100+
const db = await setupDatabase();
101+
//await db.connect(new DummyConnector());
102+
if (mounted) await loadCustomers();
103+
} catch (error) {
104+
console.error('Database initialization error:', error);
105+
} finally {
106+
if (mounted) setLoading(false);
107+
}
108+
};
109+
110+
init();
111+
return () => {
112+
mounted = false;
113+
};
114+
}, [loadCustomers]);
115+
116+
const addRandomCustomer = async () => {
117+
if (!powerSync || adding) return;
118+
setAdding(true);
119+
try {
120+
const name = RANDOM_NAMES[Math.floor(Math.random() * RANDOM_NAMES.length)];
121+
await powerSync.execute('INSERT INTO customers(id, name) VALUES(uuid(), ?)', [name]);
122+
await loadCustomers();
123+
} catch (e) {
124+
console.error('Failed to add customer:', e);
125+
} finally {
126+
setAdding(false);
127+
}
128+
};
129+
130+
const deleteCustomer = async (id: string) => {
131+
if (!powerSync || deletingId) return;
132+
setDeletingId(id);
133+
try {
134+
await powerSync.execute('DELETE FROM customers WHERE id = ?', [id]);
135+
await loadCustomers();
136+
} catch (e) {
137+
console.error('Failed to delete customer:', e);
138+
} finally {
139+
setDeletingId(null);
140+
}
141+
};
142+
143+
return (
144+
<SafeAreaProvider>
145+
<SafeAreaView style={[backgroundStyle, styles.container]}>
146+
<StatusBar
147+
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
148+
/>
149+
<View style={styles.header}>
150+
<Text style={[styles.headerTitle, { color: textColor }]}>Customers</Text>
151+
<Text style={[styles.headerSubtitle, { color: mutedColor }]}>PowerSync on React Native</Text>
152+
</View>
153+
154+
{loading ? (
155+
<View style={styles.centered}>
156+
<ActivityIndicator size="large" color={Colors.primary} />
157+
<Text style={[styles.mutedText, { color: mutedColor }]}>Loading…</Text>
158+
</View>
159+
) : (
160+
<ScrollView
161+
contentInsetAdjustmentBehavior="automatic"
162+
style={backgroundStyle}
163+
contentContainerStyle={styles.scrollContent}>
164+
<View style={[styles.card, { backgroundColor: cardBg }]}>
165+
{customers.length === 0 ? (
166+
<Text style={[styles.emptyText, { color: mutedColor }]}>No customers yet.</Text>
167+
) : (
168+
customers.map((c) => (
169+
<View key={c.id} style={styles.row}>
170+
<Text style={[styles.customerName, { color: textColor }]}>{c.name}</Text>
171+
<TouchableOpacity
172+
style={styles.deleteButton}
173+
onPress={() => deleteCustomer(c.id)}
174+
disabled={deletingId !== null}>
175+
{deletingId === c.id ? (
176+
<ActivityIndicator size="small" color={Colors.primary} />
177+
) : (
178+
<Text style={styles.deleteButtonText}>Delete</Text>
179+
)}
180+
</TouchableOpacity>
181+
</View>
182+
))
183+
)}
184+
</View>
185+
186+
<TouchableOpacity
187+
style={[styles.button, adding && styles.buttonDisabled]}
188+
onPress={addRandomCustomer}
189+
disabled={adding}>
190+
{adding ? (
191+
<ActivityIndicator size="small" color={Colors.white} />
192+
) : (
193+
<Text style={styles.buttonText}>Add random customer</Text>
194+
)}
195+
</TouchableOpacity>
196+
</ScrollView>
197+
)}
198+
</SafeAreaView>
199+
</SafeAreaProvider>
200+
);
201+
}
202+
203+
const styles = StyleSheet.create({
204+
container: {
205+
flex: 1
206+
},
207+
header: {
208+
paddingVertical: 20,
209+
paddingHorizontal: 24
210+
},
211+
headerTitle: {
212+
fontSize: 28,
213+
fontWeight: '700'
214+
},
215+
headerSubtitle: {
216+
fontSize: 14,
217+
marginTop: 4
218+
},
219+
scrollContent: {
220+
padding: 24,
221+
paddingBottom: 48
222+
},
223+
card: {
224+
borderRadius: 12,
225+
padding: 16,
226+
marginBottom: 24
227+
},
228+
row: {
229+
flexDirection: 'row',
230+
alignItems: 'center',
231+
justifyContent: 'space-between',
232+
paddingVertical: 12,
233+
borderBottomWidth: StyleSheet.hairlineWidth,
234+
borderBottomColor: 'rgba(0,0,0,0.08)'
235+
},
236+
customerName: {
237+
fontSize: 18,
238+
flex: 1
239+
},
240+
deleteButton: {
241+
paddingVertical: 8,
242+
paddingHorizontal: 12,
243+
minWidth: 72,
244+
alignItems: 'center'
245+
},
246+
deleteButtonText: {
247+
color: '#c53030',
248+
fontSize: 15,
249+
fontWeight: '500'
250+
},
251+
emptyText: {
252+
fontSize: 16,
253+
textAlign: 'center',
254+
paddingVertical: 24
255+
},
256+
button: {
257+
backgroundColor: Colors.primary,
258+
paddingVertical: 16,
259+
paddingHorizontal: 24,
260+
borderRadius: 12,
261+
alignItems: 'center',
262+
minHeight: 52,
263+
justifyContent: 'center'
264+
},
265+
buttonDisabled: {
266+
opacity: 0.7
267+
},
268+
buttonText: {
269+
color: Colors.white,
270+
fontSize: 17,
271+
fontWeight: '600'
272+
},
273+
centered: {
274+
flex: 1,
275+
justifyContent: 'center',
276+
alignItems: 'center',
277+
gap: 12
278+
},
279+
mutedText: {
280+
fontSize: 16
281+
}
282+
});
283+
284+
export default App;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
source 'https://rubygems.org'
2+
3+
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4+
ruby ">= 2.6.10"
5+
6+
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
7+
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
8+
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
9+
gem 'xcodeproj', '< 1.26.0'
10+
gem 'concurrent-ruby', '< 1.3.4'
11+
12+
# Ruby 3.4.0 has removed some libraries from the standard library.
13+
gem 'bigdecimal'
14+
gem 'logger'
15+
gem 'benchmark'
16+
gem 'mutex_m'
17+
gem 'nkf'

0 commit comments

Comments
 (0)