@nextsparkjs/mobile 0.1.0-beta.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 (123) hide show
  1. package/README.md +339 -0
  2. package/dist/api/client.d.ts +102 -0
  3. package/dist/api/client.js +189 -0
  4. package/dist/api/client.js.map +1 -0
  5. package/dist/api/client.types.d.ts +39 -0
  6. package/dist/api/client.types.js +12 -0
  7. package/dist/api/client.types.js.map +1 -0
  8. package/dist/api/core/auth.d.ts +26 -0
  9. package/dist/api/core/auth.js +52 -0
  10. package/dist/api/core/auth.js.map +1 -0
  11. package/dist/api/core/index.d.ts +4 -0
  12. package/dist/api/core/index.js +5 -0
  13. package/dist/api/core/index.js.map +1 -0
  14. package/dist/api/core/teams.d.ts +20 -0
  15. package/dist/api/core/teams.js +19 -0
  16. package/dist/api/core/teams.js.map +1 -0
  17. package/dist/api/core/types.d.ts +58 -0
  18. package/dist/api/core/types.js +1 -0
  19. package/dist/api/core/types.js.map +1 -0
  20. package/dist/api/core/users.d.ts +43 -0
  21. package/dist/api/core/users.js +41 -0
  22. package/dist/api/core/users.js.map +1 -0
  23. package/dist/api/entities/factory.d.ts +43 -0
  24. package/dist/api/entities/factory.js +31 -0
  25. package/dist/api/entities/factory.js.map +1 -0
  26. package/dist/api/entities/index.d.ts +3 -0
  27. package/dist/api/entities/index.js +3 -0
  28. package/dist/api/entities/index.js.map +1 -0
  29. package/dist/api/entities/types.d.ts +32 -0
  30. package/dist/api/entities/types.js +1 -0
  31. package/dist/api/entities/types.js.map +1 -0
  32. package/dist/api/index.d.ts +7 -0
  33. package/dist/api/index.js +15 -0
  34. package/dist/api/index.js.map +1 -0
  35. package/dist/hooks/index.d.ts +4 -0
  36. package/dist/hooks/index.js +5 -0
  37. package/dist/hooks/index.js.map +1 -0
  38. package/dist/index.d.ts +14 -0
  39. package/dist/index.js +28 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lib/alert.d.ts +34 -0
  42. package/dist/lib/alert.js +73 -0
  43. package/dist/lib/alert.js.map +1 -0
  44. package/dist/lib/index.d.ts +2 -0
  45. package/dist/lib/index.js +10 -0
  46. package/dist/lib/index.js.map +1 -0
  47. package/dist/lib/storage.d.ts +1 -0
  48. package/dist/lib/storage.js +29 -0
  49. package/dist/lib/storage.js.map +1 -0
  50. package/dist/providers/AuthProvider.d.ts +21 -0
  51. package/dist/providers/AuthProvider.js +113 -0
  52. package/dist/providers/AuthProvider.js.map +1 -0
  53. package/dist/providers/QueryProvider.d.ts +11 -0
  54. package/dist/providers/QueryProvider.js +23 -0
  55. package/dist/providers/QueryProvider.js.map +1 -0
  56. package/dist/providers/index.d.ts +6 -0
  57. package/dist/providers/index.js +9 -0
  58. package/dist/providers/index.js.map +1 -0
  59. package/dist/storage-BaRppHUz.d.ts +22 -0
  60. package/package.json +99 -0
  61. package/templates/app/(app)/_layout.tsx +216 -0
  62. package/templates/app/(app)/customer/[id].tsx +68 -0
  63. package/templates/app/(app)/customer/create.tsx +24 -0
  64. package/templates/app/(app)/customers.tsx +164 -0
  65. package/templates/app/(app)/index.tsx +310 -0
  66. package/templates/app/(app)/notifications.tsx +242 -0
  67. package/templates/app/(app)/profile.tsx +254 -0
  68. package/templates/app/(app)/settings.tsx +241 -0
  69. package/templates/app/(app)/task/[id].tsx +70 -0
  70. package/templates/app/(app)/task/create.tsx +24 -0
  71. package/templates/app/(app)/tasks.tsx +164 -0
  72. package/templates/app/_layout.tsx +54 -0
  73. package/templates/app/index.tsx +35 -0
  74. package/templates/app/login.tsx +179 -0
  75. package/templates/app.config.ts +39 -0
  76. package/templates/babel.config.js +9 -0
  77. package/templates/eas.json +18 -0
  78. package/templates/jest.config.js +12 -0
  79. package/templates/metro.config.js +23 -0
  80. package/templates/package.json.template +52 -0
  81. package/templates/src/components/entities/customers/CustomerCard.tsx +59 -0
  82. package/templates/src/components/entities/customers/CustomerForm.tsx +194 -0
  83. package/templates/src/components/entities/customers/index.ts +6 -0
  84. package/templates/src/components/entities/index.ts +9 -0
  85. package/templates/src/components/entities/tasks/TaskCard.tsx +89 -0
  86. package/templates/src/components/entities/tasks/TaskForm.tsx +231 -0
  87. package/templates/src/components/entities/tasks/index.ts +6 -0
  88. package/templates/src/components/features/index.ts +6 -0
  89. package/templates/src/components/navigation/BottomTabBar.tsx +80 -0
  90. package/templates/src/components/navigation/CreateSheet.tsx +108 -0
  91. package/templates/src/components/navigation/MoreSheet.tsx +403 -0
  92. package/templates/src/components/navigation/TopBar.tsx +74 -0
  93. package/templates/src/components/navigation/index.ts +8 -0
  94. package/templates/src/components/ui/index.ts +89 -0
  95. package/templates/src/components/ui/text.tsx +64 -0
  96. package/templates/src/config/api.config.ts +26 -0
  97. package/templates/src/config/app.config.ts +15 -0
  98. package/templates/src/config/hooks.ts +58 -0
  99. package/templates/src/config/permissions.config.ts +119 -0
  100. package/templates/src/constants/colors.ts +55 -0
  101. package/templates/src/data/notifications.mock.json +100 -0
  102. package/templates/src/entities/customers/api.ts +10 -0
  103. package/templates/src/entities/customers/constants.internal.ts +6 -0
  104. package/templates/src/entities/customers/constants.ts +14 -0
  105. package/templates/src/entities/customers/index.ts +9 -0
  106. package/templates/src/entities/customers/mutations.ts +58 -0
  107. package/templates/src/entities/customers/queries.ts +40 -0
  108. package/templates/src/entities/customers/types.ts +43 -0
  109. package/templates/src/entities/index.ts +8 -0
  110. package/templates/src/entities/tasks/api.ts +10 -0
  111. package/templates/src/entities/tasks/constants.internal.ts +6 -0
  112. package/templates/src/entities/tasks/constants.ts +39 -0
  113. package/templates/src/entities/tasks/index.ts +9 -0
  114. package/templates/src/entities/tasks/mutations.ts +108 -0
  115. package/templates/src/entities/tasks/queries.ts +42 -0
  116. package/templates/src/entities/tasks/types.ts +52 -0
  117. package/templates/src/hooks/useCustomers.ts +17 -0
  118. package/templates/src/hooks/useTasks.ts +18 -0
  119. package/templates/src/lib/utils.ts +10 -0
  120. package/templates/src/styles/globals.css +103 -0
  121. package/templates/src/types/index.ts +45 -0
  122. package/templates/tailwind.config.js +108 -0
  123. package/templates/tsconfig.json +15 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Settings Screen
