diff --git a/app/(app)/_layout.tsx b/app/(app)/_layout.tsx index 5889056..0813a5b 100644 --- a/app/(app)/_layout.tsx +++ b/app/(app)/_layout.tsx @@ -1,44 +1,51 @@ import { Tabs } from 'expo-router'; -import { Text } from 'react-native'; +import { Icon } from '../../components/Icon'; export default function AppLayout() { return ( ๐Ÿ  }} + options={{ title: 'Home', tabBarIcon: ({ color }) => }} /> ๐Ÿ‘ฅ }} + options={{ title: 'Clients', tabBarIcon: ({ color }) => }} /> ๐Ÿ’ฐ }} + options={{ title: 'Collect', tabBarIcon: ({ color }) => }} /> ๐Ÿ“‹ }} - /> - ๐ŸŽซ }} - /> - ๐Ÿ”Œ }} + name="tasks" + options={{ title: 'Tickets', tabBarIcon: ({ color }) => }} /> ๐Ÿ‘ค }} + options={{ title: 'Profile', tabBarIcon: ({ color }) => }} /> + {/* Hidden โ€” accessed programmatically */} + + ); } diff --git a/app/(app)/clients/[id].tsx b/app/(app)/clients/[id].tsx index ed1ec4b..75eb29e 100644 --- a/app/(app)/clients/[id].tsx +++ b/app/(app)/clients/[id].tsx @@ -1,25 +1,24 @@ import { useState } from 'react'; import { View, Text, ScrollView, TouchableOpacity, ActivityIndicator, Linking } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, router } from 'expo-router'; import { useQuery } from '@tanstack/react-query'; import { api } from '../../../services/api'; const TABS = ['Profile', 'Subscription', 'Invoices', 'Payments']; -const STATUS_COLORS: Record = { - ACTIVE: '#16A34A', SUSPENDED: '#D97706', CANCELLED: '#DC2626', PENDING: '#6B7280', +const STATUS_COLOR: Record = { + ACTIVE: '#166534', SUSPENDED: '#92400E', CANCELLED: '#991B1B', PENDING: '#475569', }; - -const INV_STATUS: Record = { - PAID: { label: 'Paid', color: '#16A34A' }, - UNPAID: { label: 'Unpaid', color: '#D97706' }, - OVERDUE: { label: 'Overdue', color: '#DC2626' }, - PARTIAL: { label: 'Partial', color: '#2563EB' }, - VOID: { label: 'Void', color: '#6B7280' }, +const STATUS_BG: Record = { + ACTIVE: '#DCFCE7', SUSPENDED: '#FEF3C7', CANCELLED: '#FEE2E2', PENDING: '#F1F5F9', }; - -const PAYMENT_METHODS: Record = { - CASH: '๐Ÿ’ต', GCASH: '๐Ÿ“ฑ', MAYA: '๐Ÿ’™', BANK: '๐Ÿฆ', +const INV_STATUS: Record = { + PAID: { label: 'Paid', color: '#166534', bg: '#DCFCE7' }, + UNPAID: { label: 'Unpaid', color: '#92400E', bg: '#FEF3C7' }, + OVERDUE: { label: 'Overdue', color: '#991B1B', bg: '#FEE2E2' }, + PARTIAL: { label: 'Partial', color: '#0E7490', bg: '#CFFAFE' }, + VOID: { label: 'Void', color: '#6B7280', bg: '#F1F5F9' }, }; function InfoRow({ label, value, onPress, isLast }: { label: string; value?: string | null; onPress?: () => void; isLast?: boolean }) { @@ -27,10 +26,11 @@ function InfoRow({ label, value, onPress, isLast }: { label: string; value?: str - {label} - {value ?? 'โ€”'} + {label} + {value ?? 'โ€”'} ); } @@ -43,177 +43,180 @@ export default function ClientDetailScreen() { queryKey: ['client', id], queryFn: () => api.get(`/api/v1/clients/${id}`).then(r => r.data), }); - const { data: subData, isLoading: subLoading } = useQuery({ queryKey: ['client-subscription', id], queryFn: () => api.get(`/api/v1/subscriptions?clientId=${id}&limit=1`).then(r => r.data?.data?.[0] ?? r.data?.[0] ?? null), enabled: tab === 'Subscription', }); - const { data: invoices, isLoading: invLoading } = useQuery({ queryKey: ['client-invoices', id], queryFn: () => api.get(`/api/v1/invoices?clientId=${id}&limit=20`).then(r => r.data?.data ?? r.data ?? []), enabled: tab === 'Invoices', }); - const { data: payments, isLoading: payLoading } = useQuery({ queryKey: ['client-payments', id], queryFn: () => api.get(`/api/v1/payments?clientId=${id}&limit=20`).then(r => r.data?.data ?? r.data ?? []), enabled: tab === 'Payments', }); - if (isLoading) return ( - - - - ); + if (isLoading) { + return ( + + + + + + ); + } + + const statusColor = STATUS_COLOR[client?.status] ?? '#475569'; + const statusBg = STATUS_BG[client?.status] ?? '#F1F5F9'; return ( - - {/* Header */} - - router.back()} className="mr-3 p-1"> - โ† - - - {client?.firstName} {client?.lastName} - {client?.accountNumber} - - - - {client?.status} - - - - - {/* Tabs */} - - {TABS.map(t => ( - setTab(t)} - className={`flex-1 py-3 items-center border-b-2 ${tab === t ? 'border-primary' : 'border-transparent'}`} - > - {t} + + + {/* Header */} + + router.back()} style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 12 }} activeOpacity={0.7} hitSlop={{ top: 10, bottom: 10, left: 0, right: 20 }}> + โ† Back - ))} - - - - {/* PROFILE TAB */} - {tab === 'Profile' && ( - - - - client?.phone && Linking.openURL(`tel:${client.phone}`)} /> - - - + + + {client?.firstName} {client?.lastName} + {client?.accountNumber} + + + {client?.status} + - )} + - {/* SUBSCRIPTION TAB */} - {tab === 'Subscription' && ( - subLoading ? ( - - ) : !subData ? ( - - ๐Ÿ“ก - No active subscription + {/* Tabs */} + + {TABS.map(t => ( + setTab(t)} + style={{ flex: 1, paddingVertical: 14, alignItems: 'center', borderBottomWidth: 2.5, borderBottomColor: tab === t ? '#0891B2' : 'transparent' }} + activeOpacity={0.7} + > + {t} + + ))} + + + + {/* PROFILE */} + {tab === 'Profile' && ( + + + + client?.phone && Linking.openURL(`tel:${client.phone}`)} /> + + + - ) : ( - - - - - - - - + )} + + {/* SUBSCRIPTION */} + {tab === 'Subscription' && ( + subLoading ? ( + + ) : !subData ? ( + + No active subscription - {subData.nextBillingDate && ( - - - ๐Ÿ“… Next billing: {new Date(subData.nextBillingDate).toLocaleDateString()} - + ) : ( + + + + + + + + - )} - - ) - )} + {subData.nextBillingDate && ( + + Next billing date + {new Date(subData.nextBillingDate).toLocaleDateString('en-PH', { year: 'numeric', month: 'long', day: 'numeric' })} + + )} + + ) + )} - {/* INVOICES TAB */} - {tab === 'Invoices' && ( - invLoading ? ( - - ) : !invoices?.length ? ( - - ๐Ÿงพ - No invoices yet - - ) : ( - invoices.map((inv: any) => { - const st = INV_STATUS[inv.status] ?? { label: inv.status, color: '#6B7280' }; - return ( - - - {inv.invoiceNumber} - - {st.label} + {/* INVOICES */} + {tab === 'Invoices' && ( + invLoading ? ( + + ) : !invoices?.length ? ( + + No invoices yet + + ) : ( + invoices.map((inv: any) => { + const st = INV_STATUS[inv.status] ?? { label: inv.status, color: '#6B7280', bg: '#F1F5F9' }; + return ( + + + {inv.invoiceNumber} + + {st.label} + + + Due: {inv.dueDate ? new Date(inv.dueDate).toLocaleDateString() : 'โ€”'} + โ‚ฑ{Number(inv.amount ?? inv.totalAmount ?? 0).toLocaleString()} + + {inv.balance > 0 && ( + Balance: โ‚ฑ{Number(inv.balance).toLocaleString()} + )} - - {inv.dueDate ? new Date(inv.dueDate).toLocaleDateString() : 'โ€”'} - โ‚ฑ{Number(inv.amount ?? inv.totalAmount).toLocaleString()} - - {inv.balance > 0 && ( - Balance: โ‚ฑ{Number(inv.balance).toLocaleString()} - )} - - ); - }) - ) - )} + ); + }) + ) + )} - {/* PAYMENTS TAB */} - {tab === 'Payments' && ( - payLoading ? ( - - ) : !payments?.length ? ( - - ๐Ÿ’ณ - No payments recorded - - ) : ( - <> - router.push({ pathname: '/(app)/payments/record', params: { prefillClientId: id, prefillName: `${client?.firstName} ${client?.lastName}`, prefillAccountNumber: client?.accountNumber } })} - > - + Record Payment - - {payments.map((p: any) => ( - - - - - {PAYMENT_METHODS[p.paymentMethod] ?? '๐Ÿ’ณ'} {p.paymentMethod} - - - {p.paymentDate ? new Date(p.paymentDate).toLocaleDateString() : new Date(p.createdAt).toLocaleDateString()} - - {p.referenceNumber && ( - Ref: {p.referenceNumber} - )} - - โ‚ฑ{Number(p.amount).toLocaleString()} + {/* PAYMENTS */} + {tab === 'Payments' && ( + payLoading ? ( + + ) : ( + <> + router.push({ pathname: '/(app)/payments/record', params: { prefillClientId: id, prefillName: `${client?.firstName} ${client?.lastName}`, prefillAccountNumber: client?.accountNumber } })} + activeOpacity={0.8} + > + + Record Payment + + + {!payments?.length ? ( + + No payments recorded - - ))} - - ) - )} - - + ) : ( + payments.map((p: any) => ( + + + + {p.paymentMethod} + + {p.paymentDate ? new Date(p.paymentDate).toLocaleDateString('en-PH') : new Date(p.createdAt).toLocaleDateString('en-PH')} + + {p.referenceNumber && Ref: {p.referenceNumber}} + + โ‚ฑ{Number(p.amount).toLocaleString()} + + + )) + )} + + ) + )} + + + ); } diff --git a/app/(app)/clients/_layout.tsx b/app/(app)/clients/_layout.tsx new file mode 100644 index 0000000..8d87bcb --- /dev/null +++ b/app/(app)/clients/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router'; +export default function ClientsLayout() { + return ; +} diff --git a/app/(app)/clients/index.tsx b/app/(app)/clients/index.tsx index 31c3838..c81d2f8 100644 --- a/app/(app)/clients/index.tsx +++ b/app/(app)/clients/index.tsx @@ -1,11 +1,15 @@ import { useState } from 'react'; import { View, Text, FlatList, TextInput, TouchableOpacity, ActivityIndicator, RefreshControl } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useQuery } from '@tanstack/react-query'; import { router } from 'expo-router'; import { api } from '../../../services/api'; -const STATUS_COLORS: Record = { - ACTIVE: '#16A34A', SUSPENDED: '#D97706', CANCELLED: '#DC2626', PENDING: '#6B7280', +const STATUS_CONFIG: Record = { + ACTIVE: { label: 'Active', color: '#166534', bg: '#DCFCE7' }, + SUSPENDED: { label: 'Suspended', color: '#92400E', bg: '#FEF3C7' }, + CANCELLED: { label: 'Cancelled', color: '#991B1B', bg: '#FEE2E2' }, + PENDING: { label: 'Pending', color: '#475569', bg: '#F1F5F9' }, }; export default function ClientsScreen() { @@ -20,54 +24,73 @@ export default function ClientsScreen() { ); return ( - - - Clients - - - - - {isLoading ? ( - - + + + {/* Header */} + + Clients + {data?.length ?? 0} subscribers - ) : ( - item.id} - refreshControl={} - contentContainerStyle={{ paddingHorizontal: 16, paddingBottom: 24 }} - renderItem={({ item }) => ( - router.push(`/(app)/clients/${item.id}`)} - > - - - {item.firstName} {item.lastName} - {item.accountNumber} - {item.phone && {item.phone}} - - - - {item.status} - + + {/* Search */} + + + + {search.length > 0 && ( + setSearch('')} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + + ร— + + )} + + + + {isLoading ? ( + + + + ) : ( + item.id} + refreshControl={} + contentContainerStyle={{ padding: 16, paddingBottom: 32 }} + renderItem={({ item }) => { + const st = STATUS_CONFIG[item.status] ?? { label: item.status, color: '#475569', bg: '#F1F5F9' }; + return ( + router.push(`/(app)/clients/${item.id}`)} + activeOpacity={0.7} + > + + + {item.firstName} {item.lastName} + {item.accountNumber} + {item.phone && {item.phone}} + + + {st.label} + + + + ); + }} + ListEmptyComponent={ + + No clients found - - )} - ListEmptyComponent={ - - No clients found - - } - /> - )} - + } + /> + )} + + ); } diff --git a/app/(app)/dashboard.tsx b/app/(app)/dashboard.tsx index 37ea1ba..7ed0fae 100644 --- a/app/(app)/dashboard.tsx +++ b/app/(app)/dashboard.tsx @@ -1,141 +1,194 @@ import { View, Text, ScrollView, RefreshControl, ActivityIndicator, TouchableOpacity } from 'react-native'; -import { useQuery } from '@tanstack/react-query'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useQueries } from '@tanstack/react-query'; import { router } from 'expo-router'; import { api } from '../../services/api'; import { useAuthStore } from '../../stores/authStore'; -const PRIORITY_COLOR: Record = { HIGH: '#DC2626', MEDIUM: '#D97706', LOW: '#6B7280' }; -const TICKET_STATUS_COLOR: Record = { OPEN: '#2563EB', IN_PROGRESS: '#D97706', RESOLVED: '#16A34A', CLOSED: '#6B7280' }; +// โ”€โ”€โ”€ Constants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +const PRIORITY_COLOR: Record = { HIGH: '#DC2626', NORMAL: '#0891B2' }; +const PRIORITY_BG: Record = { HIGH: '#FEE2E2', NORMAL: '#ECFEFF' }; +const STATUS_COLOR: Record = { OPEN: '#0891B2', IN_PROGRESS: '#D97706', RESOLVED: '#16A34A', CLOSED: '#6B7280' }; +const TYPE_COLOR: Record = { INSTALLATION: '#0891B2', SUPPORT: '#7C3AED', BILLING: '#D97706' }; + +// โ”€โ”€โ”€ KPI Card โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +function KpiCard({ label, value, color, bg }: { label: string; value: string | number; color: string; bg: string }) { + return ( + + {label} + {value} + + ); +} + +// โ”€โ”€โ”€ Ticket Row โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +function TaskRow({ task, onPress }: { task: any; onPress: () => void }) { + const typeColor = TYPE_COLOR[task.type] ?? '#6B7280'; + const isHigh = task.priority === 'HIGH'; -function KpiCard({ label, value, color, onPress }: { label: string; value: string | number; color: string; onPress?: () => void }) { return ( - {label} - {value} - - ); -} - -function QuickAction({ icon, label, onPress }: { icon: string; label: string; onPress: () => void }) { - return ( - - {icon} - {label} - - ); -} - -export default function DashboardScreen() { - const { user } = useAuthStore(); - const { data, isLoading, refetch, isRefetching } = useQuery({ - queryKey: ['dashboard'], - queryFn: () => api.get('/api/v1/dashboard/summary').then(r => r.data), - }); - - const greeting = () => { - const h = new Date().getHours(); - if (h < 12) return 'Good morning'; - if (h < 17) return 'Good afternoon'; - return 'Good evening'; - }; - - return ( - } - > - {/* Header */} - - {greeting()}, - {user?.firstName ?? 'Field Staff'} ๐Ÿ‘‹ - {new Date().toLocaleDateString('en-PH', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })} - - - {isLoading ? ( - - - - ) : ( - - {/* KPIs */} - Overview - - router.push('/(app)/clients')} - /> - + + + + {task.type} - - router.push('/(app)/clients')} - /> - router.push('/(app)/payments')} - /> - - - {/* Quick Actions */} - Quick Actions - - router.push('/(app)/payments/record')} /> - router.push('/(app)/tickets/create')} /> - router.push('/(app)/installations')} /> - router.push('/(app)/remittances/submit')} /> - - - {/* Recent Tickets */} - Recent Tickets - {(data?.recentTickets ?? []).length === 0 ? ( - - No recent tickets - router.push('/(app)/tickets/create')} - > - Create Ticket - + {isHigh && ( + + HIGH - ) : ( - (data?.recentTickets ?? []).map((t: any) => ( - router.push(`/(app)/tickets/${t.id}`)} - > - - {t.subject} - - {t.priority} - - - - {t.clientName ?? 'No client'} - - {t.status} - - - - )) )} - )} - + + {task.status?.replace('_', ' ')} + + + {task.subject} + + {task.client?.firstName} {task.client?.lastName} + {task.assignedTo + ? ` ยท ${task.assignedTo.firstName} ${task.assignedTo.lastName}` + : ' ยท Unassigned'} + + + ); +} + +// โ”€โ”€โ”€ Main Screen โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +export default function DashboardScreen() { + const { user } = useAuthStore(); + const hour = new Date().getHours(); + const greeting = hour < 12 ? 'Good morning' : hour < 18 ? 'Good afternoon' : 'Good evening'; + + const [summaryQ, tasksQ] = useQueries({ + queries: [ + { + queryKey: ['dashboard'], + queryFn: () => api.get('/api/v1/dashboard/summary').then(r => r.data), + }, + { + queryKey: ['dashboard-tasks'], + queryFn: () => + api.get('/api/v1/tickets?status=OPEN&status=IN_PROGRESS&limit=20') + .then(r => r.data?.data ?? r.data ?? []), + }, + ], + }); + + const isLoading = summaryQ.isLoading || tasksQ.isLoading; + const isRefetching = summaryQ.isRefetching || tasksQ.isRefetching; + const summary = summaryQ.data; + + // Real dashboard API shape: + // { subscribers: { total, active, pending, suspended }, + // billing: { unpaidInvoices, overdueInvoices }, + // support: { openTickets, inProgressTickets }, + // tasks: { pending }, + // revenue: { thisMonth, lastMonth, growth } } + const totalClients = summary?.subscribers?.total ?? 'โ€”'; + const activeSubscribers = summary?.subscribers?.active ?? 'โ€”'; + const unpaidInvoices = summary?.billing?.unpaidInvoices ?? 'โ€”'; + const openTickets = summary?.support?.openTickets ?? 'โ€”'; + const thisMonthRevenue = summary?.revenue?.thisMonth ?? null; + + const allTasks: any[] = tasksQ.data ?? []; + const unassigned = allTasks.filter((t: any) => !t.assignedToId); + const assigned = allTasks.filter((t: any) => !!t.assignedToId); + const prioOrder: Record = { HIGH: 0, NORMAL: 1 }; + const byPrio = (a: any, b: any) => (prioOrder[a.priority] ?? 2) - (prioOrder[b.priority] ?? 2); + + const refetchAll = () => { summaryQ.refetch(); tasksQ.refetch(); }; + + return ( + + } + > + {/* Header */} + + {greeting}, + {user?.firstName ?? 'Field Staff'} + + + {isLoading ? ( + + + + ) : ( + + {/* KPI Row 1 */} + + + + + + {/* KPI Row 2 */} + + + + + + {/* Revenue card */} + {thisMonthRevenue !== null && ( + + + This Month's Revenue + โ‚ฑ{Number(thisMonthRevenue).toLocaleString()} + + {summary?.revenue?.growth !== undefined && ( + + +{summary.revenue.growth}% + + )} + + )} + + {/* Unassigned Tasks */} + + + Unassigned + {unassigned.length > 0 && ( + + {unassigned.length} + + )} + + router.push('/(app)/tasks')} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + View all + + + + {unassigned.length === 0 ? ( + + No unassigned tasks + + ) : ( + + {[...unassigned].sort(byPrio).slice(0, 5).map((t: any) => ( + router.push(`/(app)/tasks/${t.id}`)} /> + ))} + + )} + + {/* Assigned Tasks */} + {assigned.length > 0 && ( + <> + Assigned Tasks + {[...assigned].sort(byPrio).slice(0, 5).map((t: any) => ( + router.push(`/(app)/tasks/${t.id}`)} /> + ))} + + )} + + + + )} + + ); } diff --git a/app/(app)/installations/[id].tsx b/app/(app)/installations/[id].tsx deleted file mode 100644 index 710ec5c..0000000 --- a/app/(app)/installations/[id].tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useState } from 'react'; -import { View, Text, TouchableOpacity, ScrollView, Alert, Image, ActivityIndicator } from 'react-native'; -import { useLocalSearchParams, router } from 'expo-router'; -import * as ImagePicker from 'expo-image-picker'; -import * as Location from 'expo-location'; -import { api } from '../../../services/api'; - -export default function InstallationConfirmScreen() { - const { id } = useLocalSearchParams<{ id: string }>(); - const [photo, setPhoto] = useState(null); - const [coords, setCoords] = useState<{ lat: number; lng: number } | null>(null); - const [loading, setLoading] = useState(false); - const [gpsLoading, setGpsLoading] = useState(false); - - const capturePhoto = async () => { - const { status } = await ImagePicker.requestCameraPermissionsAsync(); - if (status !== 'granted') return Alert.alert('Permission denied', 'Camera access is required.'); - const result = await ImagePicker.launchCameraAsync({ quality: 0.7, base64: false }); - if (!result.canceled) setPhoto(result.assets[0].uri); - }; - - const captureGPS = async () => { - setGpsLoading(true); - try { - const { status } = await Location.requestForegroundPermissionsAsync(); - if (status !== 'granted') { Alert.alert('Permission denied', 'Location access is required.'); return; } - const loc = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High }); - setCoords({ lat: loc.coords.latitude, lng: loc.coords.longitude }); - } catch { Alert.alert('Error', 'Could not get location.'); } - finally { setGpsLoading(false); } - }; - - const confirm = async () => { - if (!coords) return Alert.alert('Required', 'Capture GPS location first.'); - setLoading(true); - try { - await api.patch(`/api/v1/tickets/${id}/confirm-installation`, { - latitude: coords.lat, - longitude: coords.lng, - photoUrl: photo, - }); - Alert.alert('Done!', 'Installation confirmed.', [{ text: 'OK', onPress: () => router.back() }]); - } catch (e: any) { - Alert.alert('Error', e?.response?.data?.message ?? 'Confirmation failed.'); - } finally { setLoading(false); } - }; - - return ( - - - router.back()} className="mr-3"> - โ† - - Installation Confirmation - - - - ๐Ÿ“ GPS Location - {coords ? ( - โœ“ {coords.lat.toFixed(6)}, {coords.lng.toFixed(6)} - ) : ( - No location captured yet - )} - - {gpsLoading ? : Capture GPS} - - - - - ๐Ÿ“ท Photo Proof - {photo && } - - {photo ? 'Retake Photo' : 'Take Photo'} - - - - - {loading ? : โœ“ Confirm Installation} - - - - ); -} diff --git a/app/(app)/installations/index.tsx b/app/(app)/installations/index.tsx deleted file mode 100644 index 95e940f..0000000 --- a/app/(app)/installations/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { View, Text, FlatList, TouchableOpacity, ActivityIndicator, RefreshControl } from 'react-native'; -import { useQuery } from '@tanstack/react-query'; -import { router } from 'expo-router'; -import { api } from '../../../services/api'; - -// Installations are tickets of type INSTALLATION (or filtered by subject prefix) -// We query tickets with type=INSTALLATION if the API supports it, fallback to all open tickets -async function fetchInstallations() { - try { - const res = await api.get('/api/v1/tickets?type=INSTALLATION&limit=50'); - return res.data?.data ?? res.data ?? []; - } catch { - // Fallback: all OPEN tickets - const res = await api.get('/api/v1/tickets?status=OPEN&limit=50'); - return res.data?.data ?? res.data ?? []; - } -} - -const STATUS_STYLE: Record = { - OPEN: { bg: '#EFF6FF', text: '#2563EB' }, - IN_PROGRESS: { bg: '#FFFBEB', text: '#D97706' }, - RESOLVED: { bg: '#F0FDF4', text: '#16A34A' }, - CLOSED: { bg: '#F3F4F6', text: '#6B7280' }, -}; - -export default function InstallationsScreen() { - const { data, isLoading, refetch, isRefetching } = useQuery({ - queryKey: ['installations'], - queryFn: fetchInstallations, - }); - - const installations: any[] = data ?? []; - - return ( - - {/* Header */} - - Installations - - {installations.length} pending - - - - {isLoading ? ( - - - - ) : ( - item.id} - refreshControl={} - contentContainerStyle={{ padding: 16 }} - renderItem={({ item }) => { - const statusStyle = STATUS_STYLE[item.status] ?? { bg: '#F3F4F6', text: '#6B7280' }; - return ( - router.push(`/(app)/installations/${item.id}`)} - > - - - {item.subject} - - - - {item.status?.replace('_', ' ')} - - - - - - - {item.client?.firstName} {item.client?.lastName} - - - {item.createdAt ? new Date(item.createdAt).toLocaleDateString() : ''} - - - - {item.client?.address && ( - - ๐Ÿ“ {item.client.address} - - )} - - {/* Confirm button if not yet resolved */} - {item.status !== 'RESOLVED' && item.status !== 'CLOSED' && ( - router.push(`/(app)/installations/${item.id}`)} - > - ๐Ÿ“ท Confirm Installation - - )} - - ); - }} - ListEmptyComponent={ - - ๐Ÿ”Œ - No installations pending - All caught up! - - } - /> - )} - - ); -} diff --git a/app/(app)/payments/_layout.tsx b/app/(app)/payments/_layout.tsx new file mode 100644 index 0000000..483e0bb --- /dev/null +++ b/app/(app)/payments/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router'; +export default function PaymentsLayout() { + return ; +} diff --git a/app/(app)/payments/index.tsx b/app/(app)/payments/index.tsx index 81d9331..e1f5f71 100644 --- a/app/(app)/payments/index.tsx +++ b/app/(app)/payments/index.tsx @@ -1,87 +1,48 @@ -import { useState } from 'react'; -import { View, Text, FlatList, TouchableOpacity, ActivityIndicator, RefreshControl } from 'react-native'; -import { useQuery } from '@tanstack/react-query'; +import { View, Text, TouchableOpacity, ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; -import { api } from '../../../services/api'; - -const METHOD_ICON: Record = { CASH: '๐Ÿ’ต', GCASH: '๐Ÿ“ฑ', MAYA: '๐Ÿ’™', BANK: '๐Ÿฆ' }; - -export default function PaymentsScreen() { - const { data, isLoading, refetch, isRefetching } = useQuery({ - queryKey: ['payments'], - queryFn: () => api.get('/api/v1/payments?limit=50').then(r => r.data?.data ?? r.data ?? []), - }); - - const payments: any[] = data ?? []; - - // Calculate today's total - const today = new Date().toDateString(); - const todayTotal = payments - .filter((p: any) => new Date(p.paymentDate ?? p.createdAt).toDateString() === today) - .reduce((sum: number, p: any) => sum + Number(p.amount), 0); +export default function CollectScreen() { return ( - - {/* Header */} - - - Payments - Today: โ‚ฑ{todayTotal.toLocaleString()} + + + + Collect + Payments & remittances - router.push('/(app)/payments/record')} - > - + Record - - - {isLoading ? ( - - ) : ( - item.id} - refreshControl={} - contentContainerStyle={{ padding: 16, paddingBottom: 32 }} - ListEmptyComponent={ - - ๐Ÿ’ณ - No payments yet - router.push('/(app)/payments/record')} - > - Record First Payment - + + router.push('/(app)/payments/record')} + activeOpacity={0.7} + > + + ๐Ÿ’ณ - } - renderItem={({ item }) => ( - - - - - {METHOD_ICON[item.paymentMethod] ?? '๐Ÿ’ณ'} - - {item.client?.firstName} {item.client?.lastName} - - - {item.client?.accountNumber} - - {new Date(item.paymentDate ?? item.createdAt).toLocaleDateString()} ยท {item.paymentMethod} - - {item.referenceNumber && ( - Ref: {item.referenceNumber} - )} - - - โ‚ฑ{Number(item.amount).toLocaleString()} - - + + Record Payment + Cash, GCash, Maya, or bank - )} - /> - )} - + โ€บ + + + router.push('/(app)/remittances')} + activeOpacity={0.7} + > + + ๐Ÿ“‹ + + + Remittances + Submit & track daily collections + + โ€บ + + + + ); } diff --git a/app/(app)/payments/record.tsx b/app/(app)/payments/record.tsx index 6e9bf58..fa07a84 100644 --- a/app/(app)/payments/record.tsx +++ b/app/(app)/payments/record.tsx @@ -1,189 +1,211 @@ import { useState, useEffect } from 'react'; -import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator, FlatList, Modal } from 'react-native'; +import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useLocalSearchParams } from 'expo-router'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; import { api } from '../../../services/api'; -const METHODS = ['CASH', 'GCASH', 'MAYA', 'BANK']; +const METHODS = [ + { id: 'CASH', label: 'Cash' }, + { id: 'GCASH', label: 'GCash' }, + { id: 'MAYA', label: 'Maya' }, + { id: 'BANK', label: 'Bank Transfer' }, +]; export default function RecordPaymentScreen() { - const params = useLocalSearchParams<{ prefillClientId?: string; prefillName?: string; prefillAccountNumber?: string }>(); - const qc = useQueryClient(); + // Prefill params when navigated from client detail + const params = useLocalSearchParams<{ + prefillClientId?: string; + prefillName?: string; + prefillAccountNumber?: string; + }>(); - const [search, setSearch] = useState(''); - const [showPicker, setShowPicker] = useState(false); - const [client, setClient] = useState( - params.prefillClientId - ? { id: params.prefillClientId, firstName: params.prefillName?.split(' ')[0], lastName: params.prefillName?.split(' ').slice(1).join(' '), accountNumber: params.prefillAccountNumber } - : null - ); - const [amount, setAmount] = useState(''); - const [method, setMethod] = useState('CASH'); + const [search, setSearch] = useState(''); + const [client, setClient] = useState(null); + const [amount, setAmount] = useState(''); + const [method, setMethod] = useState('CASH'); const [reference, setReference] = useState(''); - const [notes, setNotes] = useState(''); - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false); + const [searching, setSearching] = useState(false); - // Debounced client search - const [debouncedSearch, setDebouncedSearch] = useState(''); + // Auto-fill client if navigated from client detail useEffect(() => { - const t = setTimeout(() => setDebouncedSearch(search), 400); - return () => clearTimeout(t); - }, [search]); + if (params.prefillClientId && params.prefillName) { + setClient({ + id: params.prefillClientId, + firstName: params.prefillName.split(' ')[0] ?? '', + lastName: params.prefillName.split(' ').slice(1).join(' ') ?? '', + accountNumber: params.prefillAccountNumber ?? '', + }); + } + }, []); - const { data: searchResults, isFetching: searching } = useQuery({ - queryKey: ['client-search', debouncedSearch], - queryFn: () => api.get(`/api/v1/clients?search=${debouncedSearch}&limit=8`).then(r => r.data?.data ?? r.data ?? []), - enabled: debouncedSearch.trim().length >= 2, - }); + const searchClient = async () => { + if (!search.trim()) return; + setSearching(true); + try { + const res = await api.get(`/api/v1/clients?search=${encodeURIComponent(search.trim())}&limit=5`); + const found = res.data?.data ?? res.data ?? []; + if (Array.isArray(found) && found.length === 1) { + setClient(found[0]); + } else if (Array.isArray(found) && found.length > 1) { + // Show picker if multiple results + Alert.alert( + 'Multiple clients found', + found.map((c: any, i: number) => `${i + 1}. ${c.firstName} ${c.lastName} (${c.accountNumber})`).join('\n'), + [ + ...found.slice(0, 5).map((c: any, i: number) => ({ + text: `${i + 1}. ${c.firstName} ${c.lastName}`, + onPress: () => setClient(c), + })), + { text: 'Cancel', style: 'cancel' as const }, + ] + ); + } else { + Alert.alert('Not Found', 'No client found. Try account number or full name.'); + } + } catch { + Alert.alert('Error', 'Search failed. Please try again.'); + } finally { setSearching(false); } + }; const submit = async () => { - if (!client) return Alert.alert('Required', 'Select a client first.'); - if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) - return Alert.alert('Required', 'Enter a valid amount.'); + if (!client) return Alert.alert('Required', 'Search and select a client first.'); + const amt = Number(amount); + if (!amount || isNaN(amt) || amt <= 0) return Alert.alert('Required', 'Enter a valid amount.'); setLoading(true); try { await api.post('/api/v1/payments', { - clientId: client.id, - amount: Number(amount), - paymentMethod: method, - referenceNumber: reference || undefined, - notes: notes || undefined, - paymentDate: new Date().toISOString(), + clientId: client.id, + amount: amt, + channel: method, // API uses `channel` not `paymentMethod` + referenceNumber: reference.trim() || undefined, + paymentDate: new Date().toISOString(), }); - // Invalidate relevant queries - qc.invalidateQueries({ queryKey: ['payments'] }); - qc.invalidateQueries({ queryKey: ['client-payments', client.id] }); - qc.invalidateQueries({ queryKey: ['dashboard'] }); - Alert.alert('โœ… Payment Recorded', `โ‚ฑ${Number(amount).toLocaleString()} from ${client.firstName} ${client.lastName}`, [ + Alert.alert('Payment Recorded!', `โ‚ฑ${amt.toLocaleString()} from ${client.firstName} ${client.lastName}`, [ + { text: 'Record Another', onPress: () => { setClient(null); setAmount(''); setSearch(''); setReference(''); } }, { text: 'Done', onPress: () => router.back() }, - { text: 'Record Another', onPress: () => { setClient(null); setAmount(''); setReference(''); setNotes(''); setSearch(''); } }, ]); } catch (e: any) { - Alert.alert('Error', e?.response?.data?.message ?? 'Payment failed. Try again.'); - } finally { - setLoading(false); - } + const msg = e?.response?.data?.message; + Alert.alert('Error', Array.isArray(msg) ? msg.join('\n') : msg ?? 'Payment failed.'); + } finally { setLoading(false); } }; + const canSubmit = !!client && !!amount && Number(amount) > 0; + return ( - - - router.back()} className="mr-3 p-1"> - โ† - - Record Payment - - - - {/* Client selector */} - Client * - {client ? ( - - - {client.firstName} {client.lastName} - {client.accountNumber} - - { setClient(null); setSearch(''); }} className="p-2"> - Change - - - ) : ( - - - - {searching && } - - {debouncedSearch.trim().length >= 2 && ( - - {(searchResults ?? []).length === 0 && !searching && ( - No clients found - )} - {(searchResults ?? []).map((c: any) => ( - { setClient(c); setSearch(''); }} - > - {c.firstName} {c.lastName} - {c.accountNumber} - - ))} - - )} - - )} - - {/* Amount */} - Amount (โ‚ฑ) * - - - {/* Payment method */} - Payment Method * - - {METHODS.map(m => ( - setMethod(m)} - className={`rounded-xl px-5 py-2.5 mr-2 mb-2 border ${method === m ? 'bg-primary border-primary' : 'bg-white border-gray-200'}`} - > - {m} - - ))} + + + {/* Header */} + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + Record Payment + Field collection - {/* Reference (for non-cash) */} - {method !== 'CASH' && ( - <> - Reference # * - - - )} + + {/* Client section */} + Client - {/* Notes */} - Notes (optional) - + {client ? ( + + {client.firstName} {client.lastName} + {client.accountNumber} + { setClient(null); setSearch(''); }} style={{ marginTop: 10 }} hitSlop={{ top: 8, bottom: 8, left: 0, right: 8 }}> + ร— Change client + + + ) : ( + + + + + {search.length > 0 && ( + setSearch('')} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + + ร— + + + )} + + + {searching + ? + : Find + } + + + Search by account number, first name, or last name + + )} - {/* Submit */} - - {loading - ? - : - Submit Payment {amount ? `ยท โ‚ฑ${Number(amount || 0).toLocaleString()}` : ''} - - } - + {/* Amount */} + Amount (โ‚ฑ) + - - - + {/* Payment method */} + Payment Method + + {METHODS.map(m => ( + setMethod(m.id)} + style={{ flex: 1, borderRadius: 14, paddingVertical: 14, alignItems: 'center', marginHorizontal: 4, backgroundColor: method === m.id ? '#0891B2' : '#FFF', borderWidth: 1.5, borderColor: method === m.id ? '#0891B2' : '#E2E8F0' }} + activeOpacity={0.7} + > + {m.label} + + ))} + + + {/* Reference */} + + Reference # (optional) + + + + + {loading + ? + : + {canSubmit ? `Record โ‚ฑ${Number(amount || 0).toLocaleString()} Payment` : 'Record Payment'} + + } + + + + ); } diff --git a/app/(app)/profile.tsx b/app/(app)/profile.tsx index a83c9f8..5bf137b 100644 --- a/app/(app)/profile.tsx +++ b/app/(app)/profile.tsx @@ -1,57 +1,81 @@ import { View, Text, TouchableOpacity, Alert, ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useAuthStore } from '../../stores/authStore'; import { router } from 'expo-router'; export default function ProfileScreen() { const { user, logout, tenantSlug } = useAuthStore(); + const initials = `${user?.firstName?.[0] ?? ''}${user?.lastName?.[0] ?? ''}`.toUpperCase() || 'U'; + const fullName = `${user?.firstName ?? ''} ${user?.lastName ?? ''}`.trim(); + const role = user?.roles?.[0] ?? user?.role ?? 'Staff'; const handleLogout = () => { Alert.alert('Sign Out', 'Are you sure you want to sign out?', [ { text: 'Cancel', style: 'cancel' }, - { - text: 'Sign Out', style: 'destructive', - onPress: async () => { - await logout(); - router.replace('/(auth)/company-code'); - } - } + { text: 'Sign Out', style: 'destructive', onPress: async () => { await logout(); router.replace('/(auth)/company-code'); } }, ]); }; return ( - - - - - {user?.firstName?.[0]?.toUpperCase() ?? 'U'} - - - {user?.firstName} {user?.lastName} - {user?.role} ยท {tenantSlug} - - - - - {[ - { label: 'Username', value: user?.username }, - { label: 'Email', value: user?.email }, - { label: 'Role', value: user?.role }, - { label: 'Company', value: tenantSlug }, - ].map((item, i) => ( - 0 ? 'border-t border-gray-100' : ''}`}> - {item.label} - {item.value ?? 'โ€”'} - - ))} + + + {/* Header */} + + + {initials} + + {fullName} + + {role} + - - Sign Out - - - + + {/* Info */} + + {[ + { label: 'Email', value: user?.email }, + { label: 'Company', value: tenantSlug }, + { label: 'Role', value: role }, + ].map((row, i, arr) => ( + + {row.label} + {row.value ?? 'โ€”'} + + ))} + + + {/* User Management โ€” admin only */} + {(user?.roles?.includes('ADMIN') || user?.role === 'ADMIN' || role === 'ADMIN') && ( + router.push('/(app)/users')} + activeOpacity={0.7} + > + + User Management + Add & manage team members + + โ€บ + + )} + + {/* App version */} + + App + FiberOps Mobile v1.0.0 + + + {/* Sign out */} + + Sign Out + + + + ); } diff --git a/app/(app)/remittances/[id].tsx b/app/(app)/remittances/[id].tsx index cbf8c4a..b24d04d 100644 --- a/app/(app)/remittances/[id].tsx +++ b/app/(app)/remittances/[id].tsx @@ -1,10 +1,24 @@ import { View, Text, ScrollView, TouchableOpacity, ActivityIndicator } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, router } from 'expo-router'; import { useQuery } from '@tanstack/react-query'; import { api } from '../../../services/api'; -const STATUS_COLOR: Record = { PENDING: '#D97706', CONFIRMED: '#16A34A', DISPUTED: '#DC2626' }; -const METHOD_ICON: Record = { CASH: '๐Ÿ’ต', GCASH: '๐Ÿ“ฑ', MAYA: '๐Ÿ’™', BANK: '๐Ÿฆ' }; +const STATUS_CONFIG: Record = { + PENDING: { color: '#92400E', bg: '#FEF3C7' }, + CONFIRMED: { color: '#166534', bg: '#DCFCE7' }, + DISPUTED: { color: '#991B1B', bg: '#FEE2E2' }, +}; + +function InfoRow({ label, value, isLast }: { label: string; value?: string | null; isLast?: boolean }) { + if (!value) return null; + return ( + + {label} + {value} + + ); +} export default function RemittanceDetailScreen() { const { id } = useLocalSearchParams<{ id: string }>(); @@ -14,76 +28,97 @@ export default function RemittanceDetailScreen() { queryFn: () => api.get(`/api/v1/remittances/${id}`).then(r => r.data), }); - if (isLoading) return ( - - - - ); + if (isLoading) { + return ( + + + + + + ); + } const status = data?.status ?? 'PENDING'; - const statusColor = STATUS_COLOR[status] ?? '#6B7280'; + const st = STATUS_CONFIG[status] ?? { color: '#6B7280', bg: '#F1F5F9' }; + const payments: any[] = data?.payments ?? []; return ( - - - router.back()} className="mr-3 p-1"> - โ† - - - Remittance - {data?.createdAt ? new Date(data.createdAt).toLocaleDateString() : ''} - - - {status} - - - - - {/* Summary card */} - - Total Amount - โ‚ฑ{Number(data?.totalAmount ?? 0).toLocaleString()} - {data?.notes && {data.notes}} - - - {/* Details */} - - {[ - { label: 'Submitted by', value: data?.collector?.firstName ? `${data.collector.firstName} ${data.collector.lastName}` : undefined }, - { label: 'Submitted on', value: data?.createdAt ? new Date(data.createdAt).toLocaleString() : undefined }, - { label: 'Confirmed on', value: data?.confirmedAt ? new Date(data.confirmedAt).toLocaleString() : undefined }, - { label: 'Confirmed by', value: data?.confirmedBy?.firstName ? `${data.confirmedBy.firstName} ${data.confirmedBy.lastName}` : undefined }, - ].filter(r => r.value).map((row, i, arr) => ( - - {row.label} - {row.value} + + + {/* Header */} + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + + + Remittance + + {data?.createdAt ? new Date(data.createdAt).toLocaleDateString('en-PH', { year: 'numeric', month: 'long', day: 'numeric' }) : ''} + - ))} + + {status} + + - {/* Included payments */} - {(data?.payments ?? []).length > 0 && ( - <> - Included Payments ({data.payments.length}) - {data.payments.map((p: any) => ( - - - - - {METHOD_ICON[p.paymentMethod] ?? '๐Ÿ’ณ'} {p.client?.firstName} {p.client?.lastName} - - {p.client?.accountNumber} ยท {p.paymentMethod} - {p.referenceNumber && Ref: {p.referenceNumber}} - - โ‚ฑ{Number(p.amount).toLocaleString()} - - - ))} - - )} + + {/* Total amount card */} + + Total Amount + โ‚ฑ{Number(data?.totalAmount ?? 0).toLocaleString()} + {payments.length > 0 && ( + {payments.length} payment{payments.length !== 1 ? 's' : ''} included + )} + {data?.notes && ( + "{data.notes}" + )} + - - - + {/* Details */} + + + + + + + + {/* Payments breakdown */} + {payments.length > 0 && ( + <> + + Payments ({payments.length}) + + {payments.map((p: any) => ( + + + + + {p.client?.firstName} {p.client?.lastName} + + + {p.client?.accountNumber} ยท {p.channel ?? p.paymentMethod} + + {p.referenceNumber && ( + Ref: {p.referenceNumber} + )} + + + โ‚ฑ{Number(p.amount).toLocaleString()} + + + + ))} + + )} + + + ); } diff --git a/app/(app)/remittances/_layout.tsx b/app/(app)/remittances/_layout.tsx new file mode 100644 index 0000000..e0b3d48 --- /dev/null +++ b/app/(app)/remittances/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router'; +export default function RemittancesLayout() { + return ; +} diff --git a/app/(app)/remittances/index.tsx b/app/(app)/remittances/index.tsx index 0529a58..c5a6567 100644 --- a/app/(app)/remittances/index.tsx +++ b/app/(app)/remittances/index.tsx @@ -1,49 +1,120 @@ import { View, Text, FlatList, TouchableOpacity, ActivityIndicator, RefreshControl } from 'react-native'; -import { useQuery } from '@tanstack/react-query'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useQueries } from '@tanstack/react-query'; import { router } from 'expo-router'; import { api } from '../../../services/api'; -const STATUS_COLOR: Record = { PENDING: '#D97706', CONFIRMED: '#16A34A', DISPUTED: '#DC2626' }; +const STATUS_CONFIG: Record = { + PENDING: { color: '#92400E', bg: '#FEF3C7' }, + CONFIRMED: { color: '#166534', bg: '#DCFCE7' }, + DISPUTED: { color: '#991B1B', bg: '#FEE2E2' }, +}; export default function RemittancesScreen() { - const { data, isLoading, refetch, isRefetching } = useQuery({ - queryKey: ['remittances'], - queryFn: () => api.get('/api/v1/remittances?limit=50').then(r => r.data?.data ?? r.data), + const [remittancesQ, unremittedQ] = useQueries({ + queries: [ + { queryKey: ['remittances'], queryFn: () => api.get('/api/v1/remittances?limit=50').then(r => r.data?.data ?? r.data) }, + { queryKey: ['unremitted'], queryFn: () => api.get('/api/v1/payments?unremitted=true').then(r => r.data).catch(() => null) }, + ], }); + const data = remittancesQ.data ?? []; + const isLoading = remittancesQ.isLoading; + const isRefetching = remittancesQ.isRefetching || unremittedQ.isRefetching; + const refetchAll = () => { remittancesQ.refetch(); unremittedQ.refetch(); }; + + // Compute unremitted total from raw payments or summary + const unremittedPayments: any[] = Array.isArray(unremittedQ.data?.data) + ? unremittedQ.data.data + : Array.isArray(unremittedQ.data) + ? unremittedQ.data + : []; + const unremittedTotal = unremittedQ.data?.totalUnremitted + ?? unremittedPayments.reduce((s: number, p: any) => s + Number(p.amount ?? 0), 0); + const unremittedCount = unremittedQ.data?.count ?? unremittedPayments.length; + return ( - - - Remittances - router.push('/(app)/remittances/submit')}> - + Submit - - - {isLoading ? ( - - ) : ( - item.id} - refreshControl={} - contentContainerStyle={{ padding: 16 }} - renderItem={({ item }) => ( + + + {/* Header */} + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + + + Remittances + {data.length} submissions + router.push(`/(app)/remittances/${item.id}`)} + style={{ backgroundColor: 'rgba(255,255,255,0.2)', borderRadius: 12, paddingHorizontal: 16, paddingVertical: 10 }} + onPress={() => router.push('/(app)/remittances/submit')} + activeOpacity={0.7} > - - โ‚ฑ{Number(item.totalAmount).toLocaleString()} - - {item.status} - - - {new Date(item.createdAt).toLocaleDateString()} + + Submit - )} - ListEmptyComponent={No remittances yet} - /> - )} - + + + + {isLoading ? ( + + + + ) : ( + item.id} + refreshControl={} + ListHeaderComponent={ + unremittedTotal > 0 ? ( + router.push('/(app)/remittances/submit')} + style={{ backgroundColor: '#FFF7ED', borderRadius: 16, padding: 18, marginBottom: 16, borderWidth: 1.5, borderColor: '#FED7AA' }} + activeOpacity={0.7} + > + + Unremitted Amount + + + โ‚ฑ{Number(unremittedTotal).toLocaleString()} + + {unremittedCount > 0 && ( + {unremittedCount} payment{unremittedCount !== 1 ? 's' : ''} pending remittance + )} + Tap to submit โ†’ + + ) : null + } + contentContainerStyle={{ padding: 16, paddingBottom: 32 }} + renderItem={({ item }) => { + const st = STATUS_CONFIG[item.status] ?? { color: '#6B7280', bg: '#F1F5F9' }; + return ( + router.push(`/(app)/remittances/${item.id}`)} + activeOpacity={0.7} + > + + โ‚ฑ{Number(item.totalAmount).toLocaleString()} + + {item.status} + + + {new Date(item.createdAt).toLocaleDateString('en-PH', { year: 'numeric', month: 'long', day: 'numeric' })} + {item.payments?.length > 0 && ( + {item.payments.length} payment{item.payments.length !== 1 ? 's' : ''} + )} + + ); + }} + ListEmptyComponent={ + + No remittances yet + + } + /> + )} + + ); } diff --git a/app/(app)/remittances/submit.tsx b/app/(app)/remittances/submit.tsx index f8492c0..2450456 100644 --- a/app/(app)/remittances/submit.tsx +++ b/app/(app)/remittances/submit.tsx @@ -1,57 +1,112 @@ import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; +import { useQuery } from '@tanstack/react-query'; import { api } from '../../../services/api'; export default function SubmitRemittanceScreen() { - const [amount, setAmount] = useState(''); const [notes, setNotes] = useState(''); const [loading, setLoading] = useState(false); + // Fetch unremitted payments to auto-fill amount + const { data: unremittedData, isLoading: loadingUnremitted } = useQuery({ + queryKey: ['unremitted'], + queryFn: () => api.get('/api/v1/payments?unremitted=true').then(r => r.data).catch(() => null), + }); + + const unremittedPayments: any[] = Array.isArray(unremittedData?.data) + ? unremittedData.data + : Array.isArray(unremittedData) + ? unremittedData + : []; + const totalAmount = unremittedData?.totalUnremitted + ?? unremittedPayments.reduce((s: number, p: any) => s + Number(p.amount ?? 0), 0); + const submit = async () => { - if (!amount || isNaN(Number(amount))) return Alert.alert('Required', 'Enter a valid amount.'); + if (totalAmount <= 0) return Alert.alert('Nothing to Submit', 'You have no unremitted payments to submit.'); setLoading(true); try { - await api.post('/api/v1/remittances', { totalAmount: Number(amount), notes }); - Alert.alert('Submitted', 'Remittance submitted successfully.', [{ text: 'OK', onPress: () => router.back() }]); + await api.post('/api/v1/remittances', { totalAmount: Number(totalAmount), notes: notes.trim() || undefined }); + Alert.alert('Submitted!', `โ‚ฑ${Number(totalAmount).toLocaleString()} remittance submitted.`, [ + { text: 'OK', onPress: () => router.back() }, + ]); } catch (e: any) { - Alert.alert('Error', e?.response?.data?.message ?? 'Submission failed.'); + Alert.alert('Error', e?.response?.data?.message ?? 'Submission failed. Please try again.'); } finally { setLoading(false); } }; return ( - - - router.back()} className="mr-3"> - โ† - - Submit Remittance + + + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + Submit Remittance + End-of-day collection + + + + {/* Total amount summary card */} + + Total to Remit + {loadingUnremitted ? ( + + ) : ( + <> + 0 ? '#059669' : '#94A3B8' }}> + โ‚ฑ{Number(totalAmount).toLocaleString()} + + {unremittedPayments.length > 0 && ( + + From {unremittedPayments.length} collection{unremittedPayments.length !== 1 ? 's' : ''} + + )} + + )} + + + {/* Breakdown of payments */} + {unremittedPayments.length > 0 && ( + + Breakdown + {unremittedPayments.map((p: any) => ( + + + {p.client?.firstName} {p.client?.lastName} + {p.paymentMethod} ยท {p.client?.accountNumber} + + โ‚ฑ{Number(p.amount).toLocaleString()} + + ))} + + )} + + {/* Notes */} + Notes (optional) + + + 0 ? '#059669' : '#CBD5E1', borderRadius: 14, paddingVertical: 18, alignItems: 'center' }} + onPress={submit} + disabled={loading || loadingUnremitted || totalAmount <= 0} + activeOpacity={0.8} + > + {loading ? : Submit โ‚ฑ{Number(totalAmount).toLocaleString()}} + + + - - Total Collection (โ‚ฑ) - - Notes (optional) - - - {loading ? : Submit Remittance} - - - + ); } diff --git a/app/(app)/tasks/[id].tsx b/app/(app)/tasks/[id].tsx new file mode 100644 index 0000000..ac9c6c9 --- /dev/null +++ b/app/(app)/tasks/[id].tsx @@ -0,0 +1,548 @@ +import { useState, useRef } from 'react'; +import { + View, Text, ScrollView, TextInput, TouchableOpacity, + ActivityIndicator, Alert, Modal, KeyboardAvoidingView, Platform, +} from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useLocalSearchParams, router } from 'expo-router'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import * as Location from 'expo-location'; +import { api } from '../../../services/api'; +import { useAuthStore } from '../../../stores/authStore'; + +// โ”€โ”€โ”€ Constants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +const STATUS_FLOW = ['OPEN', 'IN_PROGRESS', 'RESOLVED', 'CLOSED'] as const; +type TaskStatus = typeof STATUS_FLOW[number]; + +const STATUS_STYLE: Record = { + OPEN: { bg: '#ECFEFF', color: '#0891B2' }, + IN_PROGRESS: { bg: '#FFFBEB', color: '#D97706' }, + RESOLVED: { bg: '#F0FDF4', color: '#16A34A' }, + CLOSED: { bg: '#F1F5F9', color: '#6B7280' }, +}; +const PRIORITY_COLOR: Record = { HIGH: '#DC2626', NORMAL: '#0891B2' }; +const PRIORITY_BG: Record = { HIGH: '#FEE2E2', NORMAL: '#ECFEFF' }; +const TYPE_COLOR: Record = { INSTALLATION: '#0891B2', SUPPORT: '#7C3AED', BILLING: '#D97706' }; +const TYPE_BG: Record = { INSTALLATION: '#ECFEFF', SUPPORT: '#F5F3FF', BILLING: '#FFFBEB' }; + +function formatDate(iso: string) { + return new Date(iso).toLocaleDateString('en-PH', { + month: 'short', day: 'numeric', year: 'numeric', + hour: '2-digit', minute: '2-digit', + }); +} + +function InfoRow({ label, value, isLast }: { label: string; value?: string | null; isLast?: boolean }) { + if (!value) return null; + return ( + + {label} + {value} + + ); +} + +// โ”€โ”€โ”€ Main Screen โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +export default function TicketDetailScreen() { + const { id } = useLocalSearchParams<{ id: string }>(); + const { user } = useAuthStore(); + const qc = useQueryClient(); + const scrollRef = useRef(null); + + const [activeTab, setActiveTab] = useState<'details' | 'comments'>('details'); + const [showStatusPicker, setShowStatusPicker] = useState(false); + const [instNotes, setInstNotes] = useState(''); + const [instConfirming, setInstConfirming] = useState(false); + const [coords, setCoords] = useState<{ lat: number; lng: number } | null>(null); + const [locLoading, setLocLoading] = useState(false); + const [comment, setComment] = useState(''); + const [sendingComment, setSendingComment] = useState(false); + + const { data: ticket, isLoading, refetch } = useQuery({ + queryKey: ['task', id], + queryFn: () => api.get(`/api/v1/tickets/${id}`).then(r => r.data), + }); + + const updateStatus = useMutation({ + mutationFn: async (status: TaskStatus) => { + await api.patch(`/api/v1/tickets/${id}`, { status }); + // Log status change as a system comment + const who = user?.firstName ?? 'Staff'; + await api.post(`/api/v1/tickets/${id}/messages`, { + message: `Status changed to ${status.replace('_', ' ')} by ${who}`, + }).catch(() => {}); + }, + onSuccess: () => { + setShowStatusPicker(false); + refetch(); + qc.invalidateQueries({ queryKey: ['tasks'] }); + }, + onError: () => Alert.alert('Error', 'Could not update status.'), + }); + + const captureLocation = async () => { + setLocLoading(true); + try { + const { status } = await Location.requestForegroundPermissionsAsync(); + if (status !== 'granted') { + Alert.alert('Permission Denied', 'Location permission is required to record the installation site.'); + return; + } + const loc = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High }); + setCoords({ lat: loc.coords.latitude, lng: loc.coords.longitude }); + } catch { + Alert.alert('Error', 'Could not get location. Make sure GPS is enabled.'); + } finally { + setLocLoading(false); + } + }; + + const confirmInstallation = async () => { + if (!coords) { + Alert.alert('Location Required', 'Please capture the installation coordinates before confirming.', [ + { text: 'Cancel', style: 'cancel' }, + { text: 'Capture Now', onPress: captureLocation }, + ]); + return; + } + setInstConfirming(true); + try { + // 1. Resolve the ticket + await api.patch(`/api/v1/tickets/${id}`, { status: 'RESOLVED' }); + + // 2. Update client location with recorded coordinates + if (ticket?.clientId) { + await api.patch(`/api/v1/clients/${ticket.clientId}`, { + lat: coords.lat, + lng: coords.lng, + }).catch(() => {}); + } + + // 3. Log activity comment + const coordStr = `${coords.lat.toFixed(6)}, ${coords.lng.toFixed(6)}`; + const note = instNotes.trim() + ? `Installation confirmed. Location recorded: ${coordStr}. Notes: ${instNotes.trim()}` + : `Installation confirmed. Location recorded: ${coordStr}`; + await api.post(`/api/v1/tickets/${id}/messages`, { message: note }).catch(() => {}); + + setInstNotes(''); + setCoords(null); + Alert.alert('Installation Complete!', 'Ticket resolved and client location updated.'); + refetch(); + qc.invalidateQueries({ queryKey: ['tasks'] }); + qc.invalidateQueries({ queryKey: ['client', ticket?.clientId] }); + setActiveTab('comments'); + } catch { + Alert.alert('Error', 'Could not confirm installation. Please try again.'); + } finally { + setInstConfirming(false); + } + }; + + const sendComment = async () => { + if (!comment.trim()) return; + setSendingComment(true); + const text = comment.trim(); + setComment(''); // clear immediately for responsiveness + try { + await api.post(`/api/v1/tickets/${id}/messages`, { message: text }); + refetch(); + setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 300); + } catch { + Alert.alert('Error', 'Could not send comment.'); + setComment(text); // restore on failure + } finally { + setSendingComment(false); + } + }; + + if (isLoading) { + return ( + + + + + + ); + } + + const currentStatus: string = ticket?.status ?? 'OPEN'; + const statusStyle = STATUS_STYLE[currentStatus] ?? STATUS_STYLE.OPEN; + const isInstallation = ticket?.type === 'INSTALLATION'; + const isDone = currentStatus === 'RESOLVED' || currentStatus === 'CLOSED'; + const typeColor = TYPE_COLOR[ticket?.type] ?? '#6B7280'; + const typeBg = TYPE_BG[ticket?.type] ?? '#F1F5F9'; + const messages: any[] = ticket?.messages ?? []; + + return ( + + + + + {/* โ”€โ”€ Header โ”€โ”€ */} + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + + {ticket?.subject} + + + {/* Type */} + + {ticket?.type} + + {/* Status โ€” tappable to change */} + setShowStatusPicker(true)} + style={{ borderRadius: 20, paddingHorizontal: 14, paddingVertical: 7, backgroundColor: statusStyle.bg }} + activeOpacity={0.7} + > + + {currentStatus.replace('_', ' ')} โ–พ + + + {/* Priority โ€” only show HIGH */} + {ticket?.priority === 'HIGH' && ( + + HIGH + + )} + + {ticket?.client && ( + + {ticket.client.firstName} {ticket.client.lastName} ยท {ticket.client.accountNumber} + {ticket.assignedTo + ? ` ยท Assigned: ${ticket.assignedTo.firstName} ${ticket.assignedTo.lastName}` + : ' ยท Unassigned'} + + )} + + + {/* โ”€โ”€ Tabs โ”€โ”€ */} + + {[ + { key: 'details', label: 'Details' }, + { key: 'comments', label: `Comments${messages.length > 0 ? ` (${messages.length})` : ''}` }, + ].map(tab => ( + setActiveTab(tab.key as 'details' | 'comments')} + style={{ + flex: 1, paddingVertical: 16, alignItems: 'center', + borderBottomWidth: 2.5, + borderBottomColor: activeTab === tab.key ? '#0891B2' : 'transparent', + }} + activeOpacity={0.7} + > + + {tab.label} + + + ))} + + + {/* โ”€โ”€ DETAILS TAB โ”€โ”€ */} + {activeTab === 'details' && ( + + {/* Info card */} + + + + + + + + + + {/* Description */} + {ticket?.description ? ( + + Description + {ticket.description} + + ) : null} + + {/* โ”€โ”€ INSTALLATION SECTION โ”€โ”€ */} + {isInstallation && ( + <> + + + + Installation + + + + + {isDone ? ( + /* โ”€ Already confirmed โ”€ */ + + โœ… + Installation Complete + {ticket?.resolvedAt && ( + + Confirmed on {formatDate(ticket.resolvedAt)} + + )} + setActiveTab('comments')} + style={{ marginTop: 12 }} + activeOpacity={0.7} + > + + View activity log โ†’ + + + + ) : ( + /* โ”€ Confirm installation form โ”€ */ + + + Confirm Installation + + + {/* โ”€โ”€ GPS Coordinates (required) โ”€โ”€ */} + + ๐Ÿ“ Installation Location * + + {coords ? ( + + + โœ“ Location Captured + + {coords.lat.toFixed(6)}, {coords.lng.toFixed(6)} + + + + + {locLoading ? '...' : 'Retake'} + + + + ) : ( + + {locLoading + ? <>Getting GPS... + : <>๐Ÿ“Capture Current Location + } + + )} + + {/* โ”€โ”€ Notes โ”€โ”€ */} + + Notes / Remarks + + + + + Alert.alert( + 'Confirm Installation', + `Mark this installation as complete?\n\nLocation: ${coords ? `${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)}` : 'Not captured'}\n\nThis will update the client's location and resolve the ticket.`, + [ + { text: 'Cancel', style: 'cancel' }, + { text: 'Confirm', onPress: confirmInstallation }, + ] + ) + } + disabled={instConfirming || !coords} + activeOpacity={0.8} + > + {instConfirming + ? + : + {coords ? 'โœ“ Mark Installation Complete' : 'Capture Location First'} + + } + + + )} + + )} + + )} + + {/* โ”€โ”€ COMMENTS TAB โ”€โ”€ */} + {activeTab === 'comments' && ( + + + {messages.length === 0 ? ( + + No comments yet + + Add a note or update below + + + ) : ( + messages.map((m: any, i: number) => { + const isSystem = m.senderType === 'SYSTEM' || m.message?.startsWith('Status changed') || m.message?.startsWith('Installation confirmed'); + const isMe = m.sender?.id === user?.id; + + if (isSystem) { + // System messages โ€” centered pill + return ( + + + {m.message} + + {m.createdAt && ( + + {formatDate(m.createdAt)} + + )} + + ); + } + + // User messages โ€” chat bubbles + return ( + + {!isMe && ( + + {m.senderName ?? m.sender?.firstName ?? 'Staff'} + + )} + + + {m.message} + + + {m.createdAt && ( + + {formatDate(m.createdAt)} + + )} + + ); + }) + )} + + + {/* โ”€โ”€ Comment input โ€” ALWAYS visible โ”€โ”€ */} + + + + {sendingComment + ? + : + Send + + } + + + + )} + + + {/* โ”€โ”€ Status Picker Modal โ”€โ”€ */} + setShowStatusPicker(false)}> + setShowStatusPicker(false)} + > + + Update Status + + Current: {currentStatus.replace('_', ' ')} + + {STATUS_FLOW.map(s => { + const style = STATUS_STYLE[s]; + const isActive = s === currentStatus; + return ( + !isActive && updateStatus.mutate(s)} + disabled={isActive || updateStatus.isPending} + style={{ + flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', + padding: 18, borderRadius: 16, marginBottom: 10, + backgroundColor: style.bg, opacity: isActive ? 0.5 : 1, + }} + activeOpacity={0.7} + > + {s.replace('_', ' ')} + {isActive && โœ“ Current} + {updateStatus.isPending && !isActive && } + + ); + })} + setShowStatusPicker(false)} style={{ paddingVertical: 14, alignItems: 'center' }}> + Cancel + + + + + + + ); +} diff --git a/app/(app)/tasks/_layout.tsx b/app/(app)/tasks/_layout.tsx new file mode 100644 index 0000000..8e14a2b --- /dev/null +++ b/app/(app)/tasks/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router'; +export default function TasksLayout() { + return ; +} diff --git a/app/(app)/tasks/index.tsx b/app/(app)/tasks/index.tsx new file mode 100644 index 0000000..7c2f478 --- /dev/null +++ b/app/(app)/tasks/index.tsx @@ -0,0 +1,142 @@ +import { useState } from 'react'; +import { View, Text, FlatList, TextInput, TouchableOpacity, ActivityIndicator, RefreshControl, ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useQuery } from '@tanstack/react-query'; +import { router } from 'expo-router'; +import { api } from '../../../services/api'; + +const PRIORITY_COLOR: Record = { HIGH: '#DC2626', NORMAL: '#0891B2', LOW: '#6B7280' }; +const PRIORITY_BG: Record = { HIGH: '#FEE2E2', NORMAL: '#ECFEFF', LOW: '#F1F5F9' }; +const STATUS_COLOR: Record = { OPEN: '#0891B2', IN_PROGRESS: '#D97706', RESOLVED: '#16A34A', CLOSED: '#6B7280' }; +const STATUS_BG: Record = { OPEN: '#ECFEFF', IN_PROGRESS: '#FFFBEB', RESOLVED: '#F0FDF4', CLOSED: '#F1F5F9' }; +const TYPE_COLOR: Record = { INSTALLATION: '#0891B2', SUPPORT: '#7C3AED', BILLING: '#D97706' }; +const TYPE_BG: Record = { INSTALLATION: '#ECFEFF', SUPPORT: '#F5F3FF', BILLING: '#FFFBEB' }; + +const STATUS_FILTERS = ['All', 'OPEN', 'IN_PROGRESS', 'RESOLVED', 'CLOSED']; + +export default function TasksScreen() { + const [search, setSearch] = useState(''); + const [statusFilter, setStatusFilter] = useState('All'); + + const { data, isLoading, refetch, isRefetching } = useQuery({ + queryKey: ['tasks'], + queryFn: () => api.get('/api/v1/tickets?limit=100').then(r => r.data?.data ?? r.data ?? []), + }); + + const tasks = (data ?? []).filter((t: any) => { + const matchSearch = `${t.subject} ${t.client?.firstName ?? ''} ${t.client?.lastName ?? ''}`.toLowerCase().includes(search.toLowerCase()); + const matchStatus = statusFilter === 'All' || t.status === statusFilter; + return matchSearch && matchStatus; + }); + + return ( + + + + + Tickets + {tasks.length} showing + + router.push('/(app)/tasks/new')} + activeOpacity={0.7} + > + + Ticket + + + + + + + {search.length > 0 && ( + setSearch('')} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + + ร— + + + )} + + + + {STATUS_FILTERS.map(f => { + const isActive = statusFilter === f; + const color = f === 'All' ? '#0891B2' : STATUS_COLOR[f] ?? '#6B7280'; + return ( + setStatusFilter(f)} + style={{ borderRadius: 20, paddingHorizontal: 16, paddingVertical: 8, marginRight: 8, backgroundColor: isActive ? color : '#F1F5F9' }} + activeOpacity={0.7} + > + + {f === 'All' ? 'All' : f.replace('_', ' ')} + + + ); + })} + + + + {isLoading ? ( + + + + ) : ( + item.id} + refreshControl={} + contentContainerStyle={{ padding: 16, paddingBottom: 32 }} + renderItem={({ item }) => { + const typeColor = TYPE_COLOR[item.type] ?? '#6B7280'; + const typeBg = TYPE_BG[item.type] ?? '#F1F5F9'; + return ( + router.push(`/(app)/tasks/${item.id}`)} + activeOpacity={0.7} + > + + + + {item.type} + + {item.priority === 'HIGH' && ( + + HIGH + + )} + + + {item.status?.replace('_', ' ')} + + + {item.subject} + + {item.client?.firstName} {item.client?.lastName} + {item.assignedTo ? ` ยท ${item.assignedTo.firstName} ${item.assignedTo.lastName}` : ' ยท Unassigned'} + + {item._count?.messages > 0 && ( + {item._count.messages} message{item._count.messages !== 1 ? 's' : ''} + )} + + ); + }} + ListEmptyComponent={ + + No tasks found + + } + /> + )} + + + ); +} diff --git a/app/(app)/tasks/new.tsx b/app/(app)/tasks/new.tsx new file mode 100644 index 0000000..ded4b30 --- /dev/null +++ b/app/(app)/tasks/new.tsx @@ -0,0 +1,202 @@ +import { useState } from 'react'; +import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { router } from 'expo-router'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { api } from '../../../services/api'; + +const PRIORITIES = ['NORMAL', 'HIGH']; +const PRIORITY_COLOR: Record = { HIGH: '#DC2626', NORMAL: '#0891B2' }; +const PRIORITY_BG: Record = { HIGH: '#FEE2E2', NORMAL: '#ECFEFF' }; + +const TYPES = [ + { value: 'SUPPORT', label: 'Support' }, + { value: 'INSTALLATION', label: 'Installation' }, + { value: 'BILLING', label: 'Billing' }, +]; + +export default function NewTaskScreen() { + const qc = useQueryClient(); + const [subject, setSubject] = useState(''); + const [description, setDescription] = useState(''); + const [priority, setPriority] = useState('NORMAL'); + const [type, setType] = useState('SUPPORT'); + const [search, setSearch] = useState(''); + const [debouncedSearch, setDebouncedSearch] = useState(''); + const [client, setClient] = useState(null); + const [loading, setLoading] = useState(false); + + const { data: searchResults, isFetching: searching } = useQuery({ + queryKey: ['client-search', debouncedSearch], + queryFn: () => api.get(`/api/v1/clients?search=${debouncedSearch}&limit=8`).then(r => r.data?.data ?? r.data ?? []), + enabled: debouncedSearch.trim().length >= 2, + }); + + const handleSearchChange = (v: string) => { + setSearch(v); + setTimeout(() => setDebouncedSearch(v), 400); + }; + + const submit = async () => { + if (!subject.trim()) return Alert.alert('Required', 'Please enter a subject.'); + if (!client) return Alert.alert('Required', 'Please select a client.'); + setLoading(true); + try { + await api.post('/api/v1/tickets', { + subject: subject.trim(), + description: description.trim() || undefined, + priority, type, clientId: client.id, + }); + qc.invalidateQueries({ queryKey: ['tasks'] }); + qc.invalidateQueries({ queryKey: ['dashboard'] }); + Alert.alert('Task Created', subject, [{ text: 'OK', onPress: () => router.back() }]); + } catch (e: any) { + Alert.alert('Error', e?.response?.data?.message ?? 'Could not create task.'); + } finally { setLoading(false); } + }; + + return ( + + + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + New Ticket + + + + {/* Client Search */} + + Client * + + {client ? ( + + + {client.firstName} {client.lastName} + {client.accountNumber} + + { setClient(null); setSearch(''); setDebouncedSearch(''); }} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + Change + + + ) : ( + + + + {search.length > 0 && ( + { setSearch(''); setDebouncedSearch(''); }} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + + ร— + + + )} + {searching && } + + {debouncedSearch.trim().length >= 2 && ( + + {(searchResults ?? []).length === 0 && !searching ? ( + No clients found + ) : ( + (searchResults ?? []).map((c: any, i: number, arr: any[]) => ( + { setClient(c); setSearch(''); setDebouncedSearch(''); }} + activeOpacity={0.7} + > + {c.firstName} {c.lastName} + {c.accountNumber} + + )) + )} + + )} + + )} + + {/* Subject */} + + Subject * + + + + {/* Type */} + Type + + {TYPES.map(t => ( + setType(t.value)} + style={{ borderRadius: 20, paddingHorizontal: 16, paddingVertical: 10, marginRight: 8, marginBottom: 8, backgroundColor: type === t.value ? '#0891B2' : '#FFF', borderWidth: 1.5, borderColor: type === t.value ? '#0891B2' : '#E2E8F0' }} + activeOpacity={0.7} + > + {t.label} + + ))} + + + {/* Priority */} + Priority + + {PRIORITIES.map(p => { + const isSelected = priority === p; + const isHigh = p === 'HIGH'; + const selectedBg = isHigh ? '#DC2626' : '#0891B2'; + const unselectedBg = isHigh ? '#FEF2F2' : '#F0F9FF'; + const selectedText = '#FFF'; + const unselectedText = isHigh ? '#DC2626' : '#0891B2'; + const desc = isHigh ? 'Urgent, escalate' : 'Standard queue'; + return ( + setPriority(p)} + style={{ flex: 1, borderRadius: 14, paddingVertical: 16, alignItems: 'center', marginHorizontal: 4, backgroundColor: isSelected ? selectedBg : unselectedBg, borderWidth: 1.5, borderColor: isSelected ? selectedBg : '#E2E8F0' }} + activeOpacity={0.7} + > + {p} + {desc} + + ); + })} + + + {/* Description */} + + Description (optional) + + + + + {loading ? : Create Ticket} + + + + + ); +} diff --git a/app/(app)/tickets/[id].tsx b/app/(app)/tickets/[id].tsx deleted file mode 100644 index 984c065..0000000 --- a/app/(app)/tickets/[id].tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { useState } from 'react'; -import { - View, Text, ScrollView, TextInput, TouchableOpacity, - ActivityIndicator, Alert, Modal, -} from 'react-native'; -import { useLocalSearchParams, router } from 'expo-router'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { api } from '../../../services/api'; - -const STATUS_FLOW = ['OPEN', 'IN_PROGRESS', 'RESOLVED', 'CLOSED'] as const; -type TicketStatus = typeof STATUS_FLOW[number]; - -const STATUS_STYLE: Record = { - OPEN: { bg: '#EFF6FF', text: '#2563EB' }, - IN_PROGRESS: { bg: '#FFFBEB', text: '#D97706' }, - RESOLVED: { bg: '#F0FDF4', text: '#16A34A' }, - CLOSED: { bg: '#F3F4F6', text: '#6B7280' }, -}; - -const PRIORITY_COLOR: Record = { - HIGH: '#DC2626', MEDIUM: '#D97706', LOW: '#6B7280', -}; - -export default function TicketDetailScreen() { - const { id } = useLocalSearchParams<{ id: string }>(); - const [reply, setReply] = useState(''); - const [showStatusPicker, setShowStatusPicker] = useState(false); - const qc = useQueryClient(); - - const { data, isLoading } = useQuery({ - queryKey: ['ticket', id], - queryFn: () => api.get(`/api/v1/tickets/${id}`).then(r => r.data), - }); - - const addReply = useMutation({ - mutationFn: () => api.post(`/api/v1/tickets/${id}/messages`, { message: reply }), - onSuccess: () => { - setReply(''); - qc.invalidateQueries({ queryKey: ['ticket', id] }); - }, - onError: () => Alert.alert('Error', 'Could not send reply.'), - }); - - const updateStatus = useMutation({ - mutationFn: (status: TicketStatus) => - api.patch(`/api/v1/tickets/${id}`, { status }), - onSuccess: () => { - setShowStatusPicker(false); - qc.invalidateQueries({ queryKey: ['ticket', id] }); - qc.invalidateQueries({ queryKey: ['tickets'] }); - }, - onError: () => Alert.alert('Error', 'Could not update status.'), - }); - - if (isLoading) { - return ( - - - - ); - } - - const currentStatus: string = data?.status ?? 'OPEN'; - const statusStyle = STATUS_STYLE[currentStatus] ?? { bg: '#F3F4F6', text: '#6B7280' }; - const priorityColor = PRIORITY_COLOR[data?.priority] ?? '#6B7280'; - - return ( - - {/* Header */} - - - router.back()} className="mr-3"> - โ† - - - {data?.subject} - - - - {/* Status badge - tappable */} - setShowStatusPicker(true)} - className="rounded-full px-3 py-1 flex-row items-center" - style={{ backgroundColor: statusStyle.bg }} - > - - {currentStatus.replace('_', ' ')} - - โ–พ - - {/* Priority */} - - - {data?.priority} - - - {/* Client name */} - {data?.client && ( - - {data.client.firstName} {data.client.lastName} - - )} - - - - {/* Messages */} - - {data?.description && ( - - Description - {data.description} - - )} - - {(data?.messages ?? []).length === 0 && !data?.description && ( - - No messages yet. Send the first reply. - - )} - - {(data?.messages ?? []).map((m: any) => { - const isAgent = m.senderType === 'AGENT' || m.senderType === 'STAFF'; - return ( - - - {m.message} - - - {m.senderName ?? m.sender?.name ?? 'System'} - - - ); - })} - - - {/* Reply bar โ€” hide if ticket is closed */} - {currentStatus !== 'CLOSED' ? ( - - - reply.trim() && addReply.mutate()} - disabled={addReply.isPending || !reply.trim()} - style={{ opacity: !reply.trim() ? 0.5 : 1 }} - > - {addReply.isPending - ? - : Send - } - - - ) : ( - - This ticket is closed - - )} - - {/* Status picker modal */} - setShowStatusPicker(false)} - > - setShowStatusPicker(false)} - > - - Update Status - - Current: {currentStatus.replace('_', ' ')} - - {STATUS_FLOW.map((s) => { - const style = STATUS_STYLE[s] ?? { bg: '#F3F4F6', text: '#6B7280' }; - const isActive = s === currentStatus; - return ( - !isActive && updateStatus.mutate(s)} - disabled={isActive || updateStatus.isPending} - className={`flex-row items-center justify-between p-4 rounded-xl mb-2 ${isActive ? 'opacity-40' : ''}`} - style={{ backgroundColor: style.bg }} - > - - {s.replace('_', ' ')} - - {isActive && โœ“ Current} - {updateStatus.isPending && !isActive && } - - ); - })} - setShowStatusPicker(false)} - > - Cancel - - - - - - ); -} diff --git a/app/(app)/tickets/index.tsx b/app/(app)/tickets/index.tsx deleted file mode 100644 index ae9f600..0000000 --- a/app/(app)/tickets/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useState } from 'react'; -import { View, Text, FlatList, TextInput, TouchableOpacity, ActivityIndicator, RefreshControl, ScrollView } from 'react-native'; -import { useQuery } from '@tanstack/react-query'; -import { router } from 'expo-router'; -import { api } from '../../../services/api'; - -const PRIORITY_COLOR: Record = { HIGH: '#DC2626', MEDIUM: '#D97706', LOW: '#16A34A' }; -const STATUS_FILTERS = ['ALL', 'OPEN', 'IN_PROGRESS', 'RESOLVED', 'CLOSED']; - -export default function TicketsScreen() { - const [search, setSearch] = useState(''); - const [statusFilter, setStatusFilter] = useState('ALL'); - - const { data, isLoading, refetch, isRefetching } = useQuery({ - queryKey: ['tickets'], - queryFn: () => api.get('/api/v1/tickets?limit=100').then(r => r.data?.data ?? r.data ?? []), - }); - - const tickets = (data ?? []).filter((t: any) => { - const matchSearch = `${t.subject} ${t.client?.firstName} ${t.client?.lastName}`.toLowerCase().includes(search.toLowerCase()); - const matchStatus = statusFilter === 'ALL' || t.status === statusFilter; - return matchSearch && matchStatus; - }); - - return ( - - {/* Header */} - - Tickets - router.push('/(app)/tickets/new')} - > - + New - - - - {/* Search */} - - - {/* Status filter chips */} - - {STATUS_FILTERS.map(s => ( - setStatusFilter(s)} - className={`rounded-full px-3 py-1.5 mr-2 ${statusFilter === s ? 'bg-primary' : 'bg-gray-100'}`} - > - - {s.replace('_', ' ')} - - - ))} - - - - {isLoading ? ( - - ) : ( - item.id} - refreshControl={} - contentContainerStyle={{ paddingHorizontal: 16, paddingVertical: 12, paddingBottom: 32 }} - renderItem={({ item }) => ( - router.push(`/(app)/tickets/${item.id}`)} - > - - {item.subject} - - {item.priority} - - - - - {item.client?.firstName} {item.client?.lastName} - - {item.status?.replace('_', ' ')} - - - )} - ListEmptyComponent={ - - ๐ŸŽซ - No tickets found - router.push('/(app)/tickets/new')} - > - Create First Ticket - - - } - /> - )} - - ); -} diff --git a/app/(app)/tickets/new.tsx b/app/(app)/tickets/new.tsx deleted file mode 100644 index ff5c5b8..0000000 --- a/app/(app)/tickets/new.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { useState } from 'react'; -import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; -import { router } from 'expo-router'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { api } from '../../../services/api'; - -const PRIORITIES = ['LOW', 'MEDIUM', 'HIGH']; -const PRIORITY_COLOR: Record = { HIGH: '#DC2626', MEDIUM: '#D97706', LOW: '#16A34A' }; - -const CATEGORIES: { value: string; label: string }[] = [ - { value: 'NO_SIGNAL', label: 'No Signal' }, - { value: 'SLOW_CONNECTION', label: 'Slow Connection' }, - { value: 'BILLING', label: 'Billing' }, - { value: 'INSTALLATION', label: 'Installation' }, - { value: 'RELOCATION', label: 'Relocation' }, - { value: 'OTHER', label: 'Other' }, -]; - -export default function NewTicketScreen() { - const qc = useQueryClient(); - const [subject, setSubject] = useState(''); - const [description, setDescription] = useState(''); - const [priority, setPriority] = useState('MEDIUM'); - const [category, setCategory] = useState('NO_SIGNAL'); - const [search, setSearch] = useState(''); - const [debouncedSearch, setDebouncedSearch] = useState(''); - const [client, setClient] = useState(null); - const [loading, setLoading] = useState(false); - - const { data: searchResults, isFetching: searching } = useQuery({ - queryKey: ['client-search', debouncedSearch], - queryFn: () => api.get(`/api/v1/clients?search=${debouncedSearch}&limit=8`).then(r => r.data?.data ?? r.data ?? []), - enabled: debouncedSearch.trim().length >= 2, - }); - - const handleSearchChange = (v: string) => { - setSearch(v); - setTimeout(() => setDebouncedSearch(v), 400); - }; - - const submit = async () => { - if (!subject.trim()) return Alert.alert('Required', 'Enter a subject.'); - if (!client) return Alert.alert('Required', 'Select a client.'); - setLoading(true); - try { - await api.post('/api/v1/tickets', { - subject: subject.trim(), - description: description.trim() || undefined, - priority, - category, - clientId: client.id, - }); - qc.invalidateQueries({ queryKey: ['tickets'] }); - qc.invalidateQueries({ queryKey: ['dashboard'] }); - Alert.alert('โœ… Ticket Created', subject, [{ text: 'OK', onPress: () => router.back() }]); - } catch (e: any) { - Alert.alert('Error', e?.response?.data?.message ?? 'Could not create ticket.'); - } finally { - setLoading(false); - } - }; - - return ( - - - router.back()} className="mr-3 p-1"> - โ† - - New Ticket - - - - {/* Client */} - Client * - {client ? ( - - - {client.firstName} {client.lastName} - {client.accountNumber} - - { setClient(null); setSearch(''); setDebouncedSearch(''); }} className="p-2"> - Change - - - ) : ( - - - - {searching && } - - {debouncedSearch.trim().length >= 2 && ( - - {(searchResults ?? []).length === 0 && !searching && ( - No clients found - )} - {(searchResults ?? []).map((c: any) => ( - { setClient(c); setSearch(''); setDebouncedSearch(''); }} - > - {c.firstName} {c.lastName} - {c.accountNumber} - - ))} - - )} - - )} - - {/* Subject */} - Subject * - - - {/* Category */} - Category - - {CATEGORIES.map(c => ( - setCategory(c.value)} - className={`rounded-xl px-3 py-2 mr-2 mb-2 border ${category === c.value ? 'bg-primary border-primary' : 'bg-white border-gray-200'}`} - > - - {c.label} - - - ))} - - - {/* Priority */} - Priority - - {PRIORITIES.map(p => ( - setPriority(p)} - className={`flex-1 rounded-xl py-2.5 items-center mx-1 border ${priority === p ? 'border-transparent' : 'bg-white border-gray-200'}`} - style={priority === p ? { backgroundColor: PRIORITY_COLOR[p] } : {}} - > - {p} - - ))} - - - {/* Description */} - Description (optional) - - - - {loading ? : Create Ticket} - - - - - - ); -} diff --git a/app/(app)/users/[id].tsx b/app/(app)/users/[id].tsx new file mode 100644 index 0000000..524cad5 --- /dev/null +++ b/app/(app)/users/[id].tsx @@ -0,0 +1,183 @@ +import { useState } from 'react'; +import { View, Text, TouchableOpacity, ScrollView, Alert, ActivityIndicator, Switch } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useLocalSearchParams, router } from 'expo-router'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { api } from '../../../services/api'; + +const ROLE_COLOR: Record = { ADMIN: '#7C3AED', STAFF: '#0891B2', TECHNICIAN: '#059669', COLLECTOR: '#D97706' }; +const ROLE_BG: Record = { ADMIN: '#F5F3FF', STAFF: '#ECFEFF', TECHNICIAN: '#F0FDF4', COLLECTOR: '#FFFBEB' }; + +const ROLES = [ + { value: 'TECHNICIAN', label: 'Technician', desc: 'Field work & installations' }, + { value: 'COLLECTOR', label: 'Collector', desc: 'Payments & remittances' }, + { value: 'STAFF', label: 'Staff', desc: 'General access' }, + { value: 'ADMIN', label: 'Admin', desc: 'Full access + user mgmt' }, +]; + +function InfoRow({ label, value }: { label: string; value?: string | null }) { + return ( + + {label} + {value ?? 'โ€”'} + + ); +} + +export default function UserDetailScreen() { + const { id } = useLocalSearchParams<{ id: string }>(); + const qc = useQueryClient(); + const [editingRole, setEditingRole] = useState(false); + const [newRole, setNewRole] = useState(''); + + const { data: user, isLoading } = useQuery({ + queryKey: ['user', id], + queryFn: () => api.get(`/api/v1/users/${id}`).then(r => r.data), + }); + + const toggleActive = useMutation({ + mutationFn: (isActive: boolean) => api.patch(`/api/v1/users/${id}`, { isActive }), + onSuccess: () => qc.invalidateQueries({ queryKey: ['user', id] }), + onError: () => Alert.alert('Error', 'Could not update user status.'), + }); + + const changeRole = useMutation({ + mutationFn: (role: string) => api.patch(`/api/v1/users/${id}`, { role }), + onSuccess: () => { + setEditingRole(false); + qc.invalidateQueries({ queryKey: ['user', id] }); + qc.invalidateQueries({ queryKey: ['users'] }); + }, + onError: () => Alert.alert('Error', 'Could not update role.'), + }); + + if (isLoading) { + return ( + + + + + + ); + } + + const role = user?.roleAssignments?.[0]?.role ?? 'STAFF'; + const roleColor = ROLE_COLOR[role] ?? '#6B7280'; + const roleBg = ROLE_BG[role] ?? '#F1F5F9'; + const initials = `${user?.firstName?.[0] ?? ''}${user?.lastName?.[0] ?? ''}`.toUpperCase(); + const isActive = user?.isActive ?? true; + const lastLogin = user?.lastLoginAt ? new Date(user.lastLoginAt).toLocaleDateString('en-PH', { month: 'long', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit' }) : 'Never'; + + return ( + + + {/* Header */} + + router.back()} style={{ alignSelf: 'flex-start', marginBottom: 16 }} activeOpacity={0.7}> + โ† Back + + + {initials} + + {user?.firstName} {user?.lastName} + + {role} + + {!isActive && ( + + Inactive Account + + )} + + + + {/* Info Card */} + + + + + + Account Status + + + + {isActive ? 'Active' : 'Inactive'} + + + {isActive ? 'User can log in' : 'Login is blocked'} + + + Alert.alert( + val ? 'Activate User' : 'Deactivate User', + val ? `Allow ${user?.firstName} to log in?` : `Block ${user?.firstName} from logging in?`, + [ + { text: 'Cancel', style: 'cancel' }, + { text: val ? 'Activate' : 'Deactivate', onPress: () => toggleActive.mutate(val), style: val ? 'default' : 'destructive' }, + ] + )} + trackColor={{ false: '#E2E8F0', true: '#0891B2' }} + thumbColor="#FFF" + /> + + + + + {/* Role Change */} + + + Role + { setEditingRole(!editingRole); setNewRole(role); }} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + {editingRole ? 'Cancel' : 'Change'} + + + {editingRole && ( + + {ROLES.map(r => { + const isSelected = (newRole || role) === r.value; + const rc = ROLE_COLOR[r.value] ?? '#6B7280'; + const rb = ROLE_BG[r.value] ?? '#F1F5F9'; + return ( + setNewRole(r.value)} + style={{ flexDirection: 'row', alignItems: 'center', borderRadius: 14, padding: 14, marginBottom: 8, borderWidth: 2, borderColor: isSelected ? rc : '#E2E8F0', backgroundColor: isSelected ? rb : '#FFF' }} + activeOpacity={0.7} + > + + {r.label} + {r.desc} + + + {isSelected && } + + + ); + })} + newRole && newRole !== role && Alert.alert( + 'Change Role', + `Change ${user?.firstName}'s role to ${newRole}?`, + [ + { text: 'Cancel', style: 'cancel' }, + { text: 'Change', onPress: () => changeRole.mutate(newRole) }, + ] + )} + disabled={changeRole.isPending || !newRole || newRole === role} + activeOpacity={0.8} + > + {changeRole.isPending + ? + : Apply Role Change + } + + + )} + + + + + ); +} diff --git a/app/(app)/users/_layout.tsx b/app/(app)/users/_layout.tsx new file mode 100644 index 0000000..eb2f331 --- /dev/null +++ b/app/(app)/users/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router'; +export default function UsersLayout() { + return ; +} diff --git a/app/(app)/users/index.tsx b/app/(app)/users/index.tsx new file mode 100644 index 0000000..db3530a --- /dev/null +++ b/app/(app)/users/index.tsx @@ -0,0 +1,141 @@ +import { useState } from 'react'; +import { View, Text, FlatList, TextInput, TouchableOpacity, ActivityIndicator, RefreshControl, Alert } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { router } from 'expo-router'; +import { api } from '../../../services/api'; + +const ROLE_COLOR: Record = { + ADMIN: '#7C3AED', + STAFF: '#0891B2', + TECHNICIAN: '#059669', + COLLECTOR: '#D97706', +}; +const ROLE_BG: Record = { + ADMIN: '#F5F3FF', + STAFF: '#ECFEFF', + TECHNICIAN: '#F0FDF4', + COLLECTOR: '#FFFBEB', +}; + +export default function UsersScreen() { + const [search, setSearch] = useState(''); + const qc = useQueryClient(); + + const { data, isLoading, refetch, isRefetching } = useQuery({ + queryKey: ['users'], + queryFn: () => api.get('/api/v1/users').then(r => Array.isArray(r.data) ? r.data : r.data?.data ?? []), + }); + + const toggleActive = useMutation({ + mutationFn: ({ id, isActive }: { id: string; isActive: boolean }) => + api.patch(`/api/v1/users/${id}`, { isActive }), + onSuccess: () => qc.invalidateQueries({ queryKey: ['users'] }), + onError: () => Alert.alert('Error', 'Could not update user.'), + }); + + const users = (data ?? []).filter((u: any) => + `${u.firstName} ${u.lastName} ${u.email}`.toLowerCase().includes(search.toLowerCase()) + ); + + return ( + + + {/* Header */} + + + router.back()} activeOpacity={0.7} style={{ marginBottom: 8 }}> + โ† Back + + Users + {users.length} members + + router.push('/(app)/users/new')} + activeOpacity={0.7} + > + + Add User + + + + {/* Search */} + + + + {search.length > 0 && ( + setSearch('')} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + + ร— + + + )} + + + + {isLoading ? ( + + + + ) : ( + item.id} + refreshControl={} + contentContainerStyle={{ padding: 16, paddingBottom: 32 }} + renderItem={({ item }) => { + const role = item.roleAssignments?.[0]?.role ?? 'STAFF'; + const roleColor = ROLE_COLOR[role] ?? '#6B7280'; + const roleBg = ROLE_BG[role] ?? '#F1F5F9'; + const initials = `${item.firstName?.[0] ?? ''}${item.lastName?.[0] ?? ''}`.toUpperCase(); + + return ( + router.push(`/(app)/users/${item.id}`)} + activeOpacity={0.7} + > + {/* Avatar */} + + {initials} + + + {/* Info */} + + + + {item.firstName} {item.lastName} + + {!item.isActive && ( + + Inactive + + )} + + {item.email} + + + {/* Role badge */} + + {role} + + + ); + }} + ListEmptyComponent={ + + No users found + + } + /> + )} + + + ); +} diff --git a/app/(app)/users/new.tsx b/app/(app)/users/new.tsx new file mode 100644 index 0000000..3f0bdc2 --- /dev/null +++ b/app/(app)/users/new.tsx @@ -0,0 +1,175 @@ +import { useState } from 'react'; +import { View, Text, TextInput, TouchableOpacity, ScrollView, Alert, ActivityIndicator } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { router } from 'expo-router'; +import { useQueryClient } from '@tanstack/react-query'; +import { api } from '../../../services/api'; + +const ROLES = [ + { value: 'TECHNICIAN', label: 'Technician', desc: 'Field work & installations', color: '#059669', bg: '#F0FDF4' }, + { value: 'COLLECTOR', label: 'Collector', desc: 'Payments & remittances', color: '#D97706', bg: '#FFFBEB' }, + { value: 'STAFF', label: 'Staff', desc: 'General access', color: '#0891B2', bg: '#ECFEFF' }, + { value: 'ADMIN', label: 'Admin', desc: 'Full access + user mgmt', color: '#7C3AED', bg: '#F5F3FF' }, +]; + +export default function NewUserScreen() { + const qc = useQueryClient(); + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [email, setEmail] = useState(''); + const [phone, setPhone] = useState(''); + const [password, setPassword] = useState(''); + const [showPass, setShowPass] = useState(false); + const [role, setRole] = useState('TECHNICIAN'); + const [loading, setLoading] = useState(false); + + const isValid = firstName.trim() && lastName.trim() && email.trim() && password.length >= 8; + + const submit = async () => { + if (!isValid) return Alert.alert('Required', 'Please fill all required fields. Password must be at least 8 characters.'); + setLoading(true); + try { + await api.post('/api/v1/users', { + firstName: firstName.trim(), + lastName: lastName.trim(), + email: email.trim().toLowerCase(), + phone: phone.trim() || undefined, + password, + role, + }); + qc.invalidateQueries({ queryKey: ['users'] }); + Alert.alert('User Created!', `${firstName} ${lastName} can now log in with ${email.trim().toLowerCase()}`, [ + { text: 'Add Another', onPress: () => { setFirstName(''); setLastName(''); setEmail(''); setPhone(''); setPassword(''); } }, + { text: 'Done', onPress: () => router.back() }, + ]); + } catch (e: any) { + const msg = e?.response?.data?.message; + Alert.alert('Error', Array.isArray(msg) ? msg.join('\n') : msg ?? 'Could not create user.'); + } finally { + setLoading(false); + } + }; + + return ( + + + {/* Header */} + + router.back()} style={{ marginBottom: 12 }} activeOpacity={0.7}> + โ† Back + + Add User + Create a new team member + + + + {/* Name row */} + + + First Name * + + + + Last Name * + + + + + {/* Email */} + Email * + + + {/* Phone */} + + Phone (optional) + + + + {/* Password */} + Password * + + + setShowPass(!showPass)} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + {showPass ? 'Hide' : 'Show'} + + + They can change this after first login. + + {/* Role */} + Role * + {ROLES.map(r => ( + setRole(r.value)} + style={{ flexDirection: 'row', alignItems: 'center', backgroundColor: role === r.value ? r.bg : '#FFF', borderRadius: 16, padding: 18, marginBottom: 10, borderWidth: 2, borderColor: role === r.value ? r.color : '#E2E8F0' }} + activeOpacity={0.7} + > + + {r.value.slice(0,4)} + + + {r.label} + {r.desc} + + + {role === r.value && } + + + ))} + + + + {/* Submit */} + + {loading + ? + : Create User + } + + + + + ); +} diff --git a/app/(auth)/company-code.tsx b/app/(auth)/company-code.tsx index 34fee8e..3918f56 100644 --- a/app/(auth)/company-code.tsx +++ b/app/(auth)/company-code.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, Alert, KeyboardAvoidingView, Platform } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; import { api } from '../../services/api'; @@ -18,51 +19,51 @@ export default function CompanyCodeScreen() { Alert.alert('Not Found', 'Company code not found. Please check and try again.'); } } catch { - Alert.alert('Error', 'Could not verify company code. Please try again.'); - } finally { - setLoading(false); - } + Alert.alert('Error', 'Could not verify. Please try again.'); + } finally { setLoading(false); } }; return ( - - - - - F + + + + {/* Logo */} + + + F + + FiberOps + Field Operations Platform - FiberOps - Field Operations + + Enter Company Code + Ask your admin for your company's unique code. + + + + + {loading + ? + : Continue โ†’ + } + - - Enter Company Code - Ask your admin for your company's unique code. - - - - - {loading ? ( - - ) : ( - Continue - )} - - - + + ); } diff --git a/app/(auth)/login.tsx b/app/(auth)/login.tsx index ab3f93a..0cb4e9b 100644 --- a/app/(auth)/login.tsx +++ b/app/(auth)/login.tsx @@ -1,18 +1,20 @@ import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, Alert, KeyboardAvoidingView, Platform } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, router } from 'expo-router'; import { useAuthStore } from '../../stores/authStore'; export default function LoginScreen() { const { tenantSlug } = useLocalSearchParams<{ tenantSlug: string }>(); - const [username, setUsername] = useState(''); + const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [showPassword, setShowPassword] = useState(false); const { login, isLoading } = useAuthStore(); const handleLogin = async () => { - if (!username.trim() || !password) return Alert.alert('Required', 'Please enter username and password.'); + if (!email.trim() || !password) return Alert.alert('Required', 'Please enter email and password.'); try { - await login(tenantSlug, username.trim(), password); + await login(tenantSlug, email.trim(), password); router.replace('/(app)/dashboard'); } catch (e: any) { const msg = e?.response?.data?.message ?? 'Login failed. Check your credentials.'; @@ -21,52 +23,61 @@ export default function LoginScreen() { }; return ( - - - router.back()}> - โ† Back - + + + + router.back()} style={{ marginBottom: 32 }} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + โ† Back + - Welcome back - - Signing in to {tenantSlug} - + Welcome back + + Signing in to {tenantSlug} + - Username - + {/* Email */} + Email + - Password - + {/* Password */} + Password + + + setShowPassword(!showPassword)} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}> + {showPassword ? 'Hide' : 'Show'} + + - - {isLoading ? ( - - ) : ( - Sign In - )} - - - + + {isLoading + ? + : Sign In + } + + + + ); } diff --git a/assets/adaptive-icon.png b/assets/adaptive-icon.png new file mode 100644 index 0000000..7165a53 Binary files /dev/null and b/assets/adaptive-icon.png differ diff --git a/components/Icon.tsx b/components/Icon.tsx new file mode 100644 index 0000000..22ab9fe --- /dev/null +++ b/components/Icon.tsx @@ -0,0 +1,44 @@ +import { Svg, Path, Circle, Rect } from 'react-native-svg'; + +type IconName = 'home' | 'users' | 'collect' | 'ticket' | 'user' | 'arrow-left' | 'phone' | 'refresh' | 'send' | 'plus' | 'check' | 'location' | 'camera'; + +interface IconProps { + name: IconName; + size?: number; + color?: string; +} + +export function Icon({ name, size = 24, color = '#111827' }: IconProps) { + const props = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none' }; + + switch (name) { + case 'home': + return ; + case 'users': + return ; + case 'collect': + return ; + case 'ticket': + return ; + case 'user': + return ; + case 'arrow-left': + return ; + case 'phone': + return ; + case 'refresh': + return ; + case 'send': + return ; + case 'plus': + return ; + case 'check': + return ; + case 'location': + return ; + case 'camera': + return ; + default: + return null; + } +} diff --git a/constants/index.ts b/constants/index.ts index ba256dd..a22e032 100644 --- a/constants/index.ts +++ b/constants/index.ts @@ -1,8 +1,8 @@ export const API_URL = process.env.EXPO_PUBLIC_API_URL ?? 'http://192.168.1.167:3001'; export const COLORS = { - primary: '#2563EB', - primaryDark: '#1D4ED8', + primary: '#0891B2', + primaryDark: '#0E7490', danger: '#DC2626', success: '#16A34A', warning: '#D97706', diff --git a/metro.config.js b/metro.config.js index e621938..f3321ba 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,10 +1,6 @@ const { getDefaultConfig } = require('expo/metro-config'); const { withNativeWind } = require('nativewind/metro'); -const path = require('path'); const config = getDefaultConfig(__dirname); -// Allow Metro to resolve assets (png/jpg) from inside node_modules -config.resolver.assetExts.push('png', 'jpg', 'jpeg', 'gif', 'webp'); - module.exports = withNativeWind(config, { input: './global.css' }); diff --git a/package-lock.json b/package-lock.json index 4519a69..b4198af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,37 +8,52 @@ "name": "fiberops-mobile", "version": "1.0.0", "dependencies": { - "@react-native-async-storage/async-storage": "^2.2.0", + "@react-native-async-storage/async-storage": "2.2.0", "@tanstack/react-query": "^5.95.0", "axios": "^1.13.6", - "expo": "~55.0.8", - "expo-camera": "^55.0.10", - "expo-constants": "^55.0.9", - "expo-image-picker": "^55.0.13", - "expo-linking": "^55.0.8", - "expo-location": "^55.1.4", - "expo-notifications": "^55.0.13", - "expo-router": "^55.0.7", - "expo-secure-store": "^55.0.9", - "expo-status-bar": "~55.0.4", - "expo-updates": "~55.0.15", - "hermes-parser": "0.32.0", + "expo": "~54.0.33", + "expo-camera": "~17.0.10", + "expo-constants": "~18.0.13", + "expo-dev-client": "^55.0.18", + "expo-image-picker": "~17.0.10", + "expo-linking": "~8.0.11", + "expo-location": "~19.0.8", + "expo-notifications": "~0.32.16", + "expo-router": "~6.0.23", + "expo-secure-store": "~15.0.8", + "expo-status-bar": "~3.0.9", + "expo-updates": "~29.0.16", "nativewind": "^4.1.23", - "react": "19.2.0", - "react-native": "0.83.2", - "react-native-reanimated": "4.2.1", - "react-native-safe-area-context": "^5.6.2", - "react-native-screens": "^4.23.0", - "react-native-worklets": "0.7.2", + "react": "19.1.0", + "react-native": "0.81.5", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-svg": "^15.15.4", + "react-native-worklets": "^0.8.1", "zustand": "^5.0.12" }, "devDependencies": { "@expo/ngrok": "^4.1.3", - "@types/react": "~19.2.2", + "@types/react": "~19.1.10", "tailwindcss": "^3.4.19", "typescript": "~5.9.2" } }, + "node_modules/@0no-co/graphql.web": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", + "integrity": "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -413,6 +428,92 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/parser": { "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", @@ -1488,11 +1589,128 @@ "node": ">=6.9.0" } }, - "node_modules/@expo-google-fonts/material-symbols": { - "version": "0.4.27", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.27.tgz", - "integrity": "sha512-cnb3DZnWUWpezGFkJ8y4MT5f/lw6FcgDzeJzic+T+vpQHLHG1cg3SC3i1w1i8Bk4xKR4HPY3t9iIRNvtr5ml8A==", - "license": "MIT AND Apache-2.0" + "node_modules/@expo/cli": { + "version": "54.0.23", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.23.tgz", + "integrity": "sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.8", + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.0.8", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@expo/metro": "~54.2.0", + "@expo/metro-config": "~54.0.14", + "@expo/osascript": "^2.3.8", + "@expo/package-manager": "^1.9.10", + "@expo/plist": "^0.4.8", + "@expo/prebuild-config": "^54.0.8", + "@expo/schema-utils": "^0.1.8", + "@expo/spawn-async": "^1.7.2", + "@expo/ws-tunnel": "^1.0.1", + "@expo/xcpretty": "^4.3.0", + "@react-native/dev-middleware": "0.81.5", + "@urql/core": "^5.0.6", + "@urql/exchange-retry": "^1.3.0", + "accepts": "^1.3.8", + "arg": "^5.0.2", + "better-opn": "~3.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "env-editor": "^0.4.1", + "expo-server": "^1.0.5", + "freeport-async": "^2.0.0", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.1.6", + "minimatch": "^9.0.0", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^3.0.1", + "pretty-bytes": "^5.6.0", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "qrcode-terminal": "0.11.0", + "require-from-string": "^2.0.2", + "requireg": "^0.2.2", + "resolve": "^1.22.2", + "resolve-from": "^5.0.0", + "resolve.exports": "^2.0.3", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "source-map-support": "~0.5.21", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "tar": "^7.5.2", + "terminal-link": "^2.1.1", + "undici": "^6.18.2", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1" + }, + "bin": { + "expo-internal": "build/bin/cli" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@expo/cli/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@expo/cli/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/cli/node_modules/picomatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/@expo/code-signing-certificates": { "version": "0.0.6", @@ -1504,33 +1722,35 @@ } }, "node_modules/@expo/config": { - "version": "55.0.10", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.10.tgz", - "integrity": "sha512-qCHxo9H1ZoeW+y0QeMtVZ3JfGmumpGrgUFX60wLWMarraoQZSe47ZUm9kJSn3iyoPjUtUNanO3eXQg+K8k4rag==", + "version": "12.0.13", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", + "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", "license": "MIT", "dependencies": { - "@expo/config-plugins": "~55.0.7", - "@expo/config-types": "^55.0.5", - "@expo/json-file": "^10.0.12", - "@expo/require-utils": "^55.0.3", + "@babel/code-frame": "~7.10.4", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/json-file": "^10.0.8", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", + "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", - "slugify": "^1.3.4" + "slugify": "^1.3.4", + "sucrase": "~3.35.1" } }, "node_modules/@expo/config-plugins": { - "version": "55.0.7", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.7.tgz", - "integrity": "sha512-XZUoDWrsHEkH3yasnDSJABM/UxP5a1ixzRwU/M+BToyn/f0nTrSJJe/Ay/FpxkI4JSNz2n0e06I23b2bleXKVA==", + "version": "54.0.4", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", + "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", "license": "MIT", "dependencies": { - "@expo/config-types": "^55.0.5", - "@expo/json-file": "~10.0.12", - "@expo/plist": "^0.5.2", + "@expo/config-types": "^54.0.10", + "@expo/json-file": "~10.0.8", + "@expo/plist": "^0.4.8", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", @@ -1538,17 +1758,27 @@ "glob": "^13.0.0", "resolve-from": "^5.0.0", "semver": "^7.5.4", + "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "node_modules/@expo/config-types": { - "version": "55.0.5", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.5.tgz", - "integrity": "sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==", + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", + "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", "license": "MIT" }, + "node_modules/@expo/config/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, "node_modules/@expo/devcert": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", @@ -1569,9 +1799,9 @@ } }, "node_modules/@expo/devtools": { - "version": "55.0.2", - "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-55.0.2.tgz", - "integrity": "sha512-4VsFn9MUriocyuhyA+ycJP3TJhUsOFHDc270l9h3LhNpXMf6wvIdGcA0QzXkZtORXmlDybWXRP2KT1k36HcQkA==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-0.1.8.tgz", + "integrity": "sha512-SVLxbuanDjJPgc0sy3EfXUMLb/tXzp6XIHkhtPVmTWJAp+FOr6+5SeiCfJrCzZFet0Ifyke2vX3sFcKwEvCXwQ==", "license": "MIT", "dependencies": { "chalk": "^4.1.2" @@ -1589,38 +1819,25 @@ } } }, - "node_modules/@expo/dom-webview": { - "version": "55.0.3", - "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-55.0.3.tgz", - "integrity": "sha512-bY4/rfcZ0f43DvOtMn8/kmPlmo01tex5hRoc5hKbwBwQjqWQuQt0ACwu7akR9IHI4j0WNG48eL6cZB6dZUFrzg==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, "node_modules/@expo/env": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.1.1.tgz", - "integrity": "sha512-rVvHC4I6xlPcg+mAO09ydUi2Wjv1ZytpLmHOSzvXzBAz9mMrJggqCe4s4dubjJvi/Ino/xQCLhbaLCnTtLpikg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.11.tgz", + "integrity": "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q==", "license": "MIT", "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" - }, - "engines": { - "node": ">=20.12.0" } }, "node_modules/@expo/fingerprint": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.16.6.tgz", - "integrity": "sha512-nRITNbnu3RKSHPvKVehrSU4KG2VY9V8nvULOHBw98ukHCAU4bGrU5APvcblOkX3JAap+xEHsg/mZvqlvkLInmQ==", + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.15.4.tgz", + "integrity": "sha512-eYlxcrGdR2/j2M6pEDXo9zU9KXXF1vhP+V+Tl+lyY+bU8lnzrN6c637mz6Ye3em2ANy8hhUR03Raf8VsT9Ogng==", "license": "MIT", "dependencies": { - "@expo/env": "^2.0.11", "@expo/spawn-async": "^1.7.2", "arg": "^5.0.2", "chalk": "^4.1.2", @@ -1628,7 +1845,8 @@ "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", - "minimatch": "^10.2.2", + "minimatch": "^9.0.0", + "p-limit": "^3.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, @@ -1636,6 +1854,45 @@ "fingerprint": "bin/cli.js" } }, + "node_modules/@expo/fingerprint/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@expo/fingerprint/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/fingerprint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@expo/image-utils": { "version": "0.8.12", "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.12.tgz", @@ -1661,33 +1918,6 @@ "json5": "^2.2.3" } }, - "node_modules/@expo/local-build-cache-provider": { - "version": "55.0.7", - "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-55.0.7.tgz", - "integrity": "sha512-Qg9uNZn1buv4zJUA4ZQaz+ZnKDCipRgjoEg2Gcp8Qfy+2Gq5yZKX4YN1TThCJ01LJk/pvJsCRxXlXZSwdZppgg==", - "license": "MIT", - "dependencies": { - "@expo/config": "~55.0.10", - "chalk": "^4.1.2" - } - }, - "node_modules/@expo/log-box": { - "version": "55.0.7", - "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-55.0.7.tgz", - "integrity": "sha512-m7V1k2vlMp4NOj3fopjOg4zl/ANXyTRF3HMTMep2GZAKsPiDzgOQ41nm8CaU50/HlDIGXlCObss07gOn20UpHQ==", - "license": "MIT", - "dependencies": { - "@expo/dom-webview": "^55.0.3", - "anser": "^1.4.9", - "stacktrace-parser": "^0.1.10" - }, - "peerDependencies": { - "@expo/dom-webview": "^55.0.3", - "expo": "*", - "react": "*", - "react-native": "*" - } - }, "node_modules/@expo/metro": { "version": "54.2.0", "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-54.2.0.tgz", @@ -1710,6 +1940,133 @@ "metro-transform-worker": "0.83.3" } }, + "node_modules/@expo/metro-config": { + "version": "54.0.14", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.14.tgz", + "integrity": "sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8", + "@expo/json-file": "~10.0.8", + "@expo/metro": "~54.2.0", + "@expo/spawn-async": "^1.7.2", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.29.1", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "minimatch": "^9.0.0", + "postcss": "~8.4.32", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "node_modules/@expo/metro-config/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@expo/metro-config/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/@expo/metro-config/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/@expo/metro-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/metro-config/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@expo/metro-runtime": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-6.1.2.tgz", + "integrity": "sha512-nvM+Qv45QH7pmYvP8JB1G8JpScrWND3KrMA6ZKe62cwwNiX/BjHU28Ear0v/4bQWXlOY0mv6B8CDIm8JxXde9g==", + "license": "MIT", + "dependencies": { + "anser": "^1.4.9", + "pretty-format": "^29.7.0", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-dom": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/@expo/ngrok": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@expo/ngrok/-/ngrok-4.1.3.tgz", @@ -1939,28 +2296,28 @@ } }, "node_modules/@expo/plist": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.2.tgz", - "integrity": "sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", + "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", + "base64-js": "^1.2.3", "xmlbuilder": "^15.1.1" } }, "node_modules/@expo/prebuild-config": { - "version": "55.0.10", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-55.0.10.tgz", - "integrity": "sha512-AMylDld5G7YJGfEhEyXtgWRuBB83802QBoewF1vJ6NMDtufukuPhMJzOs9E4UXNsjLTaQcgT4yTWhsAWl7o1AQ==", + "version": "54.0.8", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-54.0.8.tgz", + "integrity": "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg==", "license": "MIT", "dependencies": { - "@expo/config": "~55.0.10", - "@expo/config-plugins": "~55.0.7", - "@expo/config-types": "^55.0.5", - "@expo/image-utils": "^0.8.12", - "@expo/json-file": "^10.0.12", - "@react-native/normalize-colors": "0.83.2", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@react-native/normalize-colors": "0.81.5", "debug": "^4.3.1", "resolve-from": "^5.0.0", "semver": "^7.6.0", @@ -1990,9 +2347,9 @@ } }, "node_modules/@expo/schema-utils": { - "version": "55.0.2", - "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-55.0.2.tgz", - "integrity": "sha512-QZ5WKbJOWkCrMq0/kfhV9ry8te/OaS34YgLVpG8u9y2gix96TlpRTbxM/YATjNcUR2s4fiQmPCOxkGtog4i37g==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-0.1.8.tgz", + "integrity": "sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A==", "license": "MIT" }, "node_modules/@expo/sdk-runtime-versions": { @@ -2019,6 +2376,17 @@ "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==", "license": "MIT" }, + "node_modules/@expo/vector-icons": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", + "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", + "license": "MIT", + "peerDependencies": { + "expo-font": ">=14.0.4", + "react": "*", + "react-native": "*" + } + }, "node_modules/@expo/ws-tunnel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz", @@ -2057,6 +2425,24 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@ide/backoff": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz", + "integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==", + "license": "MIT" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@isaacs/ttlcache": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", @@ -2647,9 +3033,9 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2664,6 +3050,36 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", @@ -2762,26 +3178,155 @@ } }, "node_modules/@react-native/assets-registry": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.83.2.tgz", - "integrity": "sha512-9I5l3pGAKnlpQ15uVkeB9Mgjvt3cZEaEc8EDtdexvdtZvLSjtwBzgourrOW4yZUijbjJr8h3YO2Y0q+THwUHTA==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", + "integrity": "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w==", "license": "MIT", "engines": { "node": ">= 20.19.4" } }, - "node_modules/@react-native/community-cli-plugin": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.83.2.tgz", - "integrity": "sha512-sTEF0eiUKtmImEP07Qo5c3Khvm1LIVX1Qyb6zWUqPL6W3MqFiXutZvKBjqLz6p49Szx8cplQLoXfLHT0bcDXKg==", + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.5.tgz", + "integrity": "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ==", "license": "MIT", "dependencies": { - "@react-native/dev-middleware": "0.83.2", + "@babel/traverse": "^7.25.3", + "@react-native/codegen": "0.81.5" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.81.5.tgz", + "integrity": "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/template": "^7.25.0", + "@react-native/babel-plugin-codegen": "0.81.5", + "babel-plugin-syntax-hermes-parser": "0.29.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.81.5.tgz", + "integrity": "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.29.1", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native/codegen/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/@react-native/codegen/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.5.tgz", + "integrity": "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.81.5", "debug": "^4.4.0", "invariant": "^2.2.4", - "metro": "^0.83.3", - "metro-config": "^0.83.3", - "metro-core": "^0.83.3", + "metro": "^0.83.1", + "metro-config": "^0.83.1", + "metro-core": "^0.83.1", "semver": "^7.1.3" }, "engines": { @@ -2801,36 +3346,22 @@ } }, "node_modules/@react-native/debugger-frontend": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.83.2.tgz", - "integrity": "sha512-t4fYfa7xopbUF5S4+ihNEwgaq4wLZLKLY0Ms8z72lkMteVd3bOX2Foxa8E2wTfRvdhPOkSpOsTeNDmD8ON4DoQ==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.81.5.tgz", + "integrity": "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w==", "license": "BSD-3-Clause", "engines": { "node": ">= 20.19.4" } }, - "node_modules/@react-native/debugger-shell": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.83.2.tgz", - "integrity": "sha512-z9go6NJMsLSDJT5MW6VGugRsZHjYvUTwxtsVc3uLt4U9W6T3J6FWI2wHpXIzd2dUkXRfAiRQ3Zi8ZQQ8fRFg9A==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "fb-dotslash": "0.5.8" - }, - "engines": { - "node": ">= 20.19.4" - } - }, "node_modules/@react-native/dev-middleware": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.83.2.tgz", - "integrity": "sha512-Zi4EVaAm28+icD19NN07Gh8Pqg/84QQu+jn4patfWKNkcToRFP5vPEbbp0eLOGWS+BVB1d1Fn5lvMrJsBbFcOg==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.81.5.tgz", + "integrity": "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA==", "license": "MIT", "dependencies": { "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.83.2", - "@react-native/debugger-shell": "0.83.2", + "@react-native/debugger-frontend": "0.81.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", @@ -2839,27 +3370,68 @@ "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", - "ws": "^7.5.10" + "ws": "^6.2.3" }, "engines": { "node": ">= 20.19.4" } }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, "node_modules/@react-native/gradle-plugin": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.83.2.tgz", - "integrity": "sha512-PqN11fXRAU+uJ0inZY1HWYlwJOXHOhF4SPyeHBBxjajKpm2PGunmvFWwkmBjmmUkP/CNO0ezTUudV0oj+2wiHQ==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz", + "integrity": "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.81.5.tgz", + "integrity": "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==", "license": "MIT", "engines": { "node": ">= 20.19.4" } }, "node_modules/@react-native/normalize-colors": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.83.2.tgz", - "integrity": "sha512-gkZAb9LoVVzNuYzzOviH7DiPTXQoZPHuiTH2+O2+VWNtOkiznjgvqpwYAhg58a5zfRq5GXlbBdf5mzRj5+3Y5Q==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", + "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", "license": "MIT" }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz", + "integrity": "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@react-navigation/bottom-tabs": { "version": "7.15.6", "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.15.6.tgz", @@ -3095,12 +3667,6 @@ "@types/responselike": "^1.0.0" } }, - "node_modules/@types/emscripten": { - "version": "1.41.5", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", - "integrity": "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==", - "license": "MIT" - }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -3161,13 +3727,13 @@ } }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "19.1.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", + "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", "dev": true, "license": "MIT", "dependencies": { - "csstype": "^3.2.2" + "csstype": "^3.0.2" } }, "node_modules/@types/responselike": { @@ -3207,6 +3773,29 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@urql/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", + "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.13", + "wonka": "^6.3.2" + } + }, + "node_modules/@urql/exchange-retry": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@urql/exchange-retry/-/exchange-retry-1.3.2.tgz", + "integrity": "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==", + "license": "MIT", + "dependencies": { + "@urql/core": "^5.1.2", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^5.0.0" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", @@ -3323,7 +3912,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { @@ -3378,12 +3966,46 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", @@ -3511,12 +4133,27 @@ "license": "MIT" }, "node_modules/babel-plugin-syntax-hermes-parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.32.0.tgz", - "integrity": "sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg==", + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.29.1.tgz", + "integrity": "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA==", "license": "MIT", "dependencies": { - "hermes-parser": "0.32.0" + "hermes-parser": "0.29.1" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" } }, "node_modules/babel-plugin-transform-flow-enums": { @@ -3555,12 +4192,11 @@ } }, "node_modules/babel-preset-expo": { - "version": "55.0.12", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-55.0.12.tgz", - "integrity": "sha512-oR46ExGZpRijmPUsr0rFH5X4lR/mvwqJAFXJRLpynZcvyv2pHPTeGMNfd/p5oPMbdbaeMS6G+3k18p48u2Qjbw==", + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz", + "integrity": "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw==", "license": "MIT", "dependencies": { - "@babel/generator": "^7.20.5", "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", @@ -3576,10 +4212,10 @@ "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", - "@react-native/babel-preset": "0.83.2", + "@react-native/babel-preset": "0.81.5", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", - "babel-plugin-syntax-hermes-parser": "^0.32.0", + "babel-plugin-syntax-hermes-parser": "^0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" @@ -3587,7 +4223,6 @@ "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", - "expo-widgets": "^55.0.6", "react-refresh": ">=0.14.0 <1.0.0" }, "peerDependenciesMeta": { @@ -3596,154 +4231,9 @@ }, "expo": { "optional": true - }, - "expo-widgets": { - "optional": true } } }, - "node_modules/babel-preset-expo/node_modules/@react-native/babel-plugin-codegen": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.83.2.tgz", - "integrity": "sha512-XbcN/BEa64pVlb0Hb/E/Ph2SepjVN/FcNKrJcQvtaKZA6mBSO8pW8Eircdlr61/KBH94LihHbQoQDzkQFpeaTg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.3", - "@react-native/codegen": "0.83.2" - }, - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/babel-preset-expo/node_modules/@react-native/babel-preset": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.83.2.tgz", - "integrity": "sha512-X/RAXDfe6W+om/Fw1i6htTxQXFhBJ2jgNOWx3WpI3KbjeIWbq7ib6vrpTeIAW2NUMg+K3mML1NzgD4dpZeqdjA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-proposal-export-default-from": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-default-from": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.1", - "@babel/plugin-transform-literals": "^7.25.2", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.25.2", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/template": "^7.25.0", - "@react-native/babel-plugin-codegen": "0.83.2", - "babel-plugin-syntax-hermes-parser": "0.32.0", - "babel-plugin-transform-flow-enums": "^0.0.2", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": ">= 20.19.4" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/babel-preset-expo/node_modules/@react-native/codegen": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.83.2.tgz", - "integrity": "sha512-9uK6X1miCXqtL4c759l74N/XbQeneWeQVjoV7SD2CGJuW7ZefxaoYenwGPs7rMoCdtS6wuIyR3hXQ+uWEBGYXA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.25.3", - "glob": "^7.1.1", - "hermes-parser": "0.32.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "yargs": "^17.6.2" - }, - "engines": { - "node": ">= 20.19.4" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/babel-preset-expo/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/babel-preset-expo/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/babel-preset-expo/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/babel-preset-expo/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/babel-preset-jest": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", @@ -3767,22 +4257,10 @@ "license": "MIT" }, "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/barcode-detector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.1.1.tgz", - "integrity": "sha512-ghWlEAV93ZCUniO7Co3ih/01XPm+U30CV+NoPbO6Chj5lZzHydDAqKlrBEd+37TkoR+QTH3tnnwd8k8epGTfIg==", - "license": "MIT", - "dependencies": { - "zxing-wasm": "3.0.1" - } + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3867,6 +4345,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/bplist-creator": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", @@ -3877,9 +4361,9 @@ } }, "node_modules/bplist-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", + "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", "license": "MIT", "dependencies": { "big-integer": "1.6.x" @@ -3889,15 +4373,13 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -3954,6 +4436,30 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3998,6 +4504,24 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -4011,6 +4535,22 @@ "node": ">= 0.4" } }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -4107,6 +4647,15 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/chrome-launcher": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", @@ -4140,10 +4689,19 @@ } }, "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT" + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/cli-cursor": { "version": "2.1.0", @@ -4189,6 +4747,38 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -4409,6 +4999,56 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -4484,6 +5124,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -4515,6 +5164,23 @@ "node": ">=10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -4524,6 +5190,23 @@ "node": ">=8" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4581,11 +5264,87 @@ "dev": true, "license": "MIT" }, - "node_modules/dnssd-advertise": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dnssd-advertise/-/dnssd-advertise-1.1.3.tgz", - "integrity": "sha512-XENsHi3MBzWOCAXif3yZvU1Ah0l+nhJj1sjWL6TnOAYKvGiFhbTx32xHN7+wLMLUOCj7Nr0evADWG4R8JtqCDA==", - "license": "MIT" + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } }, "node_modules/dunder-proto": { "version": "1.0.1", @@ -4613,12 +5372,6 @@ "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", "license": "ISC" }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -4638,6 +5391,27 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-editor": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", + "integrity": "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/error-stack-parser": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", @@ -4751,34 +5525,32 @@ } }, "node_modules/expo": { - "version": "55.0.8", - "resolved": "https://registry.npmjs.org/expo/-/expo-55.0.8.tgz", - "integrity": "sha512-sziDGiDmeRmaSpFwMuSxFhr4vfWrQS1UgVXSTovsUDY0ximABzYdnF5L2OwtD8zjtIww8x2oJGmD6mKS+AoVsw==", + "version": "54.0.33", + "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.33.tgz", + "integrity": "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "55.0.18", - "@expo/config": "~55.0.10", - "@expo/config-plugins": "~55.0.7", - "@expo/devtools": "55.0.2", - "@expo/fingerprint": "0.16.6", - "@expo/local-build-cache-provider": "55.0.7", - "@expo/log-box": "55.0.7", + "@expo/cli": "54.0.23", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devtools": "0.1.8", + "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", - "@expo/metro-config": "55.0.11", - "@expo/vector-icons": "^15.0.2", + "@expo/metro-config": "54.0.14", + "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~55.0.12", - "expo-asset": "~55.0.10", - "expo-constants": "~55.0.9", - "expo-file-system": "~55.0.11", - "expo-font": "~55.0.4", - "expo-keep-awake": "~55.0.4", - "expo-modules-autolinking": "55.0.11", - "expo-modules-core": "55.0.17", + "babel-preset-expo": "~54.0.10", + "expo-asset": "~12.0.12", + "expo-constants": "~18.0.13", + "expo-file-system": "~19.0.21", + "expo-font": "~14.0.11", + "expo-keep-awake": "~15.0.8", + "expo-modules-autolinking": "3.0.24", + "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", - "whatwg-url-minimum": "^0.1.1" + "whatwg-url-without-unicode": "8.0.0-3" }, "bin": { "expo": "bin/cli", @@ -4805,21 +5577,36 @@ } }, "node_modules/expo-application": { - "version": "55.0.10", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-55.0.10.tgz", - "integrity": "sha512-5ccf+S6hsQz+doi907TOJxKzV5AKgAgw004z4FoDWSoGhfab0LUPg6uyvOspuU4cbNvqw8EAy08hZbVO8nKc9Q==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz", + "integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==", "license": "MIT", "peerDependencies": { "expo": "*" } }, - "node_modules/expo-camera": { - "version": "55.0.10", - "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-55.0.10.tgz", - "integrity": "sha512-ftDNJbGsAPNJ/QrM3j6g8/rQAOqTwZpqtvmzF7V9VX0movaCznZFdYsLi/Fff9WeEk1KzcnLIlmSz4Tj+BCrJA==", + "node_modules/expo-asset": { + "version": "12.0.12", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.12.tgz", + "integrity": "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ==", "license": "MIT", "dependencies": { - "barcode-detector": "^3.0.0" + "@expo/image-utils": "^0.8.8", + "expo-constants": "~18.0.12" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-camera": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-17.0.10.tgz", + "integrity": "sha512-w1RBw83mAGVk4BPPwNrCZyFop0VLiVSRE3c2V9onWbdFwonpRhzmB4drygG8YOUTl1H3wQvALJHyMPTbgsK1Jg==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", @@ -4834,124 +5621,99 @@ } }, "node_modules/expo-constants": { - "version": "55.0.9", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-55.0.9.tgz", - "integrity": "sha512-iBiXjZeuU5S/8docQeNzsVvtDy4w0zlmXBpFEi1ypwugceEpdQQab65TVRbusXAcwpNVxCPMpNlDssYp0Pli2g==", + "version": "18.0.13", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz", + "integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==", "license": "MIT", "dependencies": { - "@expo/config": "~55.0.10", - "@expo/env": "~2.1.1" + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, - "node_modules/expo-eas-client": { - "version": "55.0.2", - "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-55.0.2.tgz", - "integrity": "sha512-fjOgSXaZFBK2Xmzn/uw0DTF3BsYv97JEa4PYXXqVCEvNJPwJB1cV1eX6Xyq6iKGIhMPH9k62sOc+oUdt094WCw==", + "node_modules/expo-dev-client": { + "version": "55.0.18", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-55.0.18.tgz", + "integrity": "sha512-zQeCGk+doTMIKwPe9lNlGcUiBlMpJQNyrrsYc5eRdxuMwBrDVAU7zshARmamSw8zlAIHCsThJH2zeJg/lgQrKA==", + "license": "MIT", + "dependencies": { + "expo-dev-launcher": "55.0.19", + "expo-dev-menu": "55.0.16", + "expo-dev-menu-interface": "55.0.1", + "expo-manifests": "~55.0.11", + "expo-updates-interface": "~55.1.3" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-client/node_modules/@expo/config": { + "version": "55.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.10.tgz", + "integrity": "sha512-qCHxo9H1ZoeW+y0QeMtVZ3JfGmumpGrgUFX60wLWMarraoQZSe47ZUm9kJSn3iyoPjUtUNanO3eXQg+K8k4rag==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~55.0.7", + "@expo/config-types": "^55.0.5", + "@expo/json-file": "^10.0.12", + "@expo/require-utils": "^55.0.3", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/expo-dev-client/node_modules/@expo/config-plugins": { + "version": "55.0.7", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.7.tgz", + "integrity": "sha512-XZUoDWrsHEkH3yasnDSJABM/UxP5a1ixzRwU/M+BToyn/f0nTrSJJe/Ay/FpxkI4JSNz2n0e06I23b2bleXKVA==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^55.0.5", + "@expo/json-file": "~10.0.12", + "@expo/plist": "^0.5.2", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/expo-dev-client/node_modules/@expo/config-types": { + "version": "55.0.5", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.5.tgz", + "integrity": "sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==", "license": "MIT" }, - "node_modules/expo-font": { - "version": "55.0.4", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-55.0.4.tgz", - "integrity": "sha512-ZKeGTFffPygvY5dM/9ATM2p7QDkhsaHopH7wFAWgP2lKzqUMS9B/RxCvw5CaObr9Ro7x9YptyeRKX2HmgmMfrg==", + "node_modules/expo-dev-client/node_modules/@expo/plist": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.2.tgz", + "integrity": "sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==", "license": "MIT", "dependencies": { - "fontfaceobserver": "^2.1.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" } }, - "node_modules/expo-glass-effect": { - "version": "55.0.8", - "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-55.0.8.tgz", - "integrity": "sha512-IvUjHb/4t6r2H/LXDjcQ4uDoHrmO2cLOvEb9leLavQ4HX5+P4LRtQrMDMlkWAn5Wo5DkLcG8+1CrQU2nqgogTA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-image": { - "version": "55.0.6", - "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-55.0.6.tgz", - "integrity": "sha512-TKuu0uBmgTZlhd91Glv+V4vSBMlfl0bdQxfl97oKKZUo3OBC13l3eLik7v3VNLJN7PZbiwOAiXkZkqSOBx/Xsw==", - "license": "MIT", - "dependencies": { - "sf-symbols-typescript": "^2.2.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } - } - }, - "node_modules/expo-image-loader": { - "version": "55.0.0", - "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-55.0.0.tgz", - "integrity": "sha512-NOjp56wDrfuA5aiNAybBIjqIn1IxKeGJ8CECWZncQ/GzjZfyTYAHTCyeApYkdKkMBLHINzI4BbTGSlbCa0fXXQ==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-image-picker": { - "version": "55.0.13", - "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-55.0.13.tgz", - "integrity": "sha512-G+W11rcoUi3rK+6cnKWkTfZilMkGVZnYe90TiM3R98nPSlzGBoto3a/TkGGTJXedz/dmMzr49L+STlWhuKKIFw==", - "license": "MIT", - "dependencies": { - "expo-image-loader": "~55.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-json-utils": { + "node_modules/expo-dev-client/node_modules/expo-json-utils": { "version": "55.0.0", "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-55.0.0.tgz", "integrity": "sha512-aupt/o5PDAb8dXDCb0JcRdkqnTLxe/F+La7jrnyd/sXlYFfRgBJLFOa1SqVFXm1E/Xam1SE/yw6eAb+DGY7Arg==", "license": "MIT" }, - "node_modules/expo-linking": { - "version": "55.0.8", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-55.0.8.tgz", - "integrity": "sha512-O9QgKAfEqKfsjL6IKs5p7pFAjo/3/TQwjMzzNPl8BCndbxWMPQfMeViXPYYNS9bA2ujUqrtF1OYhO6woI7GNQQ==", - "license": "MIT", - "dependencies": { - "expo-constants": "~55.0.8", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-location": { - "version": "55.1.4", - "resolved": "https://registry.npmjs.org/expo-location/-/expo-location-55.1.4.tgz", - "integrity": "sha512-0QWQ4QP8I6svtGUL895Y8bvKM3nGUWNp/MdCoCQNH3uAuwvLf2TQ6ZDVD3kdlkl2wGGdw6ziHQIYDHL96OlfnA==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.8.12" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-manifests": { + "node_modules/expo-dev-client/node_modules/expo-manifests": { "version": "55.0.11", "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-55.0.11.tgz", "integrity": "sha512-3+pFun4C9F/eFMVpwZgOBrBWq5sfu7rS1uxTrcg9G7jUFatNe5W6hr+M7z7aQPDf0J1afaSudUZPawx1LLf15w==", @@ -4964,25 +5726,255 @@ "expo": "*" } }, - "node_modules/expo-modules-autolinking": { - "version": "55.0.11", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-55.0.11.tgz", - "integrity": "sha512-9dqnPzQoIl1dIvEctMWpQ8eaiXDeBTgAwebCc1WF0BbEo+pcdKjZWoCSqlLj+d7IX+OnTgM+k6cY2kPDGIu4sg==", + "node_modules/expo-dev-client/node_modules/expo-updates-interface": { + "version": "55.1.3", + "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-55.1.3.tgz", + "integrity": "sha512-UVVIiZqymQZJL+o/jh65kXOI97xdkbqBJJM0LMabaPMNLFnc6/WvOMOzmQs7SPyKb8+0PeBaFd7tj5DzF6JeQg==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher": { + "version": "55.0.19", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-55.0.19.tgz", + "integrity": "sha512-RtiC/K7Cg7RafNlq32GtilMEO5cy61HPBKASQHwLK6Gz5+FYepx0KSHIXIhWqekZMfpcj1w80tvEjMNFjUJ9Dg==", "license": "MIT", "dependencies": { + "@expo/schema-utils": "^55.0.2", + "expo-dev-menu": "55.0.16", + "expo-manifests": "~55.0.11" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher/node_modules/@expo/config": { + "version": "55.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.10.tgz", + "integrity": "sha512-qCHxo9H1ZoeW+y0QeMtVZ3JfGmumpGrgUFX60wLWMarraoQZSe47ZUm9kJSn3iyoPjUtUNanO3eXQg+K8k4rag==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~55.0.7", + "@expo/config-types": "^55.0.5", + "@expo/json-file": "^10.0.12", "@expo/require-utils": "^55.0.3", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/expo-dev-launcher/node_modules/@expo/config-plugins": { + "version": "55.0.7", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.7.tgz", + "integrity": "sha512-XZUoDWrsHEkH3yasnDSJABM/UxP5a1ixzRwU/M+BToyn/f0nTrSJJe/Ay/FpxkI4JSNz2n0e06I23b2bleXKVA==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^55.0.5", + "@expo/json-file": "~10.0.12", + "@expo/plist": "^0.5.2", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/expo-dev-launcher/node_modules/@expo/config-types": { + "version": "55.0.5", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.5.tgz", + "integrity": "sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==", + "license": "MIT" + }, + "node_modules/expo-dev-launcher/node_modules/@expo/plist": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.2.tgz", + "integrity": "sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/expo-dev-launcher/node_modules/@expo/schema-utils": { + "version": "55.0.2", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-55.0.2.tgz", + "integrity": "sha512-QZ5WKbJOWkCrMq0/kfhV9ry8te/OaS34YgLVpG8u9y2gix96TlpRTbxM/YATjNcUR2s4fiQmPCOxkGtog4i37g==", + "license": "MIT" + }, + "node_modules/expo-dev-launcher/node_modules/expo-json-utils": { + "version": "55.0.0", + "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-55.0.0.tgz", + "integrity": "sha512-aupt/o5PDAb8dXDCb0JcRdkqnTLxe/F+La7jrnyd/sXlYFfRgBJLFOa1SqVFXm1E/Xam1SE/yw6eAb+DGY7Arg==", + "license": "MIT" + }, + "node_modules/expo-dev-launcher/node_modules/expo-manifests": { + "version": "55.0.11", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-55.0.11.tgz", + "integrity": "sha512-3+pFun4C9F/eFMVpwZgOBrBWq5sfu7rS1uxTrcg9G7jUFatNe5W6hr+M7z7aQPDf0J1afaSudUZPawx1LLf15w==", + "license": "MIT", + "dependencies": { + "@expo/config": "~55.0.10", + "expo-json-utils": "~55.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-menu": { + "version": "55.0.16", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-55.0.16.tgz", + "integrity": "sha512-UhduIh/6wQmFLIy1EeQJBCN09irOrC1kf/UMQ9CxXCkXit9SOtJx+26YfCmbrIRV/lYK2qZK8Y178/HNkt7yeA==", + "license": "MIT", + "dependencies": { + "expo-dev-menu-interface": "55.0.1" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-menu-interface": { + "version": "55.0.1", + "resolved": "https://registry.npmjs.org/expo-dev-menu-interface/-/expo-dev-menu-interface-55.0.1.tgz", + "integrity": "sha512-FkNtwq1q6NmYoy28pj+ZLuHmirJgc039pQbJ167MZJIaprLcMN1yy67qA7xBHK+FNJ8AN8kGCtMTPByg5UC72A==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-eas-client": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-1.0.8.tgz", + "integrity": "sha512-5or11NJhSeDoHHI6zyvQDW2cz/yFyE+1Cz8NTs5NK8JzC7J0JrkUgptWtxyfB6Xs/21YRNifd3qgbBN3hfKVgA==", + "license": "MIT" + }, + "node_modules/expo-file-system": { + "version": "19.0.21", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.21.tgz", + "integrity": "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-font": { + "version": "14.0.11", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz", + "integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-image-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-6.0.0.tgz", + "integrity": "sha512-nKs/xnOGw6ACb4g26xceBD57FKLFkSwEUTDXEDF3Gtcu3MqF3ZIYd3YM+sSb1/z9AKV1dYT7rMSGVNgsveXLIQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-image-picker": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-17.0.10.tgz", + "integrity": "sha512-a2xrowp2trmvXyUWgX3O6Q2rZaa2C59AqivKI7+bm+wLvMfTEbZgldLX4rEJJhM8xtmEDTNU+lzjtObwzBRGaw==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~6.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-json-utils": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-0.15.0.tgz", + "integrity": "sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==", + "license": "MIT" + }, + "node_modules/expo-keep-awake": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz", + "integrity": "sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "node_modules/expo-linking": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.11.tgz", + "integrity": "sha512-+VSaNL5om3kOp/SSKO5qe6cFgfSIWnnQDSbA7XLs3ECkYzXRquk5unxNS3pg7eK5kNUmQ4kgLI7MhTggAEUBLA==", + "license": "MIT", + "dependencies": { + "expo-constants": "~18.0.12", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-location": { + "version": "19.0.8", + "resolved": "https://registry.npmjs.org/expo-location/-/expo-location-19.0.8.tgz", + "integrity": "sha512-H/FI75VuJ1coodJbbMu82pf+Zjess8X8Xkiv9Bv58ZgPKS/2ztjC1YO1/XMcGz7+s9DrbLuMIw22dFuP4HqneA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-manifests": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-1.0.10.tgz", + "integrity": "sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.11", + "expo-json-utils": "~0.15.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-autolinking": { + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz", + "integrity": "sha512-TP+6HTwhL7orDvsz2VzauyQlXJcAWyU3ANsZ7JGL4DQu8XaZv/A41ZchbtAYLfozNA2Ya1Hzmhx65hXryBMjaQ==", + "license": "MIT", + "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", - "commander": "^7.2.0" + "commander": "^7.2.0", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "node_modules/expo-modules-core": { - "version": "55.0.17", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-55.0.17.tgz", - "integrity": "sha512-pw3cZiaSlBrqRJUD/pHuMnKGsRTW6XJ255FrjDd3HC4QrqErCnfSQPmz+Sv4Qkelcvd9UGdAewyTqZdFwjLwOw==", + "version": "3.0.29", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.29.tgz", + "integrity": "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q==", "license": "MIT", "dependencies": { "invariant": "^2.2.4" @@ -4993,16 +5985,18 @@ } }, "node_modules/expo-notifications": { - "version": "55.0.13", - "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-55.0.13.tgz", - "integrity": "sha512-vbtSBcMkYtNTO+6WKdeOzysOqvtmiq/sQrUKJpYcB75m9hBFcAfI2klpXdUiGg5kMr/ygBmFENSolQt1B9QY8A==", + "version": "0.32.16", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.16.tgz", + "integrity": "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw==", "license": "MIT", "dependencies": { - "@expo/image-utils": "^0.8.12", + "@expo/image-utils": "^0.8.8", + "@ide/backoff": "^1.0.0", "abort-controller": "^3.0.0", + "assert": "^2.0.0", "badgin": "^1.1.5", - "expo-application": "~55.0.10", - "expo-constants": "~55.0.8" + "expo-application": "~7.0.8", + "expo-constants": "~18.0.13" }, "peerDependencies": { "expo": "*", @@ -5011,31 +6005,28 @@ } }, "node_modules/expo-router": { - "version": "55.0.7", - "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-55.0.7.tgz", - "integrity": "sha512-UdraTi8/1LGCCEnq/3+wEVnM11b4ezFEIvMsWP9ajFvEhFGkcXlQitvSehT2yI5cbBrBaIMP2p/2naBiPyYVyw==", + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.23.tgz", + "integrity": "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA==", "license": "MIT", "dependencies": { - "@expo/metro-runtime": "^55.0.6", - "@expo/schema-utils": "^55.0.2", - "@radix-ui/react-slot": "^1.2.0", + "@expo/metro-runtime": "^6.1.2", + "@expo/schema-utils": "^0.1.8", + "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", - "@react-navigation/bottom-tabs": "^7.15.5", - "@react-navigation/native": "^7.1.33", - "@react-navigation/native-stack": "^7.14.5", + "@react-navigation/bottom-tabs": "^7.4.0", + "@react-navigation/native": "^7.1.8", + "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "expo-glass-effect": "^55.0.8", - "expo-image": "^55.0.6", - "expo-server": "^55.0.6", - "expo-symbols": "^55.0.5", + "expo-server": "^1.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", - "react-native-is-edge-to-edge": "^1.2.1", + "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", @@ -5044,13 +6035,12 @@ "vaul": "^1.1.2" }, "peerDependencies": { - "@expo/log-box": "55.0.7", - "@expo/metro-runtime": "^55.0.6", - "@react-navigation/drawer": "^7.9.4", - "@testing-library/react-native": ">= 13.2.0", + "@expo/metro-runtime": "^6.1.2", + "@react-navigation/drawer": "^7.5.0", + "@testing-library/react-native": ">= 12.0.0", "expo": "*", - "expo-constants": "^55.0.8", - "expo-linking": "^55.0.8", + "expo-constants": "^18.0.13", + "expo-linking": "^8.0.11", "react": "*", "react-dom": "*", "react-native": "*", @@ -5085,60 +6075,6 @@ } } }, - "node_modules/expo-router/node_modules/@expo/metro-runtime": { - "version": "55.0.6", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-55.0.6.tgz", - "integrity": "sha512-l8VvgKN9md+URjeQDB+DnHVmvpcWI6zFLH6yv7GTv4sfRDKyaZ5zDXYjTP1phYdgW6ea2NrRtCGNIxylWhsgtg==", - "license": "MIT", - "dependencies": { - "@expo/log-box": "55.0.7", - "anser": "^1.4.9", - "pretty-format": "^29.7.0", - "stacktrace-parser": "^0.1.10", - "whatwg-fetch": "^3.0.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-dom": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/expo-router/node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/expo-router/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -5152,27 +6088,27 @@ } }, "node_modules/expo-secure-store": { - "version": "55.0.9", - "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-55.0.9.tgz", - "integrity": "sha512-TIPGjM73LKlebpXwgAu/yL7lNWr6RQYmFw3vgYHOqLFYQMpsBqkQmopovbNX3c/0+RCE9KZlLAkcz8r6detILQ==", + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-15.0.8.tgz", + "integrity": "sha512-lHnzvRajBu4u+P99+0GEMijQMFCOYpWRO4dWsXSuMt77+THPIGjzNvVKrGSl6mMrLsfVaKL8BpwYZLGlgA+zAw==", "license": "MIT", "peerDependencies": { "expo": "*" } }, "node_modules/expo-server": { - "version": "55.0.6", - "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-55.0.6.tgz", - "integrity": "sha512-xI72FTm469FfuuBL2R5aNtthgH+GR7ygOpsx/KcPS0K8AZaZd7VjtEExbzn9/qyyYkWW3T+3dAmCDKOMX8gdmQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.5.tgz", + "integrity": "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA==", "license": "MIT", "engines": { "node": ">=20.16.0" } }, "node_modules/expo-status-bar": { - "version": "55.0.4", - "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-55.0.4.tgz", - "integrity": "sha512-BPDjUXKqv1F9j2YNGLRZfkBEZXIEEpqj+t81y4c+4fdSN3Pos7goIHXgcl2ozbKQLgKRZQyNZQtbUgh5UjHYUQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-3.0.9.tgz", + "integrity": "sha512-xyYyVg6V1/SSOZWh4Ni3U129XHCnFHBTcUo0dhWtFDrZbNp/duw5AGsQfb2sVeU0gxWHXSY1+5F0jnKYC7WuOw==", "license": "MIT", "dependencies": { "react-native-is-edge-to-edge": "^1.2.1" @@ -5183,43 +6119,27 @@ } }, "node_modules/expo-structured-headers": { - "version": "55.0.0", - "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-55.0.0.tgz", - "integrity": "sha512-udaNvuWb45/Sryq9FLC/blwgOChhznuqlTrUzVjC0T83pMdcmscKJX23lnNDW6hCec8p81Y3z1DIFwIyk0g/PQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-5.0.0.tgz", + "integrity": "sha512-RmrBtnSphk5REmZGV+lcdgdpxyzio5rJw8CXviHE6qH5pKQQ83fhMEcigvrkBdsn2Efw2EODp4Yxl1/fqMvOZw==", "license": "MIT" }, - "node_modules/expo-symbols": { - "version": "55.0.5", - "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-55.0.5.tgz", - "integrity": "sha512-W/QYRvnYVes947ZYOHtuKL8Gobs7BUjeu9oknzbo4jGnou7Ks6bj1CwdT0ZWNBgaTopbS4/POXumJIkW4cTPSQ==", - "license": "MIT", - "dependencies": { - "@expo-google-fonts/material-symbols": "^0.4.1", - "sf-symbols-typescript": "^2.0.0" - }, - "peerDependencies": { - "expo": "*", - "expo-font": "*", - "react": "*", - "react-native": "*" - } - }, "node_modules/expo-updates": { - "version": "55.0.15", - "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-55.0.15.tgz", - "integrity": "sha512-UE9Ik56trq//kNeJ/BlC5vOTYdNTvsHwhfWFYMazP1UOQK4lnX59/t0qz8Ut+3aPXZZT7+B6mnbWtic0QqN1wA==", + "version": "29.0.16", + "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-29.0.16.tgz", + "integrity": "sha512-E9/fxRz/Eurtc7hxeI/6ZPyHH3To9Xoccm1kXoICZTRojmuTo+dx0Xv53UHyHn4G5zGMezyaKF2Qtj3AKcT93w==", "license": "MIT", "dependencies": { "@expo/code-signing-certificates": "^0.0.6", - "@expo/plist": "^0.5.2", + "@expo/plist": "^0.4.8", "@expo/spawn-async": "^1.7.2", - "arg": "^4.1.0", + "arg": "4.1.0", "chalk": "^4.1.2", "debug": "^4.3.4", - "expo-eas-client": "~55.0.2", - "expo-manifests": "~55.0.11", - "expo-structured-headers": "~55.0.0", - "expo-updates-interface": "~55.1.3", + "expo-eas-client": "~1.0.8", + "expo-manifests": "~1.0.10", + "expo-structured-headers": "~5.0.0", + "expo-updates-interface": "~2.0.0", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", @@ -5235,292 +6155,20 @@ } }, "node_modules/expo-updates-interface": { - "version": "55.1.3", - "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-55.1.3.tgz", - "integrity": "sha512-UVVIiZqymQZJL+o/jh65kXOI97xdkbqBJJM0LMabaPMNLFnc6/WvOMOzmQs7SPyKb8+0PeBaFd7tj5DzF6JeQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-2.0.0.tgz", + "integrity": "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==", "license": "MIT", "peerDependencies": { "expo": "*" } }, "node_modules/expo-updates/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", "license": "MIT" }, - "node_modules/expo/node_modules/@expo/cli": { - "version": "55.0.18", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-55.0.18.tgz", - "integrity": "sha512-3sJwu8KvCvQIXBnhUlHgLBZBe+ZK4Da9R5rgI4znaowJavYWMqzRClLzyE6Kri66WVoMX7Q4HUVIh8prRlO0XA==", - "license": "MIT", - "dependencies": { - "@expo/code-signing-certificates": "^0.0.6", - "@expo/config": "~55.0.10", - "@expo/config-plugins": "~55.0.7", - "@expo/devcert": "^1.2.1", - "@expo/env": "~2.1.1", - "@expo/image-utils": "^0.8.12", - "@expo/json-file": "^10.0.12", - "@expo/log-box": "55.0.7", - "@expo/metro": "~54.2.0", - "@expo/metro-config": "~55.0.11", - "@expo/osascript": "^2.4.2", - "@expo/package-manager": "^1.10.3", - "@expo/plist": "^0.5.2", - "@expo/prebuild-config": "^55.0.10", - "@expo/require-utils": "^55.0.3", - "@expo/router-server": "^55.0.11", - "@expo/schema-utils": "^55.0.2", - "@expo/spawn-async": "^1.7.2", - "@expo/ws-tunnel": "^1.0.1", - "@expo/xcpretty": "^4.4.0", - "@react-native/dev-middleware": "0.83.2", - "accepts": "^1.3.8", - "arg": "^5.0.2", - "better-opn": "~3.0.2", - "bplist-creator": "0.1.0", - "bplist-parser": "^0.3.1", - "chalk": "^4.0.0", - "ci-info": "^3.3.0", - "compression": "^1.7.4", - "connect": "^3.7.0", - "debug": "^4.3.4", - "dnssd-advertise": "^1.1.3", - "expo-server": "^55.0.6", - "fetch-nodeshim": "^0.4.6", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "lan-network": "^0.2.0", - "multitars": "^0.2.3", - "node-forge": "^1.3.3", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "picomatch": "^4.0.3", - "pretty-format": "^29.7.0", - "progress": "^2.0.3", - "prompts": "^2.3.2", - "resolve-from": "^5.0.0", - "semver": "^7.6.0", - "send": "^0.19.0", - "slugify": "^1.3.4", - "source-map-support": "~0.5.21", - "stacktrace-parser": "^0.1.10", - "structured-headers": "^0.4.1", - "terminal-link": "^2.1.1", - "toqr": "^0.1.1", - "wrap-ansi": "^7.0.0", - "ws": "^8.12.1", - "zod": "^3.25.76" - }, - "bin": { - "expo-internal": "build/bin/cli" - }, - "peerDependencies": { - "expo": "*", - "expo-router": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "expo-router": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { - "version": "55.0.11", - "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-55.0.11.tgz", - "integrity": "sha512-Kd8J1OOlFR00DZxn+1KfiQiXZtRut6cj8+ynqHJa7dtt/lTL4tGkYistqmVhpKJ6w886eRY5WivKy7o0ZBFkJA==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "@expo/metro-runtime": "^55.0.6", - "expo": "*", - "expo-constants": "^55.0.9", - "expo-font": "^55.0.4", - "expo-router": "*", - "expo-server": "^55.0.6", - "react": "*", - "react-dom": "*", - "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" - }, - "peerDependenciesMeta": { - "@expo/metro-runtime": { - "optional": true - }, - "expo-router": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-server-dom-webpack": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/metro-config": { - "version": "55.0.11", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-55.0.11.tgz", - "integrity": "sha512-qGxq7RwWpj0zNvZO/e5aizKrOKYYBrVPShSbxPOVB1EXcexxTPTxnOe4pYFg/gKkLIJe0t3jSSF8IDWlGdaaOg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.5", - "@expo/config": "~55.0.10", - "@expo/env": "~2.1.1", - "@expo/json-file": "~10.0.12", - "@expo/metro": "~54.2.0", - "@expo/spawn-async": "^1.7.2", - "browserslist": "^4.25.0", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "hermes-parser": "^0.32.0", - "jsc-safe-url": "^0.2.4", - "lightningcss": "^1.30.1", - "picomatch": "^4.0.3", - "postcss": "~8.4.32", - "resolve-from": "^5.0.0" - }, - "peerDependencies": { - "expo": "*" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/vector-icons": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", - "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", - "license": "MIT", - "peerDependencies": { - "expo-font": ">=14.0.4", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo/node_modules/expo-asset": { - "version": "55.0.10", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-55.0.10.tgz", - "integrity": "sha512-wxjNBKIaDyachq7oJgVlWVFzZ6SnNpJFJhkkcymXoTPt5O3XmDM+a6fT91xQQawCXTyZuCc1sNxKMetEofeYkg==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.8.12", - "expo-constants": "~55.0.9" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/expo-file-system": { - "version": "55.0.11", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-55.0.11.tgz", - "integrity": "sha512-KMUd6OY375J9WD79ZvjvCDZMveT7YfgiGWdi58/gfuTBsr14TRuoPk8RRQHAtc4UquzWViKcHwna9aPY7/XPpw==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/expo-keep-awake": { - "version": "55.0.4", - "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-55.0.4.tgz", - "integrity": "sha512-vwfdMtMS5Fxaon8gC0AiE70SpxTsHJ+rjeoVJl8kdfdbxczF7OIaVmfjFJ5Gfigd/WZiLqxhfZk34VAkXF4PNg==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*" - } - }, - "node_modules/expo/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/expo/node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/expo/node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -5579,18 +6227,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fb-dotslash": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", - "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "dotslash": "bin/dotslash" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -5600,12 +6236,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-nodeshim": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/fetch-nodeshim/-/fetch-nodeshim-0.4.9.tgz", - "integrity": "sha512-XIQWlB2A4RZ7NebXWGxS0uDMdvRHkiUDTghBVJKFg9yEOd45w/PP8cZANuPf2H08W6Cor3+2n7Q6TTZgAS3Fkw==", - "license": "MIT" - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -5705,6 +6335,21 @@ "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", "license": "BSD-2-Clause" }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", @@ -5721,6 +6366,15 @@ "node": ">= 6" } }, + "node_modules/freeport-async": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", + "integrity": "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -5759,6 +6413,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5887,6 +6550,42 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5940,6 +6639,18 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -5979,27 +6690,6 @@ "node": ">= 0.4" } }, - "node_modules/hermes-compiler": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-0.14.1.tgz", - "integrity": "sha512-+RPPQlayoZ9n6/KXKt5SFILWXCGJ/LV5d24L5smXrvTDrPS4L6dSctPczXauuvzFP3QEJbD1YO7Z3Ra4a+4IhA==", - "license": "MIT" - }, - "node_modules/hermes-estree": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", - "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", - "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.32.0" - } - }, "node_modules/hosted-git-info": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", @@ -6081,6 +6771,26 @@ "node": ">= 14" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6131,6 +6841,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -6140,6 +6856,22 @@ "loose-envify": "^1.0.0" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", @@ -6159,6 +6891,18 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -6208,6 +6952,25 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -6221,6 +6984,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -6239,6 +7018,39 @@ "node": ">=8" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -6402,21 +7214,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/jest-validate": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", @@ -6556,9 +7353,9 @@ } }, "node_modules/lan-network": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.0.tgz", - "integrity": "sha512-EZgbsXMrGS+oK+Ta12mCjzBFse+SIewGdwrSTr5g+MSymnjpox2x05ceI20PQejJOFvOgzcXrfDk/SdY7dSCtw==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.1.7.tgz", + "integrity": "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==", "license": "MIT", "bin": { "lan-network": "dist/lan-network-cli.js" @@ -6864,7 +7661,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -7029,6 +7825,12 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -7132,6 +7934,21 @@ "node": ">=20.19.4" } }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, "node_modules/metro-cache": { "version": "0.83.3", "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", @@ -7332,6 +8149,48 @@ "node": ">=20.19.4" } }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/metro/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -7378,15 +8237,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -7398,18 +8248,24 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "18 || 20 || >=22" - }, + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { @@ -7421,6 +8277,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -7439,17 +8307,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/multitars": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/multitars/-/multitars-0.2.4.tgz", - "integrity": "sha512-XgLbg1HHchFauMCQPRwMj6MSyDd5koPlTA1hM3rUFkeXzGpjU/I9fP3to7yrObE9jcN8ChIOQGrM0tV0kUZaKg==", - "license": "MIT" - }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -7501,6 +8362,12 @@ "node": ">= 0.6" } }, + "node_modules/nested-error-stacks": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", + "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", + "license": "MIT" + }, "node_modules/node-forge": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", @@ -7559,6 +8426,18 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -7581,7 +8460,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7597,6 +8475,51 @@ "node": ">= 6" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -7627,18 +8550,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", @@ -7949,6 +8860,15 @@ "node": ">=4.0.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", @@ -8112,6 +9032,18 @@ "dev": true, "license": "MIT" }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -8201,6 +9133,23 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", + "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, "node_modules/query-string": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", @@ -8271,10 +9220,25 @@ "node": ">= 0.6" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8290,6 +9254,27 @@ "ws": "^7" } }, + "node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -8315,45 +9300,44 @@ "license": "MIT" }, "node_modules/react-native": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.83.2.tgz", - "integrity": "sha512-ZDma3SLkRN2U2dg0/EZqxNBAx4of/oTnPjXAQi299VLq2gdnbZowGy9hzqv+O7sTA62g+lM1v+2FM5DUnJ/6hg==", + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz", + "integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==", "license": "MIT", "dependencies": { "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.83.2", - "@react-native/codegen": "0.83.2", - "@react-native/community-cli-plugin": "0.83.2", - "@react-native/gradle-plugin": "0.83.2", - "@react-native/js-polyfills": "0.83.2", - "@react-native/normalize-colors": "0.83.2", - "@react-native/virtualized-lists": "0.83.2", + "@react-native/assets-registry": "0.81.5", + "@react-native/codegen": "0.81.5", + "@react-native/community-cli-plugin": "0.81.5", + "@react-native/gradle-plugin": "0.81.5", + "@react-native/js-polyfills": "0.81.5", + "@react-native/normalize-colors": "0.81.5", + "@react-native/virtualized-lists": "0.81.5", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", - "babel-plugin-syntax-hermes-parser": "0.32.0", + "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", - "hermes-compiler": "0.14.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", - "metro-runtime": "^0.83.3", - "metro-source-map": "^0.83.3", + "metro-runtime": "^0.83.1", + "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", - "scheduler": "0.27.0", + "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", - "ws": "^7.5.10", + "ws": "^6.2.3", "yargs": "^17.6.2" }, "bin": { @@ -8363,8 +9347,8 @@ "node": ">= 20.19.4" }, "peerDependencies": { - "@types/react": "^19.1.1", - "react": "^19.2.0" + "@types/react": "^19.1.0", + "react": "^19.1.0" }, "peerDependenciesMeta": { "@types/react": { @@ -8414,40 +9398,18 @@ } }, "node_modules/react-native-reanimated": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.2.1.tgz", - "integrity": "sha512-/NcHnZMyOvsD/wYXug/YqSKw90P9edN0kEPL5lP4PFf1aQ4F1V7MKe/E0tvfkXKIajy3Qocp5EiEnlcrK/+BZg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.7.tgz", + "integrity": "sha512-Q4H6xA3Tn7QL0/E/KjI86I1KK4tcf+ErRE04LH34Etka2oVQhW6oXQ+Q8ZcDCVxiWp5vgbBH6XcH8BOo4w/Rhg==", "license": "MIT", "dependencies": { - "react-native-is-edge-to-edge": "1.2.1", - "semver": "7.7.3" + "react-native-is-edge-to-edge": "^1.2.1", + "semver": "^7.7.2" }, "peerDependencies": { "react": "*", - "react-native": "*", - "react-native-worklets": ">=0.7.0" - } - }, - "node_modules/react-native-reanimated/node_modules/react-native-is-edge-to-edge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz", - "integrity": "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==", - "license": "MIT", - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-reanimated/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "react-native": "0.78 - 0.82", + "react-native-worklets": "0.5 - 0.8" } }, "node_modules/react-native-safe-area-context": { @@ -8461,12 +9423,13 @@ } }, "node_modules/react-native-screens": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.23.0.tgz", - "integrity": "sha512-XhO3aK0UeLpBn4kLecd+J+EDeRRJlI/Ro9Fze06vo1q163VeYtzfU9QS09/VyDFMWR1qxDC1iazCArTPSFFiPw==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz", + "integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==", "license": "MIT", "dependencies": { "react-freeze": "^1.0.0", + "react-native-is-edge-to-edge": "^1.2.1", "warn-once": "^0.1.0" }, "peerDependencies": { @@ -8474,195 +9437,44 @@ "react-native": "*" } }, - "node_modules/react-native-worklets": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.7.2.tgz", - "integrity": "sha512-DuLu1kMV/Uyl9pQHp3hehAlThoLw7Yk2FwRTpzASOmI+cd4845FWn3m2bk9MnjUw8FBRIyhwLqYm2AJaXDXsog==", + "node_modules/react-native-svg": { + "version": "15.15.4", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.4.tgz", + "integrity": "sha512-boT/vIRgj6zZKBpfTPJJiYWMbZE9duBMOwPK6kCSTgxsS947IFMOq9OgIFkpWZTB7t229H24pDRkh3W9ZK/J1A==", "license": "MIT", "dependencies": { - "@babel/plugin-transform-arrow-functions": "7.27.1", - "@babel/plugin-transform-class-properties": "7.27.1", - "@babel/plugin-transform-classes": "7.28.4", - "@babel/plugin-transform-nullish-coalescing-operator": "7.27.1", - "@babel/plugin-transform-optional-chaining": "7.27.1", - "@babel/plugin-transform-shorthand-properties": "7.27.1", - "@babel/plugin-transform-template-literals": "7.27.1", - "@babel/plugin-transform-unicode-regex": "7.27.1", - "@babel/preset-typescript": "7.27.1", - "convert-source-map": "2.0.0", - "semver": "7.7.3" + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-worklets": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.8.1.tgz", + "integrity": "sha512-oWP/lStsAHU6oYCaWDXrda/wOHVdhusQJz1e6x9gPnXdFf4ndNDAOtWCmk2zGrAnlapfyA3rM6PCQq94mPg9cw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/preset-typescript": "^7.27.1", + "convert-source-map": "^2.0.0", + "semver": "^7.7.3" }, "peerDependencies": { "@babel/core": "*", + "@react-native/metro-config": "*", "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-worklets/node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/react-native-worklets/node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/react-native-worklets/node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/react-native-worklets/node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/react-native-worklets/node_modules/@babel/preset-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", - "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/react-native-worklets/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/react-native/node_modules/@react-native/codegen": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.83.2.tgz", - "integrity": "sha512-9uK6X1miCXqtL4c759l74N/XbQeneWeQVjoV7SD2CGJuW7ZefxaoYenwGPs7rMoCdtS6wuIyR3hXQ+uWEBGYXA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.25.3", - "glob": "^7.1.1", - "hermes-parser": "0.32.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "yargs": "^17.6.2" - }, - "engines": { - "node": ">= 20.19.4" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/react-native/node_modules/@react-native/js-polyfills": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.83.2.tgz", - "integrity": "sha512-dk6fIY2OrKW/2Nk2HydfYNrQau8g6LOtd7NVBrgaqa+lvuRyIML5iimShP5qPqQnx2ofHuzjFw+Ya0b5Q7nDbA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.4" - } - }, - "node_modules/react-native/node_modules/@react-native/virtualized-lists": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.83.2.tgz", - "integrity": "sha512-N7mRjHLW/+KWxMp9IHRWyE3VIkeG1m3PnZJAGEFLCN8VFb7e4VfI567o7tE/HYcdcXCylw+Eqhlciz8gDeQ71g==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">= 20.19.4" - }, - "peerDependencies": { - "@types/react": "^19.2.0", - "react": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-native/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/react-native/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "react-native": "0.81 - 0.85" } }, "node_modules/react-native/node_modules/commander": { @@ -8695,16 +9507,13 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/react-native/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", + "node_modules/react-native/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "async-limiter": "~1.0.0" } }, "node_modules/react-refresh": { @@ -8876,6 +9685,37 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireg": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz", + "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==", + "dependencies": { + "nested-error-stacks": "~2.0.1", + "rc": "~1.2.7", + "resolve": "~1.7.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/requireg/node_modules/resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "license": "MIT", + "dependencies": { + "path-parse": "^1.0.5" + } + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -8918,6 +9758,15 @@ "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", "license": "MIT" }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -8944,6 +9793,27 @@ "node": ">=4" } }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -8971,22 +9841,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -9008,18 +9862,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -9064,6 +9906,23 @@ ], "license": "MIT" }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sax": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", @@ -9074,9 +9933,9 @@ } }, "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "license": "MIT" }, "node_modules/semver": { @@ -9199,6 +10058,23 @@ "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", "license": "MIT" }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -9270,6 +10146,18 @@ "plist": "^3.0.5" } }, + "node_modules/simple-plist/node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/simple-swizzle": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", @@ -9421,30 +10309,13 @@ "node": ">=4" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/structured-headers": { @@ -9457,7 +10328,6 @@ "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -9480,7 +10350,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -9523,18 +10392,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tagged-tag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", - "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -9573,6 +10430,31 @@ "node": ">=14.0.0" } }, + "node_modules/tar": { + "version": "7.5.12", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.12.tgz", + "integrity": "sha512-9TsuLcdhOn4XztcQqhNyq1KOwOOED/3k58JAvtULiYqbO8B/0IBAAIE1hj0Svmm58k27TmcigyDI0deMlgG3uw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -9627,22 +10509,6 @@ "node": ">=8" } }, - "node_modules/test-exclude/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/test-exclude/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -9664,23 +10530,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -9690,7 +10543,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -9709,7 +10561,6 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -9726,7 +10577,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -9744,7 +10594,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9780,17 +10629,10 @@ "node": ">=0.6" } }, - "node_modules/toqr": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/toqr/-/toqr-0.1.1.tgz", - "integrity": "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==", - "license": "MIT" - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, "license": "Apache-2.0" }, "node_modules/tslib": { @@ -9831,6 +10673,15 @@ "node": ">=14.17" } }, + "node_modules/undici": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", @@ -9977,6 +10828,19 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -9993,15 +10857,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/validate-npm-package-name": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", @@ -10069,11 +10924,28 @@ "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", "license": "MIT" }, - "node_modules/whatwg-url-minimum": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.1.1.tgz", - "integrity": "sha512-u2FNVjFVFZhdjb502KzXy1gKn1mEisQRJssmSJT8CPhZdZa0AP6VCbWlXERKyGu0l09t0k50FiDiralpGhBxgA==", - "license": "MIT" + "node_modules/whatwg-url-without-unicode": { + "version": "8.0.0-3", + "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz", + "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==", + "license": "MIT", + "dependencies": { + "buffer": "^5.4.3", + "punycode": "^2.1.1", + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } }, "node_modules/which": { "version": "2.0.2", @@ -10090,6 +10962,33 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wonka": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz", + "integrity": "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==", + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -10107,6 +11006,38 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -10127,16 +11058,16 @@ } }, "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -10160,6 +11091,15 @@ "node": ">=10.0.0" } }, + "node_modules/xcode/node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/xml2js": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", @@ -10248,13 +11188,48 @@ "node": ">=12" } }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/colinhacks" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zustand": { @@ -10285,34 +11260,6 @@ "optional": true } } - }, - "node_modules/zxing-wasm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-3.0.1.tgz", - "integrity": "sha512-3CLj6iaGkpqPWXAB4pIWkFOR63MwqGekpMzaROFKto4dFowiPmLlC56KoMoOSXzqOCOpI5DAvMdB8ku2va6fUg==", - "license": "MIT", - "dependencies": { - "@types/emscripten": "^1.41.5", - "type-fest": "^5.4.4" - }, - "peerDependencies": { - "@types/emscripten": ">=1.39.6" - } - }, - "node_modules/zxing-wasm/node_modules/type-fest": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz", - "integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==", - "license": "(MIT OR CC0-1.0)", - "dependencies": { - "tagged-tag": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/package.json b/package.json index a97bbe0..8622a7b 100644 --- a/package.json +++ b/package.json @@ -9,33 +9,34 @@ "web": "expo start --web" }, "dependencies": { - "@react-native-async-storage/async-storage": "^2.2.0", + "@react-native-async-storage/async-storage": "2.2.0", "@tanstack/react-query": "^5.95.0", "axios": "^1.13.6", - "expo": "~55.0.8", - "expo-camera": "^55.0.10", - "expo-constants": "^55.0.9", - "expo-image-picker": "^55.0.13", - "expo-linking": "^55.0.8", - "expo-location": "^55.1.4", - "expo-notifications": "^55.0.13", - "expo-router": "^55.0.7", - "expo-secure-store": "^55.0.9", - "expo-status-bar": "~55.0.4", - "expo-updates": "~55.0.15", - "hermes-parser": "0.32.0", + "expo": "~54.0.33", + "expo-camera": "~17.0.10", + "expo-constants": "~18.0.13", + "expo-dev-client": "^55.0.18", + "expo-image-picker": "~17.0.10", + "expo-linking": "~8.0.11", + "expo-location": "~19.0.8", + "expo-notifications": "~0.32.16", + "expo-router": "~6.0.23", + "expo-secure-store": "~15.0.8", + "expo-status-bar": "~3.0.9", + "expo-updates": "~29.0.16", "nativewind": "^4.1.23", - "react": "19.2.0", - "react-native": "0.83.2", - "react-native-reanimated": "4.2.1", - "react-native-safe-area-context": "^5.6.2", - "react-native-screens": "^4.23.0", - "react-native-worklets": "0.7.2", + "react": "19.1.0", + "react-native": "0.81.5", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-svg": "^15.15.4", + "react-native-worklets": "^0.8.1", "zustand": "^5.0.12" }, "devDependencies": { "@expo/ngrok": "^4.1.3", - "@types/react": "~19.2.2", + "@types/react": "~19.1.10", "tailwindcss": "^3.4.19", "typescript": "~5.9.2" }, diff --git a/services/api.ts b/services/api.ts index a9b10ec..2987cd3 100644 --- a/services/api.ts +++ b/services/api.ts @@ -11,7 +11,7 @@ export const api = axios.create({ }); api.interceptors.request.use(async (config) => { - const token = await SecureStore.getItemAsync(STORAGE_KEYS.TOKEN); + const token = await SecureStore.getItemAsync('fiberops_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } @@ -22,8 +22,8 @@ api.interceptors.response.use( (response) => response, async (error) => { if (error.response?.status === 401) { - await SecureStore.deleteItemAsync(STORAGE_KEYS.TOKEN); - await SecureStore.deleteItemAsync(STORAGE_KEYS.USER); + await SecureStore.deleteItemAsync('fiberops_token'); + await SecureStore.deleteItemAsync('fiberops_tenant'); } return Promise.reject(error); } diff --git a/stores/authStore.ts b/stores/authStore.ts index 88144aa..6d1a799 100644 --- a/stores/authStore.ts +++ b/stores/authStore.ts @@ -2,12 +2,15 @@ import { create } from 'zustand'; import * as SecureStore from 'expo-secure-store'; import { api } from '../services/api'; +const TOKEN_KEY = 'fiberops_token'; +const TENANT_KEY = 'fiberops_tenant'; + interface AuthState { token: string | null; tenantSlug: string | null; user: any | null; isLoading: boolean; - login: (tenantSlug: string, username: string, password: string) => Promise; + login: (tenantSlug: string, email: string, password: string) => Promise; logout: () => Promise; hydrate: () => Promise; } @@ -20,8 +23,8 @@ export const useAuthStore = create((set) => ({ hydrate: async () => { try { - const token = await SecureStore.getItemAsync('auth_token'); - const tenantSlug = await SecureStore.getItemAsync('tenant_slug'); + const token = await SecureStore.getItemAsync(TOKEN_KEY); + const tenantSlug = await SecureStore.getItemAsync(TENANT_KEY); if (token && tenantSlug) { const res = await api.get('/api/v1/auth/me'); set({ token, tenantSlug, user: res.data, isLoading: false }); @@ -29,23 +32,23 @@ export const useAuthStore = create((set) => ({ set({ isLoading: false }); } } catch { - await SecureStore.deleteItemAsync('auth_token'); - await SecureStore.deleteItemAsync('tenant_slug'); + await SecureStore.deleteItemAsync(TOKEN_KEY); + await SecureStore.deleteItemAsync(TENANT_KEY); set({ token: null, tenantSlug: null, user: null, isLoading: false }); } }, - login: async (tenantSlug, username, password) => { - const res = await api.post('/api/v1/auth/login', { tenantSlug, username, password }); - const { token, user } = res.data; - await SecureStore.setItemAsync('auth_token', token); - await SecureStore.setItemAsync('tenant_slug', tenantSlug); - set({ token, tenantSlug, user }); + login: async (tenantSlug, email, password) => { + const res = await api.post('/api/v1/auth/login', { tenantSlug, email, password }); + const { accessToken, user } = res.data; + await SecureStore.setItemAsync(TOKEN_KEY, accessToken); + await SecureStore.setItemAsync(TENANT_KEY, tenantSlug); + set({ token: accessToken, tenantSlug, user }); }, logout: async () => { - await SecureStore.deleteItemAsync('auth_token'); - await SecureStore.deleteItemAsync('tenant_slug'); + await SecureStore.deleteItemAsync(TOKEN_KEY); + await SecureStore.deleteItemAsync(TENANT_KEY); set({ token: null, tenantSlug: null, user: null }); }, })); diff --git a/tailwind.config.js b/tailwind.config.js index 86cf3a4..53f4c75 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -5,7 +5,7 @@ module.exports = { theme: { extend: { colors: { - primary: '#2563EB', + primary: '#0891B2', 'primary-dark': '#1D4ED8', danger: '#DC2626', success: '#16A34A', diff --git a/tsconfig.json b/tsconfig.json index 56c26ad..bd8aed9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,12 +4,24 @@ "strict": true, "baseUrl": ".", "paths": { - "@/*": ["./*"], - "@/components/*": ["./components/*"], - "@/stores/*": ["./stores/*"], - "@/services/*": ["./services/*"], - "@/hooks/*": ["./hooks/*"], - "@/constants/*": ["./constants/*"] + "@/*": [ + "./*" + ], + "@/components/*": [ + "./components/*" + ], + "@/stores/*": [ + "./stores/*" + ], + "@/services/*": [ + "./services/*" + ], + "@/hooks/*": [ + "./hooks/*" + ], + "@/constants/*": [ + "./constants/*" + ] } }, "include": [ @@ -17,7 +29,6 @@ "**/*.tsx", "nativewind-env.d.ts", "types/**/*.d.ts", - ".expo/types/**/*.d.ts", - "expo-env.d.ts" + ".expo/types/**/*.d.ts" ] }