diff --git a/apps/expo/features/catalog/screens/AddCatalogItemDetailsScreen.tsx b/apps/expo/features/catalog/screens/AddCatalogItemDetailsScreen.tsx index cedaffedec..6d6ebf694a 100644 --- a/apps/expo/features/catalog/screens/AddCatalogItemDetailsScreen.tsx +++ b/apps/expo/features/catalog/screens/AddCatalogItemDetailsScreen.tsx @@ -22,6 +22,7 @@ import { View, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; +import { CatalogItemImage } from '../components/CatalogItemImage'; import { useCatalogItemDetails } from '../hooks'; import { cacheCatalogItemImage } from '../lib/cacheCatalogItemImage'; import type { CatalogItem } from '../types'; @@ -140,53 +141,48 @@ export function AddCatalogItemDetailsScreen() { > - - {catalogItem.name} - {catalogItem.description} - - - - - {catalogItem.weight} {catalogItem.weightUnit} + + + + + + {t('catalog.adding')} - - {catalogItem.brand && ( - - - {catalogItem.brand} + + {catalogItem.name} + + + + + {catalogItem.weight} {catalogItem.weightUnit} + + {catalogItem.brand && ( + <> + + {catalogItem.brand} + + )} - )} + {/* Selected Pack */} - - - {t('catalog.selectedPack')} - {pack.name} - - - - {pack.items.length}{' '} - {pack.items.length === 1 ? t('catalog.item') : t('catalog.items')} - - - {pack.category} - - - + {t('catalog.selectedPack')} + {pack.name} + + + + {pack.items.length}{' '} + {pack.items.length === 1 ? t('catalog.item') : t('catalog.items')} + + + {pack.category} diff --git a/apps/expo/features/catalog/screens/CatalogItemDetailScreen.tsx b/apps/expo/features/catalog/screens/CatalogItemDetailScreen.tsx index 2d164b6859..82c09368ff 100644 --- a/apps/expo/features/catalog/screens/CatalogItemDetailScreen.tsx +++ b/apps/expo/features/catalog/screens/CatalogItemDetailScreen.tsx @@ -62,7 +62,7 @@ export function CatalogItemDetailScreen() { } return ( - + + + + {t('catalog.noPacksAvailable')} + + + {t('catalog.createPackMessage')} + + + + ); + return ( - - {catalogItem && ( - - - - - {t('catalog.adding')} - - {catalogItem.name} + + {/* Fixed: search + count label always visible */} + + + {filteredPacks.length > 0 && ( + + {t('catalog.selectPack', { count: filteredPacks.length })} + + )} + + + item.id} + ListEmptyComponent={ + searchQuery.trim() !== '' ? ( + + + {t('catalog.noPacksFound')} - - - - {catalogItem.weight} {catalogItem.weightUnit} - - {catalogItem.brand && ( - <> - - {catalogItem.brand} - - )} - - - - )} - - - - - - - {filteredPacks && filteredPacks.length > 0 ? ( - <> - - {t('catalog.selectPack', { count: filteredPacks.length })} - - item.id} - renderItem={({ item }) => ( - handlePackSelect(item.id)} - activeOpacity={0.7} - > - - - - - {item.name} - - - - - - {item.items?.length}{' '} - {item.items?.length === 1 ? t('catalog.item') : t('catalog.items')} - - - - - - {item.baseWeight?.toFixed(2)} g - - - - - - {item.category} - - - - - + ) : ( + EmptyState + ) + } + renderItem={({ item }) => ( + handlePackSelect(item.id)} + activeOpacity={0.7} + > + + + + + {item.name} + + + + + + {item.items?.length}{' '} + {item.items?.length === 1 ? t('catalog.item') : t('catalog.items')} + + + + + + {item.baseWeight?.toFixed(2)} g + + + + + + {item.category} + - - )} - ListEmptyComponent={ - - - {t('catalog.noPacksFound')} - - } - /> - - ) : ( - - - - {t('catalog.noPacksAvailable')} - - - {t('catalog.createPackMessage')} - - - + + + + )} - + contentContainerStyle={{ paddingBottom: 24 }} + /> ); } diff --git a/apps/expo/lib/api/getBaseUrl.ts b/apps/expo/lib/api/getBaseUrl.ts new file mode 100644 index 0000000000..8196bb0435 --- /dev/null +++ b/apps/expo/lib/api/getBaseUrl.ts @@ -0,0 +1,10 @@ +import { clientEnvs } from '@packrat/env/expo-client'; +import { Platform } from 'react-native'; + +export function getApiBaseUrl(): string { + const url = clientEnvs.EXPO_PUBLIC_API_URL; + if (Platform.OS === 'android') { + return url.split('localhost').join('10.0.2.2'); + } + return url; +} diff --git a/apps/expo/lib/api/packrat.ts b/apps/expo/lib/api/packrat.ts index 94ae708bc5..cf85382b93 100644 --- a/apps/expo/lib/api/packrat.ts +++ b/apps/expo/lib/api/packrat.ts @@ -1,8 +1,8 @@ import { createApiClient } from '@packrat/api-client'; -import { clientEnvs } from '@packrat/env/expo-client'; import { fromZod } from '@packrat/guards'; import { store } from 'expo-app/atoms/store'; import { needsReauthAtom } from 'expo-app/features/auth/atoms/authAtoms'; +import { getApiBaseUrl } from 'expo-app/lib/api/getBaseUrl'; import { authClient } from 'expo-app/lib/auth-client'; import * as SecureStore from 'expo-secure-store'; import { z } from 'zod'; @@ -27,7 +27,7 @@ function parseSessionToken(cookieJson: string | null): string | null { } export const apiClient = createApiClient({ - baseUrl: clientEnvs.EXPO_PUBLIC_API_URL, + baseUrl: getApiBaseUrl(), auth: { // Read the token from SecureStore — no network call on every API request. getAccessToken: async () => { diff --git a/apps/expo/lib/auth-client.ts b/apps/expo/lib/auth-client.ts index b685923235..f2556aee28 100644 --- a/apps/expo/lib/auth-client.ts +++ b/apps/expo/lib/auth-client.ts @@ -1,10 +1,10 @@ import { expoClient } from '@better-auth/expo/client'; -import { clientEnvs } from '@packrat/env/expo-client'; import { createAuthClient } from 'better-auth/react'; +import { getApiBaseUrl } from 'expo-app/lib/api/getBaseUrl'; import * as SecureStore from 'expo-secure-store'; export const authClient = createAuthClient({ - baseURL: clientEnvs.EXPO_PUBLIC_API_URL, + baseURL: getApiBaseUrl(), plugins: [ expoClient({ scheme: 'packrat', diff --git a/apps/expo/lib/i18n/locales/en.json b/apps/expo/lib/i18n/locales/en.json index dd81640f75..8f960aee78 100644 --- a/apps/expo/lib/i18n/locales/en.json +++ b/apps/expo/lib/i18n/locales/en.json @@ -233,7 +233,7 @@ "createPack": "Create Pack", "editPack": "Edit Pack", "noPacks": "No packs available", - "packName": "Pack Name", + "packName": "Choose a Pack", "packDescription": "Pack Description", "packWeight": "Pack Weight", "packItems": "Pack Items",