3
+ */
4
+
5
+ import { View, Text, TouchableOpacity, ScrollView, StyleSheet, Switch } from 'react-native'
6
+ import { useState } from 'react'
7
+ import { router } from 'expo-router'
8
+ import { Colors } from '@/src/constants/colors'
9
+
10
+ interface SettingItem {
11
+ key: string
12
+ label: string
13
+ description?: string
14
+ icon: string
15
+ type: 'navigation' | 'toggle'
16
+ screen?: string
17
+ }
18
+
19
+ const SETTINGS_SECTIONS = [
20
+ {
21
+ title: 'Cuenta',
22
+ items: [
23
+ {
24
+ key: 'profile',
25
+ label: 'Información Personal',
26
+ description: 'Nombre, email, idioma',
27
+ icon: '👤',
28
+ type: 'navigation' as const,
29
+ screen: 'profile',
30
+ },
31
+ {
32
+ key: 'security',
33
+ label: 'Seguridad',
34
+ description: 'Contraseña, autenticación',
35
+ icon: '🔒',
36
+ type: 'navigation' as const,
37
+ },
38
+ ],
39
+ },
40
+ {
41
+ title: 'Preferencias',
42
+ items: [
43
+ {
44
+ key: 'notifications',
45
+ label: 'Notificaciones',
46
+ icon: '🔔',
47
+ type: 'toggle' as const,
48
+ },
49
+ {
50
+ key: 'darkMode',
51
+ label: 'Modo Oscuro',
52
+ icon: '🌙',
53
+ type: 'toggle' as const,
54
+ },
55
+ ],
56
+ },
57
+ {
58
+ title: 'Soporte',
59
+ items: [
60
+ {
61
+ key: 'help',
62
+ label: 'Centro de Ayuda',
63
+ icon: '❓',
64
+ type: 'navigation' as const,
65
+ },
66
+ {
67
+ key: 'feedback',
68
+ label: 'Enviar Comentarios',
69
+ icon: '💬',
70
+ type: 'navigation' as const,
71
+ },
72
+ ],
73
+ },
74
+ ]
75
+
76
+ export default function SettingsScreen() {
77
+ const [toggleStates, setToggleStates] = useState<Record<string, boolean>>({
78
+ notifications: true,
79
+ darkMode: false,
80
+ })
81
+
82
+ const handleToggle = (key: string) => {
83
+ setToggleStates((prev) => ({ ...prev, [key]: !prev[key] }))
84
+ }
85
+
86
+ const handleNavigation = (item: SettingItem) => {
87
+ if (item.screen) {
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ router.push(`/(app)/${item.screen}` as any)
90
+ }
91
+ }
92
+
93
+ return (
94
+ <ScrollView style={styles.container}>
95
+ {/* Page Header */}
96
+ <View style={styles.header}>
97
+ <Text style={styles.pageTitle}>Ajustes</Text>
98
+ <Text style={styles.pageSubtitle}>
99
+ Configura tu cuenta y preferencias
100
+ </Text>
101
+ </View>
102
+
103
+ {/* Settings Sections */}
104
+ {SETTINGS_SECTIONS.map((section) => (
105
+ <View key={section.title} style={styles.section}>
106
+ <Text style={styles.sectionTitle}>{section.title}</Text>
107
+ <View style={styles.sectionContent}>
108
+ {section.items.map((item, index) => (
109
+ <TouchableOpacity
110
+ key={item.key}
111
+ style={[
112
+ styles.settingItem,
113
+ index < section.items.length - 1 && styles.settingItemBorder,
114
+ ]}
115
+ onPress={() =>
116
+ item.type === 'navigation'
117
+ ? handleNavigation(item)
118
+ : handleToggle(item.key)
119
+ }
120
+ activeOpacity={0.7}
121
+ >
122
+ <Text style={styles.settingIcon}>{item.icon}</Text>
123
+ <View style={styles.settingInfo}>
124
+ <Text style={styles.settingLabel}>{item.label}</Text>
125
+ {'description' in item && item.description && (
126
+ <Text style={styles.settingDescription}>
127
+ {item.description}
128
+ </Text>
129
+ )}
130
+ </View>
131
+ {item.type === 'navigation' ? (
132
+ <Text style={styles.chevron}>›</Text>
133
+ ) : (
134
+ <Switch
135
+ value={toggleStates[item.key]}
136
+ onValueChange={() => handleToggle(item.key)}
137
+ trackColor={{
138
+ false: Colors.border,
139
+ true: Colors.primary,
140
+ }}
141
+ thumbColor={Colors.background}
142
+ />
143
+ )}
144
+ </TouchableOpacity>
145
+ ))}
146
+ </View>
147
+ </View>
148
+ ))}
149
+
150
+ {/* App Version */}
151
+ <View style={styles.footer}>
152
+ <Text style={styles.versionText}>NextSpark Mobile v1.0.0</Text>
153
+ </View>
154
+
155
+ <View style={styles.spacer} />
156
+ </ScrollView>
157
+ )
158
+ }
159
+
160
+ const styles = StyleSheet.create({
161
+ container: {
162
+ flex: 1,
163
+ backgroundColor: Colors.backgroundSecondary,
164
+ },
165
+ header: {
166
+ padding: 20,
167
+ paddingBottom: 12,
168
+ },
169
+ pageTitle: {
170
+ fontSize: 28,
171
+ fontWeight: '700',
172
+ color: Colors.foreground,
173
+ marginBottom: 4,
174
+ },
175
+ pageSubtitle: {
176
+ fontSize: 15,
177
+ color: Colors.foregroundSecondary,
178
+ },
179
+ section: {
180
+ marginBottom: 24,
181
+ },
182
+ sectionTitle: {
183
+ fontSize: 13,
184
+ fontWeight: '600',
185
+ color: Colors.foregroundSecondary,
186
+ textTransform: 'uppercase',
187
+ letterSpacing: 0.5,
188
+ marginHorizontal: 20,
189
+ marginBottom: 8,
190
+ },
191
+ sectionContent: {
192
+ backgroundColor: Colors.card,
193
+ marginHorizontal: 16,
194
+ borderRadius: 12,
195
+ borderWidth: 1,
196
+ borderColor: Colors.border,
197
+ },
198
+ settingItem: {
199
+ flexDirection: 'row',
200
+ alignItems: 'center',
201
+ paddingVertical: 14,
202
+ paddingHorizontal: 16,
203
+ },
204
+ settingItemBorder: {
205
+ borderBottomWidth: 1,
206
+ borderBottomColor: Colors.border,
207
+ },
208
+ settingIcon: {
209
+ fontSize: 20,
210
+ width: 32,
211
+ },
212
+ settingInfo: {
213
+ flex: 1,
214
+ },
215
+ settingLabel: {
216
+ fontSize: 16,
217
+ color: Colors.foreground,
218
+ fontWeight: '400',
219
+ },
220
+ settingDescription: {
221
+ fontSize: 13,
222
+ color: Colors.foregroundSecondary,
223
+ marginTop: 2,
224
+ },
225
+ chevron: {
226
+ fontSize: 24,
227
+ color: Colors.foregroundMuted,
228
+ fontWeight: '300',
229
+ },
230
+ footer: {
231
+ alignItems: 'center',
232
+ paddingVertical: 20,
233
+ },
234
+ versionText: {
235
+ fontSize: 13,
236
+ color: Colors.foregroundMuted,
237
+ },
238
+ spacer: {
239
+ height: 40,
240
+ },
241
+ })
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Edit Task Screen
3
+ */
4
+
5
+ import { View, Text, ActivityIndicator, StyleSheet } from 'react-native'
6
+ import { useLocalSearchParams, router } from 'expo-router'
7
+ import { TaskForm } from '@/src/components/entities/tasks'
8
+ import { useTask, useUpdateTask, useDeleteTask, type UpdateTaskInput } from '@/src/entities/tasks'
9
+
10
+ export default function EditTaskScreen() {
11
+ const { id } = useLocalSearchParams<{ id: string }>()
12
+ const { data, isLoading, error } = useTask(id)
13
+ const updateTask = useUpdateTask()
14
+ const deleteTask = useDeleteTask()
15
+
16
+ const handleSubmit = async (formData: UpdateTaskInput) => {
17
+ if (!id) return
18
+ await updateTask.mutateAsync({ id, data: formData })
19
+ router.back()
20
+ }
21
+
22
+ const handleDelete = async () => {
23
+ if (!id) return
24
+ await deleteTask.mutateAsync(id)
25
+ router.back()
26
+ }
27
+
28
+ if (isLoading) {
29
+ return (
30
+ <View style={styles.centerContainer}>
31
+ <ActivityIndicator size="large" color="#3B82F6" />
32
+ </View>
33
+ )
34
+ }
35
+
36
+ if (error || !data) {
37
+ return (
38
+ <View style={styles.centerContainer}>
39
+ <Text style={styles.errorText}>
40
+ {error instanceof Error ? error.message : 'Task not found'}
41
+ </Text>
42
+ </View>
43
+ )
44
+ }
45
+
46
+ return (
47
+ <TaskForm
48
+ mode="edit"
49
+ initialData={data.data}
50
+ onSubmit={handleSubmit}
51
+ onDelete={handleDelete}
52
+ isLoading={updateTask.isPending || deleteTask.isPending}
53
+ />
54
+ )
55
+ }
56
+
57
+ const styles = StyleSheet.create({
58
+ centerContainer: {
59
+ flex: 1,
60
+ justifyContent: 'center',
61
+ alignItems: 'center',
62
+ backgroundColor: '#F9FAFB',
63
+ },
64
+ errorText: {
65
+ fontSize: 16,
66
+ color: '#DC2626',
67
+ textAlign: 'center',
68
+ paddingHorizontal: 32,
69
+ },
70
+ })
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Create Task Screen
3
+ */
4
+
5
+ import { router } from 'expo-router'
6
+ import { TaskForm } from '@/src/components/entities/tasks'
7
+ import { useCreateTask, type CreateTaskInput } from '@/src/entities/tasks'
8
+
9
+ export default function CreateTaskScreen() {
10
+ const createTask = useCreateTask()
11
+
12
+ const handleSubmit = async (data: CreateTaskInput) => {
13
+ await createTask.mutateAsync(data)
14
+ router.back()
15
+ }
16
+
17
+ return (
18
+ <TaskForm
19
+ mode="create"
20
+ onSubmit={handleSubmit}
21
+ isLoading={createTask.isPending}
22
+ />
23
+ )
24
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Tasks List Screen
3
+ */
4
+
5
+ import { useCallback, useState } from 'react'
6
+ import {
7
+ View,
8
+ Text,
9
+ FlatList,
10
+ RefreshControl,
11
+ StyleSheet,
12
+ } from 'react-native'
13
+ import { router } from 'expo-router'
14
+ import { useTasks, type Task } from '@/src/entities/tasks'
15
+ import { TaskCard } from '@/src/components/entities/tasks'
16
+ import { Button } from '@/src/components/ui'
17
+ import { Colors } from '@/src/constants/colors'
18
+
19
+ export default function TasksScreen() {
20
+ const { data, isLoading, error, refetch } = useTasks()
21
+ const [refreshing, setRefreshing] = useState(false)
22
+
23
+ const onRefresh = useCallback(async () => {
24
+ setRefreshing(true)
25
+ try {
26
+ await refetch()
27
+ } finally {
28
+ setRefreshing(false)
29
+ }
30
+ }, [refetch])
31
+
32
+ const handleTaskPress = (task: Task) => {
33
+ router.push(`/(app)/task/${task.id}`)
34
+ }
35
+
36
+ const renderTask = ({ item }: { item: Task }) => (
37
+ <TaskCard task={item} onPress={() => handleTaskPress(item)} />
38
+ )
39
+
40
+ const renderEmpty = () => {
41
+ if (isLoading) return null
42
+
43
+ return (
44
+ <View style={styles.emptyContainer}>
45
+ <Text style={styles.emptyIcon}>☑</Text>
46
+ <Text style={styles.emptyTitle}>Sin tareas</Text>
47
+ <Text style={styles.emptyText}>
48
+ Toca el botón Crear para agregar tu primera tarea
49
+ </Text>
50
+ </View>
51
+ )
52
+ }
53
+
54
+ const renderError = () => (
55
+ <View style={styles.errorContainer}>
56
+ <Text style={styles.errorTitle}>Algo salió mal</Text>
57
+ <Text style={styles.errorText}>
58
+ {error instanceof Error ? error.message : 'Error al cargar tareas'}
59
+ </Text>
60
+ <Button onPress={() => refetch()}>
61
+ Reintentar
62
+ </Button>
63
+ </View>
64
+ )
65
+
66
+ return (
67
+ <View style={styles.container}>
68
+ {/* Page Header */}
69
+ <View style={styles.header}>
70
+ <Text style={styles.pageTitle}>Tareas</Text>
71
+ <Text style={styles.pageSubtitle}>
72
+ Gestiona y organiza tus tareas pendientes
73
+ </Text>
74
+ </View>
75
+
76
+ {/* Error State */}
77
+ {error && renderError()}
78
+
79
+ {/* Tasks List */}
80
+ {!error && (
81
+ <FlatList
82
+ data={data?.data || []}
83
+ renderItem={renderTask}
84
+ keyExtractor={(item) => item.id}
85
+ contentContainerStyle={styles.listContent}
86
+ refreshControl={
87
+ <RefreshControl
88
+ refreshing={refreshing}
89
+ onRefresh={onRefresh}
90
+ tintColor={Colors.primary}
91
+ />
92
+ }
93
+ ListEmptyComponent={renderEmpty}
94
+ showsVerticalScrollIndicator={false}
95
+ />
96
+ )}
97
+ </View>
98
+ )
99
+ }
100
+
101
+ const styles = StyleSheet.create({
102
+ container: {
103
+ flex: 1,
104
+ backgroundColor: Colors.backgroundSecondary,
105
+ },
106
+ header: {
107
+ padding: 20,
108
+ paddingBottom: 12,
109
+ },
110
+ pageTitle: {
111
+ fontSize: 28,
112
+ fontWeight: '700',
113
+ color: Colors.foreground,
114
+ marginBottom: 4,
115
+ },
116
+ pageSubtitle: {
117
+ fontSize: 15,
118
+ color: Colors.foregroundSecondary,
119
+ },
120
+ listContent: {
121
+ paddingBottom: 12,
122
+ flexGrow: 1,
123
+ },
124
+ emptyContainer: {
125
+ flex: 1,
126
+ justifyContent: 'center',
127
+ alignItems: 'center',
128
+ paddingHorizontal: 32,
129
+ },
130
+ emptyIcon: {
131
+ fontSize: 48,
132
+ marginBottom: 16,
133
+ opacity: 0.5,
134
+ },
135
+ emptyTitle: {
136
+ fontSize: 18,
137
+ fontWeight: '600',
138
+ color: Colors.foreground,
139
+ marginBottom: 8,
140
+ },
141
+ emptyText: {
142
+ fontSize: 14,
143
+ color: Colors.foregroundSecondary,
144
+ textAlign: 'center',
145
+ },
146
+ errorContainer: {
147
+ flex: 1,
148
+ justifyContent: 'center',
149
+ alignItems: 'center',
150
+ paddingHorizontal: 32,
151
+ },
152
+ errorTitle: {
153
+ fontSize: 18,
154
+ fontWeight: '600',
155
+ color: Colors.destructive,
156
+ marginBottom: 8,
157
+ },
158
+ errorText: {
159
+ fontSize: 14,
160
+ color: Colors.foregroundSecondary,
161
+ textAlign: 'center',
162
+ marginBottom: 16,
163
+ },
164
+ })
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Root Layout - Sets up providers
3
+ */
4
+
5
+ import "../src/styles/globals.css";
6
+
7
+ import { Stack } from "expo-router";
8
+ import { StatusBar } from "expo-status-bar";
9
+ import { QueryProvider, AuthProvider } from "@nextsparkjs/mobile";
10
+ import { ThemeProvider } from "@nextsparkjs/ui";
11
+
12
+ /**
13
+ * Custom colors demo - Override any color from ThemeColors
14
+ * These match the web app's default design system.
15
+ * Uncomment and modify to customize your app's theme.
16
+ */
17
+ const customColors = {
18
+ // Primary: Dark neutral (matches web)
19
+ primary: "#171717",
20
+ primaryForeground: "#fafafa",
21
+
22
+ // Secondary: Light gray
23
+ secondary: "#f5f5f5",
24
+ secondaryForeground: "#1a1a1a",
25
+
26
+ // Destructive: Red for errors/danger
27
+ destructive: "#ef4444",
28
+ destructiveForeground: "#FFFFFF",
29
+
30
+ // Success: Green for confirmations
31
+ success: "#22c55e",
32
+ successForeground: "#FFFFFF",
33
+ };
34
+
35
+ export default function RootLayout() {
36
+ return (
37
+ <QueryProvider>
38
+ <AuthProvider>
39
+ <ThemeProvider colors={customColors}>
40
+ <StatusBar style="auto" />
41
+ <Stack
42
+ screenOptions={{
43
+ headerShown: false,
44
+ }}
45
+ >
46
+ <Stack.Screen name="index" />
47
+ <Stack.Screen name="login" />
48
+ <Stack.Screen name="(app)" />
49
+ </Stack>
50
+ </ThemeProvider>
51
+ </AuthProvider>
52
+ </QueryProvider>
53
+ );
54
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Entry point - Redirects based on auth state
3
+ */
4
+
5
+ import { useEffect } from 'react'
6
+ import { View, ActivityIndicator, StyleSheet } from 'react-native'
7
+ import { Redirect } from 'expo-router'
8
+ import { useAuth } from '@nextsparkjs/mobile'
9
+
10
+ export default function Index() {
11
+ const { isAuthenticated, isLoading } = useAuth()
12
+
13
+ if (isLoading) {
14
+ return (
15
+ <View style={styles.container}>
16
+ <ActivityIndicator size="large" color="#3B82F6" />
17
+ </View>
18
+ )
19
+ }
20
+
21
+ if (isAuthenticated) {
22
+ return <Redirect href="/(app)" />
23
+ }
24
+
25
+ return <Redirect href="/login" />
26
+ }
27
+
28
+ const styles = StyleSheet.create({
29
+ container: {
30
+ flex: 1,
31
+ justifyContent: 'center',
32
+ alignItems: 'center',
33
+ backgroundColor: '#F9FAFB',
34
+ },
35
+ })