diff --git a/frontend/sac-mobile/app/(app)/(tabs)/search.tsx b/frontend/sac-mobile/app/(app)/(tabs)/search.tsx index 55f256958..89b989329 100644 --- a/frontend/sac-mobile/app/(app)/(tabs)/search.tsx +++ b/frontend/sac-mobile/app/(app)/(tabs)/search.tsx @@ -1,11 +1,23 @@ import React from 'react'; -import { Text, View } from 'react-native'; +import { SafeAreaView, ScrollView, Text, View } from 'react-native'; +import { TextInput } from 'react-native-gesture-handler'; + +import { Button } from '@/components/button'; const Search = () => { return ( - - Search - + + + Search + + + + + + ); }; diff --git a/frontend/sac-mobile/app/(app)/_layout.tsx b/frontend/sac-mobile/app/(app)/_layout.tsx index 3071cb8e8..48928119d 100644 --- a/frontend/sac-mobile/app/(app)/_layout.tsx +++ b/frontend/sac-mobile/app/(app)/_layout.tsx @@ -8,6 +8,74 @@ import { MenuView } from '@react-native-menu/menu'; import { LeftArrow } from '@/components/left-arrow'; +const EventDotsVertical = () => { + return ( + { + console.warn(JSON.stringify(nativeEvent)); + }} + actions={[ + { + id: 'share', + title: 'Share Event', + image: Platform.select({ + ios: 'square.and.arrow.up', + android: 'share-variant' + }) + }, + { + id: 'report', + title: 'Report Event', + image: Platform.select({ + ios: 'person.crop.circle.badge.exclamationmark.fill', + android: 'person-circle-outline' + }) + } + ]} + > + + + ); +}; + +const ClubDotsVertical = () => { + return ( + { + console.warn(JSON.stringify(nativeEvent)); + }} + actions={[ + { + id: 'share', + title: 'Share Club', + image: Platform.select({ + ios: 'square.and.arrow.up', + android: 'share-variant' + }) + }, + { + id: 'report', + title: 'Report Club', + image: Platform.select({ + ios: 'person.crop.circle.badge.exclamationmark.fill', + android: 'person-circle-outline' + }) + } + ]} + > + + + ); +}; + const Layout = () => { return ( @@ -15,8 +83,6 @@ const Layout = () => { { ), headerLeft: () => , - headerRight: () => { - return ( - { - console.warn(JSON.stringify(nativeEvent)); - }} - actions={[ - { - id: 'share', - title: 'Share Event', - image: Platform.select({ - ios: 'square.and.arrow.up', - android: 'share-variant' - }) - }, - { - id: 'report', - title: 'Report Event', - image: Platform.select({ - ios: 'person.crop.circle.badge.exclamationmark.fill', - android: 'person-circle-outline' - }) - } - ]} - > - - - ); - } + headerRight: () => }} /> { ), headerLeft: () => , - headerRight: () => { - return ( - { - console.warn(JSON.stringify(nativeEvent)); - }} - actions={[ - { - id: 'share', - title: 'Share Club', - image: Platform.select({ - ios: 'square.and.arrow.up', - android: 'share-variant' - }) - }, - { - id: 'report', - title: 'Report Club', - image: Platform.select({ - ios: 'person.crop.circle.badge.exclamationmark.fill', - android: 'person-circle-outline' - }) - } - ]} - > - - - ); - } + headerRight: () => }} /> diff --git a/frontend/sac-mobile/app/(app)/club/[id].tsx b/frontend/sac-mobile/app/(app)/club/[id].tsx index 5c2e6a67a..73112c17c 100644 --- a/frontend/sac-mobile/app/(app)/club/[id].tsx +++ b/frontend/sac-mobile/app/(app)/club/[id].tsx @@ -1,19 +1,36 @@ import React from 'react'; -import { SafeAreaView, Text } from 'react-native'; +import { Text, View } from 'react-native'; -import { Link, Stack, useLocalSearchParams } from 'expo-router'; +import { Stack, useLocalSearchParams } from 'expo-router'; + +import { useClub } from '@/hooks/use-club'; const ClubPage = () => { const { id } = useLocalSearchParams<{ id: string }>(); + const { data: club, isLoading, error } = useClub(id); + + if (isLoading) { + return Loading...; + } + + if (error) { + return Error: {error.message}; + } + + if (!club) { + return Club not found; + } + return ( - - - ClubPage - - FAQ - - + <> + + + {club.name} + {club.recruitment_cycle} + {club.application_link} + + ); }; diff --git a/frontend/sac-mobile/app/(app)/event/[id].tsx b/frontend/sac-mobile/app/(app)/event/[id].tsx index 84e5a7fa8..64831e3dd 100644 --- a/frontend/sac-mobile/app/(app)/event/[id].tsx +++ b/frontend/sac-mobile/app/(app)/event/[id].tsx @@ -1,29 +1,32 @@ -import React from 'react'; +import React, { useRef } from 'react'; import { ScrollView, Text, View } from 'react-native'; import { Stack, useLocalSearchParams } from 'expo-router'; +import BottomSheet from '@gorhom/bottom-sheet'; + import { AllHosts } from '@/app/(app)/event/_components/all-hosts'; import { TagList } from '@/components/all-tags'; import { Button } from '@/components/button'; import { Description } from '@/components/description'; -import { useAuthStore } from '@/hooks/use-auth'; +import { Title } from '@/components/title'; import { useEvent } from '@/hooks/use-event'; -import { Title } from '../_components/title'; import { EventHeader } from './_components/event-header'; import { EventLocation } from './_components/event-location'; import { EventTime } from './_components/event-time'; import { HostNames } from './_components/host-names'; import { LocationView } from './_components/location-view'; +import RSVPBottomSheet from './_components/rsvp-bottom-sheet'; // TODO: handle link OR location const EventPage = () => { const { id } = useLocalSearchParams<{ id: string }>(); - const { user } = useAuthStore(); const { data: event, isLoading, error } = useEvent(id); + const ref = useRef(null); + if (error) { console.error(error); return Error fetching event; @@ -41,14 +44,12 @@ const EventPage = () => { return ( <> - + - + <HostNames eventID={event.id} /> @@ -84,6 +85,7 @@ const EventPage = () => { </View> </View> </ScrollView> + <RSVPBottomSheet ref={ref} /> </> ); }; diff --git a/frontend/sac-mobile/app/(app)/event/_components/event-header.tsx b/frontend/sac-mobile/app/(app)/event/_components/event-header.tsx index 094661de5..6003a6d75 100644 --- a/frontend/sac-mobile/app/(app)/event/_components/event-header.tsx +++ b/frontend/sac-mobile/app/(app)/event/_components/event-header.tsx @@ -1,10 +1,21 @@ +import { forwardRef } from 'react'; import { Platform, View } from 'react-native'; +import BottomSheet from '@gorhom/bottom-sheet'; import { MenuView } from '@react-native-menu/menu'; import { Button } from '@/components/button'; -const EventHeader = () => { +type Ref = BottomSheet; + +const EventHeader = forwardRef<Ref>((_, ref) => { + if (!ref) { + return null; + } + + // @ts-ignore + const handleOpenPress = () => ref.current?.snapToIndex(0); + return ( <View className="flex-row items-center justify-between -translate-y-10"> <View className="w-24 h-24 bg-gray-300 rounded-xl" /> @@ -51,9 +62,18 @@ const EventHeader = () => { RSVP </Button> </MenuView> + + <Button + size={'default'} + variant={'default'} + className="w-18" + onPress={handleOpenPress} + > + Save + </Button> </View> </View> ); -}; +}); export { EventHeader }; diff --git a/frontend/sac-mobile/app/(app)/event/_components/location-view.tsx b/frontend/sac-mobile/app/(app)/event/_components/location-view.tsx index 647a6ef61..abc882879 100644 --- a/frontend/sac-mobile/app/(app)/event/_components/location-view.tsx +++ b/frontend/sac-mobile/app/(app)/event/_components/location-view.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import { Image, Linking, Text, TouchableOpacity, View } from 'react-native'; +import { Linking, Text, TouchableOpacity, View } from 'react-native'; +import MapView from 'react-native-maps'; import { createOpenLink } from 'react-native-open-maps'; -import { useAssets } from 'expo-asset'; - import { Button } from '@/components/button'; type LocationViewProps = { @@ -12,16 +11,9 @@ type LocationViewProps = { }; const LocationView = ({ location, meetingLink }: LocationViewProps) => { - const [assets, error] = useAssets([ - require('@/assets/images/placeholder_location.png') - ]); const coordinates = { latitude: 42.3393326, longitude: -71.0869942 }; const openMap = createOpenLink({ ...coordinates }); - if (error) { - console.error(error); - } - return ( <> <View className="inline-flex flex-row items-center justify-between"> @@ -52,13 +44,15 @@ const LocationView = ({ location, meetingLink }: LocationViewProps) => { )} <View className="w-full mt-4 overflow-hidden border-2 rounded-xl border-zinc-300"> - {assets ? ( - <Image - source={{ uri: assets[0].uri }} - style={{ width: '100%', height: assets[0].height }} - className="rounded-[22px]" - /> - ) : null} + <MapView + onPress={openMap} + style={{ width: '100%', height: 200 }} + initialRegion={{ + ...coordinates, + latitudeDelta: 0.0922, + longitudeDelta: 0.0421 + }} + /> </View> </> ); diff --git a/frontend/sac-mobile/app/(app)/event/_components/rsvp-bottom-sheet.tsx b/frontend/sac-mobile/app/(app)/event/_components/rsvp-bottom-sheet.tsx new file mode 100644 index 000000000..e397d2c8a --- /dev/null +++ b/frontend/sac-mobile/app/(app)/event/_components/rsvp-bottom-sheet.tsx @@ -0,0 +1,56 @@ +import React, { forwardRef, useCallback } from 'react'; +import { Text, View } from 'react-native'; + +import BottomSheet, { BottomSheetBackdrop } from '@gorhom/bottom-sheet'; + +import { Button } from '@/components/button'; + +type Ref = BottomSheet; + +const RSVPBottomSheet = forwardRef<Ref>((_, ref) => { + const snapPoints = ['35%']; + + const renderBackdrop = useCallback( + (props: any) => ( + <BottomSheetBackdrop + appearsOnIndex={0} + disappearsOnIndex={-1} + {...props} + /> + ), + [] + ); + + // @ts-ignore + const handleClosePress = () => ref.current?.close(); + + return ( + <BottomSheet + ref={ref} + index={-1} + snapPoints={snapPoints} + enablePanDownToClose={true} + backgroundStyle={{ backgroundColor: 'white' }} + backdropComponent={renderBackdrop} + > + <View className="items-center justify-center p-4"> + <Text className="text-2xl font-bold">Save Event</Text> + <Text className="mt-2 text-lg"> + By saving this event, you are automatically signed up for + notifications and this event will be added to your calendar. + </Text> + <View className="w-full mt-4"> + <Button + className="rounded-xl" + onPress={handleClosePress} + size={'screenwide'} + > + Save Event + </Button> + </View> + </View> + </BottomSheet> + ); +}); + +export default RSVPBottomSheet; diff --git a/frontend/sac-mobile/app/(app)/tag/[id].tsx b/frontend/sac-mobile/app/(app)/tag/[id].tsx new file mode 100644 index 000000000..426581a43 --- /dev/null +++ b/frontend/sac-mobile/app/(app)/tag/[id].tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Text, View } from 'react-native'; + +const TagPage = () => { + return ( + <View> + <Text>TagPage</Text> + </View> + ); +}; + +export default TagPage; diff --git a/frontend/sac-mobile/app/(auth)/_components/registration-form.tsx b/frontend/sac-mobile/app/(auth)/_components/registration-form.tsx index 90f880692..a4c9b0861 100644 --- a/frontend/sac-mobile/app/(auth)/_components/registration-form.tsx +++ b/frontend/sac-mobile/app/(auth)/_components/registration-form.tsx @@ -168,6 +168,7 @@ const RegistrationForm = () => { <Input title="Password" autoCorrect={false} + autoComplete="password" placeholder="Password" onChangeText={onChange} value={value} @@ -218,6 +219,7 @@ const RegistrationForm = () => { <Input title="Password Confirmation" autoCorrect={false} + autoComplete="password" placeholder="Confirm your password" onChangeText={onChange} value={value} diff --git a/frontend/sac-mobile/app/(auth)/_layout.tsx b/frontend/sac-mobile/app/(auth)/_layout.tsx index 9dc36228e..15f8f8514 100644 --- a/frontend/sac-mobile/app/(auth)/_layout.tsx +++ b/frontend/sac-mobile/app/(auth)/_layout.tsx @@ -1,8 +1,12 @@ import React from 'react'; +import { View } from 'react-native'; -import { Stack } from 'expo-router'; +import { Stack, router } from 'expo-router'; -const AuthLayout = () => { +import { Button } from '@/components/button'; +import { Wordmark } from '@/components/wordmark'; + +const Layout = () => { return ( <Stack initialRouteName="welcome"> <Stack.Screen @@ -10,22 +14,49 @@ const AuthLayout = () => { options={{ title: '', headerShown: true, - animationTypeForReplace: 'push', + animationTypeForReplace: 'pop', + animation: 'slide_from_left', statusBarColor: 'dark' }} /> - <Stack.Screen name="login" options={{ headerShown: false }} /> - <Stack.Screen name="register" options={{ headerShown: false }} /> <Stack.Screen - name="verification" - options={{ headerShown: false }} + name="login" + options={{ + title: '', + headerShown: true, + headerLeft: () => <Wordmark />, + headerBackground: () => ( + <View className="h-full bg-neutral-500" /> + ), + animationTypeForReplace: 'push', + animation: 'slide_from_right' + }} /> <Stack.Screen - name="user-details" - options={{ headerShown: false }} + name="register" + options={{ + title: '', + headerShown: true, + headerLeft: () => <Wordmark />, + headerRight: () => ( + <Button + variant={'secondary'} + onPress={() => router.replace('/login')} + > + Login + </Button> + ), + headerBackground: () => ( + <View className="h-full bg-neutral-500" /> + ), + animationTypeForReplace: 'pop', + animation: 'slide_from_left' + }} /> + <Stack.Screen name="verification" options={{ headerShown: true }} /> + <Stack.Screen name="user-details" options={{ headerShown: true }} /> </Stack> ); }; -export default AuthLayout; +export default Layout; diff --git a/frontend/sac-mobile/app/(auth)/login.tsx b/frontend/sac-mobile/app/(auth)/login.tsx index 8e106bab0..97d54aac2 100644 --- a/frontend/sac-mobile/app/(auth)/login.tsx +++ b/frontend/sac-mobile/app/(auth)/login.tsx @@ -1,20 +1,15 @@ import React from 'react'; -import { Text, View } from 'react-native'; +import { KeyboardAvoidingView, Text, View } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; -import { Wordmark } from '@/components/wordmark'; - import { LoginForm } from './_components/login-form'; const Login = () => { return ( <SafeAreaView className="bg-neutral-500 h-[100%]" edges={['top']}> - <View className="flex-1"> - <View className="px-[8%] pb-[10%]"> - <View className="pt-[1%]"> - <Wordmark /> - </View> - <View className="pt-[9.5%] pb-[6%]"> + <KeyboardAvoidingView behavior={'padding'} className="flex-1"> + <View className="px-[8%] pb-[8%]"> + <View className="pt-[2%] pb-[1%]"> <Text className="text-5xl font-bold text-white"> Let's go </Text> @@ -35,7 +30,7 @@ const Login = () => { </Text> </View> </View> - </View> + </KeyboardAvoidingView> </SafeAreaView> ); }; diff --git a/frontend/sac-mobile/app/(auth)/register.tsx b/frontend/sac-mobile/app/(auth)/register.tsx index db5ec52d5..da33237bf 100644 --- a/frontend/sac-mobile/app/(auth)/register.tsx +++ b/frontend/sac-mobile/app/(auth)/register.tsx @@ -1,43 +1,30 @@ import React from 'react'; -import { ScrollView, Text, View } from 'react-native'; +import { KeyboardAvoidingView, ScrollView, Text, View } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; -import { router } from 'expo-router'; - -import { Button } from '@/components/button'; -import { Wordmark } from '@/components/wordmark'; - import { RegistrationForm } from './_components/registration-form'; const Register = () => { return ( <SafeAreaView className="bg-neutral-500" edges={['top']}> - <ScrollView> - <View className="px-[8%] pb-[9%]"> - <View className="flex flex-row justify-between mx-auto w-full items-center pt-[3%] pb-[5.5%]"> - <Wordmark /> - <Button - onPress={() => router.replace('/(auth)/login')} - variant="secondary" - size="sm" - > - Login - </Button> - </View> - <View className="pt-[9%] pb-[7.5%]"> - <Text className="text-5xl font-bold text-white"> - Sign up + <KeyboardAvoidingView behavior={'padding'}> + <ScrollView> + <View className="px-[8%] pb-[9%]"> + <View className="pt-[9%] pb-[7.5%]"> + <Text className="text-5xl font-bold text-white"> + Sign up + </Text> + </View> + <Text className="text-lg leading-6 text-white"> + Discover, follow, and join all the clubs & events + Northeastern has to offer </Text> </View> - <Text className="text-lg leading-6 text-white"> - Discover, follow, and join all the clubs & events - Northeastern has to offer - </Text> - </View> - <View className="bg-white px-[8%] pt-[13%] rounded-t-3xl"> - <RegistrationForm /> - </View> - </ScrollView> + <View className="bg-white px-[8%] pt-[13%] rounded-t-3xl"> + <RegistrationForm /> + </View> + </ScrollView> + </KeyboardAvoidingView> </SafeAreaView> ); }; diff --git a/frontend/sac-mobile/app/_layout.tsx b/frontend/sac-mobile/app/_layout.tsx index 7b61e7db8..46b16131d 100644 --- a/frontend/sac-mobile/app/_layout.tsx +++ b/frontend/sac-mobile/app/_layout.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { View } from 'react-native'; +import { GestureHandlerRootView } from 'react-native-gesture-handler'; import Spinner from 'react-native-loading-spinner-overlay'; import { useFonts } from 'expo-font'; @@ -91,8 +92,10 @@ const RootLayout = () => { return ( <QueryClientProvider client={queryClient}> - <StatusBar style="light" /> - <InitalLayout /> + <GestureHandlerRootView style={{ flex: 1 }}> + <StatusBar style="light" /> + <InitalLayout /> + </GestureHandlerRootView> </QueryClientProvider> ); }; diff --git a/frontend/sac-mobile/babel.config.js b/frontend/sac-mobile/babel.config.js index 0464179ed..94046263e 100644 --- a/frontend/sac-mobile/babel.config.js +++ b/frontend/sac-mobile/babel.config.js @@ -2,6 +2,6 @@ module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], - plugins: ['nativewind/babel'] + plugins: ['nativewind/babel', 'react-native-reanimated/plugin'] }; }; diff --git a/frontend/sac-mobile/components/tag.tsx b/frontend/sac-mobile/components/tag.tsx index faea441ad..455cc24a8 100644 --- a/frontend/sac-mobile/components/tag.tsx +++ b/frontend/sac-mobile/components/tag.tsx @@ -1,5 +1,7 @@ import { Text } from 'react-native'; +import { router } from 'expo-router'; + import { Button } from '@/components/button'; import { Tag as T } from '@/types/tag'; @@ -10,7 +12,7 @@ type TagProps = { const Tag = ({ tag }: TagProps) => { return ( <Button - onPress={() => console.log('Pressed:', tag)} + onPress={() => router.push(`/tag/${tag.id}`)} size={'pill'} variant={'pill'} className="my-1 mr-1" diff --git a/frontend/sac-mobile/app/(app)/_components/title.tsx b/frontend/sac-mobile/components/title.tsx similarity index 100% rename from frontend/sac-mobile/app/(app)/_components/title.tsx rename to frontend/sac-mobile/components/title.tsx diff --git a/frontend/sac-mobile/hooks/use-auth.ts b/frontend/sac-mobile/hooks/use-auth.ts index 8c92470ed..de4f97d68 100644 --- a/frontend/sac-mobile/hooks/use-auth.ts +++ b/frontend/sac-mobile/hooks/use-auth.ts @@ -6,21 +6,21 @@ import { getCurrentUser } from '@/services/user'; import { Tokens } from '@/types/auth'; import { User } from '@/types/user'; -export type UserSignUp = { +type UserSignUp = { first_name: string; last_name: string; email: string; password: string; }; -export type AuthStoreState = { +type AuthStoreState = { user: User | null; isLoggedIn: boolean | null; isVerified: boolean | null; tokens: Tokens | null; }; -export type AuthStoreActions = { +type AuthStoreActions = { fetchUser: () => void; fetchCache: () => Promise<void>; setTokens: (tokens: Tokens) => void; @@ -30,73 +30,73 @@ export type AuthStoreActions = { signOut: () => void; }; -export const useAuthStore = create<AuthStoreState & AuthStoreActions>( - (set) => ({ - user: null, - isLoggedIn: null, - isVerified: null, - tokens: null, - setTokens: (tokens: Tokens) => { - set({ tokens }); - tokenCache.saveToken('accessToken', tokens.accessToken); - tokenCache.saveToken('refreshToken', tokens.refreshToken); - }, - fetchCache: async () => { - const accessToken = await tokenCache.getToken('accessToken'); - const refreshToken = await tokenCache.getToken('refreshToken'); - const user = await tokenCache.getToken('user'); +const useAuthStore = create<AuthStoreState & AuthStoreActions>((set) => ({ + user: null, + isLoggedIn: null, + isVerified: null, + tokens: null, + setTokens: (tokens: Tokens) => { + set({ tokens }); + tokenCache.saveToken('accessToken', tokens.accessToken); + tokenCache.saveToken('refreshToken', tokens.refreshToken); + }, + fetchCache: async () => { + const accessToken = await tokenCache.getToken('accessToken'); + const refreshToken = await tokenCache.getToken('refreshToken'); + const user = await tokenCache.getToken('user'); - if (accessToken && refreshToken && user) { - set({ - user: JSON.parse(user), - tokens: { accessToken, refreshToken }, - isLoggedIn: true - }); - } else { - set({ isLoggedIn: false }); - } - }, - signIn: async (email: string, password: string) => { - const { user, tokens } = await login(email, password); - if (user.is_verified === false) { - set({ user, tokens, isLoggedIn: true, isVerified: false }); - } else { - set({ user, tokens, isLoggedIn: true, isVerified: true }); - } - await tokenCache.saveToken('user', JSON.stringify(user)); - await tokenCache.saveToken('accessToken', tokens.accessToken); - await tokenCache.saveToken('refreshToken', tokens.refreshToken); - }, - signUp: async (userObj: UserSignUp) => { - const { user, tokens } = await signUp( - userObj.first_name, - userObj.last_name, - userObj.email, - userObj.password - ); - set({ user, tokens, isLoggedIn: true, isVerified: false }); - await tokenCache.saveToken('user', JSON.stringify(user)); - await tokenCache.saveToken('accessToken', tokens.accessToken); - await tokenCache.saveToken('refreshToken', tokens.refreshToken); - }, - completeVerification: async (email: string, code: string) => { - await completeVerification(email, code); - set({ isVerified: true }); - }, - signOut: async () => { - await logout(); + if (accessToken && refreshToken && user) { set({ - tokens: null, - isLoggedIn: false, - isVerified: false, - user: null + user: JSON.parse(user), + tokens: { accessToken, refreshToken }, + isLoggedIn: true }); - tokenCache.deleteToken('accessToken'); - tokenCache.deleteToken('refreshToken'); - }, - fetchUser: async () => { - const user = await getCurrentUser(); - set({ user, isLoggedIn: true, isVerified: user.is_verified }); + } else { + set({ isLoggedIn: false }); + } + }, + signIn: async (email: string, password: string) => { + const { user, tokens } = await login(email, password); + if (user.is_verified === false) { + set({ user, tokens, isLoggedIn: true, isVerified: false }); + } else { + set({ user, tokens, isLoggedIn: true, isVerified: true }); } - }) -); + await tokenCache.saveToken('user', JSON.stringify(user)); + await tokenCache.saveToken('accessToken', tokens.accessToken); + await tokenCache.saveToken('refreshToken', tokens.refreshToken); + }, + signUp: async (userObj: UserSignUp) => { + const { user, tokens } = await signUp( + userObj.first_name, + userObj.last_name, + userObj.email, + userObj.password + ); + set({ user, tokens, isLoggedIn: true, isVerified: false }); + await tokenCache.saveToken('user', JSON.stringify(user)); + await tokenCache.saveToken('accessToken', tokens.accessToken); + await tokenCache.saveToken('refreshToken', tokens.refreshToken); + }, + completeVerification: async (email: string, code: string) => { + await completeVerification(email, code); + set({ isVerified: true }); + }, + signOut: async () => { + await logout(); + set({ + tokens: null, + isLoggedIn: false, + isVerified: false, + user: null + }); + tokenCache.deleteToken('accessToken'); + tokenCache.deleteToken('refreshToken'); + }, + fetchUser: async () => { + const user = await getCurrentUser(); + set({ user, isLoggedIn: true, isVerified: user.is_verified }); + } +})); + +export { UserSignUp, AuthStoreState, AuthStoreActions, useAuthStore }; diff --git a/frontend/sac-mobile/hooks/use-club.ts b/frontend/sac-mobile/hooks/use-club.ts index 9181de8e5..754230285 100644 --- a/frontend/sac-mobile/hooks/use-club.ts +++ b/frontend/sac-mobile/hooks/use-club.ts @@ -1,11 +1,20 @@ import { UseQueryResult, useQuery } from '@tanstack/react-query'; -import { fetchClub, fetchClubContacts } from '@/services/club'; +import { fetchClub, fetchClubContacts, fetchClubs } from '@/services/club'; import { Club } from '@/types/club'; import { Contact } from '@/types/contact'; import { uuid } from '@/types/uuid'; -export const useClub = (clubID: uuid): UseQueryResult<Club, Error> => { +const useClubs = (): UseQueryResult<Club[], Error> => { + return useQuery<Club[], Error>({ + queryKey: ['clubs'], + queryFn: () => { + return fetchClubs(); + } + }); +}; + +const useClub = (clubID: uuid): UseQueryResult<Club, Error> => { return useQuery<Club, Error>({ queryKey: ['club', clubID], queryFn: () => { @@ -14,9 +23,7 @@ export const useClub = (clubID: uuid): UseQueryResult<Club, Error> => { }); }; -export const useClubContacts = ( - clubID: uuid -): UseQueryResult<Contact[], Error> => { +const useClubContacts = (clubID: uuid): UseQueryResult<Contact[], Error> => { return useQuery<Contact[], Error>({ queryKey: ['club', clubID, 'contacts'], queryFn: () => { @@ -43,3 +50,5 @@ export const useClubContacts = ( } }); }; + +export { useClub, useClubs, useClubContacts }; diff --git a/frontend/sac-mobile/hooks/use-event.ts b/frontend/sac-mobile/hooks/use-event.ts index 274f4ab20..936bf9956 100644 --- a/frontend/sac-mobile/hooks/use-event.ts +++ b/frontend/sac-mobile/hooks/use-event.ts @@ -11,7 +11,7 @@ import { Event } from '@/types/event'; import { Tag } from '@/types/tag'; import { uuid } from '@/types/uuid'; -export const useEvent = (eventID: string): UseQueryResult<Event, Error> => { +const useEvent = (eventID: string): UseQueryResult<Event, Error> => { return useQuery<Event, Error>({ queryKey: ['event', eventID], queryFn: () => { @@ -20,7 +20,7 @@ export const useEvent = (eventID: string): UseQueryResult<Event, Error> => { }); }; -export const useEvents = (): UseQueryResult<Event[], Error> => { +const useEvents = (): UseQueryResult<Event[], Error> => { return useQuery<Event[], Error>({ queryKey: ['events'], queryFn: () => { @@ -29,7 +29,7 @@ export const useEvents = (): UseQueryResult<Event[], Error> => { }); }; -export const useEventTags = (eventID: uuid): UseQueryResult<Tag[], Error> => { +const useEventTags = (eventID: uuid): UseQueryResult<Tag[], Error> => { return useQuery<Tag[], Error>({ queryKey: ['event', eventID, 'tags'], queryFn: () => { @@ -38,7 +38,7 @@ export const useEventTags = (eventID: uuid): UseQueryResult<Tag[], Error> => { }); }; -export const useEventHosts = (eventID: uuid): UseQueryResult<Club[], Error> => { +const useEventHosts = (eventID: uuid): UseQueryResult<Club[], Error> => { return useQuery<Club[], Error>({ queryKey: ['event', eventID, 'hosts'], queryFn: () => { @@ -46,3 +46,5 @@ export const useEventHosts = (eventID: uuid): UseQueryResult<Club[], Error> => { } }); }; + +export { useEvent, useEvents, useEventTags, useEventHosts }; diff --git a/frontend/sac-mobile/lib/const.ts b/frontend/sac-mobile/lib/const.ts index 6be4c895a..838a619bd 100644 --- a/frontend/sac-mobile/lib/const.ts +++ b/frontend/sac-mobile/lib/const.ts @@ -1 +1 @@ -export const API_BASE_URL = 'https://ad79-50-170-49-148.ngrok-free.app/api/v1'; // 'http://localhost:8080/api/v1'; +export const API_BASE_URL = 'http://localhost:8080/api/v1'; diff --git a/frontend/sac-mobile/package.json b/frontend/sac-mobile/package.json index 4623b7374..aa6dec37e 100644 --- a/frontend/sac-mobile/package.json +++ b/frontend/sac-mobile/package.json @@ -4,8 +4,8 @@ "version": "1.0.0", "scripts": { "start": "expo start", - "android": "expo run:android", - "ios": "expo run:ios", + "android": "expo start --android", + "ios": "expo start --ios", "web": "expo start --web", "test": "echo \"Woah there, we have no frontend tests as of right now. Let's just say we're passing.\" && exit 0", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", @@ -17,10 +17,11 @@ }, "dependencies": { "@expo/vector-icons": "^14.0.0", + "@gorhom/bottom-sheet": "^4", "@react-native-menu/menu": "^0.9.1", "@react-navigation/native": "^6.1.17", - "@types/uuid": "^9.0.8", "@tanstack/react-query": "^5.29.0", + "@types/uuid": "^9.0.8", "axios": "^1.6.8", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -45,9 +46,11 @@ "react-native": "0.73.6", "react-native-cookies": "^3.3.0", "react-native-element-dropdown": "^2.10.4", + "react-native-gesture-handler": "~2.14.0", "react-native-loading-spinner-overlay": "^3.0.1", + "react-native-maps": "1.10.0", "react-native-open-maps": "^0.4.3", - "react-native-reanimated": "^3.8.1", + "react-native-reanimated": "~3.6.2", "react-native-safe-area-context": "4.9.0", "react-native-screens": "~3.30.1", "react-native-svg": "^15.1.0", @@ -68,7 +71,7 @@ "prettier": "^3.2.4", "react-native-svg-transformer": "^1.3.0", "react-test-renderer": "18.2.0", - "tailwindcss": "3.4.3", + "tailwindcss": "3.3.2", "typescript": "^5.4.4" }, "private": true diff --git a/frontend/sac-mobile/services/club.ts b/frontend/sac-mobile/services/club.ts index e93ce0360..40c41228e 100644 --- a/frontend/sac-mobile/services/club.ts +++ b/frontend/sac-mobile/services/club.ts @@ -5,6 +5,23 @@ import { uuid } from '@/types/uuid'; import { api } from './api'; +/** + * Fetches all clubs. + * + * @returns A Promise that resolves to the fetched clubs or rejects with an error + * @throws Error if the clubs cannot be fetched + * @see Club + */ +const fetchClubs = async (): Promise<Club[]> => { + return api + .get('/clubs') + .then((response) => response.data as Club[]) + .catch((error) => { + console.error(error); + throw new Error('Error fetching clubs'); + }); +}; + /** * Fetches a club by its ID. * @@ -13,7 +30,7 @@ import { api } from './api'; * @throws Error if the club cannot be fetched * @see Club */ -export const fetchClub = async (clubID: uuid): Promise<Club> => { +const fetchClub = async (clubID: uuid): Promise<Club> => { return api .get(`/clubs/${clubID}`) .then((response) => response.data as Club) @@ -32,7 +49,7 @@ export const fetchClub = async (clubID: uuid): Promise<Club> => { * @see Contact * @see Contact[] */ -export const fetchClubContacts = async (clubID: uuid): Promise<Contact[]> => { +const fetchClubContacts = async (clubID: uuid): Promise<Contact[]> => { // return api // .get(`/clubs/${clubID}/contacts`) // .then((response) => response.data as Contact[]) @@ -50,3 +67,5 @@ export const fetchClubContacts = async (clubID: uuid): Promise<Contact[]> => { return allContacts; }; + +export { fetchClubContacts, fetchClub, fetchClubs }; diff --git a/frontend/sac-mobile/types/categories.ts b/frontend/sac-mobile/types/categories.ts index 1571c1474..e8d257c10 100644 --- a/frontend/sac-mobile/types/categories.ts +++ b/frontend/sac-mobile/types/categories.ts @@ -3,10 +3,10 @@ import { z } from 'zod'; import { rootModelSchema } from './root'; import { tagSchema } from './tag'; -export const categorySchema = z.object({ +export const categorySchemaIntermediate = z.object({ name: z.string(), tags: z.array(tagSchema) }); -const Category = categorySchema.merge(rootModelSchema); -export type Category = z.infer<typeof Category>; +export const categorySchema = categorySchemaIntermediate.merge(rootModelSchema); +export type Category = z.infer<typeof categorySchema>; diff --git a/frontend/sac-mobile/types/tag.ts b/frontend/sac-mobile/types/tag.ts index fb7a14220..d0dd9dfd8 100644 --- a/frontend/sac-mobile/types/tag.ts +++ b/frontend/sac-mobile/types/tag.ts @@ -2,9 +2,9 @@ import { z } from 'zod'; import { rootModelSchema } from './root'; -export const tagSchema = z.object({ +export const tagSchemaIntermediate = z.object({ name: z.string().max(255) }); -const Tag = tagSchema.merge(rootModelSchema); -export type Tag = z.infer<typeof Tag>; +export const tagSchema = tagSchemaIntermediate.merge(rootModelSchema); +export type Tag = z.infer<typeof tagSchema>; diff --git a/frontend/sac-mobile/yarn.lock b/frontend/sac-mobile/yarn.lock index 75f99b6da..335e266b8 100644 --- a/frontend/sac-mobile/yarn.lock +++ b/frontend/sac-mobile/yarn.lock @@ -134,6 +134,21 @@ "@babel/helper-split-export-declaration" "^7.22.6" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz#c806f73788a6800a5cfbbc04d2df7ee4d927cce3" + integrity sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-member-expression-to-functions" "^7.23.0" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": version "7.22.15" resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz" @@ -252,6 +267,15 @@ "@babel/helper-member-expression-to-functions" "^7.22.15" "@babel/helper-optimise-call-expression" "^7.22.5" +"@babel/helper-replace-supers@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz#7085bd19d4a0b7ed8f405c1ed73ccb70f323abc1" + integrity sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.23.0" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" @@ -536,6 +560,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" +"@babel/plugin-syntax-jsx@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" @@ -599,6 +630,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" +"@babel/plugin-syntax-typescript@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" @@ -607,7 +645,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.0.0-0", "@babel/plugin-transform-arrow-functions@^7.23.3": +"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.23.3": version "7.23.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz" integrity sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ== @@ -804,6 +842,15 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-simple-access" "^7.22.5" +"@babel/plugin-transform-modules-commonjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz#e71ba1d0d69e049a22bf90b3867e263823d3f1b9" + integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-simple-access" "^7.22.5" + "@babel/plugin-transform-modules-systemjs@^7.23.9": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz#105d3ed46e4a21d257f83a2f9e2ee4203ceda6be" @@ -837,7 +884,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-nullish-coalescing-operator@^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator@^7.23.4": +"@babel/plugin-transform-nullish-coalescing-operator@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz#45556aad123fc6e52189ea749e33ce090637346e" integrity sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA== @@ -853,6 +900,13 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" +"@babel/plugin-transform-object-assign@^7.16.7": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.24.1.tgz#46a70169e56970aafd13a6ae677d5b497fc227e7" + integrity sha512-I1kctor9iKtupb7jv7FyjApHCuKLBKCblVAeHVK9PB6FW7GI0ac6RtobC3MwwJy8CZ1JxuhQmnbrsqI5G8hAIg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-transform-object-rest-spread@^7.12.13": version "7.23.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz" @@ -891,7 +945,7 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.0.0-0", "@babel/plugin-transform-optional-chaining@^7.23.3", "@babel/plugin-transform-optional-chaining@^7.23.4": +"@babel/plugin-transform-optional-chaining@^7.23.3", "@babel/plugin-transform-optional-chaining@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz#6acf61203bdfc4de9d4e52e64490aeb3e52bd017" integrity sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA== @@ -1006,7 +1060,7 @@ babel-plugin-polyfill-regenerator "^0.5.5" semver "^6.3.1" -"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.0.0-0", "@babel/plugin-transform-shorthand-properties@^7.23.3": +"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.23.3": version "7.23.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz" integrity sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg== @@ -1028,7 +1082,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.0.0-0", "@babel/plugin-transform-template-literals@^7.23.3": +"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.23.3": version "7.23.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz" integrity sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg== @@ -1052,6 +1106,16 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-typescript" "^7.23.3" +"@babel/plugin-transform-typescript@^7.24.1": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz#03e0492537a4b953e491f53f2bc88245574ebd15" + integrity sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.4" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-typescript" "^7.24.1" + "@babel/plugin-transform-unicode-escapes@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz#1f66d16cab01fab98d784867d24f70c1ca65b925" @@ -1199,7 +1263,7 @@ "@babel/plugin-transform-react-jsx-development" "^7.22.5" "@babel/plugin-transform-react-pure-annotations" "^7.23.3" -"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.16.7": +"@babel/preset-typescript@^7.13.0": version "7.23.3" resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz" integrity sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ== @@ -1210,6 +1274,17 @@ "@babel/plugin-transform-modules-commonjs" "^7.23.3" "@babel/plugin-transform-typescript" "^7.23.3" +"@babel/preset-typescript@^7.16.7": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz#89bdf13a3149a17b3b2a2c9c62547f06db8845ec" + integrity sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-syntax-jsx" "^7.24.1" + "@babel/plugin-transform-modules-commonjs" "^7.24.1" + "@babel/plugin-transform-typescript" "^7.24.1" + "@babel/register@^7.13.16": version "7.23.7" resolved "https://registry.npmjs.org/@babel/register/-/register-7.23.7.tgz" @@ -1305,6 +1380,13 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@egjs/hammerjs@^2.0.17": + version "2.0.17" + resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124" + integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A== + dependencies: + "@types/hammerjs" "^2.0.36" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -1694,6 +1776,21 @@ resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@gorhom/bottom-sheet@^4": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.6.1.tgz#e45e2183246e338cf732fe4f8f2c91875b22ddce" + integrity sha512-sXqsYqX1/rAbmCC5fb9o6hwSF3KXriC0EGUGvLlhFvjaEEMBrRKFTNndiluRK1HmpUzazVaYdTm/lLkSiA2ooQ== + dependencies: + "@gorhom/portal" "1.0.14" + invariant "^2.2.4" + +"@gorhom/portal@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@gorhom/portal/-/portal-1.0.14.tgz#1953edb76aaba80fb24021dc774550194a18e111" + integrity sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A== + dependencies: + nanoid "^3.3.1" + "@graphql-typed-document-node/core@^3.1.0": version "3.2.0" resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz" @@ -2768,6 +2865,11 @@ resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz" integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== +"@types/geojson@^7946.0.13": + version "7946.0.14" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613" + integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" @@ -2775,6 +2877,11 @@ dependencies: "@types/node" "*" +"@types/hammerjs@^2.0.36": + version "2.0.45" + resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.45.tgz#ffa764bb68a66c08db6efb9c816eb7be850577b1" + integrity sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" @@ -5222,7 +5329,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.5, fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.9: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -5772,6 +5879,13 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^3.0.2: version "3.0.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d" @@ -6765,7 +6879,7 @@ jimp-compact@0.16.1: resolved "https://registry.yarnpkg.com/jimp-compact/-/jimp-compact-0.16.1.tgz#9582aea06548a2c1e04dd148d7c3ab92075aefa3" integrity sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww== -jiti@^1.21.0: +jiti@^1.18.2: version "1.21.0" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== @@ -7602,7 +7716,7 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@^3.1.23, nanoid@^3.3.7: +nanoid@^3.1.23, nanoid@^3.3.1, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== @@ -8493,7 +8607,7 @@ react-hook-form@^7.51.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@^16.13.0, react-is@^16.13.1: +react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -8517,11 +8631,29 @@ react-native-element-dropdown@^2.10.4: dependencies: lodash "^4.17.21" +react-native-gesture-handler@~2.14.0: + version "2.14.1" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.14.1.tgz#930640231024b7921435ab476aa501dd4a6b2e01" + integrity sha512-YiM1BApV4aKeuwsM6O4C2ufwewYEKk6VMXOt0YqEZFMwABBFWhXLySFZYjBSNRU2USGppJbfHP1q1DfFQpKhdA== + dependencies: + "@egjs/hammerjs" "^2.0.17" + hoist-non-react-statics "^3.3.0" + invariant "^2.2.4" + lodash "^4.17.21" + prop-types "^15.7.2" + react-native-loading-spinner-overlay@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-3.0.1.tgz#092481b8cce157d3af5ef942f845ad981f96bd36" integrity sha512-4GdR54HQnKg2HPSSisVizfTLuyhSh4splY9eb8mKiYF1Ihjn/5EmdNo5bN3S7uKPFRC3WLzIZIouX6G6fXfnjw== +react-native-maps@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-1.10.0.tgz#1b78270473f4caadc5ff8e8400285b6db9f14e12" + integrity sha512-Zs6lHZucEijTwkRVFyInMbPVkJ2UudDEI2fJPc8ArdzdnwDFAdL6OagqTjNRZyI1DBPHRihazfIWpy2+X1VwLg== + dependencies: + "@types/geojson" "^7946.0.13" + react-native-open-maps@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/react-native-open-maps/-/react-native-open-maps-0.4.3.tgz#767c6621dcf558241afe78a62c5f7924031f270e" @@ -8529,16 +8661,12 @@ react-native-open-maps@^0.4.3: dependencies: query-string "^7.1.0" -react-native-reanimated@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-3.8.1.tgz#45c13d4bedebef8df3d5a8756f25072de65960d7" - integrity sha512-EdM0vr3JEaNtqvstqESaPfOBy0gjYBkr1iEolWJ82Ax7io8y9OVUIphgsLKTB36CtR1XtmBw0RZVj7KArc7ZVA== +react-native-reanimated@~3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-3.6.3.tgz#859cf2320e37c80e3a21e19db24f82c34d6d3ded" + integrity sha512-2KkkPozoIvDbJcHuf8qeyoLROXQxizSi+2CTCkuNVkVZOxxY4B0Omvgq61aOQhSZUh/649x1YHoAaTyGMGDJUw== dependencies: - "@babel/plugin-transform-arrow-functions" "^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-object-assign" "^7.16.7" "@babel/preset-typescript" "^7.16.7" convert-source-map "^2.0.0" invariant "^2.2.4" @@ -9638,20 +9766,20 @@ tailwind-merge@^2.2.2: dependencies: "@babel/runtime" "^7.24.0" -tailwindcss@3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.3.tgz#be48f5283df77dfced705451319a5dffb8621519" - integrity sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A== +tailwindcss@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3" + integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.3.0" + fast-glob "^3.2.12" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.21.0" + jiti "^1.18.2" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" @@ -9663,6 +9791,7 @@ tailwindcss@3.4.3: postcss-load-config "^4.0.1" postcss-nested "^6.0.1" postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" resolve "^1.22.2" sucrase "^3.32.0"