diff --git a/apps/expo/app/(app)/current-pack/[id].tsx b/apps/expo/app/(app)/current-pack/[id].tsx index b7412516ca..db114c3fe7 100644 --- a/apps/expo/app/(app)/current-pack/[id].tsx +++ b/apps/expo/app/(app)/current-pack/[id].tsx @@ -15,8 +15,8 @@ import { getRelativeTime } from 'expo-app/lib/utils/getRelativeTime'; import type { PackItem } from 'expo-app/types'; import { useLocalSearchParams } from 'expo-router'; import type React from 'react'; -import { Platform, ScrollView, View } from 'react-native'; -import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; +import { ScrollView, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; function WeightCard({ title, @@ -132,20 +132,17 @@ export default function CurrentPackScreen() { const pack = usePackDetailsFromStore(params.id as string); const uniqueCategories = computeCategorySummaries(pack); - const insets = useSafeAreaInsets(); return ( - + - + diff --git a/apps/expo/app/(app)/gear-inventory.tsx b/apps/expo/app/(app)/gear-inventory.tsx index 980c9f21d2..f2fa21b2ed 100644 --- a/apps/expo/app/(app)/gear-inventory.tsx +++ b/apps/expo/app/(app)/gear-inventory.tsx @@ -47,9 +47,9 @@ export default function GearInventoryScreen() { const itemsByCategory = groupByCategory(items); return ( - + - + {t('packs.itemsInInventory', { count: items?.length })} diff --git a/apps/expo/app/(app)/pack-stats/[id].tsx b/apps/expo/app/(app)/pack-stats/[id].tsx index 85809d1af3..3277f6d134 100644 --- a/apps/expo/app/(app)/pack-stats/[id].tsx +++ b/apps/expo/app/(app)/pack-stats/[id].tsx @@ -7,6 +7,7 @@ import { computeCategorySummaries } from 'expo-app/features/packs/utils'; import { useTranslation } from 'expo-app/lib/hooks/useTranslation'; import { useLocalSearchParams } from 'expo-router'; import { ScrollView, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; export default function PackStatsScreen() { const params = useLocalSearchParams(); @@ -30,10 +31,10 @@ export default function PackStatsScreen() { })); return ( - + {weightHistory || CATEGORY_DISTRIBUTION ? ( - + {/* Weight History Section */} {WEIGHT_HISTORY && ( @@ -157,6 +158,6 @@ export default function PackStatsScreen() { {t('packs.noStatsAvailable')} )} - + ); } diff --git a/apps/expo/app/(app)/recent-packs.tsx b/apps/expo/app/(app)/recent-packs.tsx index 8c0fc21734..20fa2db13a 100644 --- a/apps/expo/app/(app)/recent-packs.tsx +++ b/apps/expo/app/(app)/recent-packs.tsx @@ -6,6 +6,7 @@ import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme'; import { useTranslation } from 'expo-app/lib/hooks/useTranslation'; import { getRelativeTime } from 'expo-app/lib/utils/getRelativeTime'; import { Image, ScrollView, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; function RecentPackCard({ pack }: { pack: Pack }) { const { colors } = useColorScheme(); @@ -58,10 +59,10 @@ export default function RecentPacksScreen() { const { t } = useTranslation(); return ( - + {recentPacks.length ? ( - + {t('packs.recentlyUpdated')} @@ -81,6 +82,6 @@ export default function RecentPacksScreen() { )} - + ); } diff --git a/apps/expo/app/(app)/shared-packs.tsx b/apps/expo/app/(app)/shared-packs.tsx index bc6132c563..76ab6cf6ed 100644 --- a/apps/expo/app/(app)/shared-packs.tsx +++ b/apps/expo/app/(app)/shared-packs.tsx @@ -8,6 +8,7 @@ import { import { cn } from 'expo-app/lib/cn'; import { useTranslation } from 'expo-app/lib/hooks/useTranslation'; import { ScrollView, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; // Mock data for shared packs const SHARED_PACKS = [ @@ -179,9 +180,9 @@ function SharedPackCard({ pack }: { pack: (typeof SHARED_PACKS)[0] }) { export default function SharedPacksScreen() { const { t } = useTranslation(); return ( - <> + - + {t('packs.collaborateOnPacks')} @@ -210,6 +211,6 @@ export default function SharedPacksScreen() { {t('packs.sharingBenefit3')} - + ); } diff --git a/apps/expo/app/(app)/shopping-list.tsx b/apps/expo/app/(app)/shopping-list.tsx index f0f2c25381..931afdd7e4 100644 --- a/apps/expo/app/(app)/shopping-list.tsx +++ b/apps/expo/app/(app)/shopping-list.tsx @@ -8,6 +8,7 @@ import { useTranslation } from 'expo-app/lib/hooks/useTranslation'; import type { TranslationKeys } from 'expo-app/lib/i18n/types'; import { useState } from 'react'; import { Pressable, ScrollView, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; // Mock data for shopping list const SHOPPING_LIST = [ @@ -168,9 +169,9 @@ export default function ShoppingListScreen() { }); return ( - <> + - + @@ -251,6 +252,6 @@ export default function ShoppingListScreen() { • Compare prices across multiple retailers before purchasing - + ); } diff --git a/apps/expo/app/(app)/trail-conditions.tsx b/apps/expo/app/(app)/trail-conditions.tsx index dded885c76..984a7cf2f3 100644 --- a/apps/expo/app/(app)/trail-conditions.tsx +++ b/apps/expo/app/(app)/trail-conditions.tsx @@ -7,7 +7,7 @@ import type { TrailConditionReport, TrailSurface } from 'expo-app/features/trail import { useTranslation } from 'expo-app/lib/hooks/useTranslation'; import { useMemo, useState } from 'react'; import { FlatList, Modal, Pressable, ScrollView, View } from 'react-native'; -import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; +import { SafeAreaView } from 'react-native-safe-area-context'; type SurfaceFilter = TrailSurface | 'all'; @@ -40,7 +40,6 @@ export default function TrailConditionsScreen() { const [selectedSurface, setSelectedSurface] = useState('all'); const { data: reports, isLoading, error } = useTrailConditionReports(); const { t } = useTranslation(); - const insets = useSafeAreaInsets(); const SURFACE_FILTERS: FilterItem[] = useMemo( () => [ @@ -160,7 +159,7 @@ export default function TrailConditionsScreen() { ); return ( - + ( @@ -186,6 +185,7 @@ export default function TrailConditionsScreen() { ListFooterComponent={listFooter} ListEmptyComponent={listEmptyComponent} contentContainerClassName="pb-4" + contentInsetAdjustmentBehavior="automatic" /> {/* Submit Report Modal */} diff --git a/apps/expo/app/(app)/weather-alerts.tsx b/apps/expo/app/(app)/weather-alerts.tsx index fffe578cb3..c02838c9a4 100644 --- a/apps/expo/app/(app)/weather-alerts.tsx +++ b/apps/expo/app/(app)/weather-alerts.tsx @@ -133,9 +133,9 @@ export default function WeatherAlertsScreen() { const { alerts, loading, error, activeLocation } = useWeatherAlerts(); return ( - + - + + - + { if (Platform.OS === 'android') { @@ -10,14 +9,8 @@ export const LargeTitleHeaderOverlapFixIOS = ({ children }: { children?: React.R } } - const insets = useSafeAreaInsets(); - return ( - + {children} {!children && } diff --git a/apps/expo/features/ai/screens/ReportedContentScreen.tsx b/apps/expo/features/ai/screens/ReportedContentScreen.tsx index b277eec3fe..b7e98df99d 100644 --- a/apps/expo/features/ai/screens/ReportedContentScreen.tsx +++ b/apps/expo/features/ai/screens/ReportedContentScreen.tsx @@ -34,144 +34,147 @@ export default function ReportedContentScreen() { - - setSelectedFilter('pending')} - /> - setSelectedFilter('reviewed')} - /> - setSelectedFilter('dismissed')} - /> - setSelectedFilter('all')} - /> - + item.id.toString()} + contentContainerClassName="p-4" + contentInsetAdjustmentBehavior="automatic" + ListHeaderComponent={ + + setSelectedFilter('pending')} + /> + setSelectedFilter('reviewed')} + /> + setSelectedFilter('dismissed')} + /> + setSelectedFilter('all')} + /> + + } + ListEmptyComponent={ + isLoading ? ( + + + + ) : error ? ( + + + {t('ai.reportedContent.errorLoading')} + + + ) : ( + + + + {t('ai.reportedContent.noReportsFound')} + + + ) + } + renderItem={({ item }) => ( + + + {item.user.firstName} + + {new Date(item.createdAt).toLocaleDateString()} + + - {isLoading ? ( - - - - ) : error ? ( - - - {t('ai.reportedContent.errorLoading')} - - - ) : filteredData?.length === 0 ? ( - - - - {t('ai.reportedContent.noReportsFound')} - - - ) : ( - item.id.toString()} - contentContainerClassName="p-4" - renderItem={({ item }) => ( - - - {item.user.firstName} - - {new Date(item.createdAt).toLocaleDateString()} + {/* Report reason badge */} + + + + {t( + reportReasonTranslationKeys[ + item.reason as keyof typeof reportReasonTranslationKeys + ], + )} + - {/* Report reason badge */} - - - - {t( - reportReasonTranslationKeys[ - item.reason as keyof typeof reportReasonTranslationKeys - ], - )} - - + {/* User Query Section */} + + + {t('ai.reportedContent.userQuery')} + + + {item.userQuery} + - {/* User Query Section */} - - - {t('ai.reportedContent.userQuery')} - - - {item.userQuery} - + {/* AI Response Section */} + + + {t('ai.reportedContent.aiResponse')} + + + {item.aiResponse} + - {/* AI Response Section */} + {/* User Comment Section - only show if there is a comment */} + {item.userComment && ( - {t('ai.reportedContent.aiResponse')} + {t('ai.reportedContent.userComment')} - - {item.aiResponse} - - - - {/* User Comment Section - only show if there is a comment */} - {item.userComment && ( - - - {t('ai.reportedContent.userComment')} + + + {item.userComment} - - - {item.userComment} - - - )} + + )} - {item.status === 'pending' ? ( - - - - - ) : ( - - - {item.status === 'resolved' - ? t('ai.reportedContent.resolved') - : t('ai.reportedContent.dismissed')} - - - )} - - )} - /> - )} + {item.status === 'pending' ? ( + + + + + ) : ( + + + {item.status === 'resolved' + ? t('ai.reportedContent.resolved') + : t('ai.reportedContent.dismissed')} + + + )} + + )} + /> ); } diff --git a/apps/expo/features/catalog/screens/CatalogItemsScreen.tsx b/apps/expo/features/catalog/screens/CatalogItemsScreen.tsx index 4fe67890bf..e7a3dc89a9 100644 --- a/apps/expo/features/catalog/screens/CatalogItemsScreen.tsx +++ b/apps/expo/features/catalog/screens/CatalogItemsScreen.tsx @@ -223,6 +223,7 @@ function CatalogItemsScreen() { onEndReached={loadMore} onEndReachedThreshold={0.5} contentContainerStyle={{ flexGrow: 1, padding: 16 }} + contentInsetAdjustmentBehavior="automatic" ListFooterComponent={ <> diff --git a/apps/expo/features/feed/screens/FeedScreen.tsx b/apps/expo/features/feed/screens/FeedScreen.tsx index 0b50985786..43067d4019 100644 --- a/apps/expo/features/feed/screens/FeedScreen.tsx +++ b/apps/expo/features/feed/screens/FeedScreen.tsx @@ -106,6 +106,7 @@ export const FeedScreen = () => { renderItem={renderItem} keyExtractor={(item) => String(item.id)} contentContainerStyle={{ paddingHorizontal: 16, paddingTop: 8, paddingBottom: 24 }} + contentInsetAdjustmentBehavior="automatic" refreshControl={} onEndReached={handleLoadMore} onEndReachedThreshold={0.3} diff --git a/apps/expo/features/guides/screens/GuidesListScreen.tsx b/apps/expo/features/guides/screens/GuidesListScreen.tsx index 928a52746c..847b9a7538 100644 --- a/apps/expo/features/guides/screens/GuidesListScreen.tsx +++ b/apps/expo/features/guides/screens/GuidesListScreen.tsx @@ -216,6 +216,7 @@ export const GuidesListScreen = () => { renderItem={renderGuide} ListHeaderComponent={listHeader} contentContainerStyle={{ paddingHorizontal: 16, flexGrow: 1 }} + contentInsetAdjustmentBehavior="automatic" refreshControl={ item.id} + contentInsetAdjustmentBehavior="automatic" renderItem={({ item }) => ( diff --git a/apps/expo/features/packs/screens/PackDetailScreen.tsx b/apps/expo/features/packs/screens/PackDetailScreen.tsx index 0ed7252c7f..dcb9fe8757 100644 --- a/apps/expo/features/packs/screens/PackDetailScreen.tsx +++ b/apps/expo/features/packs/screens/PackDetailScreen.tsx @@ -453,7 +453,7 @@ export function PackDetailScreen() { } return ( - + {pack.image && ( diff --git a/apps/expo/features/packs/screens/PackItemDetailScreen.tsx b/apps/expo/features/packs/screens/PackItemDetailScreen.tsx index bb3fbaa18f..c1b67368a9 100644 --- a/apps/expo/features/packs/screens/PackItemDetailScreen.tsx +++ b/apps/expo/features/packs/screens/PackItemDetailScreen.tsx @@ -49,7 +49,7 @@ export function ItemDetailScreen() { // Loading state for non-owned items if (!isOwnedByUser && isLoading) { return ( - + @@ -60,7 +60,7 @@ export function ItemDetailScreen() { // Error state for non-owned packs if (!isOwnedByUser && isError) { return ( - + @@ -86,7 +86,7 @@ export function ItemDetailScreen() { if (!isDefined(item)) { return ( - + @@ -134,7 +134,7 @@ export function ItemDetailScreen() { }; return ( - + diff --git a/apps/expo/features/packs/screens/PackListScreen.tsx b/apps/expo/features/packs/screens/PackListScreen.tsx index 5985ffcd80..0236d0c2b2 100644 --- a/apps/expo/features/packs/screens/PackListScreen.tsx +++ b/apps/expo/features/packs/screens/PackListScreen.tsx @@ -30,6 +30,7 @@ import { TouchableOpacity, View, } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { useAllPacks } from '../hooks/useAllPacks'; import { usePacks } from '../hooks/usePacks'; import type { Pack, PackCategory, PackInStore } from '../types'; @@ -186,117 +187,120 @@ export function PackListScreen() { }; return ( - - - {searchValue ? ( - - ) : ( - - {t('packs.searchPacks')} + + + + {searchValue ? ( + + ) : ( + + {t('packs.searchPacks')} + + )} + + ), + }} + rightView={() => } + /> + + pack.id} + stickyHeaderIndices={[0]} + contentInsetAdjustmentBehavior="automatic" + renderItem={({ item: pack }) => ( + + + + )} + refreshControl={ + selectedTypeIndex === ALL_PACKS_INDEX ? ( + + ) : undefined + } + ListHeaderComponent={ + + {!isAuthenticated && } + {isAuthenticated && ( + + { + setSelectedTypeIndex(index); + }} + /> )} - - ), - }} - rightView={() => } - /> - - pack.id} - stickyHeaderIndices={[0]} - renderItem={({ item: pack }) => ( - - - - )} - refreshControl={ - selectedTypeIndex === ALL_PACKS_INDEX ? ( - - ) : undefined - } - ListHeaderComponent={ - - {!isAuthenticated && } - {isAuthenticated && ( - - { - setSelectedTypeIndex(index); - }} - /> + + + {filterOptions.map(renderFilterChip)} + - )} - - - {filterOptions.map(renderFilterChip)} - + {selectedTypeIndex === USER_PACKS_INDEX && ( + + + {filteredPacks?.length || 0} {filteredPacks?.length === 1 ? 'pack' : 'packs'} + + + )} - {selectedTypeIndex === USER_PACKS_INDEX && ( - - - {filteredPacks?.length || 0} {filteredPacks?.length === 1 ? 'pack' : 'packs'} + } + ListEmptyComponent={ + selectedTypeIndex === ALL_PACKS_INDEX ? ( + renderAllPacksEmptyState() + ) : ( + + + + + + {t('packs.noPacksFound')} - - )} - - } - ListEmptyComponent={ - selectedTypeIndex === ALL_PACKS_INDEX ? ( - renderAllPacksEmptyState() - ) : ( - - - - - - {t('packs.noPacksFound')} - - - {activeFilter === 'all' - ? "You haven't created or found any public packs yet." - : `You don't have any ${activeFilter} packs.`} - - - - {t('packs.createNewPack')} + + {activeFilter === 'all' + ? "You haven't created or found any public packs yet." + : `You don't have any ${activeFilter} packs.`} - - - ) - } - ListFooterComponent={} - contentContainerStyle={{ flexGrow: 1 }} - /> - + + + {t('packs.createNewPack')} + + + + ) + } + ListFooterComponent={} + contentContainerStyle={{ flexGrow: 1 }} + /> + + ); } diff --git a/apps/expo/features/trips/screens/TripListScreen.tsx b/apps/expo/features/trips/screens/TripListScreen.tsx index d97a158f8a..0eb9b8d38a 100644 --- a/apps/expo/features/trips/screens/TripListScreen.tsx +++ b/apps/expo/features/trips/screens/TripListScreen.tsx @@ -9,6 +9,7 @@ import { asNonNullableRef } from 'expo-app/lib/utils/asNonNullableRef'; import { Link, useRouter } from 'expo-router'; import { useCallback, useMemo, useRef, useState } from 'react'; import { FlatList, Pressable, ScrollView, Text, TouchableOpacity, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { TripCard } from '../components/TripCard'; import { useTrips } from '../hooks'; import type { Trip } from '../types'; @@ -148,7 +149,7 @@ export function TripsListScreen() { }; return ( - <> + trip.id} ListHeaderComponent={} + contentInsetAdjustmentBehavior="automatic" renderItem={({ item: trip }) => ( @@ -179,6 +181,6 @@ export function TripsListScreen() { ListFooterComponent={} contentContainerStyle={{ flexGrow: 1 }} /> - + ); } diff --git a/apps/expo/features/weather/screens/LocationsScreen.tsx b/apps/expo/features/weather/screens/LocationsScreen.tsx index 62db89a680..1c48d033b2 100644 --- a/apps/expo/features/weather/screens/LocationsScreen.tsx +++ b/apps/expo/features/weather/screens/LocationsScreen.tsx @@ -1,5 +1,6 @@ import { Button, LargeTitleHeader, Text } from '@packrat/ui/nativewindui'; import { Icon } from 'expo-app/components/Icon'; +import { LargeTitleHeaderOverlapFixIOS } from 'expo-app/components/LargeTitleHeaderOverlapFixIOS'; import { SearchInput } from 'expo-app/components/SearchInput'; import { withAuthWall } from 'expo-app/features/auth/hocs'; import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme'; @@ -11,7 +12,6 @@ import { ActivityIndicator, Alert, Keyboard, - Platform, Pressable, RefreshControl, ScrollView, @@ -117,133 +117,136 @@ function LocationsScreen() { const showLocationsList = filteredLocations.length > 0; return ( - - ( - - - - )} - /> - - - setIsSearchFocused(true)} - onBlur={() => { - // Only unfocus if search is empty - if (searchQuery.length === 0) { - setIsSearchFocused(false); - } - }} + + + ( + + + + )} /> - - - {showNoSearchResults && ( - - - {t('weather.searchResults')} - - - - - {t('weather.noLocationsMatch', { query: searchQuery })} + + + setIsSearchFocused(true)} + onBlur={() => { + // Only unfocus if search is empty + if (searchQuery.length === 0) { + setIsSearchFocused(false); + } + }} + /> + + + {showNoSearchResults && ( + + + {t('weather.searchResults')} - - - {t('weather.clearSearch')} - - - {t('weather.addNewLocation')} - + + + + {t('weather.noLocationsMatch', { query: searchQuery })} + + + + {t('weather.clearSearch')} + + + {t('weather.addNewLocation')} + + + + )} + + {isLoading ? ( + + + {t('weather.loadingWeatherData')} - - )} + ) : ( + + } + keyboardShouldPersistTaps="handled" + > + {showLocationsList && ( + <> + {showSearchResults && ( + + + {filteredLocations.length}{' '} + {filteredLocations.length === 1 ? t('weather.result') : t('weather.results')} + + + )} - {isLoading ? ( - - - {t('weather.loadingWeatherData')} - - ) : ( - - } - keyboardShouldPersistTaps="handled" - > - {showLocationsList && ( - <> - {showSearchResults && ( - - {filteredLocations.length}{' '} - {filteredLocations.length === 1 ? t('weather.result') : t('weather.results')} + + {t('weather.longPressForOptions')} - )} - - - {t('weather.longPressForOptions')} + {filteredLocations.map((location) => ( + handleLocationPress(location.id)} + onSetActive={() => handleSetActive(location.id)} + onRemove={() => handleRemoveLocation(location.id)} + /> + ))} + + )} + + {showEmptyState && ( + + + + {t('weather.noSavedLocations')} + + + {t('weather.noSavedLocationsDesc')} + - - {filteredLocations.map((location) => ( - handleLocationPress(location.id)} - onSetActive={() => handleSetActive(location.id)} - onRemove={() => handleRemoveLocation(location.id)} - /> - ))} - - )} - - {showEmptyState && ( - - - - {t('weather.noSavedLocations')} - - - {t('weather.noSavedLocationsDesc')} - - - - )} - - )} + )} + + )} + ); } diff --git a/apps/expo/features/wildlife/screens/WildlifeScreen.tsx b/apps/expo/features/wildlife/screens/WildlifeScreen.tsx index 00aad4b253..c48d234e17 100644 --- a/apps/expo/features/wildlife/screens/WildlifeScreen.tsx +++ b/apps/expo/features/wildlife/screens/WildlifeScreen.tsx @@ -105,6 +105,7 @@ export function WildlifeScreen() { handleHistoryItemPress(item)} /> )} contentContainerStyle={{ paddingBottom: 24 }} + contentInsetAdjustmentBehavior="automatic" /> ) : (