diff --git a/app/(tabs)/events.tsx b/app/(tabs)/events.tsx index 1b9db16..8db5c9f 100644 --- a/app/(tabs)/events.tsx +++ b/app/(tabs)/events.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; import { View, Text, FlatList, TouchableOpacity, SafeAreaView, StyleSheet } from 'react-native'; +import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Modal, Pressable } from 'react-native'; import BadgeSvg from '../../assets/images/badge.svg'; import BadgeBackSvg from '../../assets/images/badgeback.svg'; @@ -10,16 +11,15 @@ import { getWeekday, formatAMPM } from '@/lib/utils'; import { api } from '@/api/api'; import { LinearGradient } from 'expo-linear-gradient'; import LottieView from 'lottie-react-native'; -import { Header } from '@/components/home/Header'; -import { DayTabs } from '@/components/events/DayTabs'; -import { EventListItem } from '@/components/events/EventListItem'; +import { Swipeable } from 'react-native-gesture-handler'; +import { Ionicons } from '@expo/vector-icons'; const dayTabs = [ - { label: 'TUE', dayNumber: 2, barColor: '#4F0202' }, - { label: 'WED', dayNumber: 3, barColor: '#831C1C' }, - { label: 'THU', dayNumber: 4, barColor: '#B60000' }, - { label: 'FRI', dayNumber: 5, barColor: '#E20303' }, - { label: 'SAT', dayNumber: 6, barColor: '#EF3F3F' }, + { label: 'WED', dayNumber: 3, barColor: '#4F0202' }, + { label: 'THU', dayNumber: 4, barColor: '#831C1C' }, + { label: 'FRI', dayNumber: 5, barColor: '#B60000' }, + { label: 'SAT', dayNumber: 6, barColor: '#E20303' }, + { label: 'SUN', dayNumber: 0, barColor: '#EF3F3F' }, ]; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); @@ -36,14 +36,56 @@ const typeColors = { const EventsScreen = () => { const [events, setEvents] = useState([]); + const [user, setUser] = useState(null); + const [flaggedIds, setFlaggedIds] = useState>(new Set()); const [loading, setLoading] = useState(true); - const [selectedDay, setSelectedDay] = useState(2); + const [selectedDay, setSelectedDay] = useState(3); const [selectedEvent, setSelectedEvent] = useState(null); const [error, setError] = useState(null); const slideY = useRef(new Animated.Value(-SCREEN_HEIGHT)).current; - const itemAnimations = useRef>({}); - const [user, setUser] = useState(null); - const [flaggedIds, setFlaggedIds] = useState>(new Set()); + + // fetch current user and favorites + useEffect(() => { + const fetchUser = async () => { + const resp = await api.get('/auth/info'); + setUser(resp.data); + }; + fetchUser(); + }, []); + useEffect(() => { + const fetchFavorites = async () => { + if (!user?.userId) return; + try { + const favResp = await api.get('/attendee/favorites', { params: { userId: user.userId } }); + const data: any = favResp.data; + const favs: string[] = data.favoriteEvents; + setFlaggedIds(new Set(favs)); + } catch (e) { + console.error('Failed to fetch favorites:', e); + } + }; + fetchFavorites(); + }, [user?.userId]); + + // toggle flag via swipe + const toggleFlag = async (eventId: string) => { + if (!user?.userId) return; + const route = path('/attendee/favorites/:eventId', { eventId }); + try { + let res; + if (!flaggedIds.has(eventId)) { + res = await api.post(route, { userId: user.userId }); + } else { + res = await api.delete(route, { data: { userId: user.userId } }); + } + if (res.status === 200) { + const updated: string[] = (res.data as any).favorites || []; + setFlaggedIds(new Set(updated)); + } + } catch (e) { + console.error('Failed to toggle favorite:', e); + } + }; // ADD const CARD_W = SCREEN_WIDTH * 0.85; @@ -96,16 +138,6 @@ const EventsScreen = () => { } }, [selectedEvent]); - useEffect(() => { - // Initialize selected tab to today's weekday (Tue-Sat), default Tuesday - const today = new Date().getDay(); - if (today >= 2 && today <= 6) { - setSelectedDay(today); - } else { - setSelectedDay(2); - } - }, []); - useEffect(() => { const start = Date.now(); const fetchEvents = async () => { @@ -124,17 +156,6 @@ const EventsScreen = () => { fetchEvents(); }, []); - useEffect(() => { - // Fetch user info and favorites - const fetchUser = async () => { - try { - const response = await api.get('/auth/info'); - setUser(response.data); - } catch {} - }; - fetchUser(); - }, []); - const filteredEvents = events.filter((item) => { if (!item.startTime) return false; const eventDate = new Date(item.startTime); @@ -156,6 +177,84 @@ const EventsScreen = () => { }); }; + // Component for rendering each event row, allows hooks for swipeableRef + const EventRow: React.FC<{ item: Event; index: number }> = ({ item, index }) => { + const swipeableRef = useRef(null); + const renderLeft = () => ( + + + + ); + const startDate = new Date(item.startTime); + const endDate = new Date(item.endTime); + const startStr = formatAMPM(startDate); + const endStr = formatAMPM(endDate); + return ( + { + toggleFlag(item.eventId); + swipeableRef.current?.close(); + }} + > + setSelectedEvent(item)} className="mb-3"> + + {/* Remove skew for children */} + + {/* Index */} + + + {index + 1} + + + {/* Event details */} + + + {item.name} + + + {item.location} + + + + + + {startStr} + + + {endStr} + + + + + + + ); + }; + if (loading) { return ( @@ -171,16 +270,42 @@ const EventsScreen = () => { } return ( - -
+ + Events - + + {dayTabs.map((tab) => { + const isActive = tab.dayNumber === selectedDay; + return ( + setSelectedDay(tab.dayNumber)} + className={`w-[16%] h-8 flex-row items-center ${isActive ? 'bg-black' : 'bg-white'}`} + activeOpacity={0.85} + > + + + {tab.label} + + + ); + })} + {filteredEvents.length === 0 ? ( @@ -192,33 +317,13 @@ const EventsScreen = () => { keyExtractor={(item) => item.eventId} contentContainerStyle={{ paddingHorizontal: 0, paddingBottom: 100, gap: 10 }} ListFooterComponent={ - + End of Events } - renderItem={({ item, index }) => { - if (!itemAnimations.current[item.eventId]) { - itemAnimations.current[item.eventId] = new Animated.Value(0); - } - const anim = itemAnimations.current[item.eventId]; - Animated.timing(anim, { - toValue: 1, - duration: 350, - delay: index * 80, - useNativeDriver: true, - }).start(); - return ( - setSelectedEvent(item)} - /> - ); - }} - /> - )} + renderItem={({ item, index }) => } + /> + )} { height: '100%', justifyContent: 'center', alignItems: 'center', + overflow: 'hidden', + // transform: [{ translateY: slideY } ,{ perspective: 1000 },{ rotateY }], transform: [{ perspective: 1000 }, { translateY: slideY }], }} > + {/* */} { + {/* */} + + {/* */} + + {/* */} + { style={{ position: 'absolute', top: 0, left: 0 }} color={typeColors[selectedEvent?.eventType as keyof typeof typeColors]} /> - - - {getWeekday(selectedEvent?.startTime)} - - + + + {getWeekday(selectedEvent?.startTime)} + + { + e.stopPropagation?.(); toggleFlip(); }} pointerEvents="box-only" style={{ position: 'absolute', zIndex: 2, - width: CARD_W * 1.12, // Reduce width to match badge area - height: CARD_H * 0.833, // Reduce height to match badge area - top: SCREEN_HEIGHT / 2 - (CARD_H * 0.333) / 2, - left: SCREEN_WIDTH / 2 - (CARD_W * 1.12) / 2, - borderRadius: 20, + width: CARD_W, + height: CARD_H, + top: SCREEN_HEIGHT / 2 - CARD_H / 2, + left: SCREEN_WIDTH / 2 - CARD_W / 2, }} /> - + + ); }; diff --git a/app/(tabs)/home.tsx b/app/(tabs)/home.tsx index 16a29a0..6611704 100644 --- a/app/(tabs)/home.tsx +++ b/app/(tabs)/home.tsx @@ -1,5 +1,6 @@ // apps/tabs/home.tsx import React, { useState, useEffect } from 'react'; +import { useFocusEffect } from '@react-navigation/native'; import { View, StyleSheet, Dimensions, Text, Animated } from 'react-native'; import { ThemedText } from '@/components/themed/ThemedText'; import { Header } from '@/components/home/Header'; @@ -15,7 +16,6 @@ import { } from '@/components/headers/parallax'; import { LinearGradient } from 'expo-linear-gradient'; -// import HomeBar from '@/assets/home/homeBar.svg'; import BackgroundSvg from '@/assets/home/home_background.svg'; import CarSvg from '@/assets/home/home_car.svg'; import LottieView from 'lottie-react-native'; @@ -24,21 +24,18 @@ import Toast from 'react-native-toast-message'; const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); export default function HomeScreen() { - // fetched cards const [cards, setCards] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [user, setUser] = useState(null); - // flags + modal state const [flaggedIds, setFlaggedIds] = useState>(new Set()); const [modalVisible, setModalVisible] = useState(false); const [selectedEvent, setSelectedEvent] = useState(null); + const [refreshKey, setRefreshKey] = useState(0); - // scrolling lock const [scrollEnabled, setScrollEnabled] = useState(true); - // staggered section animations const sectionAnims = React.useRef([ new Animated.Value(0), new Animated.Value(0), @@ -56,6 +53,36 @@ export default function HomeScreen() { } }, [loading, cards.length]); + const fetchFavorites = async () => { + if (!user?.userId) return; + try { + const favResponse = await api.get('/attendee/favorites', { + params: { userId: user.userId }, + }); + const data: any = favResponse.data; + const favs: string[] = data.favoriteEvents; + setFlaggedIds(new Set(favs)); + setRefreshKey((prev) => prev + 1); + } catch (e) { + console.error('Failed to fetch favorites:', e); + } + }; + + useFocusEffect( + React.useCallback(() => { + if (user?.userId) { + console.log('[HomeScreen] fetching favorites on focus for user', user.userId); + fetchFavorites(); + } + }, [user?.userId]) + ); + + useEffect(() => { + if (user?.userId) { + fetchFavorites(); + } + }, [user?.userId]); + const toggleFlag = async (id: string) => { if (!user?.userId) { closeEvent(); @@ -68,15 +95,17 @@ export default function HomeScreen() { }); return; } - const response = await api.post(path('/attendee/favorites/:eventId', { eventId: id }), { - userId: user.userId, - }); + const route = path('/attendee/favorites/:eventId', { eventId: id }); + let response; + if (!flaggedIds.has(id)) { + response = await api.post(route, { userId: user.userId }); + } else { + response = await api.delete(route, { data: { userId: user.userId } }); + } if (response.status === 200) { - setFlaggedIds((prev) => { - const next = new Set(prev); - prev.has(id) ? next.delete(id) : next.add(id); - return next; - }); + const updatedFavorites: string[] = (response.data as any).favorites || []; + setFlaggedIds(new Set(updatedFavorites)); + setRefreshKey((prev) => prev + 1); } else { console.error('Failed to toggle flag:', response.data); } @@ -117,11 +146,6 @@ export default function HomeScreen() { description: event.description, })); setCards(formattedEvents); - // Only fetch favorites if user is registered - if (user?.userId) { - const favResponse = await api.get(path('/attendee/favorites', { userId: user.userId })); - setFlaggedIds(new Set(favResponse.data.favorites)); - } } catch (e: any) { console.error('Failed to fetch or process events:', e); setError(e.message || 'Failed to load events'); @@ -135,6 +159,7 @@ export default function HomeScreen() { fetchEvents(); }, [user?.userId]); + const renderHeaderNavBarComponent = () => (
@@ -276,6 +301,7 @@ export default function HomeScreen() { > flaggedIds.has(c.id))} flaggedIds={flaggedIds} onToggleFlag={toggleFlag} diff --git a/assets/images/checkeredFlag.svg b/assets/images/checkeredFlag.svg new file mode 100644 index 0000000..e69de29 diff --git a/components/home/CarouselSection.tsx b/components/home/CarouselSection.tsx index e7330fa..da0b186 100644 --- a/components/home/CarouselSection.tsx +++ b/components/home/CarouselSection.tsx @@ -54,6 +54,8 @@ export const CarouselSection: React.FC = ({ onSwipeTouchStart={onSwipeTouchStart} onSwipeTouchEnd={onSwipeTouchEnd} disableSwipeAway={displayData.length === 1} + flaggedIds={flaggedIds} + onToggleFlag={onToggleFlag} /> diff --git a/components/home/SwipeDeck.tsx b/components/home/SwipeDeck.tsx index 3a301c9..e693ba4 100644 --- a/components/home/SwipeDeck.tsx +++ b/components/home/SwipeDeck.tsx @@ -1,6 +1,7 @@ // --- SwipeDeck.tsx --- import React, { useRef, useState } from 'react'; -import { View, StyleSheet, Dimensions, StyleProp, ViewStyle, PanResponder } from 'react-native'; +import { View, StyleSheet, Dimensions, StyleProp, ViewStyle, PanResponder, TouchableOpacity } from 'react-native'; +import { Ionicons } from '@expo/vector-icons'; import Swiper from 'react-native-deck-swiper'; import { ThemedText } from '../themed/ThemedText'; @@ -24,6 +25,8 @@ interface SwipeDeckProps { onSwipeTouchStart?: () => void; onSwipeTouchEnd?: () => void; disableSwipeAway?: boolean; + flaggedIds?: Set; + onToggleFlag?: (id: string) => void; } export default function SwipeDeck({ @@ -33,6 +36,8 @@ export default function SwipeDeck({ onSwipeTouchStart = () => {}, onSwipeTouchEnd = () => {}, disableSwipeAway = false, + flaggedIds = new Set(), + onToggleFlag = () => {}, }: SwipeDeckProps) { const [cardIndex, setCardIndex] = useState(0); @@ -87,6 +92,13 @@ export default function SwipeDeck({ > {item.title} + onToggleFlag(item.id)} style={styles.flagButton}> + + RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n if ! _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\"); then\n echo \"error: Failed to parse firebase.json, check for syntax errors.\"\n exit 1\n fi\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; @@ -557,7 +459,10 @@ LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; @@ -623,7 +528,10 @@ ); LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; MTL_ENABLE_DEBUG_INFO = NO; - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true;