diff --git a/mobile/.gitignore b/mobile/.gitignore index 954fc662..8f88897e 100644 --- a/mobile/.gitignore +++ b/mobile/.gitignore @@ -1,37 +1,8 @@ -# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files - -# dependencies node_modules/ - -# Expo .expo/ dist/ -web-build/ -expo-env.d.ts - -# Native -.kotlin/ -*.orig.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision - -# Metro -.metro-health-check* - -# debug -npm-debug.* -yarn-debug.* -yarn-error.* - -# macOS +npm-debug.log* +yarn-debug.log* +yarn-error.log* +# MacOS .DS_Store -*.pem - -# local env files -.env*.local - -# typescript -*.tsbuildinfo diff --git a/mobile/App.js b/mobile/App.js deleted file mode 100644 index f5496adf..00000000 --- a/mobile/App.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import AppNavigator from './navigation/AppNavigator'; -import { PaperProvider } from 'react-native-paper'; -import { AuthProvider } from './context/AuthContext'; - -export default function App() { - return ( - - - - - - ); -} diff --git a/mobile/api/auth.js b/mobile/api/auth.js deleted file mode 100644 index 46e0426b..00000000 --- a/mobile/api/auth.js +++ /dev/null @@ -1,15 +0,0 @@ -import { apiClient } from "./client"; - -export const login = (email, password) => { - return apiClient.post("/auth/login/email", { email, password }); -}; - -export const signup = (name, email, password) => { - return apiClient.post("/auth/signup/email", { name, email, password }); -}; - -export const updateUser = (userData) => apiClient.patch("/users/me", userData); - -export const refresh = (refresh_token) => { - return apiClient.post("/auth/refresh", { refresh_token }); -}; diff --git a/mobile/api/client.js b/mobile/api/client.js deleted file mode 100644 index 958a06b9..00000000 --- a/mobile/api/client.js +++ /dev/null @@ -1,117 +0,0 @@ -import axios from "axios"; - -const API_URL = "https://splitwiser-production.up.railway.app"; - -let accessToken = null; -let refreshToken = null; -let isRefreshing = false; -let refreshPromise = null; -let tokenUpdateListener = null; // function({ accessToken, refreshToken }) - -export const setTokenUpdateListener = (fn) => { - tokenUpdateListener = fn; -}; - -export const setAuthTokens = async ({ newAccessToken, newRefreshToken }) => { - if (newAccessToken) accessToken = newAccessToken; - if (newRefreshToken) refreshToken = newRefreshToken; -}; - -export const clearAuthTokens = async () => { - accessToken = null; - refreshToken = null; -}; - -export const getAccessToken = () => accessToken; -export const getRefreshToken = () => refreshToken; - -export const apiClient = axios.create({ - baseURL: API_URL, - headers: { "Content-Type": "application/json" }, -}); - -// Basic retry configuration -const MAX_RETRIES = 3; -const BASE_DELAY_MS = 300; // base backoff - -function sleep(ms) { - return new Promise((res) => setTimeout(res, ms)); -} - -// Attach Authorization header -apiClient.interceptors.request.use((config) => { - if (accessToken && !config.headers?.Authorization) { - config.headers = config.headers || {}; - config.headers.Authorization = `Bearer ${accessToken}`; - } - return config; -}); - -async function performRefresh() { - // Avoid multiple refresh calls - if (isRefreshing && refreshPromise) return refreshPromise; - isRefreshing = true; - refreshPromise = (async () => { - try { - if (!refreshToken) throw new Error("No refresh token"); - const resp = await axios.post( - `${API_URL}/auth/refresh`, - { refresh_token: refreshToken }, - { headers: { "Content-Type": "application/json" } } - ); - const { access_token, refresh_token } = resp.data || {}; - accessToken = access_token || accessToken; - refreshToken = refresh_token || refreshToken; - // Notify listener (AuthContext) so it can persist & update state - if (tokenUpdateListener) { - tokenUpdateListener({ accessToken, refreshToken }); - } - return accessToken; - } finally { - isRefreshing = false; - // allow GC of the completed promise - refreshPromise = null; - } - })(); - return refreshPromise; -} - -// Retry logic on 401 -apiClient.interceptors.response.use( - (response) => response, - async (error) => { - const originalRequest = error.config || {}; - const status = error.response?.status; - - // Avoid refresh loop - const isAuthRefreshCall = originalRequest.url?.includes("/auth/refresh"); - - // 1. Handle 401 with refresh - if (status === 401 && !originalRequest._retry && !isAuthRefreshCall) { - originalRequest._retry = true; - try { - await performRefresh(); - originalRequest.headers = originalRequest.headers || {}; - if (accessToken) - originalRequest.headers.Authorization = `Bearer ${accessToken}`; - return apiClient(originalRequest); - } catch (e) { - return Promise.reject(error); - } - } - - // 2. Retry on network errors or 5xx (all methods; caller should ensure idempotency where needed) - const transientError = !status || (status >= 500 && status < 600); - if (transientError) { - originalRequest._retryCount = originalRequest._retryCount || 0; - if (originalRequest._retryCount < MAX_RETRIES) { - originalRequest._retryCount += 1; - const delay = BASE_DELAY_MS * 2 ** (originalRequest._retryCount - 1); - await sleep(delay + Math.random() * 100); // jitter - return apiClient(originalRequest); - } - } - - return Promise.reject(error); - } -); diff --git a/mobile/api/groups.js b/mobile/api/groups.js deleted file mode 100644 index 8cf9cdba..00000000 --- a/mobile/api/groups.js +++ /dev/null @@ -1,47 +0,0 @@ -import { apiClient } from "./client"; - -export const getGroups = () => apiClient.get("/groups"); - -export const getOptimizedSettlements = (groupId) => - apiClient.post(`/groups/${groupId}/settlements/optimize`, {}); - -export const createExpense = (groupId, expenseData) => - apiClient.post(`/groups/${groupId}/expenses`, expenseData); - -export const getGroupDetails = (groupId) => { - return Promise.all([getGroupMembers(groupId), getGroupExpenses(groupId)]); -}; - -export const getGroupMembers = (groupId) => - apiClient.get(`/groups/${groupId}/members`); - -export const getGroupExpenses = (groupId) => - apiClient.get(`/groups/${groupId}/expenses`); - -export const createGroup = (name) => apiClient.post("/groups", { name }); - -export const joinGroup = (joinCode) => - apiClient.post("/groups/join", { joinCode }); - -export const getUserBalanceSummary = () => - apiClient.get("/users/me/balance-summary"); - -export const getFriendsBalance = () => - apiClient.get("/users/me/friends-balance"); - -// New APIs for Group Settings -export const getGroupById = (groupId) => apiClient.get(`/groups/${groupId}`); - -export const updateGroup = (groupId, updates) => - apiClient.patch(`/groups/${groupId}`, updates); - -export const deleteGroup = (groupId) => apiClient.delete(`/groups/${groupId}`); - -export const leaveGroup = (groupId) => - apiClient.post(`/groups/${groupId}/leave`, {}); - -export const updateMemberRole = (groupId, memberId, role) => - apiClient.patch(`/groups/${groupId}/members/${memberId}`, { role }); - -export const removeMember = (groupId, memberId) => - apiClient.delete(`/groups/${groupId}/members/${memberId}`); diff --git a/mobile/app.json b/mobile/app.json index db409293..8c2ae583 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -1,35 +1,51 @@ { "expo": { - "name": "frontend", - "slug": "frontend", - "platforms": ["ios", "android", "web"], + "name": "Splitwiser Mobile", + "slug": "splitwiser-mobile", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", - "newArchEnabled": true, "splash": { - "image": "./assets/splash-icon.png", + "image": "./assets/splash.png", "resizeMode": "contain", "backgroundColor": "#ffffff" }, + "assetBundlePatterns": [ + "**/*" + ], "ios": { "supportsTablet": true, - "infoPlist": { - "NSPhotoLibraryUsageDescription": "Allow Splitwiser to select a group icon from your photo library." - } + "bundleIdentifier": "com.splitwiser.mobile" }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" }, - "edgeToEdgeEnabled": true, - "permissions": ["READ_MEDIA_IMAGES"] + "package": "com.splitwiser.mobile" }, "web": { - "favicon": "./assets/favicon.png" + "favicon": "./assets/favicon.png", + "bundler": "metro" }, + "plugins": [ + "expo-router", + "expo-font", + [ + "expo-build-properties", + { + "android": { + "newArchEnabled": true + }, + "ios": { + "newArchEnabled": true + } + } + ] + ], + "scheme": "splitwiser", + "newArchEnabled": true, "extra": { "eas": { "projectId": "afe97159-52c4-425a-9ce3-c56d4f2cb568" diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx new file mode 100644 index 00000000..db8898b9 --- /dev/null +++ b/mobile/app/_layout.tsx @@ -0,0 +1,40 @@ +import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; +import { useFonts } from 'expo-font'; +import { Stack } from 'expo-router'; +import * as SplashScreen from 'expo-splash-screen'; +import { useEffect } from 'react'; +import { Inter_400Regular, Inter_700Bold } from '@expo-google-fonts/inter'; +import { SpaceGrotesk_400Regular, SpaceGrotesk_700Bold } from '@expo-google-fonts/space-grotesk'; +import "../global.css"; +import { StatusBar } from 'expo-status-bar'; + +// Prevent the splash screen from auto-hiding before asset loading is complete. +SplashScreen.preventAutoHideAsync(); + +export default function RootLayout() { + const [loaded] = useFonts({ + Inter_400Regular, + Inter_700Bold, + SpaceGrotesk_400Regular, + SpaceGrotesk_700Bold, + }); + + useEffect(() => { + if (loaded) { + SplashScreen.hideAsync(); + } + }, [loaded]); + + if (!loaded) { + return null; + } + + return ( + + + + + + + ); +} diff --git a/mobile/app/index.tsx b/mobile/app/index.tsx new file mode 100644 index 00000000..03f7c841 --- /dev/null +++ b/mobile/app/index.tsx @@ -0,0 +1,100 @@ +import { View, ScrollView } from 'react-native'; +import { ThemedText, ThemedButton, ThemedView } from '../components/Themed'; +import { NeoCard } from '../components/NeoCard'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { Wallet, PieChart, TrendingUp, ArrowRight } from 'lucide-react-native'; + +export default function HomeScreen() { + return ( + + + + + {/* Header */} + + Hello, Jules! + Welcome back to Splitwiser. + + + {/* Balance Card */} + + + TOTAL BALANCE + + + $1,234.56 + + + +2.4% this month + + + + + {/* Quick Actions */} + + console.log('Add Expense')} + /> + console.log('Settle Up')} + /> + + + {/* Recent Activity */} + + Recent Activity + View All + + + + + + + + + + Grocery Run + Yesterday + + + -$45.00 + + + + + + + + + Movie Night + 2 days ago + + + +$12.50 + + + + + + + + + Rent Payment + Oct 1 + + + -$800.00 + + + + + + + ); +} diff --git a/mobile/assets/adaptive-icon.png b/mobile/assets/adaptive-icon.png deleted file mode 100644 index adc6e21d..00000000 Binary files a/mobile/assets/adaptive-icon.png and /dev/null differ diff --git a/mobile/assets/adaptive-icon/background.png b/mobile/assets/adaptive-icon/background.png deleted file mode 100644 index 0a4332a6..00000000 Binary files a/mobile/assets/adaptive-icon/background.png and /dev/null differ diff --git a/mobile/assets/adaptive-icon/foreground.png b/mobile/assets/adaptive-icon/foreground.png deleted file mode 100644 index b56ddd29..00000000 Binary files a/mobile/assets/adaptive-icon/foreground.png and /dev/null differ diff --git a/mobile/assets/favicon.png b/mobile/assets/favicon.png deleted file mode 100644 index ffd2b4ae..00000000 Binary files a/mobile/assets/favicon.png and /dev/null differ diff --git a/mobile/assets/icon.png b/mobile/assets/icon.png deleted file mode 100644 index adc6e21d..00000000 Binary files a/mobile/assets/icon.png and /dev/null differ diff --git a/mobile/assets/pwa/chrome-icon/chrome-icon-144.png b/mobile/assets/pwa/chrome-icon/chrome-icon-144.png deleted file mode 100644 index 8afeeeaa..00000000 Binary files a/mobile/assets/pwa/chrome-icon/chrome-icon-144.png and /dev/null differ diff --git a/mobile/assets/pwa/chrome-icon/chrome-icon-192.png b/mobile/assets/pwa/chrome-icon/chrome-icon-192.png deleted file mode 100644 index 77bb31f9..00000000 Binary files a/mobile/assets/pwa/chrome-icon/chrome-icon-192.png and /dev/null differ diff --git a/mobile/assets/pwa/chrome-icon/chrome-icon-512.png b/mobile/assets/pwa/chrome-icon/chrome-icon-512.png deleted file mode 100644 index 3ef334e5..00000000 Binary files a/mobile/assets/pwa/chrome-icon/chrome-icon-512.png and /dev/null differ diff --git a/mobile/assets/splash-icon.png b/mobile/assets/splash-icon.png deleted file mode 100644 index 03d6f6b6..00000000 Binary files a/mobile/assets/splash-icon.png and /dev/null differ diff --git a/mobile/assets/splash.png b/mobile/assets/splash.png deleted file mode 100644 index 26c97a31..00000000 Binary files a/mobile/assets/splash.png and /dev/null differ diff --git a/mobile/babel.config.js b/mobile/babel.config.js new file mode 100644 index 00000000..4b84a6b2 --- /dev/null +++ b/mobile/babel.config.js @@ -0,0 +1,12 @@ +module.exports = function (api) { + api.cache(true); + return { + presets: [ + ["babel-preset-expo", { jsxImportSource: "nativewind" }], + "nativewind/babel", + ], + plugins: [ + "react-native-reanimated/plugin", + ], + }; +}; diff --git a/mobile/components/NeoCard.tsx b/mobile/components/NeoCard.tsx new file mode 100644 index 00000000..c5cb3fa8 --- /dev/null +++ b/mobile/components/NeoCard.tsx @@ -0,0 +1,15 @@ +import { View } from 'react-native'; +import { cn } from '../lib/utils'; + +interface CardProps { + className?: string; + children: React.ReactNode; +} + +export function NeoCard({ className, children }: CardProps) { + return ( + + {children} + + ); +} diff --git a/mobile/components/Themed.tsx b/mobile/components/Themed.tsx new file mode 100644 index 00000000..50213ddf --- /dev/null +++ b/mobile/components/Themed.tsx @@ -0,0 +1,45 @@ +import { View, Text, ViewProps, TouchableOpacity, TextProps } from 'react-native'; +import { cn } from '../lib/utils'; + +export function ThemedView({ style, className, ...otherProps }: ViewProps & { className?: string }) { + return ; +} + +export function ThemedText({ style, className, type = 'default', ...otherProps }: TextProps & { className?: string, type?: 'title' | 'subtitle' | 'default' | 'defaultSemiBold' | 'link' }) { + const getStyles = () => { + switch (type) { + case 'title': return "text-4xl font-mono-bold text-neo-dark"; + case 'subtitle': return "text-2xl font-mono-bold text-neo-dark"; + case 'defaultSemiBold': return "text-base font-sans-bold text-neo-dark"; + case 'link': return "text-base font-sans text-neo-main underline"; + default: return "text-base font-sans text-neo-dark"; + } + }; + + return ; +} + +export function ThemedButton({ title, onPress, variant = 'primary', className, ...otherProps }: { title: string, onPress?: () => void, variant?: 'primary' | 'secondary' | 'accent', className?: string }) { + const getBgColor = () => { + switch(variant) { + case 'secondary': return "bg-neo-second"; + case 'accent': return "bg-neo-accent"; + default: return "bg-neo-main"; + } + } + + return ( + + {title} + + ); +} diff --git a/mobile/constants/colors.ts b/mobile/constants/colors.ts new file mode 100644 index 00000000..97de42c6 --- /dev/null +++ b/mobile/constants/colors.ts @@ -0,0 +1,10 @@ +export const COLORS = { + neo: { + main: '#8855ff', + second: '#ff9900', + accent: '#00cc88', + bg: '#f0f0f0', + dark: '#1a1a1a', + white: '#ffffff', + } +}; diff --git a/mobile/context/AuthContext.js b/mobile/context/AuthContext.js deleted file mode 100644 index 1caf5326..00000000 --- a/mobile/context/AuthContext.js +++ /dev/null @@ -1,190 +0,0 @@ -import AsyncStorage from "@react-native-async-storage/async-storage"; -import { createContext, useEffect, useState } from "react"; -import * as authApi from "../api/auth"; -import { - clearAuthTokens, - setAuthTokens, - setTokenUpdateListener, -} from "../api/client"; - -export const AuthContext = createContext(); - -export const AuthProvider = ({ children }) => { - const [user, setUser] = useState(null); - const [token, setToken] = useState(null); - const [refresh, setRefresh] = useState(null); - const [isLoading, setIsLoading] = useState(true); - - // Load token and user data from AsyncStorage on app start - useEffect(() => { - const loadStoredAuth = async () => { - try { - const storedToken = await AsyncStorage.getItem("auth_token"); - const storedRefresh = await AsyncStorage.getItem("refresh_token"); - const storedUser = await AsyncStorage.getItem("user_data"); - - if (storedToken && storedUser) { - setToken(storedToken); - setRefresh(storedRefresh); - await setAuthTokens({ - newAccessToken: storedToken, - newRefreshToken: storedRefresh, - }); - // Normalize user id shape: ensure `_id` exists even if API stored `id` - const parsed = JSON.parse(storedUser); - const normalized = parsed?._id - ? parsed - : parsed?.id - ? { ...parsed, _id: parsed.id } - : parsed; - setUser(normalized); - } - } catch (error) { - console.error("Failed to load stored authentication:", error); - } finally { - setIsLoading(false); - } - }; - - loadStoredAuth(); - }, []); - - // Subscribe to token updates from the api client (refresh flow) - useEffect(() => { - setTokenUpdateListener(async ({ accessToken, refreshToken }) => { - if (accessToken && accessToken !== token) setToken(accessToken); - if (refreshToken && refreshToken !== refresh) setRefresh(refreshToken); - }); - }, [token, refresh]); - - // Save tokens to AsyncStorage whenever they change - useEffect(() => { - const saveToken = async () => { - try { - if (token) { - await AsyncStorage.setItem("auth_token", token); - } else { - await AsyncStorage.removeItem("auth_token"); - } - } catch (error) { - console.error("Failed to save token to storage:", error); - } - }; - - saveToken(); - }, [token]); - - useEffect(() => { - const saveRefresh = async () => { - try { - if (refresh) { - await AsyncStorage.setItem("refresh_token", refresh); - } else { - await AsyncStorage.removeItem("refresh_token"); - } - } catch (error) { - console.error("Failed to save refresh token to storage:", error); - } - }; - saveRefresh(); - }, [refresh]); - - // Save user data to AsyncStorage whenever it changes - useEffect(() => { - const saveUser = async () => { - try { - if (user) { - await AsyncStorage.setItem("user_data", JSON.stringify(user)); - } else { - await AsyncStorage.removeItem("user_data"); - } - } catch (error) { - console.error("Failed to save user data to storage:", error); - } - }; - - saveUser(); - }, [user]); - - const login = async (email, password) => { - try { - const response = await authApi.login(email, password); - const { access_token, refresh_token, user: userData } = response.data; - setToken(access_token); - setRefresh(refresh_token); - await setAuthTokens({ - newAccessToken: access_token, - newRefreshToken: refresh_token, - }); - // Normalize user id shape: ensure `_id` exists even if backend returns `id` - const normalizedUser = userData?._id - ? userData - : userData?.id - ? { ...userData, _id: userData.id } - : userData; - setUser(normalizedUser); - return true; - } catch (error) { - console.error( - "Login failed:", - error.response?.data?.detail || error.message - ); - return false; - } - }; - - const signup = async (name, email, password) => { - try { - await authApi.signup(name, email, password); - return true; - } catch (error) { - console.error( - "Signup failed:", - error.response?.data?.detail || error.message - ); - return false; - } - }; - - const logout = async () => { - try { - // Clear stored authentication data - await AsyncStorage.removeItem("auth_token"); - await AsyncStorage.removeItem("refresh_token"); - await AsyncStorage.removeItem("user_data"); - } catch (error) { - console.error("Failed to clear stored authentication:", error); - } - - setToken(null); - setRefresh(null); - setUser(null); - await clearAuthTokens(); - }; - - const updateUserInContext = (updatedUser) => { - // Normalize on updates too - const normalizedUser = updatedUser?._id - ? updatedUser - : updatedUser?.id - ? { ...updatedUser, _id: updatedUser.id } - : updatedUser; - setUser(normalizedUser); - }; - - return ( - - {children} - - ); -}; diff --git a/mobile/global.css b/mobile/global.css new file mode 100644 index 00000000..b5c61c95 --- /dev/null +++ b/mobile/global.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/mobile/index.js b/mobile/index.js deleted file mode 100644 index 1d6e981e..00000000 --- a/mobile/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import { registerRootComponent } from 'expo'; - -import App from './App'; - -// registerRootComponent calls AppRegistry.registerComponent('main', () => App); -// It also ensures that whether you load the app in Expo Go or in a native build, -// the environment is set up appropriately -registerRootComponent(App); diff --git a/mobile/lib/utils.ts b/mobile/lib/utils.ts new file mode 100644 index 00000000..365058ce --- /dev/null +++ b/mobile/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/mobile/metro.config.js b/mobile/metro.config.js new file mode 100644 index 00000000..b0963fe7 --- /dev/null +++ b/mobile/metro.config.js @@ -0,0 +1,6 @@ +const { getDefaultConfig } = require("expo/metro-config"); +const { withNativeWind } = require("nativewind/metro"); + +const config = getDefaultConfig(__dirname); + +module.exports = withNativeWind(config, { input: "./global.css" }); diff --git a/mobile/nativewind-env.d.ts b/mobile/nativewind-env.d.ts new file mode 100644 index 00000000..a13e3136 --- /dev/null +++ b/mobile/nativewind-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/mobile/navigation/AccountStackNavigator.js b/mobile/navigation/AccountStackNavigator.js deleted file mode 100644 index 4a5b21d8..00000000 --- a/mobile/navigation/AccountStackNavigator.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import AccountScreen from '../screens/AccountScreen'; -import EditProfileScreen from '../screens/EditProfileScreen'; - -const Stack = createNativeStackNavigator(); - -const AccountStackNavigator = () => { - return ( - - - - - ); -}; - -export default AccountStackNavigator; diff --git a/mobile/navigation/AppNavigator.js b/mobile/navigation/AppNavigator.js deleted file mode 100644 index f24c3354..00000000 --- a/mobile/navigation/AppNavigator.js +++ /dev/null @@ -1,34 +0,0 @@ -import React, { useContext } from 'react'; -import { NavigationContainer } from '@react-navigation/native'; -import { View, ActivityIndicator, StyleSheet } from 'react-native'; -import { AuthContext } from '../context/AuthContext'; -import AuthNavigator from './AuthNavigator'; -import MainNavigator from './MainNavigator'; - -const AppNavigator = () => { - const { token, isLoading } = useContext(AuthContext); - - if (isLoading) { - return ( - - - - ); - } - - return ( - - {token ? : } - - ); -}; - -const styles = StyleSheet.create({ - loaderContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - } -}) - -export default AppNavigator; diff --git a/mobile/navigation/AuthNavigator.js b/mobile/navigation/AuthNavigator.js deleted file mode 100644 index 55837d79..00000000 --- a/mobile/navigation/AuthNavigator.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import LoginScreen from '../screens/LoginScreen'; -import SignupScreen from '../screens/SignupScreen'; - -const Stack = createNativeStackNavigator(); - -const AuthNavigator = () => { - return ( - - - - - ); -}; - -export default AuthNavigator; diff --git a/mobile/navigation/GroupsStackNavigator.js b/mobile/navigation/GroupsStackNavigator.js deleted file mode 100644 index 5ede954d..00000000 --- a/mobile/navigation/GroupsStackNavigator.js +++ /dev/null @@ -1,22 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import AddExpenseScreen from '../screens/AddExpenseScreen'; -import GroupDetailsScreen from '../screens/GroupDetailsScreen'; -import GroupSettingsScreen from '../screens/GroupSettingsScreen'; -import HomeScreen from '../screens/HomeScreen'; -import JoinGroupScreen from '../screens/JoinGroupScreen'; - -const Stack = createNativeStackNavigator(); - -const GroupsStackNavigator = () => { - return ( - - - - - - - - ); -}; - -export default GroupsStackNavigator; diff --git a/mobile/navigation/MainNavigator.js b/mobile/navigation/MainNavigator.js deleted file mode 100644 index dc9d32a2..00000000 --- a/mobile/navigation/MainNavigator.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; -import { MaterialCommunityIcons } from '@expo/vector-icons'; -import GroupsStackNavigator from './GroupsStackNavigator'; -import FriendsScreen from '../screens/FriendsScreen'; -import AccountStackNavigator from './AccountStackNavigator'; - -const Tab = createBottomTabNavigator(); - -const MainNavigator = () => { - return ( - - ( - - ), - }} - /> - ( - - ), - }} - /> - ( - - ), - }} - /> - - ); -}; - -export default MainNavigator; diff --git a/mobile/package-lock.json b/mobile/package-lock.json index 329f6465..298f6917 100644 --- a/mobile/package-lock.json +++ b/mobile/package-lock.json @@ -8,25 +8,36 @@ "name": "mobile", "version": "1.0.0", "dependencies": { - "@expo/metro-runtime": "~6.1.2", - "@react-native-async-storage/async-storage": "^2.1.2", - "@react-navigation/bottom-tabs": "^7.4.4", - "@react-navigation/native": "^7.1.16", - "@react-navigation/native-stack": "^7.3.23", - "axios": "^1.11.0", - "expo": "^54.0.25", - "expo-image-picker": "~17.0.8", + "@expo-google-fonts/inter": "^0.2.3", + "@expo-google-fonts/space-grotesk": "^0.2.3", + "clsx": "^2.1.1", + "expo": "~54.0.25", + "expo-build-properties": "^1.0.9", + "expo-constants": "~18.0.10", + "expo-linking": "~8.0.9", + "expo-router": "~6.0.15", + "expo-splash-screen": "^31.0.11", "expo-status-bar": "~3.0.8", + "expo-system-ui": "~6.0.8", + "lucide-react-native": "^0.475.0", + "nativewind": "^4.1.23", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.5", - "react-native-paper": "^5.14.5", - "react-native-safe-area-context": "^5.4.0", - "react-native-screens": "^4.11.1", - "react-native-web": "^0.21.0" + "react-native-css-interop": "^0.1.22", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-svg": "15.12.1", + "react-native-web": "~0.21.0", + "react-native-worklets": "^0.6.1", + "tailwind-merge": "^2.5.2", + "tailwindcss": "^3.4.17" }, "devDependencies": { - "@babel/core": "^7.20.0" + "@babel/core": "^7.20.0", + "@types/react": "~19.1.10", + "typescript": "^5.1.3" } }, "node_modules/@0no-co/graphql.web": { @@ -43,17 +54,16 @@ } } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@babel/code-frame": { @@ -71,31 +81,31 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", "peer": true, "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -244,14 +254,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -370,13 +380,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", - "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1372,6 +1382,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", @@ -1447,10 +1472,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", - "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -1519,26 +1545,116 @@ "node": ">=6.9.0" } }, - "node_modules/@callstack/react-theme-provider": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz", - "integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==", + "node_modules/@expo-google-fonts/inter": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/inter/-/inter-0.2.3.tgz", + "integrity": "sha512-iHK9FI+dnE45X5c2Z5hSFwNH4zUWethizpbv3XUn0FIGw5jwvzriENz0a6wCdkI4/d+1QkurnHo5XHti7TbNJA==", + "license": "MIT" + }, + "node_modules/@expo-google-fonts/space-grotesk": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/space-grotesk/-/space-grotesk-0.2.3.tgz", + "integrity": "sha512-UYEMIrzegR02pauH7gVMI7j6cUroTtJug6dH/aQFjMNz0UwZe6GUcrEtJDmsUHJjEZdxbYgHhaiIwswWVo0CMA==", + "license": "MIT" + }, + "node_modules/@expo/cli": { + "version": "54.0.16", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.16.tgz", + "integrity": "sha512-hY/OdRaJMs5WsVPuVSZ+RLH3VObJmL/pv5CGCHEZHN2PxZjSZSdctyKV8UcFBXTF0yIKNAJ9XLs1dlNYXHh4Cw==", "license": "MIT", "dependencies": { - "deepmerge": "^3.2.0", - "hoist-non-react-statics": "^3.3.0" + "@0no-co/graphql.web": "^1.0.8", + "@expo/code-signing-certificates": "^0.0.5", + "@expo/config": "~12.0.10", + "@expo/config-plugins": "~54.0.2", + "@expo/devcert": "^1.1.2", + "@expo/env": "~2.0.7", + "@expo/image-utils": "^0.8.7", + "@expo/json-file": "^10.0.7", + "@expo/mcp-tunnel": "~0.1.0", + "@expo/metro": "~54.1.0", + "@expo/metro-config": "~54.0.9", + "@expo/osascript": "^2.3.7", + "@expo/package-manager": "^1.9.8", + "@expo/plist": "^0.4.7", + "@expo/prebuild-config": "^54.0.6", + "@expo/schema-utils": "^0.1.7", + "@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.4", + "freeport-async": "^2.0.0", + "getenv": "^2.0.0", + "glob": "^10.4.2", + "lan-network": "^0.1.6", + "minimatch": "^9.0.0", + "node-forge": "^1.3.1", + "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.4.3", + "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": { - "react": ">=16.3.0" + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "node_modules/@callstack/react-theme-provider/node_modules/deepmerge": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", - "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", - "license": "MIT", + "node_modules/@expo/cli/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": ">=0.10.0" + "node": ">=10" } }, "node_modules/@expo/code-signing-certificates": { @@ -1789,27 +1905,6 @@ } } }, - "node_modules/@expo/mcp-tunnel/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "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/@expo/metro": { "version": "54.1.0", "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-54.1.0.tgz", @@ -1872,7 +1967,6 @@ "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-6.1.2.tgz", "integrity": "sha512-nvM+Qv45QH7pmYvP8JB1G8JpScrWND3KrMA6ZKe62cwwNiX/BjHU28Ear0v/4bQWXlOY0mv6B8CDIm8JxXde9g==", "license": "MIT", - "peer": true, "dependencies": { "anser": "^1.4.9", "pretty-format": "^29.7.0", @@ -1891,344 +1985,42 @@ } } }, - "node_modules/@expo/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/@expo/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/@expo/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==", + "node_modules/@expo/osascript": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.3.7.tgz", + "integrity": "sha512-IClSOXxR0YUFxIriUJVqyYki7lLMIHrrzOaP01yxAL1G8pj2DWV5eW1y5jSzIcIfSCNhtGsshGd1tU/AYup5iQ==", "license": "MIT", "dependencies": { - "hermes-estree": "0.32.0" + "@expo/spawn-async": "^1.7.2", + "exec-async": "^2.2.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@expo/metro/node_modules/metro": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.2.tgz", - "integrity": "sha512-HQgs9H1FyVbRptNSMy/ImchTTE5vS2MSqLoOo7hbDoBq6hPPZokwJvBMwrYSxdjQZmLXz2JFZtdvS+ZfgTc9yw==", + "node_modules/@expo/package-manager": { + "version": "1.9.8", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.9.8.tgz", + "integrity": "sha512-4/I6OWquKXYnzo38pkISHCOCOXxfeEmu4uDoERq1Ei/9Ur/s9y3kLbAamEkitUkDC7gHk1INxRWEfFNzGbmOrA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "@babel/types": "^7.25.2", - "accepts": "^1.3.7", + "@expo/json-file": "^10.0.7", + "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "error-stack-parser": "^2.0.6", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "hermes-parser": "0.32.0", - "image-size": "^1.0.2", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "jsc-safe-url": "^0.2.2", - "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.83.2", - "metro-cache": "0.83.2", - "metro-cache-key": "0.83.2", - "metro-config": "0.83.2", - "metro-core": "0.83.2", - "metro-file-map": "0.83.2", - "metro-resolver": "0.83.2", - "metro-runtime": "0.83.2", - "metro-source-map": "0.83.2", - "metro-symbolicate": "0.83.2", - "metro-transform-plugins": "0.83.2", - "metro-transform-worker": "0.83.2", - "mime-types": "^2.1.27", - "nullthrows": "^1.1.1", - "serialize-error": "^2.1.0", - "source-map": "^0.5.6", - "throat": "^5.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "metro": "src/cli.js" - }, - "engines": { - "node": ">=20.19.4" + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" } }, - "node_modules/@expo/metro/node_modules/metro-babel-transformer": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.2.tgz", - "integrity": "sha512-rirY1QMFlA1uxH3ZiNauBninwTioOgwChnRdDcbB4tgRZ+bGX9DiXoh9QdpppiaVKXdJsII932OwWXGGV4+Nlw==", + "node_modules/@expo/plist": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.7.tgz", + "integrity": "sha512-dGxqHPvCZKeRKDU1sJZMmuyVtcASuSYh1LPFVaM1DuffqPL36n6FMEL0iUqq2Tx3xhWk8wCnWl34IKplUjJDdA==", "license": "MIT", "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.32.0", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-cache": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.2.tgz", - "integrity": "sha512-Z43IodutUZeIS7OTH+yQFjc59QlFJ6s5OvM8p2AP9alr0+F8UKr8ADzFzoGKoHefZSKGa4bJx7MZJLF6GwPDHQ==", - "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.2" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-cache-key": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.2.tgz", - "integrity": "sha512-3EMG/GkGKYoTaf5RqguGLSWRqGTwO7NQ0qXKmNBjr0y6qD9s3VBXYlwB+MszGtmOKsqE9q3FPrE5Nd9Ipv7rZw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-config": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.2.tgz", - "integrity": "sha512-1FjCcdBe3e3D08gSSiU9u3Vtxd7alGH3x/DNFqWDFf5NouX4kLgbVloDDClr1UrLz62c0fHh2Vfr9ecmrOZp+g==", - "license": "MIT", - "dependencies": { - "connect": "^3.6.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.83.2", - "metro-cache": "0.83.2", - "metro-core": "0.83.2", - "metro-runtime": "0.83.2", - "yaml": "^2.6.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-core": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.2.tgz", - "integrity": "sha512-8DRb0O82Br0IW77cNgKMLYWUkx48lWxUkvNUxVISyMkcNwE/9ywf1MYQUE88HaKwSrqne6kFgCSA/UWZoUT0Iw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.2" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-file-map": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.2.tgz", - "integrity": "sha512-cMSWnEqZrp/dzZIEd7DEDdk72PXz6w5NOKriJoDN9p1TDQ5nAYrY2lHi8d6mwbcGLoSlWmpPyny9HZYFfPWcGQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "fb-watchman": "^2.0.0", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "nullthrows": "^1.1.1", - "walker": "^1.0.7" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-minify-terser": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.2.tgz", - "integrity": "sha512-zvIxnh7U0JQ7vT4quasKsijId3dOAWgq+ip2jF/8TMrPUqQabGrs04L2dd0haQJ+PA+d4VvK/bPOY8X/vL2PWw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-resolver": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.2.tgz", - "integrity": "sha512-Yf5mjyuiRE/Y+KvqfsZxrbHDA15NZxyfg8pIk0qg47LfAJhpMVEX+36e6ZRBq7KVBqy6VDX5Sq55iHGM4xSm7Q==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-runtime": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.2.tgz", - "integrity": "sha512-nnsPtgRvFbNKwemqs0FuyFDzXLl+ezuFsUXDbX8o0SXOfsOPijqiQrf3kuafO1Zx1aUWf4NOrKJMAQP5EEHg9A==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.25.0", - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-source-map": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.2.tgz", - "integrity": "sha512-5FL/6BSQvshIKjXOennt9upFngq2lFvDakZn5LfauIVq8+L4sxXewIlSTcxAtzbtjAIaXeOSVMtCJ5DdfCt9AA==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.83.2", - "nullthrows": "^1.1.1", - "ob1": "0.83.2", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-symbolicate": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.2.tgz", - "integrity": "sha512-KoU9BLwxxED6n33KYuQQuc5bXkIxF3fSwlc3ouxrrdLWwhu64muYZNQrukkWzhVKRNFIXW7X2iM8JXpi2heIPw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.83.2", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-transform-plugins": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.2.tgz", - "integrity": "sha512-5WlW25WKPkiJk2yA9d8bMuZrgW7vfA4f4MBb9ZeHbTB3eIAoNN8vS8NENgG/X/90vpTB06X66OBvxhT3nHwP6A==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/metro-transform-worker": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.2.tgz", - "integrity": "sha512-G5DsIg+cMZ2KNfrdLnWMvtppb3+Rp1GMyj7Bvd9GgYc/8gRmvq1XVEF9XuO87Shhb03kFhGqMTgZerz3hZ1v4Q==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "metro": "0.83.2", - "metro-babel-transformer": "0.83.2", - "metro-cache": "0.83.2", - "metro-cache-key": "0.83.2", - "metro-minify-terser": "0.83.2", - "metro-source-map": "0.83.2", - "metro-transform-plugins": "0.83.2", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/metro/node_modules/ob1": { - "version": "0.83.2", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.2.tgz", - "integrity": "sha512-XlK3w4M+dwd1g1gvHzVbxiXEbUllRONEgcF2uEO0zm4nxa0eKlh41c6N65q1xbiDOeKKda1tvNOAD33fNjyvCg==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=20.19.4" - } - }, - "node_modules/@expo/osascript": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.3.7.tgz", - "integrity": "sha512-IClSOXxR0YUFxIriUJVqyYki7lLMIHrrzOaP01yxAL1G8pj2DWV5eW1y5jSzIcIfSCNhtGsshGd1tU/AYup5iQ==", - "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.7.2", - "exec-async": "^2.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@expo/package-manager": { - "version": "1.9.8", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.9.8.tgz", - "integrity": "sha512-4/I6OWquKXYnzo38pkISHCOCOXxfeEmu4uDoERq1Ei/9Ur/s9y3kLbAamEkitUkDC7gHk1INxRWEfFNzGbmOrA==", - "license": "MIT", - "dependencies": { - "@expo/json-file": "^10.0.7", - "@expo/spawn-async": "^1.7.2", - "chalk": "^4.0.0", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "resolve-workspace-root": "^2.0.0" - } - }, - "node_modules/@expo/plist": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.7.tgz", - "integrity": "sha512-dGxqHPvCZKeRKDU1sJZMmuyVtcASuSYh1LPFVaM1DuffqPL36n6FMEL0iUqq2Tx3xhWk8wCnWl34IKplUjJDdA==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", - "xmlbuilder": "^15.1.1" + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.2.3", + "xmlbuilder": "^15.1.1" } }, "node_modules/@expo/prebuild-config": { @@ -2427,6 +2219,15 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -2441,9 +2242,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -2601,15 +2402,25 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -2630,41 +2441,551 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", - "optional": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, "engines": { "node": ">=14" } }, - "node_modules/@react-native-async-storage/async-storage": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", - "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "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-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "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-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "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-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "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-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "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-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@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-slot": { + "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" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "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", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", "dependencies": { - "merge-options": "^3.0.4" + "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { - "react-native": "^0.0.0-0 || >=0.65 <1.0" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@react-native/assets-registry": { @@ -2918,17 +3239,41 @@ "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.4.4", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.4.4.tgz", - "integrity": "sha512-/YEBu/cZUgYAaNoSfUnqoRjpbt8NOsb5YvDiKVyTcOOAF1GTbUw6kRi+AGW1Sm16CqzabO/TF2RvN1RmPS9VHg==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.8.7.tgz", + "integrity": "sha512-OKdUCJ/nA6CPOO3ruxZTKphH8U9b3zr21ibrsiqM3Sr72tJ5fAPNbI+3zh2mENVRnRxQbUNHh016ruJ65nl0JQ==", "license": "MIT", "dependencies": { - "@react-navigation/elements": "^2.6.1", - "color": "^4.2.3" + "@react-navigation/elements": "^2.8.4", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { - "@react-navigation/native": "^7.1.16", + "@react-navigation/native": "^7.1.22", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", @@ -2954,12 +3299,6 @@ "react": ">= 18.2.0" } }, - "node_modules/@react-navigation/core/node_modules/react-is": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", - "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", - "license": "MIT" - }, "node_modules/@react-navigation/elements": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.8.4.tgz", @@ -3002,16 +3341,18 @@ } }, "node_modules/@react-navigation/native-stack": { - "version": "7.3.23", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.3.23.tgz", - "integrity": "sha512-WQBBnPrlM0vXj5YAFnJTyrkiCyANl2KnBV8ZmUG61HkqXFwuBbnHij6eoggXH1VZkEVRxW8k0E3qqfPtEZfUjQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.8.1.tgz", + "integrity": "sha512-76dqsWJiDzw+H6ZZJXNS32j9hYjm+J+bkV+vtribaWv5Ky0VUX1K0jGT7Z4EKiHqS7dVsqGHTnUXwwqA/xj1gg==", "license": "MIT", "dependencies": { - "@react-navigation/elements": "^2.6.1", + "@react-navigation/elements": "^2.8.4", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { - "@react-navigation/native": "^7.1.16", + "@react-navigation/native": "^7.1.22", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", @@ -3084,12 +3425,12 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/graceful-fs": { @@ -3126,12 +3467,23 @@ } }, "node_modules/@types/node": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", - "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", + "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", + "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { - "undici-types": "~7.8.0" + "csstype": "^3.0.2" } }, "node_modules/@types/stack-utils": { @@ -3141,9 +3493,9 @@ "license": "MIT" }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -3239,6 +3591,22 @@ "node": ">= 14" } }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/anser": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", @@ -3339,6 +3707,24 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "license": "MIT" + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -3351,23 +3737,6 @@ "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/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -3493,9 +3862,9 @@ } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.1.tgz", - "integrity": "sha512-23fWKohMTvS5s0wwJKycOe0dBdCwQ6+iiLaNR9zy8P13mtFRFM9qLLX6HJX5DL2pi/FNDf3fCQHM4FIMoHH/7w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -3650,6 +4019,24 @@ "node": ">=0.6" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "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", @@ -3660,9 +4047,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" @@ -3774,26 +4161,25 @@ "node": ">= 0.8" } }, - "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", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 6" } }, "node_modules/caniuse-lite": { @@ -3832,6 +4218,42 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -3912,6 +4334,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3967,6 +4395,15 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -4008,18 +4445,6 @@ "simple-swizzle": "^0.2.2" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -4029,6 +4454,20 @@ "node": ">= 10" } }, + "node_modules/comment-json": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.4.1.tgz", + "integrity": "sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==", + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4138,10 +4577,17 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cross-fetch": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", "dependencies": { "node-fetch": "^2.7.0" } @@ -4173,14 +4619,84 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "license": "MIT", "dependencies": { "hyphenate-style-name": "^1.0.3" } }, + "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", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4242,15 +4758,6 @@ "node": ">=8" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4270,13 +4777,86 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "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": { @@ -4306,20 +4886,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4333,9 +4899,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.261", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.261.tgz", - "integrity": "sha512-cmyHEWFqEt3ICUNF93ShneOF47DHoSDbLb7E/AonsWcbzg95N+kPXeLNfkdzgTT/vEUcoW76fxbLBkeYtfoM8A==", + "version": "1.5.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", + "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -4353,6 +4919,18 @@ "node": ">= 0.8" } }, + "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", @@ -4371,51 +4949,6 @@ "stackframe": "^1.3.4" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4548,11 +5081,37 @@ "react-native": "*" } }, + "node_modules/expo-build-properties": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-1.0.9.tgz", + "integrity": "sha512-2icttCy3OPTk/GWIFt+vwA+0hup53jnmYb7JKRbvNvrrOrz+WblzpeoiaOleI2dYG/vjwpNO8to8qVyKhYJtrQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "semver": "^7.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-build-properties/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/expo-constants": { "version": "18.0.10", "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.10.tgz", "integrity": "sha512-Rhtv+X974k0Cahmvx6p7ER5+pNhBC0XbP1lRviL2J1Xl4sT2FBaIuIxF/0I0CbhOsySf0ksqc5caFweAy9Ewiw==", "license": "MIT", + "peer": true, "dependencies": { "@expo/config": "~12.0.10", "@expo/env": "~2.0.7" @@ -4587,27 +5146,6 @@ "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.8", - "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-17.0.8.tgz", - "integrity": "sha512-489ByhVs2XPoAu9zodivAKLv7hG4S/FOe8hO/C2U6jVxmRjpAKakKNjMml0IwWjf1+c/RYBqm1XxKaZ+vq/fDQ==", - "license": "MIT", - "dependencies": { - "expo-image-loader": "~6.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, "node_modules/expo-keep-awake": { "version": "15.0.7", "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.7.tgz", @@ -4618,6 +5156,21 @@ "react": "*" } }, + "node_modules/expo-linking": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.9.tgz", + "integrity": "sha512-a0UHhlVyfwIbn8b1PSFPoFiIDJeps2iEq109hVH3CHd0CMKuRxFfNio9Axe2BjXhiJCYWR4OV1iIyzY/GjiVkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "expo-constants": "~18.0.10", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-modules-autolinking": { "version": "3.0.22", "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.22.tgz", @@ -4647,120 +5200,81 @@ "react-native": "*" } }, - "node_modules/expo-server": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.4.tgz", - "integrity": "sha512-IN06r3oPxFh3plSXdvBL7dx0x6k+0/g0bgxJlNISs6qL5Z+gyPuWS750dpTzOeu37KyBG0RcyO9cXUKzjYgd4A==", - "license": "MIT", - "engines": { - "node": ">=20.16.0" - } - }, - "node_modules/expo-status-bar": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-3.0.8.tgz", - "integrity": "sha512-L248XKPhum7tvREoS1VfE0H6dPCaGtoUWzRsUv7hGKdiB4cus33Rc0sxkWkoQ77wE8stlnUlL5lvmT0oqZ3ZBw==", - "license": "MIT", - "dependencies": { - "react-native-is-edge-to-edge": "^1.2.1" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/@expo/cli": { - "version": "54.0.16", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.16.tgz", - "integrity": "sha512-hY/OdRaJMs5WsVPuVSZ+RLH3VObJmL/pv5CGCHEZHN2PxZjSZSdctyKV8UcFBXTF0yIKNAJ9XLs1dlNYXHh4Cw==", + "node_modules/expo-router": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.15.tgz", + "integrity": "sha512-PAettvLifQzb6hibCmBqxbR9UljlH61GvDRLyarGxs/tG9OpMXCoZHZo8gGCO24K1/6cchBKBcjvQ0PRrKwPew==", "license": "MIT", "dependencies": { - "@0no-co/graphql.web": "^1.0.8", - "@expo/code-signing-certificates": "^0.0.5", - "@expo/config": "~12.0.10", - "@expo/config-plugins": "~54.0.2", - "@expo/devcert": "^1.1.2", - "@expo/env": "~2.0.7", - "@expo/image-utils": "^0.8.7", - "@expo/json-file": "^10.0.7", - "@expo/mcp-tunnel": "~0.1.0", - "@expo/metro": "~54.1.0", - "@expo/metro-config": "~54.0.9", - "@expo/osascript": "^2.3.7", - "@expo/package-manager": "^1.9.8", - "@expo/plist": "^0.4.7", - "@expo/prebuild-config": "^54.0.6", + "@expo/metro-runtime": "^6.1.2", "@expo/schema-utils": "^0.1.7", - "@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", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-tabs": "^1.1.12", + "@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", - "env-editor": "^0.4.1", + "escape-string-regexp": "^4.0.0", "expo-server": "^1.0.4", - "freeport-async": "^2.0.0", - "getenv": "^2.0.0", - "glob": "^10.4.2", - "lan-network": "^0.1.6", - "minimatch": "^9.0.0", - "node-forge": "^1.3.1", - "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.4.3", - "terminal-link": "^2.1.1", - "undici": "^6.18.2", - "wrap-ansi": "^7.0.0", - "ws": "^8.12.1" - }, - "bin": { - "expo-internal": "build/bin/cli" + "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.1.6", + "semver": "~7.6.3", + "server-only": "^0.0.1", + "sf-symbols-typescript": "^2.1.0", + "shallowequal": "^1.1.0", + "use-latest-callback": "^0.2.1", + "vaul": "^1.1.2" }, "peerDependencies": { + "@expo/metro-runtime": "^6.1.2", + "@react-navigation/drawer": "^7.5.0", + "@testing-library/react-native": ">= 12.0.0", "expo": "*", - "expo-router": "*", - "react-native": "*" + "expo-constants": "^18.0.10", + "expo-linking": "^8.0.9", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-gesture-handler": "*", + "react-native-reanimated": "*", + "react-native-safe-area-context": ">= 5.4.0", + "react-native-screens": "*", + "react-native-web": "*", + "react-server-dom-webpack": ">= 19.0.0" }, "peerDependenciesMeta": { - "expo-router": { + "@react-navigation/drawer": { "optional": true }, - "react-native": { + "@testing-library/react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-gesture-handler": { + "optional": true + }, + "react-native-reanimated": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-server-dom-webpack": { "optional": true } } }, - "node_modules/expo/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/expo-router/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4769,23 +5283,56 @@ "node": ">=10" } }, - "node_modules/expo/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/expo-server": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.4.tgz", + "integrity": "sha512-IN06r3oPxFh3plSXdvBL7dx0x6k+0/g0bgxJlNISs6qL5Z+gyPuWS750dpTzOeu37KyBG0RcyO9cXUKzjYgd4A==", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=20.16.0" + } + }, + "node_modules/expo-splash-screen": { + "version": "31.0.11", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-31.0.11.tgz", + "integrity": "sha512-D7MQflYn/PAN3+fACSyxHO4oxZMBezllbgFdVY8roAS1gXpCy8SS6LrGHTD0VpOPEp3X4Gn7evTnXSI9nFoI5Q==", + "license": "MIT", + "dependencies": { + "@expo/prebuild-config": "^54.0.6" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "expo": "*" + } + }, + "node_modules/expo-status-bar": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-3.0.8.tgz", + "integrity": "sha512-L248XKPhum7tvREoS1VfE0H6dPCaGtoUWzRsUv7hGKdiB4cus33Rc0sxkWkoQ77wE8stlnUlL5lvmT0oqZ3ZBw==", + "license": "MIT", + "dependencies": { + "react-native-is-edge-to-edge": "^1.2.1" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-system-ui": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-6.0.8.tgz", + "integrity": "sha512-DzJYqG2fibBSLzPDL4BybGCiilYOtnI1OWhcYFwoM4k0pnEzMBt1Vj8Z67bXglDDuz2HCQPGNtB3tQft5saKqQ==", + "license": "MIT", + "dependencies": { + "@react-native/normalize-colors": "0.81.5", + "debug": "^4.3.2" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { "optional": true } } @@ -4802,12 +5349,65 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -4821,6 +5421,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "license": "MIT", "dependencies": { "cross-fetch": "^3.1.5", "fbjs-css-vars": "^1.0.0", @@ -4834,12 +5435,14 @@ "node_modules/fbjs-css-vars": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "license": "MIT" }, "node_modules/fbjs/node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "license": "MIT", "dependencies": { "asap": "~2.0.3" } @@ -4920,26 +5523,6 @@ "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", "license": "MIT" }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/fontfaceobserver": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", @@ -4962,22 +5545,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/freeport-async": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", @@ -5043,28 +5610,13 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, "node_modules/get-package-type": { @@ -5076,19 +5628,6 @@ "node": ">=8.0.0" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/getenv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", @@ -5118,6 +5657,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", @@ -5130,18 +5681,6 @@ "node": ">=4" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -5157,33 +5696,6 @@ "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5211,21 +5723,6 @@ "hermes-estree": "0.29.1" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, "node_modules/hosted-git-info": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", @@ -5285,7 +5782,8 @@ "node_modules/hyphenate-style-name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", - "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==" + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" }, "node_modules/ieee754": { "version": "1.2.1", @@ -5367,6 +5865,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==", + "license": "MIT", "dependencies": { "css-in-js-utils": "^3.1.0" } @@ -5380,6 +5879,24 @@ "loose-envify": "^1.0.0" } }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -5410,6 +5927,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5419,6 +5945,18 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5428,14 +5966,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -5634,18 +6164,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-worker": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", @@ -5682,6 +6200,16 @@ "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==", "license": "MIT" }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "peer": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5718,6 +6246,12 @@ "node": ">=6" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6031,6 +6565,18 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6168,6 +6714,17 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react-native": { + "version": "0.475.0", + "resolved": "https://registry.npmjs.org/lucide-react-native/-/lucide-react-native-0.475.0.tgz", + "integrity": "sha512-V5tho5qQ89GD4qdzL07ZyXdrnpXZFLirGfaG6BB2vKhO6X1iA7UYYqntgBQ//ZuTUEdevskl+dVT5O4A9oOJUg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0", + "react-native": "*", + "react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -6183,14 +6740,11 @@ "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", "license": "Apache-2.0" }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "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", @@ -6198,27 +6752,25 @@ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", "license": "MIT" }, - "node_modules/merge-options": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", - "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", - "dependencies": { - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "license": "MIT" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/metro": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", - "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.2.tgz", + "integrity": "sha512-HQgs9H1FyVbRptNSMy/ImchTTE5vS2MSqLoOo7hbDoBq6hPPZokwJvBMwrYSxdjQZmLXz2JFZtdvS+ZfgTc9yw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", @@ -6242,18 +6794,18 @@ "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-config": "0.83.3", - "metro-core": "0.83.3", - "metro-file-map": "0.83.3", - "metro-resolver": "0.83.3", - "metro-runtime": "0.83.3", - "metro-source-map": "0.83.3", - "metro-symbolicate": "0.83.3", - "metro-transform-plugins": "0.83.3", - "metro-transform-worker": "0.83.3", + "metro-babel-transformer": "0.83.2", + "metro-cache": "0.83.2", + "metro-cache-key": "0.83.2", + "metro-config": "0.83.2", + "metro-core": "0.83.2", + "metro-file-map": "0.83.2", + "metro-resolver": "0.83.2", + "metro-runtime": "0.83.2", + "metro-source-map": "0.83.2", + "metro-symbolicate": "0.83.2", + "metro-transform-plugins": "0.83.2", + "metro-transform-worker": "0.83.2", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", @@ -6270,9 +6822,9 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", - "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.2.tgz", + "integrity": "sha512-rirY1QMFlA1uxH3ZiNauBninwTioOgwChnRdDcbB4tgRZ+bGX9DiXoh9QdpppiaVKXdJsII932OwWXGGV4+Nlw==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -6300,24 +6852,24 @@ } }, "node_modules/metro-cache": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", - "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.2.tgz", + "integrity": "sha512-Z43IodutUZeIS7OTH+yQFjc59QlFJ6s5OvM8p2AP9alr0+F8UKr8ADzFzoGKoHefZSKGa4bJx7MZJLF6GwPDHQ==", "license": "MIT", "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.3" + "metro-core": "0.83.2" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-cache-key": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz", - "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.2.tgz", + "integrity": "sha512-3EMG/GkGKYoTaf5RqguGLSWRqGTwO7NQ0qXKmNBjr0y6qD9s3VBXYlwB+MszGtmOKsqE9q3FPrE5Nd9Ipv7rZw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -6327,18 +6879,18 @@ } }, "node_modules/metro-config": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz", - "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.2.tgz", + "integrity": "sha512-1FjCcdBe3e3D08gSSiU9u3Vtxd7alGH3x/DNFqWDFf5NouX4kLgbVloDDClr1UrLz62c0fHh2Vfr9ecmrOZp+g==", "license": "MIT", "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", - "metro": "0.83.3", - "metro-cache": "0.83.3", - "metro-core": "0.83.3", - "metro-runtime": "0.83.3", + "metro": "0.83.2", + "metro-cache": "0.83.2", + "metro-core": "0.83.2", + "metro-runtime": "0.83.2", "yaml": "^2.6.1" }, "engines": { @@ -6346,23 +6898,23 @@ } }, "node_modules/metro-core": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz", - "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.2.tgz", + "integrity": "sha512-8DRb0O82Br0IW77cNgKMLYWUkx48lWxUkvNUxVISyMkcNwE/9ywf1MYQUE88HaKwSrqne6kFgCSA/UWZoUT0Iw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.3" + "metro-resolver": "0.83.2" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-file-map": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz", - "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.2.tgz", + "integrity": "sha512-cMSWnEqZrp/dzZIEd7DEDdk72PXz6w5NOKriJoDN9p1TDQ5nAYrY2lHi8d6mwbcGLoSlWmpPyny9HZYFfPWcGQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -6380,9 +6932,9 @@ } }, "node_modules/metro-minify-terser": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", - "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.2.tgz", + "integrity": "sha512-zvIxnh7U0JQ7vT4quasKsijId3dOAWgq+ip2jF/8TMrPUqQabGrs04L2dd0haQJ+PA+d4VvK/bPOY8X/vL2PWw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", @@ -6393,9 +6945,9 @@ } }, "node_modules/metro-resolver": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz", - "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.2.tgz", + "integrity": "sha512-Yf5mjyuiRE/Y+KvqfsZxrbHDA15NZxyfg8pIk0qg47LfAJhpMVEX+36e6ZRBq7KVBqy6VDX5Sq55iHGM4xSm7Q==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -6405,9 +6957,9 @@ } }, "node_modules/metro-runtime": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz", - "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.2.tgz", + "integrity": "sha512-nnsPtgRvFbNKwemqs0FuyFDzXLl+ezuFsUXDbX8o0SXOfsOPijqiQrf3kuafO1Zx1aUWf4NOrKJMAQP5EEHg9A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", @@ -6418,9 +6970,9 @@ } }, "node_modules/metro-source-map": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz", - "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.2.tgz", + "integrity": "sha512-5FL/6BSQvshIKjXOennt9upFngq2lFvDakZn5LfauIVq8+L4sxXewIlSTcxAtzbtjAIaXeOSVMtCJ5DdfCt9AA==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.3", @@ -6428,9 +6980,9 @@ "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.83.3", + "metro-symbolicate": "0.83.2", "nullthrows": "^1.1.1", - "ob1": "0.83.3", + "ob1": "0.83.2", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -6438,15 +6990,24 @@ "node": ">=20.19.4" } }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/metro-symbolicate": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", - "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.2.tgz", + "integrity": "sha512-KoU9BLwxxED6n33KYuQQuc5bXkIxF3fSwlc3ouxrrdLWwhu64muYZNQrukkWzhVKRNFIXW7X2iM8JXpi2heIPw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.83.3", + "metro-source-map": "0.83.2", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" @@ -6458,10 +7019,19 @@ "node": ">=20.19.4" } }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/metro-transform-plugins": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", - "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.2.tgz", + "integrity": "sha512-5WlW25WKPkiJk2yA9d8bMuZrgW7vfA4f4MBb9ZeHbTB3eIAoNN8vS8NENgG/X/90vpTB06X66OBvxhT3nHwP6A==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -6476,9 +7046,9 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", - "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.2.tgz", + "integrity": "sha512-G5DsIg+cMZ2KNfrdLnWMvtppb3+Rp1GMyj7Bvd9GgYc/8gRmvq1XVEF9XuO87Shhb03kFhGqMTgZerz3hZ1v4Q==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -6486,13 +7056,13 @@ "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", - "metro": "0.83.3", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-minify-terser": "0.83.3", - "metro-source-map": "0.83.3", - "metro-transform-plugins": "0.83.3", + "metro": "0.83.2", + "metro-babel-transformer": "0.83.2", + "metro-cache": "0.83.2", + "metro-cache-key": "0.83.2", + "metro-minify-terser": "0.83.2", + "metro-source-map": "0.83.2", + "metro-transform-plugins": "0.83.2", "nullthrows": "^1.1.1" }, "engines": { @@ -6520,6 +7090,36 @@ "hermes-estree": "0.32.0" } }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.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", @@ -6679,13 +7279,313 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "MIT", + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nativewind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-4.2.1.tgz", + "integrity": "sha512-10uUB2Dlli3MH3NDL5nMHqJHz1A3e/E6mzjTj6cl7hHECClJ7HpE6v+xZL+GXdbwQSnWE+UWMIMsNz7yOQkAJQ==", + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.5", + "debug": "^4.3.7", + "react-native-css-interop": "0.2.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "tailwindcss": ">3.3.0" + } + }, + "node_modules/nativewind/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/nativewind/node_modules/lightningcss": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz", + "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.27.0", + "lightningcss-darwin-x64": "1.27.0", + "lightningcss-freebsd-x64": "1.27.0", + "lightningcss-linux-arm-gnueabihf": "1.27.0", + "lightningcss-linux-arm64-gnu": "1.27.0", + "lightningcss-linux-arm64-musl": "1.27.0", + "lightningcss-linux-x64-gnu": "1.27.0", + "lightningcss-linux-x64-musl": "1.27.0", + "lightningcss-win32-arm64-msvc": "1.27.0", + "lightningcss-win32-x64-msvc": "1.27.0" + } + }, + "node_modules/nativewind/node_modules/lightningcss-darwin-arm64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz", + "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-darwin-x64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz", + "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-freebsd-x64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz", + "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz", + "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz", + "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz", + "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz", + "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-linux-x64-musl": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz", + "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz", + "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz", + "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nativewind/node_modules/react-native-css-interop": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.2.1.tgz", + "integrity": "sha512-B88f5rIymJXmy1sNC/MhTkb3xxBej1KkuAt7TiT9iM7oXz3RM8Bn+7GUrfR02TvSgKm4cg2XiSuLEKYfKwNsjA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.3.7", + "lightningcss": "~1.27.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": ">=18", + "react-native": "*", + "react-native-reanimated": ">=3.6.2", + "tailwindcss": "~3" + }, + "peerDependenciesMeta": { + "react-native-safe-area-context": { + "optional": true + }, + "react-native-svg": { + "optional": true + } + } + }, + "node_modules/nativewind/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": { - "nanoid": "bin/nanoid.cjs" + "semver": "bin/semver.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=10" } }, "node_modules/negotiator": { @@ -6707,6 +7607,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -6779,6 +7680,18 @@ "node": ">=10" } }, + "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", @@ -6786,9 +7699,9 @@ "license": "MIT" }, "node_modules/ob1": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz", - "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", + "version": "0.83.2", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.2.tgz", + "integrity": "sha512-XlK3w4M+dwd1g1gvHzVbxiXEbUllRONEgcF2uEO0zm4nxa0eKlh41c6N65q1xbiDOeKKda1tvNOAD33fNjyvCg==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -6806,6 +7719,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -7112,6 +8034,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", @@ -7163,6 +8094,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", @@ -7172,10 +8104,133 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" }, "node_modules/pretty-bytes": { "version": "5.6.0", @@ -7215,6 +8270,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/proc-log": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", @@ -7255,12 +8316,6 @@ "node": ">= 6" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7305,6 +8360,26 @@ "inherits": "~2.0.3" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7349,6 +8424,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-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -7362,6 +8458,12 @@ "react": "^19.1.0" } }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, "node_modules/react-freeze": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", @@ -7375,9 +8477,9 @@ } }, "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", "license": "MIT" }, "node_modules/react-native": { @@ -7438,6 +8540,49 @@ } } }, + "node_modules/react-native-css-interop": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.1.22.tgz", + "integrity": "sha512-Mu01e+H9G+fxSWvwtgWlF5MJBJC4VszTCBXopIpeR171lbeBInHb8aHqoqRPxmJpi3xIHryzqKFOJYAdk7PBxg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.3.7", + "lightningcss": "^1.27.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": ">=18", + "react-native": "*", + "react-native-reanimated": ">=3.6.2", + "tailwindcss": "~3" + }, + "peerDependenciesMeta": { + "react-native-safe-area-context": { + "optional": true + }, + "react-native-svg": { + "optional": true + } + } + }, + "node_modules/react-native-css-interop/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-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", @@ -7448,51 +8593,35 @@ "react-native": "*" } }, - "node_modules/react-native-paper": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.14.5.tgz", - "integrity": "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ==", + "node_modules/react-native-reanimated": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.5.tgz", + "integrity": "sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q==", "license": "MIT", - "workspaces": [ - "example", - "docs" - ], + "peer": true, "dependencies": { - "@callstack/react-theme-provider": "^3.0.9", - "color": "^3.1.2", - "use-latest-callback": "^0.2.3" + "react-native-is-edge-to-edge": "^1.2.1", + "semver": "7.7.2" }, "peerDependencies": { + "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*", - "react-native-safe-area-context": "*" - } - }, - "node_modules/react-native-paper/node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" + "react-native-worklets": ">=0.5.0" } }, - "node_modules/react-native-paper/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/react-native-reanimated/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/react-native-paper/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/react-native-safe-area-context": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz", @@ -7520,11 +8649,28 @@ "react-native": "*" } }, + "node_modules/react-native-svg": { + "version": "15.12.1", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.1.tgz", + "integrity": "sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-web": { "version": "0.21.2", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz", "integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-colors": "^0.74.1", @@ -7543,34 +8689,49 @@ "node_modules/react-native-web/node_modules/@react-native/normalize-colors": { "version": "0.74.89", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz", - "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==" + "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==", + "license": "MIT" }, "node_modules/react-native-web/node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, - "node_modules/react-native/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" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/react-native-worklets": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.6.1.tgz", + "integrity": "sha512-URca8l7c7Uog7gv4mcg9KILdJlnbvwdS5yfXQYf5TDkD2W1VY1sduEKrD+sA3lUPXH/TG1vmXAvNxCNwPMYgGg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-class-properties": "^7.0.0-0", + "@babel/plugin-transform-classes": "^7.0.0-0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-transform-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "@babel/plugin-transform-unicode-regex": "^7.0.0-0", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "semver": "7.7.2" }, "peerDependencies": { - "@types/react": "^19.1.0", + "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" + } + }, + "node_modules/react-native-worklets/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": ">=10" } }, "node_modules/react-native/node_modules/brace-expansion": { @@ -7626,9 +8787,9 @@ } }, "node_modules/react-native/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "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" @@ -7656,6 +8817,108 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -7830,6 +9093,16 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -7889,6 +9162,29 @@ "node": "*" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -8101,10 +9397,17 @@ "node": ">= 0.8" } }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -8112,6 +9415,21 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/sf-symbols-typescript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.1.0.tgz", + "integrity": "sha512-ezT7gu/SHTPIOEEoG6TF+O0m5eewl0ZDAO4AtdBi5HjsrUI6JdCG17+Q8+aKp0heM06wZKApRCn5olNbs0Wb/A==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8168,21 +9486,27 @@ "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.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8207,15 +9531,6 @@ "node": ">=8.0.0" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8433,7 +9748,8 @@ "node_modules/styleq": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz", - "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==" + "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==", + "license": "MIT" }, "node_modules/sucrase": { "version": "3.35.0", @@ -8503,6 +9819,54 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tar": { "version": "7.5.2", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", @@ -8691,7 +10055,8 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/ts-interface-checker": { "version": "0.1.13", @@ -8699,6 +10064,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -8717,10 +10088,24 @@ "node": ">=8" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/ua-parser-js": { - "version": "1.0.40", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz", - "integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==", + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", + "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==", "funding": [ { "type": "opencollective", @@ -8735,6 +10120,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "bin": { "ua-parser-js": "script/cli.js" }, @@ -8752,9 +10138,9 @@ } }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -8848,24 +10234,73 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-latest-callback": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.4.tgz", - "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", + "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", "license": "MIT", "peerDependencies": { "react": ">=16.8" } }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", - "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -8902,6 +10337,19 @@ "node": ">= 0.8" } }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", @@ -8933,13 +10381,10 @@ } }, "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" - } + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/whatwg-fetch": { "version": "3.6.20", @@ -8951,6 +10396,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8970,10 +10416,14 @@ "node": ">=10" } }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "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", @@ -9121,16 +10571,16 @@ "license": "ISC" }, "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.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "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": { diff --git a/mobile/package.json b/mobile/package.json index c3b85321..eeea72c1 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -1,7 +1,7 @@ { "name": "mobile", "version": "1.0.0", - "main": "index.js", + "main": "expo-router/entry", "scripts": { "start": "expo start", "android": "expo start --android", @@ -9,25 +9,40 @@ "web": "expo start --web" }, "dependencies": { - "@expo/metro-runtime": "~6.1.2", - "@react-native-async-storage/async-storage": "^2.1.2", - "@react-navigation/bottom-tabs": "^7.4.4", - "@react-navigation/native": "^7.1.16", - "@react-navigation/native-stack": "^7.3.23", - "axios": "^1.11.0", - "expo": "^54.0.25", - "expo-image-picker": "~17.0.8", + "@expo-google-fonts/inter": "^0.2.3", + "@expo-google-fonts/space-grotesk": "^0.2.3", + "clsx": "^2.1.1", + "expo": "~54.0.25", + "expo-build-properties": "^1.0.9", + "expo-constants": "~18.0.10", + "expo-linking": "~8.0.9", + "expo-router": "~6.0.15", + "expo-splash-screen": "^31.0.11", "expo-status-bar": "~3.0.8", + "expo-system-ui": "~6.0.8", + "lucide-react-native": "^0.475.0", + "nativewind": "^4.1.23", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.5", - "react-native-paper": "^5.14.5", - "react-native-safe-area-context": "^5.4.0", - "react-native-screens": "^4.11.1", - "react-native-web": "^0.21.0" + "react-native-css-interop": "^0.1.22", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-svg": "15.12.1", + "react-native-web": "~0.21.0", + "react-native-worklets": "^0.6.1", + "tailwind-merge": "^2.5.2", + "tailwindcss": "^3.4.17" }, "devDependencies": { - "@babel/core": "^7.20.0" + "@babel/core": "^7.20.0", + "@types/react": "~19.1.10", + "typescript": "^5.1.3" + }, + "overrides": { + "react": "19.1.0", + "react-dom": "19.1.0" }, "private": true } diff --git a/mobile/screens/AccountScreen.js b/mobile/screens/AccountScreen.js deleted file mode 100644 index 16ce8392..00000000 --- a/mobile/screens/AccountScreen.js +++ /dev/null @@ -1,87 +0,0 @@ -import { useContext } from "react"; -import { Alert, StyleSheet, View } from "react-native"; -import { Appbar, Avatar, Divider, List, Text } from "react-native-paper"; -import { AuthContext } from "../context/AuthContext"; - -const AccountScreen = ({ navigation }) => { - const { user, logout } = useContext(AuthContext); - - const handleLogout = () => { - logout(); - }; - - const handleComingSoon = () => { - Alert.alert("Coming Soon", "This feature is not yet implemented."); - }; - - return ( - - - - - - - {user?.imageUrl && /^(https?:|data:image)/.test(user.imageUrl) ? ( - - ) : ( - - )} - - {user?.name} - - - {user?.email} - - - - - } - onPress={() => navigation.navigate("EditProfile")} - /> - - } - onPress={handleComingSoon} - /> - - } - onPress={handleComingSoon} - /> - - } - onPress={handleLogout} - /> - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - content: { - padding: 16, - }, - profileSection: { - alignItems: "center", - marginBottom: 24, - }, - name: { - marginTop: 16, - }, - email: { - marginTop: 4, - color: "gray", - }, -}); - -export default AccountScreen; diff --git a/mobile/screens/AddExpenseScreen.js b/mobile/screens/AddExpenseScreen.js deleted file mode 100644 index 59cb65ed..00000000 --- a/mobile/screens/AddExpenseScreen.js +++ /dev/null @@ -1,494 +0,0 @@ -import { useContext, useEffect, useState } from "react"; -import { - Alert, - KeyboardAvoidingView, - Platform, - StyleSheet, - View, -} from "react-native"; -import { - ActivityIndicator, - Button, - Checkbox, - Menu, - Paragraph, - SegmentedButtons, - Text, - TextInput, - Title, -} from "react-native-paper"; -import { createExpense, getGroupMembers } from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; - -const AddExpenseScreen = ({ route, navigation }) => { - const { groupId } = route.params; - const { token, user } = useContext(AuthContext); - const [description, setDescription] = useState(""); - const [amount, setAmount] = useState(""); - const [members, setMembers] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [isSubmitting, setIsSubmitting] = useState(false); - const [splitMethod, setSplitMethod] = useState("equal"); - const [payerId, setPayerId] = useState(null); // Initialize as null until members are loaded - const [menuVisible, setMenuVisible] = useState(false); - - // State for different split methods - const [percentages, setPercentages] = useState({}); - const [shares, setShares] = useState({}); - const [exactAmounts, setExactAmounts] = useState({}); - const [selectedMembers, setSelectedMembers] = useState({}); // For equal split - - useEffect(() => { - const fetchMembers = async () => { - try { - const response = await getGroupMembers(groupId); - setMembers(response.data); - // Initialize split states - const initialShares = {}; - const initialPercentages = {}; - const initialExactAmounts = {}; - const initialSelectedMembers = {}; - const numMembers = response.data.length; - - // Calculate percentages using integer math to avoid floating-point errors - const basePercentage = Math.floor(100 / numMembers); - const remainder = 100 - basePercentage * numMembers; - - response.data.forEach((member, index) => { - initialShares[member.userId] = "1"; - - // Distribute percentages using integer math - let memberPercentage = basePercentage; - // Distribute remainder to first members (could also be last, but first is simpler) - if (index < remainder) { - memberPercentage += 1; - } - initialPercentages[member.userId] = memberPercentage.toString(); - - initialExactAmounts[member.userId] = "0.00"; - initialSelectedMembers[member.userId] = true; // Select all by default - }); - setShares(initialShares); - setPercentages(initialPercentages); - setExactAmounts(initialExactAmounts); - setSelectedMembers(initialSelectedMembers); - - // Set default payer to current user if they're a member - const currentUserMember = response.data.find( - (member) => member.userId === user._id - ); - if (currentUserMember) { - setPayerId(user._id); - } else if (response.data.length > 0) { - setPayerId(response.data[0].userId); - } - } catch (error) { - console.error("Failed to fetch members:", error); - Alert.alert("Error", "Failed to fetch group members."); - } finally { - setIsLoading(false); - } - }; - if (token && groupId) { - fetchMembers(); - } - }, [token, groupId]); - - const handleAddExpense = async () => { - if (!description || !amount) { - Alert.alert("Error", "Please fill in all fields."); - return; - } - if (!payerId) { - Alert.alert("Error", "Please select who paid for this expense."); - return; - } - const numericAmount = parseFloat(amount); - if (isNaN(numericAmount) || numericAmount <= 0) { - Alert.alert("Error", "Please enter a valid amount."); - return; - } - - setIsSubmitting(true); - let expenseData; - - try { - let splits = []; - let splitType = splitMethod; - - if (splitMethod === "equal") { - const includedMembers = Object.keys(selectedMembers).filter( - (userId) => selectedMembers[userId] - ); - if (includedMembers.length === 0) { - throw new Error("You must select at least one member for the split."); - } - const splitAmount = - Math.round((numericAmount / includedMembers.length) * 100) / 100; - // Calculate remainder to handle rounding - const totalSplitAmount = splitAmount * includedMembers.length; - const remainder = - Math.round((numericAmount - totalSplitAmount) * 100) / 100; - - splits = includedMembers.map((userId, index) => ({ - userId, - amount: index === 0 ? splitAmount + remainder : splitAmount, // Add remainder to first member - type: "equal", - })); - splitType = "equal"; - } else if (splitMethod === "exact") { - const total = Object.values(exactAmounts).reduce( - (sum, val) => sum + parseFloat(val || "0"), - 0 - ); - if (Math.abs(total - numericAmount) > 0.01) { - throw new Error( - `The exact amounts must add up to ${numericAmount.toFixed( - 2 - )}. Current total: ${total.toFixed(2)}` - ); - } - splits = Object.entries(exactAmounts) - .filter(([userId, value]) => parseFloat(value || "0") > 0) - .map(([userId, value]) => ({ - userId, - amount: Math.round(parseFloat(value) * 100) / 100, - type: "unequal", - })); - splitType = "unequal"; // Backend uses 'unequal' for exact amounts - } else if (splitMethod === "percentage") { - const total = Object.values(percentages).reduce( - (sum, val) => sum + parseFloat(val || "0"), - 0 - ); - if (Math.abs(total - 100) > 0.01) { - throw new Error( - `Percentages must add up to 100%. Current total: ${total.toFixed( - 2 - )}%` - ); - } - splits = Object.entries(percentages) - .filter(([userId, value]) => parseFloat(value || "0") > 0) - .map(([userId, value]) => ({ - userId, - amount: - Math.round(numericAmount * (parseFloat(value) / 100) * 100) / 100, - type: "percentage", - })); - splitType = "percentage"; - } else if (splitMethod === "shares") { - const nonZeroShares = Object.entries(shares).filter( - ([userId, value]) => parseInt(value || "0", 10) > 0 - ); - const totalShares = nonZeroShares.reduce( - (sum, [, value]) => sum + parseInt(value || "0", 10), - 0 - ); - - if (totalShares === 0) { - throw new Error("Total shares cannot be zero."); - } - - // Calculate amounts with proper rounding - const amounts = nonZeroShares.map(([userId, value]) => { - const shareRatio = parseInt(value, 10) / totalShares; - return { - userId, - amount: Math.round(numericAmount * shareRatio * 100) / 100, - type: "unequal", - }; - }); - - // Adjust for rounding errors - const totalCalculated = amounts.reduce( - (sum, item) => sum + item.amount, - 0 - ); - const difference = - Math.round((numericAmount - totalCalculated) * 100) / 100; - - if (Math.abs(difference) > 0) { - amounts[0].amount = - Math.round((amounts[0].amount + difference) * 100) / 100; - } - - splits = amounts; - splitType = "unequal"; // Backend uses 'unequal' for shares - } - - expenseData = { - description, - amount: numericAmount, - paidBy: payerId, // Use the selected payer - splitType, - splits, - tags: [], - }; - - await createExpense(groupId, expenseData); - Alert.alert("Success", "Expense added successfully."); - navigation.goBack(); - } catch (error) { - Alert.alert("Error", error.message || "Failed to create expense."); - } finally { - setIsSubmitting(false); - } - }; - - const handleMemberSelect = (userId) => { - setSelectedMembers((prev) => ({ ...prev, [userId]: !prev[userId] })); - }; - - // Helper function to auto-balance percentages - const balancePercentages = (updatedPercentages) => { - const total = Object.values(updatedPercentages).reduce( - (sum, val) => sum + parseFloat(val || "0"), - 0 - ); - const memberIds = Object.keys(updatedPercentages); - - if (total !== 100 && memberIds.length > 1) { - // Find the last non-zero percentage to adjust - const lastMemberId = memberIds[memberIds.length - 1]; - const otherTotal = Object.entries(updatedPercentages) - .filter(([id]) => id !== lastMemberId) - .reduce((sum, [, val]) => sum + parseFloat(val || "0"), 0); - - const newValue = Math.max(0, 100 - otherTotal); - updatedPercentages[lastMemberId] = newValue.toFixed(2); - } - - return updatedPercentages; - }; - - const renderSplitInputs = () => { - const handleSplitChange = (setter, userId, value) => { - if (setter === setPercentages) { - // Auto-balance percentages when one changes - const updatedPercentages = { ...percentages, [userId]: value }; - const balanced = balancePercentages(updatedPercentages); - setter(balanced); - } else { - setter((prev) => ({ ...prev, [userId]: value })); - } - }; - - switch (splitMethod) { - case "equal": - return members.map((member) => ( - handleMemberSelect(member.userId)} - /> - )); - case "exact": - return members.map((member) => ( - - handleSplitChange(setExactAmounts, member.userId, text) - } - keyboardType="numeric" - style={styles.splitInput} - /> - )); - case "percentage": - return members.map((member) => ( - - handleSplitChange(setPercentages, member.userId, text) - } - keyboardType="numeric" - style={styles.splitInput} - /> - )); - case "shares": - return members.map((member) => ( - - handleSplitChange(setShares, member.userId, text) - } - keyboardType="numeric" - style={styles.splitInput} - /> - )); - default: - return null; - } - }; - - if (isLoading) { - return ( - - - - ); - } - - const selectedPayerName = payerId - ? members.find((m) => m.userId === payerId)?.user.name || "Select Payer" - : "Select Payer"; - - return ( - - - - - - setMenuVisible(false)} - anchor={ - - } - > - {members.map((member) => ( - { - setPayerId(member.userId); - setMenuVisible(false); - }} - title={member.user.name} - /> - ))} - - - Split Method - - - {splitMethod === "equal" && ( - - Select members to split the expense equally among them. - - )} - {splitMethod === "exact" && ( - - Enter exact amounts for each member. Total must equal $ - {amount || "0"}. - {amount && ( - - {" "} - Current total: $ - {Object.values(exactAmounts) - .reduce((sum, val) => sum + parseFloat(val || "0"), 0) - .toFixed(2)} - - )} - - )} - {splitMethod === "percentage" && ( - - Enter percentages for each member. Total must equal 100%. - - {" "} - Current total:{" "} - {Object.values(percentages) - .reduce((sum, val) => sum + parseFloat(val || "0"), 0) - .toFixed(2)} - % - - - )} - {splitMethod === "shares" && ( - - Enter shares for each member. Higher shares = larger portion of the - expense. - - )} - - {renderSplitInputs()} - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - content: { - flex: 1, - padding: 16, - paddingBottom: 32, - }, - loaderContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - input: { - marginBottom: 16, - }, - button: { - marginTop: 24, - }, - splitTitle: { - marginTop: 16, - marginBottom: 8, - }, - splitInputsContainer: { - marginTop: 8, - }, - splitInput: { - marginBottom: 8, - }, - helperText: { - fontSize: 12, - marginBottom: 8, - opacity: 0.7, - }, - totalText: { - fontWeight: "bold", - opacity: 1, - }, -}); - -export default AddExpenseScreen; diff --git a/mobile/screens/EditProfileScreen.js b/mobile/screens/EditProfileScreen.js deleted file mode 100644 index 8201b708..00000000 --- a/mobile/screens/EditProfileScreen.js +++ /dev/null @@ -1,153 +0,0 @@ -import * as ImagePicker from "expo-image-picker"; -import { useContext, useState } from "react"; -import { Alert, StyleSheet, View } from "react-native"; -import { Appbar, Avatar, Button, TextInput, Title } from "react-native-paper"; -import { updateUser } from "../api/auth"; -import { AuthContext } from "../context/AuthContext"; - -const EditProfileScreen = ({ navigation }) => { - const { user, token, updateUserInContext } = useContext(AuthContext); - const [name, setName] = useState(user?.name || ""); - const [pickedImage, setPickedImage] = useState(null); // { uri, base64 } - const [isSubmitting, setIsSubmitting] = useState(false); - - const handleUpdateProfile = async () => { - if (!name) { - Alert.alert("Error", "Name cannot be empty."); - return; - } - setIsSubmitting(true); - try { - const updates = { name }; - - // Add image if picked - if (pickedImage?.base64) { - // Dynamically determine MIME type from picker metadata - const mime = - pickedImage.mimeType && /image\//.test(pickedImage.mimeType) - ? pickedImage.mimeType - : "image/jpeg"; // fallback - updates.imageUrl = `data:${mime};base64,${pickedImage.base64}`; - } - - const response = await updateUser(updates); - updateUserInContext(response.data); - Alert.alert("Success", "Profile updated successfully."); - navigation.goBack(); - } catch (error) { - console.error("Failed to update profile:", error); - Alert.alert("Error", "Failed to update profile."); - } finally { - setIsSubmitting(false); - } - }; - - const pickImage = async () => { - // Ask permissions - const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); - if (status !== "granted") { - Alert.alert( - "Permission required", - "We need media library permission to select an image." - ); - return; - } - const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, - base64: true, - allowsEditing: true, - aspect: [1, 1], - quality: 0.8, - }); - if (!result.canceled && result.assets && result.assets.length > 0) { - const asset = result.assets[0]; - // Capture mimeType (expo-image-picker provides mimeType on iOS/Android SDK 49+) - let mimeType = asset.mimeType || asset.type; // expo sometimes supplies type like 'image' - if (mimeType && !/image\//.test(mimeType)) { - // if it's just 'image', normalize - if (mimeType === 'image') mimeType = 'image/jpeg'; - } - if (!mimeType || !/image\//.test(mimeType)) { - // Attempt to infer from file extension as a lightweight fallback - const ext = (asset.uri || "").split(".").pop()?.toLowerCase(); - if (ext === "png") mimeType = "image/png"; - else if (ext === "webp") mimeType = "image/webp"; - else if (ext === "gif") mimeType = "image/gif"; - else if (ext === "jpg" || ext === "jpeg") mimeType = "image/jpeg"; - else mimeType = "image/jpeg"; // safe default - } - setPickedImage({ uri: asset.uri, base64: asset.base64, mimeType }); - } - }; - - return ( - - - navigation.goBack()} /> - - - - Edit Your Details - - {/* Profile Picture Section */} - - {pickedImage?.uri ? ( - - ) : user?.imageUrl && /^(https?:|data:image)/.test(user.imageUrl) ? ( - - ) : ( - - )} - - - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - content: { - padding: 16, - }, - profilePictureSection: { - alignItems: "center", - marginBottom: 24, - }, - imageButton: { - marginTop: 12, - }, - input: { - marginBottom: 16, - }, - button: { - marginTop: 8, - }, -}); - -export default EditProfileScreen; diff --git a/mobile/screens/FriendsScreen.js b/mobile/screens/FriendsScreen.js deleted file mode 100644 index 0da27955..00000000 --- a/mobile/screens/FriendsScreen.js +++ /dev/null @@ -1,306 +0,0 @@ -import { useIsFocused } from "@react-navigation/native"; -import { useContext, useEffect, useRef, useState } from "react"; -import { Alert, Animated, FlatList, StyleSheet, View } from "react-native"; -import { - Appbar, - Avatar, - Divider, - IconButton, - List, - Text, -} from "react-native-paper"; -import { getFriendsBalance, getGroups } from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; -import { formatCurrency } from "../utils/currency"; - -const FriendsScreen = () => { - const { token, user } = useContext(AuthContext); - const [friends, setFriends] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [showTooltip, setShowTooltip] = useState(true); - const isFocused = useIsFocused(); - - useEffect(() => { - const fetchData = async () => { - setIsLoading(true); - try { - // Fetch friends balance + groups concurrently for group icons - const friendsResponse = await getFriendsBalance(); - const friendsData = friendsResponse.data.friendsBalance || []; - const groupsResponse = await getGroups(); - const groups = groupsResponse?.data?.groups || []; - const groupMeta = new Map( - groups.map((g) => [g._id, { name: g.name, imageUrl: g.imageUrl }]) - ); - - const transformedFriends = friendsData.map((friend) => ({ - id: friend.userId, - name: friend.userName, - imageUrl: friend.userImageUrl || null, - netBalance: friend.netBalance, - groups: (friend.breakdown || []).map((group) => ({ - id: group.groupId, - name: group.groupName, - balance: group.balance, - imageUrl: groupMeta.get(group.groupId)?.imageUrl || null, - })), - })); - - setFriends(transformedFriends); - } catch (error) { - console.error("Failed to fetch friends balance data:", error); - Alert.alert("Error", "Failed to load friends balance data."); - } finally { - setIsLoading(false); - } - }; - - if (token && isFocused) { - fetchData(); - } - }, [token, isFocused]); - - const renderFriend = ({ item }) => { - const balanceColor = item.netBalance < 0 ? "red" : "green"; - const balanceText = - item.netBalance < 0 - ? `You owe ${formatCurrency(Math.abs(item.netBalance))}` - : `Owes you ${formatCurrency(item.netBalance)}`; - - // Determine if we have an image URL or a base64 payload - const hasImage = !!item.imageUrl; - let imageUri = null; - if (hasImage) { - // If it's a raw base64 string without prefix, add a default MIME prefix - if ( - /^data:image/.test(item.imageUrl) || - /^https?:\/\//.test(item.imageUrl) - ) { - imageUri = item.imageUrl; - } else if (/^[A-Za-z0-9+/=]+$/.test(item.imageUrl.substring(0, 50))) { - imageUri = `data:image/jpeg;base64,${item.imageUrl}`; - } - } - - return ( - - imageUri ? ( - - ) : ( - - ) - } - > - {item.groups.map((group) => { - const groupBalanceColor = group.balance < 0 ? "red" : "green"; - const groupBalanceText = - group.balance < 0 - ? `You owe ${formatCurrency(Math.abs(group.balance))}` - : `Owes you ${formatCurrency(group.balance)}`; - // Prepare group icon (imageUrl may be base64 or URL) - let groupImageUri = null; - if (group.imageUrl) { - if ( - /^data:image/.test(group.imageUrl) || - /^https?:\/\//.test(group.imageUrl) - ) { - groupImageUri = group.imageUrl; - } else if ( - /^[A-Za-z0-9+/=]+$/.test(group.imageUrl.substring(0, 50)) - ) { - groupImageUri = `data:image/jpeg;base64,${group.imageUrl}`; - } - } - - return ( - - groupImageUri ? ( - - ) : ( - - ) - } - /> - ); - })} - - ); - }; - - // Shimmer skeleton components - const opacityAnim = useRef(new Animated.Value(0.3)).current; - useEffect(() => { - const loop = Animated.loop( - Animated.sequence([ - Animated.timing(opacityAnim, { - toValue: 1, - duration: 700, - useNativeDriver: true, - }), - Animated.timing(opacityAnim, { - toValue: 0.3, - duration: 700, - useNativeDriver: true, - }), - ]) - ); - loop.start(); - return () => loop.stop(); - }, [opacityAnim]); - - const SkeletonRow = () => ( - - - - - - - - ); - - if (isLoading) { - return ( - - - - - - {Array.from({ length: 5 }).map((_, i) => ( - - ))} - - - ); - } - - return ( - - - - - {showTooltip && ( - - - - 💡 These amounts show your direct balance with each friend across - all shared groups. Check individual group details for optimized - settlement suggestions. - - setShowTooltip(false)} - style={styles.closeButton} - /> - - - )} - item.id} - ItemSeparatorComponent={Divider} - ListEmptyComponent={ - No balances with friends yet. - } - /> - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - loaderContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - explanationContainer: { - backgroundColor: "#f0f8ff", - margin: 8, - borderRadius: 8, - borderLeftWidth: 4, - borderLeftColor: "#2196f3", - }, - explanationContent: { - flexDirection: "row", - alignItems: "flex-start", - padding: 12, - }, - explanationText: { - fontSize: 12, - color: "#555", - lineHeight: 16, - flex: 1, - paddingRight: 8, - }, - closeButton: { - margin: 0, - marginTop: -4, - }, - emptyText: { - textAlign: "center", - marginTop: 20, - }, - skeletonContainer: { - padding: 16, - }, - skeletonRow: { - flexDirection: "row", - alignItems: "center", - marginBottom: 14, - }, - skeletonAvatar: { - width: 48, - height: 48, - borderRadius: 24, - backgroundColor: "#e0e0e0", - }, - skeletonLine: { - height: 14, - backgroundColor: "#e0e0e0", - borderRadius: 6, - marginBottom: 6, - }, - skeletonLineSmall: { - height: 12, - backgroundColor: "#e0e0e0", - borderRadius: 6, - }, -}); - -export default FriendsScreen; diff --git a/mobile/screens/GroupDetailsScreen.js b/mobile/screens/GroupDetailsScreen.js deleted file mode 100644 index a1050b9f..00000000 --- a/mobile/screens/GroupDetailsScreen.js +++ /dev/null @@ -1,315 +0,0 @@ -import { useContext, useEffect, useState } from "react"; -import { Alert, FlatList, StyleSheet, Text, View } from "react-native"; -import { - ActivityIndicator, - Card, - FAB, - IconButton, - Paragraph, - Title, -} from "react-native-paper"; -import { - getGroupExpenses, - getGroupMembers, - getOptimizedSettlements, -} from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; - -const GroupDetailsScreen = ({ route, navigation }) => { - const { groupId, groupName } = route.params; - const { token, user } = useContext(AuthContext); - const [members, setMembers] = useState([]); - const [expenses, setExpenses] = useState([]); - const [settlements, setSettlements] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - // Currency configuration - can be made configurable later - const currency = "₹"; // Default to INR, can be changed to '$' for USD - - // Helper function to format currency amounts - const formatCurrency = (amount) => `${currency}${amount.toFixed(2)}`; - - const fetchData = async () => { - try { - setIsLoading(true); - // Fetch members, expenses, and settlements in parallel - const [membersResponse, expensesResponse, settlementsResponse] = - await Promise.all([ - getGroupMembers(groupId), - getGroupExpenses(groupId), - getOptimizedSettlements(groupId), - ]); - setMembers(membersResponse.data); - setExpenses(expensesResponse.data.expenses); - setSettlements(settlementsResponse.data.optimizedSettlements || []); - } catch (error) { - console.error("Failed to fetch group details:", error); - Alert.alert("Error", "Failed to fetch group details."); - } finally { - setIsLoading(false); - } - }; - - useEffect(() => { - navigation.setOptions({ - title: groupName, - headerRight: () => ( - navigation.navigate("GroupSettings", { groupId })} - /> - ), - }); - if (token && groupId) { - fetchData(); - } - }, [token, groupId]); - - const getMemberName = (userId) => { - const member = members.find((m) => m.userId === userId); - return member ? member.user.name : "Unknown"; - }; - - const renderExpense = ({ item }) => { - const userSplit = item.splits.find((s) => s.userId === user._id); - const userShare = userSplit ? userSplit.amount : 0; - const paidByMe = (item.paidBy || item.createdBy) === user._id; - const net = paidByMe ? item.amount - userShare : -userShare; - - let balanceText; - let balanceColor = "black"; - - if (net > 0) { - balanceText = `You are owed ${formatCurrency(net)}`; - balanceColor = "green"; - } else if (net < 0) { - balanceText = `You borrowed ${formatCurrency(Math.abs(net))}`; - balanceColor = "red"; - } else { - balanceText = "You are settled for this expense."; - } - - return ( - - - {item.description} - Amount: {formatCurrency(item.amount)} - - Paid by: {getMemberName(item.paidBy || item.createdBy)} - - {balanceText} - - - ); - }; - - const renderSettlementSummary = () => { - const userOwes = settlements.filter((s) => s.fromUserId === user._id); - const userIsOwed = settlements.filter((s) => s.toUserId === user._id); - const totalOwed = userOwes.reduce((sum, s) => sum + s.amount, 0); - const totalToReceive = userIsOwed.reduce((sum, s) => sum + s.amount, 0); - - // If user is all settled up - if (userOwes.length === 0 && userIsOwed.length === 0) { - return ( - - ✓ You are all settled up! - - ); - } - - return ( - - {/* You owe section - only show if totalOwed > 0 */} - {totalOwed > 0 && ( - - - You need to pay:{" "} - {formatCurrency(totalOwed)} - - {userOwes.map((s, index) => ( - - - - {getMemberName(s.toUserId)} - - - {formatCurrency(s.amount)} - - - - ))} - - )} - - {/* You receive section - only show if totalToReceive > 0 */} - {totalToReceive > 0 && ( - - - You will receive:{" "} - - {formatCurrency(totalToReceive)} - - - {userIsOwed.map((s, index) => ( - - - - {getMemberName(s.fromUserId)} - - - {formatCurrency(s.amount)} - - - - ))} - - )} - - ); - }; - - if (isLoading) { - return ( - - - - ); - } - - const renderHeader = () => ( - <> - - - Settlement Summary - {renderSettlementSummary()} - - - - Expenses - - ); - - return ( - - item._id} - ListHeaderComponent={renderHeader} - ListEmptyComponent={ - No expenses recorded yet. - } - contentContainerStyle={{ paddingBottom: 80 }} // To avoid FAB overlap - /> - - navigation.navigate("AddExpense", { groupId: groupId })} - /> - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - contentContainer: { - flex: 1, - padding: 16, - }, - loaderContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - card: { - marginBottom: 16, - }, - expensesTitle: { - marginTop: 16, - marginBottom: 8, - fontSize: 20, - fontWeight: "bold", - }, - memberText: { - fontSize: 16, - lineHeight: 24, - }, - fab: { - position: "absolute", - margin: 16, - right: 0, - bottom: 0, - }, - // Settlement Summary Styles - settlementContainer: { - marginBottom: 16, - }, - settledContainer: { - alignItems: "center", - paddingVertical: 12, - }, - settledText: { - fontSize: 16, - color: "#2e7d32", - fontWeight: "500", - }, - owedSection: { - backgroundColor: "#ffebee", - borderRadius: 8, - padding: 12, - borderLeftWidth: 4, - borderLeftColor: "#d32f2f", - }, - receiveSection: { - backgroundColor: "#e8f5e8", - borderRadius: 8, - padding: 12, - borderLeftWidth: 4, - borderLeftColor: "#2e7d32", - }, - sectionTitle: { - fontSize: 16, - fontWeight: "600", - marginBottom: 8, - color: "#333", - }, - amountOwed: { - color: "#d32f2f", - fontWeight: "bold", - }, - amountReceive: { - color: "#2e7d32", - fontWeight: "bold", - }, - settlementItem: { - marginVertical: 4, - }, - personInfo: { - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - paddingVertical: 4, - }, - personName: { - fontSize: 14, - color: "#555", - flex: 1, - }, - settlementAmount: { - fontSize: 14, - fontWeight: "600", - color: "#333", - }, - emptyText: { - fontSize: 14, - color: "#666", - paddingVertical: 8, - }, -}); - -export default GroupDetailsScreen; diff --git a/mobile/screens/GroupSettingsScreen.js b/mobile/screens/GroupSettingsScreen.js deleted file mode 100644 index 90de5d16..00000000 --- a/mobile/screens/GroupSettingsScreen.js +++ /dev/null @@ -1,426 +0,0 @@ -import * as ImagePicker from "expo-image-picker"; -import { - useContext, - useEffect, - useLayoutEffect, - useMemo, - useState, -} from "react"; -import { - Alert, - Image, - ScrollView, - Share, - StyleSheet, - View, -} from "react-native"; -import { - ActivityIndicator, - Avatar, - Button, - Card, - IconButton, - List, - Text, - TextInput, -} from "react-native-paper"; -import { - deleteGroup as apiDeleteGroup, - leaveGroup as apiLeaveGroup, - removeMember as apiRemoveMember, - updateGroup as apiUpdateGroup, - getGroupById, - getGroupMembers, - getOptimizedSettlements, -} from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; - -const ICON_CHOICES = ["👥", "🏠", "🎉", "🧳", "🍽️", "🚗", "🏖️", "🎮", "💼"]; - -const GroupSettingsScreen = ({ route, navigation }) => { - const { groupId } = route.params; - const { token, user } = useContext(AuthContext); - const [loading, setLoading] = useState(true); - const [saving, setSaving] = useState(false); - const [members, setMembers] = useState([]); - const [group, setGroup] = useState(null); - const [name, setName] = useState(""); - const [icon, setIcon] = useState(""); - const [pickedImage, setPickedImage] = useState(null); // { uri, base64 } - - const isAdmin = useMemo(() => { - const me = members.find((m) => m.userId === user?._id); - return me?.role === "admin"; - }, [members, user?._id]); - - const load = async () => { - try { - setLoading(true); - const [gRes, mRes] = await Promise.all([ - getGroupById(groupId), - getGroupMembers(groupId), - ]); - setGroup(gRes.data); - setName(gRes.data.name); - setIcon(gRes.data.imageUrl || gRes.data.icon || ""); - setMembers(mRes.data); - } catch (e) { - console.error("Failed to load group settings", e); - Alert.alert("Error", "Failed to load group settings."); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - if (token && groupId) load(); - }, [token, groupId]); - - useLayoutEffect(() => { - navigation.setOptions({ title: "Group Settings" }); - }, [navigation]); - - const onSave = async () => { - if (!isAdmin) return; - const updates = {}; - if (name && name !== group?.name) updates.name = name; - - // Handle different icon types - if (pickedImage?.base64) { - // If user picked an image, use it as imageUrl - updates.imageUrl = `data:image/jpeg;base64,${pickedImage.base64}`; - } else if (icon && icon !== (group?.imageUrl || group?.icon || "")) { - // If user selected an emoji and it's different from current - // Check if it's an emoji (not a URL) - const isEmoji = ICON_CHOICES.includes(icon); - if (isEmoji) { - updates.imageUrl = icon; // Store emoji as imageUrl for now - } else { - updates.imageUrl = icon; // Store other text/URL as imageUrl - } - } - - if (Object.keys(updates).length === 0) - return Alert.alert("Nothing to update"); - try { - setSaving(true); - const res = await apiUpdateGroup(groupId, updates); - setGroup(res.data); - if (pickedImage) setPickedImage(null); - Alert.alert("Updated", "Group updated successfully."); - } catch (e) { - console.error("Update failed", e); - Alert.alert( - "Error", - e.response?.data?.detail || "Failed to update group" - ); - } finally { - setSaving(false); - } - }; - - const pickImage = async () => { - if (!isAdmin) return; - // Ask permissions - const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); - if (status !== "granted") { - Alert.alert( - "Permission required", - "We need media library permission to select an image." - ); - return; - } - const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, - base64: true, - allowsEditing: true, - aspect: [1, 1], - quality: 0.8, - }); - if (!result.canceled && result.assets && result.assets.length > 0) { - const asset = result.assets[0]; - setPickedImage({ uri: asset.uri, base64: asset.base64 }); - } - }; - - const onShareInvite = async () => { - try { - const code = group?.joinCode; - if (!code) return; - await Share.share({ - message: `Join my group on Splitwiser! Use code ${code}`, - }); - } catch (e) { - console.error("Share failed", e); - } - }; - - const onKick = (memberId, name) => { - if (!isAdmin) return; - if (memberId === user?._id) return; // safeguard - Alert.alert("Remove member", `Are you sure you want to remove ${name}?`, [ - { text: "Cancel", style: "cancel" }, - { - text: "Remove", - style: "destructive", - onPress: async () => { - try { - // Pre-check balances using optimized settlements - const settlementsRes = await getOptimizedSettlements(groupId); - const settlements = - settlementsRes?.data?.optimizedSettlements || []; - const hasUnsettled = settlements.some( - (s) => - (s.fromUserId === memberId || s.toUserId === memberId) && - (s.amount || 0) > 0 - ); - if (hasUnsettled) { - Alert.alert( - "Cannot remove", - "This member has unsettled balances in the group." - ); - return; - } - await apiRemoveMember(groupId, memberId); - await load(); - } catch (e) { - console.error("Remove failed", e); - Alert.alert( - "Error", - e.response?.data?.detail || "Failed to remove member" - ); - } - }, - }, - ]); - }; - - const onLeave = () => { - Alert.alert( - "Leave group", - "You can leave only when your balances are settled. Continue?", - [ - { text: "Cancel", style: "cancel" }, - { - text: "Leave", - style: "destructive", - onPress: async () => { - try { - await apiLeaveGroup(groupId); - Alert.alert("Left group"); - navigation.popToTop(); - } catch (e) { - console.error("Leave failed", e); - Alert.alert( - "Cannot leave", - e.response?.data?.detail || "Please settle balances first" - ); - } - }, - }, - ] - ); - }; - - const onDeleteGroup = () => { - if (!isAdmin) return; - // Only allow delete if no other members present - const others = members.filter((m) => m.userId !== user?._id); - if (others.length > 0) { - Alert.alert( - "Cannot delete", - "Remove all members first, or transfer admin." - ); - return; - } - Alert.alert( - "Delete group", - "This will permanently delete the group. Continue?", - [ - { text: "Cancel", style: "cancel" }, - { - text: "Delete", - style: "destructive", - onPress: async () => { - try { - await apiDeleteGroup(groupId); - Alert.alert("Group deleted"); - navigation.popToTop(); - } catch (e) { - console.error("Delete failed", e); - Alert.alert( - "Error", - e.response?.data?.detail || "Failed to delete group" - ); - } - }, - }, - ] - ); - }; - - const renderMemberItem = (m) => { - const isSelf = m.userId === user?._id; - const displayName = m.user?.name || "Unknown"; - const imageUrl = m.user?.imageUrl; - return ( - - imageUrl ? ( - - ) : ( - - ) - } - right={() => - isAdmin && !isSelf ? ( - onKick(m.userId, displayName)} - /> - ) : null - } - /> - ); - }; - - if (loading) { - return ( - - - - ); - } - - return ( - - - - - - - Icon - - {ICON_CHOICES.map((i) => ( - - ))} - - - - {pickedImage?.uri ? ( - - ) : group?.imageUrl && - /^(https?:|data:image)/.test(group.imageUrl) ? ( - - ) : group?.imageUrl ? ( - {group.imageUrl} - ) : null} - - {isAdmin && ( - - )} - - - - - - {members.map(renderMemberItem)} - - - - - - - Join Code: {group?.joinCode} - - - - - - - - - - - {isAdmin && ( - - )} - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { flex: 1 }, - scrollContent: { padding: 16 }, - loaderContainer: { flex: 1, justifyContent: "center", alignItems: "center" }, - card: { marginBottom: 16 }, - iconRow: { flexDirection: "row", flexWrap: "wrap", marginBottom: 8 }, - iconBtn: { marginRight: 8, marginBottom: 8 }, -}); - -export default GroupSettingsScreen; diff --git a/mobile/screens/HomeScreen.js b/mobile/screens/HomeScreen.js deleted file mode 100644 index dfb0eadd..00000000 --- a/mobile/screens/HomeScreen.js +++ /dev/null @@ -1,296 +0,0 @@ -import { useContext, useEffect, useState } from "react"; -import { Alert, FlatList, StyleSheet, View } from "react-native"; -import { - ActivityIndicator, - Appbar, - Avatar, - Button, - Card, - Modal, - Portal, - Text, - TextInput, -} from "react-native-paper"; -import { createGroup, getGroups, getOptimizedSettlements } from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; -import { formatCurrency, getCurrencySymbol } from "../utils/currency"; - -const HomeScreen = ({ navigation }) => { - const { token, logout, user } = useContext(AuthContext); - const [groups, setGroups] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [groupSettlements, setGroupSettlements] = useState({}); // Track settlement status for each group - - // State for the Create Group modal - const [modalVisible, setModalVisible] = useState(false); - const [newGroupName, setNewGroupName] = useState(""); - const [isCreatingGroup, setIsCreatingGroup] = useState(false); - - const showModal = () => setModalVisible(true); - const hideModal = () => setModalVisible(false); - - // Calculate settlement status for a group - const calculateSettlementStatus = async (groupId, userId) => { - try { - const response = await getOptimizedSettlements(groupId); - const settlements = response.data.optimizedSettlements || []; - - // Check if user has any pending settlements - const userOwes = settlements.filter((s) => s.fromUserId === userId); - const userIsOwed = settlements.filter((s) => s.toUserId === userId); - - const totalOwed = userOwes.reduce((sum, s) => sum + (s.amount || 0), 0); - const totalToReceive = userIsOwed.reduce( - (sum, s) => sum + (s.amount || 0), - 0 - ); - - return { - isSettled: totalOwed === 0 && totalToReceive === 0, - owesAmount: totalOwed, - owedAmount: totalToReceive, - netBalance: totalToReceive - totalOwed, - }; - } catch (error) { - console.error( - "Failed to fetch settlement status for group:", - groupId, - error - ); - return { - isSettled: true, - owesAmount: 0, - owedAmount: 0, - netBalance: 0, - }; - } - }; - - const fetchGroups = async () => { - try { - setIsLoading(true); - const response = await getGroups(); - const groupsList = response.data.groups; - setGroups(groupsList); - - // Fetch settlement status for each group - if (user?._id) { - const settlementPromises = groupsList.map(async (group) => { - const status = await calculateSettlementStatus(group._id, user._id); - return { groupId: group._id, status }; - }); - - const settlementResults = await Promise.all(settlementPromises); - const settlementMap = {}; - settlementResults.forEach(({ groupId, status }) => { - settlementMap[groupId] = status; - }); - setGroupSettlements(settlementMap); - } - } catch (error) { - console.error("Failed to fetch groups:", error); - Alert.alert("Error", "Failed to fetch groups."); - } finally { - setIsLoading(false); - } - }; - - useEffect(() => { - if (token) { - fetchGroups(); - } - }, [token]); - - const handleCreateGroup = async () => { - if (!newGroupName) { - Alert.alert("Error", "Please enter a group name."); - return; - } - setIsCreatingGroup(true); - try { - await createGroup(newGroupName); - hideModal(); - setNewGroupName(""); - await fetchGroups(); // Refresh the groups list - } catch (error) { - console.error("Failed to create group:", error); - Alert.alert("Error", "Failed to create group."); - } finally { - setIsCreatingGroup(false); - } - }; - - const currencySymbol = getCurrencySymbol(); - - const renderGroup = ({ item }) => { - const settlementStatus = groupSettlements[item._id]; - - // Generate settlement status text - const getSettlementStatusText = () => { - if (!settlementStatus) { - return "Calculating balances..."; - } - - if (settlementStatus.isSettled) { - return "✓ You are settled up."; - } - - if (settlementStatus.netBalance > 0) { - return `You are owed ${formatCurrency(settlementStatus.netBalance)}.`; - } else if (settlementStatus.netBalance < 0) { - return `You owe ${formatCurrency( - Math.abs(settlementStatus.netBalance) - )}.`; - } - - return "You are settled up."; - }; - - // Get text color based on settlement status - const getStatusColor = () => { - if (!settlementStatus || settlementStatus.isSettled) { - return "#4CAF50"; // Green for settled - } - - if (settlementStatus.netBalance > 0) { - return "#4CAF50"; // Green for being owed money - } else if (settlementStatus.netBalance < 0) { - return "#F44336"; // Red for owing money - } - - return "#4CAF50"; // Default green - }; - - const isImage = - item.imageUrl && /^(https?:|data:image)/.test(item.imageUrl); - const groupIcon = item.imageUrl || item.name?.charAt(0) || "?"; - return ( - - navigation.navigate("GroupDetails", { - groupId: item._id, - groupName: item.name, - groupIcon, - }) - } - > - - isImage ? ( - - ) : ( - - ) - } - /> - - - {getSettlementStatusText()} - - - - ); - }; - - return ( - - - - Create a New Group - - - - - - - - - - navigation.navigate("JoinGroup", { onGroupJoined: fetchGroups }) - } - /> - - - {isLoading ? ( - - - - ) : ( - item._id} - contentContainerStyle={styles.list} - ListEmptyComponent={ - - No groups found. Create or join one! - - } - onRefresh={fetchGroups} - refreshing={isLoading} - /> - )} - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - loaderContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - list: { - padding: 16, - }, - card: { - marginBottom: 16, - }, - settlementStatus: { - fontWeight: "500", - marginTop: 4, - }, - emptyText: { - textAlign: "center", - marginTop: 20, - }, - modalContainer: { - backgroundColor: "white", - padding: 20, - margin: 20, - borderRadius: 8, - }, - modalTitle: { - fontSize: 20, - marginBottom: 20, - textAlign: "center", - }, - input: { - marginBottom: 20, - }, -}); - -export default HomeScreen; diff --git a/mobile/screens/JoinGroupScreen.js b/mobile/screens/JoinGroupScreen.js deleted file mode 100644 index 153e4eac..00000000 --- a/mobile/screens/JoinGroupScreen.js +++ /dev/null @@ -1,79 +0,0 @@ -import { useContext, useState } from "react"; -import { Alert, StyleSheet, View } from "react-native"; -import { Appbar, Button, TextInput, Title } from "react-native-paper"; -import { joinGroup } from "../api/groups"; -import { AuthContext } from "../context/AuthContext"; - -const JoinGroupScreen = ({ navigation, route }) => { - const { token } = useContext(AuthContext); - const [joinCode, setJoinCode] = useState(""); - const [isJoining, setIsJoining] = useState(false); - const { onGroupJoined } = route.params; - - const handleJoinGroup = async () => { - if (!joinCode) { - Alert.alert("Error", "Please enter a join code."); - return; - } - setIsJoining(true); - try { - await joinGroup(joinCode); - Alert.alert("Success", "Successfully joined the group."); - onGroupJoined(); // Call the callback to refresh the groups list - navigation.goBack(); - } catch (error) { - console.error("Failed to join group:", error); - Alert.alert( - "Error", - "Failed to join group. Please check the code and try again." - ); - } finally { - setIsJoining(false); - } - }; - - return ( - - - navigation.goBack()} /> - - - - Enter Group Code - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - content: { - padding: 16, - }, - input: { - marginBottom: 16, - }, - button: { - marginTop: 8, - }, -}); - -export default JoinGroupScreen; diff --git a/mobile/screens/LoginScreen.js b/mobile/screens/LoginScreen.js deleted file mode 100644 index 076e9956..00000000 --- a/mobile/screens/LoginScreen.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useState, useContext } from 'react'; -import { View, StyleSheet, Alert } from 'react-native'; -import { Button, Text, TextInput } from 'react-native-paper'; -import { AuthContext } from '../context/AuthContext'; - -const LoginScreen = ({ navigation }) => { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [isLoading, setIsLoading] = useState(false); - const { login } = useContext(AuthContext); - - const handleLogin = async () => { - if (!email || !password) { - Alert.alert('Error', 'Please enter both email and password.'); - return; - } - setIsLoading(true); - const success = await login(email, password); - setIsLoading(false); - if (!success) { - Alert.alert('Login Failed', 'Invalid email or password. Please try again.'); - } - }; - - return ( - - Welcome Back! - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - padding: 16, - }, - title: { - textAlign: 'center', - marginBottom: 24, - }, - input: { - marginBottom: 16, - }, - button: { - marginTop: 8, - }, -}); - -export default LoginScreen; diff --git a/mobile/screens/SignupScreen.js b/mobile/screens/SignupScreen.js deleted file mode 100644 index 5594be60..00000000 --- a/mobile/screens/SignupScreen.js +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useState, useContext } from 'react'; -import { View, StyleSheet, Alert } from 'react-native'; -import { Button, Text, TextInput } from 'react-native-paper'; -import { AuthContext } from '../context/AuthContext'; - -const SignupScreen = ({ navigation }) => { - const [name, setName] = useState(''); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [confirmPassword, setConfirmPassword] = useState(''); - const [isLoading, setIsLoading] = useState(false); - const { signup } = useContext(AuthContext); - - const handleSignup = async () => { - if (!name || !email || !password || !confirmPassword) { - Alert.alert('Error', 'Please fill in all fields.'); - return; - } - if (password !== confirmPassword) { - Alert.alert('Error', "Passwords don't match!"); - return; - } - setIsLoading(true); - const success = await signup(name, email, password); - setIsLoading(false); - if (success) { - Alert.alert( - 'Success', - 'Your account has been created successfully. Please log in.', - [{ text: 'OK', onPress: () => navigation.navigate('Login') }] - ); - } else { - Alert.alert('Signup Failed', 'An error occurred. Please try again.'); - } - }; - - return ( - - Create Account - - - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - padding: 16, - }, - title: { - textAlign: 'center', - marginBottom: 24, - }, - input: { - marginBottom: 16, - }, - button: { - marginTop: 8, - }, -}); - -export default SignupScreen; diff --git a/mobile/tailwind.config.js b/mobile/tailwind.config.js new file mode 100644 index 00000000..f0a21cab --- /dev/null +++ b/mobile/tailwind.config.js @@ -0,0 +1,32 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + // NOTE: Update this to include the paths to all of your component files. + content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"], + presets: [require("nativewind/preset")], + theme: { + extend: { + fontFamily: { + sans: ['Inter_400Regular', 'sans-serif'], + mono: ['SpaceGrotesk_400Regular', 'monospace'], + 'sans-bold': ['Inter_700Bold', 'sans-serif'], + 'mono-bold': ['SpaceGrotesk_700Bold', 'monospace'], + }, + colors: { + neo: { + main: '#8855ff', + second: '#ff9900', + accent: '#00cc88', + bg: '#f0f0f0', + dark: '#1a1a1a', + white: '#ffffff', + } + }, + boxShadow: { + 'neo': '4px 4px 0px 0px #1a1a1a', + 'neo-sm': '2px 2px 0px 0px #1a1a1a', + 'neo-lg': '6px 6px 0px 0px #1a1a1a', + } + }, + }, + plugins: [], +} diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json new file mode 100644 index 00000000..ec6aeb73 --- /dev/null +++ b/mobile/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./*" + ] + } + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ".expo/types/**/*.ts", + "expo-env.d.ts", + "nativewind-env.d.ts" + ] +} diff --git a/mobile/utils/balanceCalculator.js b/mobile/utils/balanceCalculator.js deleted file mode 100644 index 3093dd8b..00000000 --- a/mobile/utils/balanceCalculator.js +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Utility functions for calculating friend balances across groups - * Includes comprehensive null safety checks to prevent runtime errors - * - * Note: Uses 'paidBy' field to determine who actually paid for an expense, - * with fallback to 'createdBy' for backward compatibility. - */ - -/** - * Safely gets a value from an object with null/undefined protection - * @param {Object} obj - The object to get value from - * @param {string} path - Dot notation path (e.g., 'user.name') - * @param {*} defaultValue - Default value if path doesn't exist - * @returns {*} The value at the path or defaultValue - */ -const safeGet = (obj, path, defaultValue = null) => { - if (!obj || typeof obj !== 'object') return defaultValue; - - const keys = path.split('.'); - let current = obj; - - for (const key of keys) { - if (current == null || typeof current !== 'object' || !(key in current)) { - return defaultValue; - } - current = current[key]; - } - - return current !== null && current !== undefined ? current : defaultValue; -}; - -/** - * Safely validates and extracts group details - * @param {Object} group - Group object with details - * @returns {Object|null} Validated group data or null if invalid - */ -const validateGroupData = (group) => { - if (!group || typeof group !== 'object') return null; - - const details = safeGet(group, 'details'); - if (!Array.isArray(details) || details.length < 2) return null; - - const [membersResponse, expensesResponse] = details; - - // Validate members response - const members = safeGet(membersResponse, 'data'); - if (!Array.isArray(members)) return null; - - // Validate expenses response - const expenses = safeGet(expensesResponse, 'data.expenses'); - if (!Array.isArray(expenses)) return null; - - return { - id: safeGet(group, 'id') || safeGet(group, '_id'), - name: safeGet(group, 'name', 'Unknown Group'), - members, - expenses - }; -}; - -/** - * Safely finds a member by userId - * @param {Array} members - Array of member objects - * @param {string} userId - User ID to find - * @returns {string} Member name or 'Unknown' - */ -const getMemberName = (members, userId) => { - if (!Array.isArray(members) || !userId) return 'Unknown'; - - const member = members.find(m => safeGet(m, 'userId') === userId); - return safeGet(member, 'user.name', 'Unknown'); -}; - -/** - * Processes a single expense and updates balances - * @param {Object} expense - Expense object - * @param {Object} balances - Current balances object - * @param {Array} members - Group members - * @param {Object} group - Group information - * @param {string} currentUserId - Current user's ID - */ -const processExpense = (expense, balances, members, group, currentUserId) => { - if (!expense || typeof expense !== 'object' || !currentUserId) return; - - const payerId = safeGet(expense, 'paidBy') || safeGet(expense, 'createdBy'); - const splits = safeGet(expense, 'splits'); - - if (!payerId || !Array.isArray(splits)) return; - - const payerIsMe = payerId === currentUserId; - - splits.forEach(split => { - if (!split || typeof split !== 'object') return; - - const memberId = safeGet(split, 'userId'); - const splitAmount = parseFloat(safeGet(split, 'amount', 0)); - - if (!memberId || isNaN(splitAmount) || splitAmount <= 0) return; - if (memberId === payerId) return; // Payer doesn't owe themselves - - const memberIsMe = memberId === currentUserId; - - // Initialize balance structure if needed - const initializeBalance = (userId) => { - if (!balances[userId]) { - balances[userId] = { - name: getMemberName(members, userId), - netBalance: 0, - groups: {} - }; - } - if (!balances[userId].groups[group.id]) { - balances[userId].groups[group.id] = { - name: group.name, - balance: 0 - }; - } - }; - - if (payerIsMe && !memberIsMe) { - // I paid, they owe me - initializeBalance(memberId); - balances[memberId].netBalance += splitAmount; - balances[memberId].groups[group.id].balance += splitAmount; - } else if (!payerIsMe && memberIsMe) { - // They paid, I owe them - initializeBalance(payerId); - balances[payerId].netBalance -= splitAmount; - balances[payerId].groups[group.id].balance -= splitAmount; - } - }); -}; - -/** - * Formats balance data for UI consumption - * @param {Object} balances - Raw balances object - * @returns {Array} Formatted friends array for UI - */ -const formatBalancesForUI = (balances) => { - if (!balances || typeof balances !== 'object') return []; - - return Object.entries(balances).map(([id, data]) => { - if (!data || typeof data !== 'object') return null; - - const groups = safeGet(data, 'groups', {}); - const formattedGroups = Object.entries(groups).map(([groupId, groupData]) => ({ - id: groupId, - name: safeGet(groupData, 'name', 'Unknown Group'), - balance: parseFloat(safeGet(groupData, 'balance', 0)) - })).filter(group => group.id && !isNaN(group.balance)); - - return { - id, - name: safeGet(data, 'name', 'Unknown'), - netBalance: parseFloat(safeGet(data, 'netBalance', 0)), - groups: formattedGroups - }; - }).filter(friend => friend !== null && friend.id); -}; - -/** - * Main function to calculate friend balances from groups with details - * @param {Array} groupsWithDetails - Array of groups with their details - * @param {string} currentUserId - Current user's ID - * @returns {Array} Formatted array of friends with balance information - */ -export const calculateFriendBalances = (groupsWithDetails, currentUserId) => { - if (!Array.isArray(groupsWithDetails) || !currentUserId) { - console.warn('Invalid input to calculateFriendBalances:', { groupsWithDetails, currentUserId }); - return []; - } - - const balances = {}; - - groupsWithDetails.forEach(group => { - try { - const validatedGroup = validateGroupData(group); - if (!validatedGroup) { - console.warn('Invalid group data, skipping:', group); - return; - } - - const { members, expenses } = validatedGroup; - - expenses.forEach(expense => { - try { - processExpense(expense, balances, members, validatedGroup, currentUserId); - } catch (error) { - console.error('Error processing expense:', error, expense); - } - }); - } catch (error) { - console.error('Error processing group:', error, group); - } - }); - - return formatBalancesForUI(balances); -}; - -export default { - calculateFriendBalances, - safeGet, - validateGroupData, - getMemberName -}; diff --git a/mobile/utils/currency.js b/mobile/utils/currency.js deleted file mode 100644 index 436059f9..00000000 --- a/mobile/utils/currency.js +++ /dev/null @@ -1,21 +0,0 @@ -// Centralized currency formatting utility -// Future enhancement: make currency code/user preference dynamic (user.profile.currency) - -const DEFAULT_CURRENCY_SYMBOL = "₹"; // INR default - -export const getCurrencySymbol = () => DEFAULT_CURRENCY_SYMBOL; - -export const formatCurrency = (amount) => { - if (amount == null || isNaN(Number(amount))) - return `${DEFAULT_CURRENCY_SYMBOL}0.00`; - const num = Number(amount); - if (!Number.isFinite(num)) { - return `${DEFAULT_CURRENCY_SYMBOL}0.00`; - } - return `${DEFAULT_CURRENCY_SYMBOL}${num.toFixed(2)}`; -}; - -export default { - getCurrencySymbol, - formatCurrency, -};