@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,403 @@
1
+ /**
2
+ * MoreSheet Component - "Más Opciones" bottom sheet
3
+ * With team switching functionality
4
+ */
5
+
6
+ import { useState } from 'react'
7
+ import {
8
+ View,
9
+ Text,
10
+ TouchableOpacity,
11
+ StyleSheet,
12
+ Modal,
13
+ Pressable,
14
+ ScrollView,
15
+ } from 'react-native'
16
+ import { Colors } from '../../constants/colors'
17
+ import { useAuth } from '@nextsparkjs/mobile'
18
+ import { Button } from '../ui'
19
+ import type { Team } from '../../types'
20
+
21
+ interface MoreSheetProps {
22
+ visible: boolean
23
+ onClose: () => void
24
+ onNavigate: (screen: string) => void
25
+ onLogout: () => void
26
+ onTeamChange?: () => void
27
+ }
28
+
29
+ interface MenuItem {
30
+ key: string
31
+ label: string
32
+ icon: string
33
+ screen?: string
34
+ }
35
+
36
+ const MENU_ITEMS: MenuItem[] = [
37
+ { key: 'profile', label: 'Perfil', icon: '👤', screen: 'profile' },
38
+ { key: 'billing', label: 'Facturación', icon: '💳', screen: 'billing' },
39
+ { key: 'api-keys', label: 'Claves API', icon: '🔑', screen: 'api-keys' },
40
+ { key: 'settings', label: 'Ajustes', icon: '⚙', screen: 'settings' },
41
+ ]
42
+
43
+ export function MoreSheet({
44
+ visible,
45
+ onClose,
46
+ onNavigate,
47
+ onLogout,
48
+ onTeamChange,
49
+ }: MoreSheetProps) {
50
+ const { team, teams, selectTeam } = useAuth()
51
+ const [showTeamList, setShowTeamList] = useState(false)
52
+
53
+ const handleMenuItem = (item: MenuItem) => {
54
+ if (item.screen) {
55
+ onNavigate(item.screen)
56
+ onClose()
57
+ }
58
+ }
59
+
60
+ const handleTeamSelect = async (selectedTeam: Team) => {
61
+ if (selectedTeam.id !== team?.id) {
62
+ await selectTeam(selectedTeam)
63
+ setShowTeamList(false)
64
+ onClose()
65
+ // Callback to refresh data in the app
66
+ onTeamChange?.()
67
+ } else {
68
+ setShowTeamList(false)
69
+ }
70
+ }
71
+
72
+ const toggleTeamList = () => {
73
+ setShowTeamList(!showTeamList)
74
+ }
75
+
76
+ return (
77
+ <Modal
78
+ visible={visible}
79
+ transparent
80
+ animationType="slide"
81
+ onRequestClose={onClose}
82
+ >
83
+ <Pressable style={styles.overlay} onPress={onClose}>
84
+ <Pressable style={styles.sheet} onPress={(e) => e.stopPropagation()}>
85
+ {/* Handle bar */}
86
+ <View style={styles.handleBar} />
87
+
88
+ {/* Close button */}
89
+ <TouchableOpacity style={styles.closeButton} onPress={onClose}>
90
+ <Text style={styles.closeIcon}>✕</Text>
91
+ </TouchableOpacity>
92
+
93
+ {/* Header */}
94
+ <Text style={styles.title}>Más Opciones</Text>
95
+ <Text style={styles.subtitle}>
96
+ Accede a configuraciones y funciones adicionales
97
+ </Text>
98
+
99
+ <ScrollView showsVerticalScrollIndicator={false}>
100
+ {/* Menu Items */}
101
+ <View style={styles.menuSection}>
102
+ {MENU_ITEMS.map((item) => (
103
+ <TouchableOpacity
104
+ key={item.key}
105
+ style={styles.menuItem}
106
+ onPress={() => handleMenuItem(item)}
107
+ activeOpacity={0.7}
108
+ >
109
+ <Text style={styles.menuIcon}>{item.icon}</Text>
110
+ <Text style={styles.menuLabel}>{item.label}</Text>
111
+ </TouchableOpacity>
112
+ ))}
113
+ </View>
114
+
115
+ {/* Team Section */}
116
+ {team && teams.length > 0 && (
117
+ <>
118
+ <View style={styles.divider} />
119
+
120
+ {/* Current Team - Clickable to toggle list */}
121
+ <TouchableOpacity
122
+ style={styles.teamItem}
123
+ onPress={toggleTeamList}
124
+ activeOpacity={0.7}
125
+ >
126
+ <View style={styles.teamAvatar}>
127
+ <Text style={styles.teamAvatarText}>
128
+ {team.name.substring(0, 2).toUpperCase()}
129
+ </Text>
130
+ </View>
131
+ <View style={styles.teamInfo}>
132
+ <Text style={styles.teamName}>{team.name}</Text>
133
+ <View style={styles.teamRoleRow}>
134
+ <Text style={styles.teamRoleIcon}>👥</Text>
135
+ <Text style={styles.teamRoleText}>
136
+ {teams.length > 1 ? `${teams.length} equipos disponibles` : 'Equipo'}
137
+ </Text>
138
+ </View>
139
+ </View>
140
+ <Text style={[styles.chevron, showTeamList && styles.chevronOpen]}>
141
+ {showTeamList ? '⌄' : '⌃'}
142
+ </Text>
143
+ </TouchableOpacity>
144
+
145
+ {/* Team List (expandable) */}
146
+ {showTeamList && teams.length > 1 && (
147
+ <View style={styles.teamListContainer}>
148
+ <Text style={styles.teamListTitle}>Cambiar de equipo</Text>
149
+ {teams.map((t) => {
150
+ const isCurrentTeam = t.id === team.id
151
+ return (
152
+ <TouchableOpacity
153
+ key={t.id}
154
+ style={[
155
+ styles.teamListItem,
156
+ isCurrentTeam && styles.teamListItemActive,
157
+ ]}
158
+ onPress={() => handleTeamSelect(t)}
159
+ activeOpacity={0.7}
160
+ >
161
+ <View style={[
162
+ styles.teamListAvatar,
163
+ isCurrentTeam && styles.teamListAvatarActive,
164
+ ]}>
165
+ <Text style={[
166
+ styles.teamListAvatarText,
167
+ isCurrentTeam && styles.teamListAvatarTextActive,
168
+ ]}>
169
+ {t.name.substring(0, 2).toUpperCase()}
170
+ </Text>
171
+ </View>
172
+ <View style={styles.teamListInfo}>
173
+ <Text style={[
174
+ styles.teamListName,
175
+ isCurrentTeam && styles.teamListNameActive,
176
+ ]}>
177
+ {t.name}
178
+ </Text>
179
+ <Text style={styles.teamListRole}>
180
+ {t.role}
181
+ </Text>
182
+ </View>
183
+ {isCurrentTeam && (
184
+ <Text style={styles.checkmark}>✓</Text>
185
+ )}
186
+ </TouchableOpacity>
187
+ )
188
+ })}
189
+ </View>
190
+ )}
191
+ </>
192
+ )}
193
+
194
+ {/* Logout */}
195
+ <View style={styles.divider} />
196
+ <Button
197
+ variant="destructive"
198
+ onPress={onLogout}
199
+ >
200
+ Cerrar Sesión
201
+ </Button>
202
+ </ScrollView>
203
+ </Pressable>
204
+ </Pressable>
205
+ </Modal>
206
+ )
207
+ }
208
+
209
+ const styles = StyleSheet.create({
210
+ overlay: {
211
+ flex: 1,
212
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
213
+ justifyContent: 'flex-end',
214
+ },
215
+ sheet: {
216
+ backgroundColor: Colors.background,
217
+ borderTopLeftRadius: 20,
218
+ borderTopRightRadius: 20,
219
+ paddingHorizontal: 24,
220
+ paddingBottom: 40,
221
+ paddingTop: 12,
222
+ maxHeight: '85%',
223
+ },
224
+ handleBar: {
225
+ width: 40,
226
+ height: 4,
227
+ backgroundColor: Colors.borderSecondary,
228
+ borderRadius: 2,
229
+ alignSelf: 'center',
230
+ marginBottom: 16,
231
+ },
232
+ closeButton: {
233
+ position: 'absolute',
234
+ top: 20,
235
+ right: 20,
236
+ width: 32,
237
+ height: 32,
238
+ borderRadius: 16,
239
+ borderWidth: 1,
240
+ borderColor: Colors.border,
241
+ justifyContent: 'center',
242
+ alignItems: 'center',
243
+ zIndex: 10,
244
+ },
245
+ closeIcon: {
246
+ fontSize: 16,
247
+ color: Colors.foregroundSecondary,
248
+ },
249
+ title: {
250
+ fontSize: 20,
251
+ fontWeight: '600',
252
+ color: Colors.foreground,
253
+ textAlign: 'center',
254
+ marginTop: 8,
255
+ },
256
+ subtitle: {
257
+ fontSize: 14,
258
+ color: Colors.foregroundSecondary,
259
+ textAlign: 'center',
260
+ marginTop: 8,
261
+ marginBottom: 24,
262
+ },
263
+ menuSection: {
264
+ gap: 4,
265
+ },
266
+ menuItem: {
267
+ flexDirection: 'row',
268
+ alignItems: 'center',
269
+ paddingVertical: 14,
270
+ gap: 16,
271
+ },
272
+ menuIcon: {
273
+ fontSize: 20,
274
+ width: 28,
275
+ textAlign: 'center',
276
+ },
277
+ menuLabel: {
278
+ fontSize: 16,
279
+ color: Colors.foreground,
280
+ fontWeight: '400',
281
+ },
282
+ divider: {
283
+ height: 1,
284
+ backgroundColor: Colors.border,
285
+ marginVertical: 16,
286
+ },
287
+ teamItem: {
288
+ flexDirection: 'row',
289
+ alignItems: 'center',
290
+ paddingVertical: 8,
291
+ gap: 12,
292
+ },
293
+ teamAvatar: {
294
+ width: 40,
295
+ height: 40,
296
+ borderRadius: 20,
297
+ backgroundColor: Colors.backgroundTertiary,
298
+ justifyContent: 'center',
299
+ alignItems: 'center',
300
+ borderWidth: 1,
301
+ borderColor: Colors.border,
302
+ },
303
+ teamAvatarText: {
304
+ fontSize: 12,
305
+ fontWeight: '600',
306
+ color: Colors.foregroundSecondary,
307
+ },
308
+ teamInfo: {
309
+ flex: 1,
310
+ },
311
+ teamName: {
312
+ fontSize: 14,
313
+ fontWeight: '600',
314
+ color: Colors.foreground,
315
+ },
316
+ teamRoleRow: {
317
+ flexDirection: 'row',
318
+ alignItems: 'center',
319
+ gap: 4,
320
+ marginTop: 2,
321
+ },
322
+ teamRoleIcon: {
323
+ fontSize: 12,
324
+ },
325
+ teamRoleText: {
326
+ fontSize: 12,
327
+ color: Colors.foregroundSecondary,
328
+ },
329
+ chevron: {
330
+ fontSize: 14,
331
+ color: Colors.foregroundSecondary,
332
+ },
333
+ chevronOpen: {
334
+ transform: [{ rotate: '180deg' }],
335
+ },
336
+ teamListContainer: {
337
+ marginTop: 12,
338
+ paddingLeft: 8,
339
+ },
340
+ teamListTitle: {
341
+ fontSize: 12,
342
+ fontWeight: '600',
343
+ color: Colors.foregroundSecondary,
344
+ textTransform: 'uppercase',
345
+ letterSpacing: 0.5,
346
+ marginBottom: 12,
347
+ },
348
+ teamListItem: {
349
+ flexDirection: 'row',
350
+ alignItems: 'center',
351
+ paddingVertical: 10,
352
+ paddingHorizontal: 12,
353
+ marginBottom: 4,
354
+ borderRadius: 8,
355
+ gap: 12,
356
+ },
357
+ teamListItemActive: {
358
+ backgroundColor: Colors.backgroundTertiary,
359
+ },
360
+ teamListAvatar: {
361
+ width: 36,
362
+ height: 36,
363
+ borderRadius: 18,
364
+ backgroundColor: Colors.backgroundSecondary,
365
+ justifyContent: 'center',
366
+ alignItems: 'center',
367
+ borderWidth: 1,
368
+ borderColor: Colors.border,
369
+ },
370
+ teamListAvatarActive: {
371
+ backgroundColor: Colors.primary,
372
+ borderColor: Colors.primary,
373
+ },
374
+ teamListAvatarText: {
375
+ fontSize: 11,
376
+ fontWeight: '600',
377
+ color: Colors.foregroundSecondary,
378
+ },
379
+ teamListAvatarTextActive: {
380
+ color: Colors.primaryForeground,
381
+ },
382
+ teamListInfo: {
383
+ flex: 1,
384
+ },
385
+ teamListName: {
386
+ fontSize: 14,
387
+ fontWeight: '500',
388
+ color: Colors.foreground,
389
+ },
390
+ teamListNameActive: {
391
+ fontWeight: '600',
392
+ },
393
+ teamListRole: {
394
+ fontSize: 12,
395
+ color: Colors.foregroundSecondary,
396
+ marginTop: 1,
397
+ },
398
+ checkmark: {
399
+ fontSize: 16,
400
+ color: Colors.success,
401
+ fontWeight: '600',
402
+ },
403
+ })
@@ -0,0 +1,74 @@
1
+ /**
2
+ * TopBar Component - NextSpark Mobile Style
3
+ * Shows user avatar, greeting, notifications, and theme toggle
4
+ * Migrated to NativeWind + UI primitives + Lucide icons
5
+ */
6
+
7
+ import { View, Pressable } from "react-native";
8
+ import { router } from "expo-router";
9
+ import { Bell, Moon } from "lucide-react-native";
10
+ import { useAuth } from "@nextsparkjs/mobile";
11
+ import {
12
+ Text,
13
+ Avatar,
14
+ AvatarImage,
15
+ AvatarFallback,
16
+ getInitials,
17
+ Badge,
18
+ } from "../ui";
19
+
20
+ interface TopBarProps {
21
+ notificationCount?: number;
22
+ }
23
+
24
+ export function TopBar({ notificationCount = 0 }: TopBarProps) {
25
+ const { user } = useAuth();
26
+
27
+ // Get first name for greeting
28
+ const getFirstName = (name?: string | null) => {
29
+ if (!name) return "Usuario";
30
+ return name.split(" ")[0];
31
+ };
32
+
33
+ return (
34
+ <View className="flex-row items-center justify-between border-b border-border bg-background px-4 py-3">
35
+ {/* Left: Avatar + Greeting */}
36
+ <View className="flex-row items-center gap-3">
37
+ <Avatar style={{ backgroundColor: "#f59e0b" }}>
38
+ <AvatarImage src={user?.image} />
39
+ <AvatarFallback style={{ backgroundColor: "#f59e0b" }}>
40
+ {getInitials(user?.name)}
41
+ </AvatarFallback>
42
+ </Avatar>
43
+ <Text weight="medium" className="text-base">
44
+ Hola, {getFirstName(user?.name)}
45
+ </Text>
46
+ </View>
47
+
48
+ {/* Right: Notifications + Theme Toggle */}
49
+ <View className="flex-row items-center gap-2">
50
+ {/* Notification Bell */}
51
+ <Pressable
52
+ onPress={() => router.push("/(app)/notifications")}
53
+ className="relative h-10 w-10 items-center justify-center"
54
+ >
55
+ <Bell size={22} color="#171717" />
56
+ {notificationCount > 0 && (
57
+ <View className="absolute right-1 top-1">
58
+ <Badge variant="destructive" className="min-w-[18px] px-1 py-0.5">
59
+ <Text className="text-[10px] font-bold text-destructive-foreground">
60
+ {notificationCount > 9 ? "9+" : notificationCount}
61
+ </Text>
62
+ </Badge>
63
+ </View>
64
+ )}
65
+ </Pressable>
66
+
67
+ {/* Theme Toggle (Moon Icon) */}
68
+ <Pressable className="h-10 w-10 items-center justify-center">
69
+ <Moon size={22} color="#171717" />
70
+ </Pressable>
71
+ </View>
72
+ </View>
73
+ );
74
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Navigation components - barrel exports
3
+ */
4
+
5
+ export { BottomTabBar, type TabKey } from './BottomTabBar'
6
+ export { TopBar } from './TopBar'
7
+ export { CreateSheet } from './CreateSheet'
8
+ export { MoreSheet } from './MoreSheet'
@@ -0,0 +1,89 @@
1
+ /**
2
+ * UI Components - Barrel Exports
3
+ * Re-export ALL from shared @nextsparkjs/ui package
4
+ */
5
+
6
+ // Core primitives - Mobile specific (uses NativeWind locally)
7
+ export { Text, type TextProps } from "./text";
8
+
9
+ // Theme system
10
+ export {
11
+ ThemeProvider,
12
+ useTheme,
13
+ defaultColors,
14
+ type ThemeProviderProps,
15
+ type ThemeColors,
16
+ } from "@nextsparkjs/ui";
17
+
18
+ // Re-exported from shared package for web/mobile compatibility
19
+ export { Button, type ButtonProps, buttonVariants } from "@nextsparkjs/ui";
20
+ export { Input, type InputProps } from "@nextsparkjs/ui";
21
+ export { Textarea, type TextareaProps } from "@nextsparkjs/ui";
22
+
23
+ // Display components
24
+ export {
25
+ Badge,
26
+ PressableBadge,
27
+ type BadgeProps,
28
+ type PressableBadgeProps,
29
+ type BadgeVariant,
30
+ } from "@nextsparkjs/ui";
31
+ export {
32
+ Avatar,
33
+ AvatarImage,
34
+ AvatarFallback,
35
+ getInitials,
36
+ type AvatarProps,
37
+ type AvatarImageProps,
38
+ type AvatarFallbackProps,
39
+ type AvatarSize,
40
+ } from "@nextsparkjs/ui";
41
+ export {
42
+ Card,
43
+ PressableCard,
44
+ CardHeader,
45
+ CardTitle,
46
+ CardDescription,
47
+ CardContent,
48
+ CardFooter,
49
+ type CardProps,
50
+ type PressableCardProps,
51
+ type CardHeaderProps,
52
+ type CardTitleProps,
53
+ type CardDescriptionProps,
54
+ type CardContentProps,
55
+ type CardFooterProps,
56
+ } from "@nextsparkjs/ui";
57
+ export { Separator, type SeparatorProps } from "@nextsparkjs/ui";
58
+ export {
59
+ Skeleton,
60
+ SkeletonText,
61
+ SkeletonTitle,
62
+ SkeletonAvatar,
63
+ SkeletonCard,
64
+ type SkeletonProps,
65
+ } from "@nextsparkjs/ui";
66
+
67
+ // Form components
68
+ export { Checkbox, type CheckboxProps } from "@nextsparkjs/ui";
69
+ export { Switch, type SwitchProps } from "@nextsparkjs/ui";
70
+ export { Select, type SelectProps, type SelectOption } from "@nextsparkjs/ui";
71
+ export { Label, type LabelProps } from "@nextsparkjs/ui";
72
+
73
+ // Overlay components
74
+ export {
75
+ Dialog,
76
+ DialogContent,
77
+ DialogHeader,
78
+ DialogTitle,
79
+ DialogDescription,
80
+ DialogFooter,
81
+ DialogClose,
82
+ type DialogProps,
83
+ type DialogContentProps,
84
+ type DialogHeaderProps,
85
+ type DialogTitleProps,
86
+ type DialogDescriptionProps,
87
+ type DialogFooterProps,
88
+ type DialogCloseProps,
89
+ } from "@nextsparkjs/ui";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Text Component - Styled text with variants
3
+ * Following shadcn/ui patterns for React Native
4
+ */
5
+
6
+ import { Text as RNText, type TextProps as RNTextProps } from "react-native";
7
+ import { cva, type VariantProps } from "class-variance-authority";
8
+ import { cn } from "@/src/lib/utils";
9
+
10
+ const textVariants = cva("text-foreground", {
11
+ variants: {
12
+ variant: {
13
+ default: "",
14
+ heading: "text-2xl font-bold",
15
+ subheading: "text-lg font-semibold",
16
+ body: "text-base",
17
+ small: "text-sm",
18
+ muted: "text-muted-foreground",
19
+ label: "text-sm font-semibold",
20
+ error: "text-destructive text-sm",
21
+ },
22
+ size: {
23
+ xs: "text-xs",
24
+ sm: "text-sm",
25
+ base: "text-base",
26
+ lg: "text-lg",
27
+ xl: "text-xl",
28
+ "2xl": "text-2xl",
29
+ },
30
+ weight: {
31
+ normal: "font-normal",
32
+ medium: "font-medium",
33
+ semibold: "font-semibold",
34
+ bold: "font-bold",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ },
40
+ });
41
+
42
+ export interface TextProps
43
+ extends RNTextProps,
44
+ VariantProps<typeof textVariants> {
45
+ className?: string;
46
+ }
47
+
48
+ export function Text({
49
+ className,
50
+ variant,
51
+ size,
52
+ weight,
53
+ children,
54
+ ...props
55
+ }: TextProps) {
56
+ return (
57
+ <RNText
58
+ className={cn(textVariants({ variant, size, weight }), className)}
59
+ {...props}
60
+ >
61
+ {children}
62
+ </RNText>
63
+ );
64
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * API Configuration
3
+ */
4
+
5
+ import Constants from 'expo-constants'
6
+
7
+ const API_URL =
8
+ Constants.expoConfig?.extra?.apiUrl ||
9
+ (Constants.expoConfig?.hostUri
10
+ ? `http://${Constants.expoConfig.hostUri.split(':')[0]}:5173`
11
+ : 'http://localhost:5173')
12
+
13
+ export const API_CONFIG = {
14
+ baseUrl: API_URL,
15
+ endpoints: {
16
+ auth: '/api/auth',
17
+ tasks: '/api/v1/tasks',
18
+ customers: '/api/v1/customers',
19
+ teams: '/api/v1/teams',
20
+ },
21
+ defaults: {
22
+ limit: 20,
23
+ staleTime: 5 * 60 * 1000, // 5 minutes
24
+ cacheTime: 10 * 60 * 1000, // 10 minutes
25
+ },
26
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Mobile App Configuration
3
+ */
4
+
5
+ export const APP_CONFIG = {
6
+ app: {
7
+ name: 'NextSpark Mobile',
8
+ version: '0.1.0',
9
+ },
10
+ features: {
11
+ tasks: { enabled: true },
12
+ customers: { enabled: true },
13
+ },
14
+ // TODO: Add more config as needed
15
+ }