Skip to content

Release v2.0.17#2004

Merged
mikib0 merged 40 commits into
mainfrom
release/2.0.17
Apr 1, 2026
Merged

Release v2.0.17#2004
mikib0 merged 40 commits into
mainfrom
release/2.0.17

Conversation

@mikib0
Copy link
Copy Markdown
Collaborator

@mikib0 mikib0 commented Mar 30, 2026

This pull request introduces a new weather alert preferences feature and improves the weather alerts experience in the Expo app. It adds a dedicated screen for configuring weather alert types, integrates live weather alert data, and updates the notification settings to support weather alerts. There are also several minor improvements and bug fixes for safe area handling and UI consistency.

Weather Alerts and Preferences Improvements:

  • Added a new weather-alert-preferences screen (weather-alert-preferences.tsx) allowing users to customize which types of weather alerts they receive, with toggles for various alert categories and location monitoring.
  • Updated the weather-alerts screen to fetch real weather alert data, display loading and error states, and allow navigation to the new preferences screen. Mock data was replaced, and alert icons/colors are now determined dynamically. [1] [2] [3]
  • Added navigation routes and modal presentation for the new weather alert screens in the app layout.

Notification Settings Enhancements:

  • Extended the notifications screen to include a weather alerts toggle and a link to configure alert types, with improved UI using icons and Pressable components. [1] [2] [3]

Safe Area and UI Consistency:

Dependency and Version Updates:

  • Changed the import for expo-file-system to use the legacy version for compatibility.
  • Bumped the app version to 2.0.17.

Summary by CodeRabbit

Release Notes – Version 2.0.17

  • New Features

    • Added weather alerts management with preferences, alert-type configuration, and notification settings.
    • Added recently used and popular items quick access in catalog browser.
    • Added quantity selection when adding multiple catalog items to packs.
    • Expanded pack template import to support online content sources beyond TikTok.
  • Improvements

    • Enhanced notification preferences with weather alert controls.
    • Improved layout consistency across device types.

Copilot AI and others added 30 commits March 9, 2026 10:24
Co-authored-by: andrew-bierman <94939237+andrew-bierman@users.noreply.github.com>
…tem quantity adjustment

Co-authored-by: andrew-bierman <94939237+andrew-bierman@users.noreply.github.com>
… through guard

Co-authored-by: andrew-bierman <94939237+andrew-bierman@users.noreply.github.com>
- Clear searchValue in handleAddSelected so search resets after adding items
- Wrap addItemsToPack in try/catch with Alert feedback on failure
- Remove redundant `packId as string` cast (already typed as string)
- Remove unused i18n keys: catalog.quickAdd, catalog.adjustQuantity, catalog.tapToAdjust
…oose-from-catalog-option-again

# Conflicts:
#	apps/expo/features/catalog/components/CatalogBrowserModal.tsx
#	apps/expo/features/packs/components/AddPackItemActions.tsx
Add Share to the react-native import to resolve the TS2304
"Cannot find name 'Share'" type-check error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
chore(wrangler): add migrations for TikTokContainer to match deletion…
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
chore(api): refactor container name to AppContainer
…template-generation

fix(api): address memory limit issue in video to pack template genera…
…from-youtube

feat: support generating of pack template from youtube videos
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 30, 2026

📝 Walkthrough

Walkthrough

This PR bundles version 2.0.17 with multiple features: a weather alerts system (new screens, preferences, dynamic data from API), catalog improvements (recently-used item tracking, popular items hook, quantity selection in browser modal), safe-area inset handling across multiple screens, pack template import refactored from TikTok-only to generalized online content (supporting YouTube + TikTok via transcript fetching), Google Genai video upload integration in the backend, container/environment variable renaming (TikTokContainer → AppContainer), and localization updates.

Changes

Cohort / File(s) Summary
Version Bumps
apps/expo/app.config.ts, apps/expo/package.json, apps/guides/package.json, apps/landing/package.json, package.json, packages/api/container_src/package.json, packages/ui/package.json
Updated version from 2.0.16 to 2.0.17 across app and package manifests.
Weather Alerts Feature – UI Screens
apps/expo/app/(app)/weather-alerts.tsx, apps/expo/app/(app)/weather-alert-preferences.tsx, apps/expo/app/(app)/_layout.tsx
New weather-alerts screen with dynamic data from useWeatherAlerts() hook, new weather-alert-preferences screen with toggles for notification types and location monitoring, and new route configuration for weather-alerts with card presentation.
Weather Alerts Feature – Hooks & Utilities
apps/expo/features/weather/hooks/useWeatherAlert.ts, apps/expo/features/weather/components/WeatherAlertsTile.tsx
New hook useWeatherAlerts() that fetches dynamic weather data, generates alerts based on API or heuristic conditions (temperature/wind/condition thresholds), and exposes loading/error state; WeatherAlertsTile updated to derive count from hook instead of hardcoded value.
Notifications Screen Update
apps/expo/app/(app)/(tabs)/profile/notifications.tsx
Added weather-alerts toggle state, new FormSection for weather-alert preferences with toggle and navigation to preferences screen.
Catalog System – Recently Used Items
apps/expo/atoms/recentlyUsedCatalogItemsAtom.ts, apps/expo/features/catalog/hooks/useRecentlyUsedCatalogItems.ts
New persisted atom storing recently-used catalog items (max 10) in async storage; new hook useRecentlyUsedCatalogItems() that reads atom and provides trackRecentlyUsed() callback for updates using deduplication logic.
Catalog System – Popular Items & Hooks
apps/expo/features/catalog/hooks/usePopularCatalogItems.ts, apps/expo/features/catalog/hooks/index.ts
New hook usePopularCatalogItems(limit=10) using React Query to fetch sorted catalog items; hooks barrel export updated to include both new hooks.
Catalog Browser Modal
apps/expo/features/catalog/components/CatalogBrowserModal.tsx
Added per-item quantity selection with itemQuantities state map, "quick access" UI showing recently-used and popular items in default view, refactored selection toggling, replaced bottom action bar with SelectedItemsQuantityPanel displaying selected items with quantity controls.
Add Item Actions – Recently Used Tracking
apps/expo/features/pack-templates/components/AddPackTemplateItemActions.tsx, apps/expo/features/packs/components/AddPackItemActions.tsx
Both components now call trackRecentlyUsed() when catalog items are selected; AddPackItemActions also adds error handling with try/catch and alert UI.
Safe Area Insets – Screen Layout
apps/expo/app/(app)/current-pack/[id].tsx, apps/expo/app/(app)/weight-analysis/[id].tsx, apps/expo/features/ai-packs/screens/AIPacksScreen.tsx, apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx, apps/expo/features/weather/screens/LocationsScreen.tsx
Multiple screens updated to use useSafeAreaInsets() and apply dynamic top/bottom padding via inline styles to respect device safe areas.
Safe Area Insets – Component Updates
apps/expo/app/(app)/(tabs)/profile/index.tsx, apps/expo/features/weather/components/LocationPicker.tsx, apps/expo/features/weather/screens/LocationSearchScreen.tsx
Profile screen switched to expo-file-system/legacy; LocationPicker wrapped modal in SafeAreaView; LocationSearchScreen adjusted ref typing and focus timing.
Pack Categories UI
apps/expo/app/(app)/pack-categories/[id].tsx
Added text-center styling to empty-state message when no categories found.
Horizontal Catalog Item Card
apps/expo/features/packs/components/HorizontalCatalogItemCard.tsx
Updated container className to add unconditional bg-red utility and metadata layout to use flex-wrap with split gaps (gap-x-4 gap-y-1).
Pack Templates – Online Content Refactoring
apps/expo/features/pack-templates/components/OnlineContentImportModal.tsx, apps/expo/features/pack-templates/components/TemplateCreationOptions.tsx, apps/expo/features/pack-templates/hooks/useGenerateTemplateFromOnlineContent.ts, apps/expo/features/pack-templates/hooks/index.ts
Renamed TikTok-specific modal/hook/types to generic "online content" equivalents; updated payload field from tiktokUrl to contentUrl; hook barrel export updated.
API Backend – Container & Environment
packages/api/src/containers/AppContainer.ts, packages/api/src/containers/index.ts, packages/api/src/index.ts, packages/api/src/utils/env-validation.ts, packages/api/wrangler.jsonc
Renamed TikTokContainer to AppContainer across container class, imports, and Wrangler config; updated environment variable binding from TIKTOK_CONTAINER to APP_CONTAINER in validation schema and Durable Object configuration; added Durable Object migrations for rename/deletion.
API Backend – Online Content Generation
packages/api/src/routes/packTemplates/generateFromOnlineContent.ts, packages/api/src/routes/packTemplates/index.ts, packages/api/src/schemas/packTemplates.ts
Replaced TikTok-specific route with generalized online-content route supporting YouTube (transcript-based) and TikTok (caption/video-based); updated request schema field tiktokUrlcontentUrl; added YouTube ID detection and transcript fetching; dynamic contentSource tracking.
API Backend – Server & Dependencies
packages/api/container_src/server.ts, packages/api/container_src/package.json, packages/api/package.json, packages/api/test/setup.ts, packages/api/test/generate-from-tiktok.test.ts
Added Google Genai client initialization and video upload function; replaced Cloudflare R2 rehosting with Google file upload and active state polling; updated dependencies to include @google/genai ^1.46.0 and youtube-transcript ^1.3.0; minor TypeScript casting adjustment in test setup; comment update referencing AppContainer.
Localization
apps/expo/lib/i18n/locales/en.json
Added weather-alerts configuration strings under profile and weather sections; expanded catalog UI copy for popular/recently-used labels; replaced TikTok-specific pack-template import strings with generic online-content equivalents supporting YouTube and TikTok.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • andrew-bierman
  • Isthisanmol

🐰 A rabbit hops through code with glee,
Weather alerts and recently-used spree!
From TikTok tubes to YouTube's ways,
Safe areas shine through sunny days,
Version bumps and carts galore—
Pack the templates, let goosebumps soar! 📦⛈️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Release v2.0.17' directly matches the primary change: a version bump from 2.0.17 across all package manifests and app configuration files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/2.0.17

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
apps/expo/app/(app)/(tabs)/profile/index.tsx (3)

33-33: ⚠️ Potential issue | 🔴 Critical

Missing Linking import causes an unresolved identifier.

Line 158 calls Linking.openSettings() but Linking is not imported in Line 33, causing TS2304.

🔧 Suggested fix
-import { Alert, Platform, TouchableOpacity, View } from 'react-native';
+import { Alert, Linking, Platform, TouchableOpacity, View } from 'react-native';

Also applies to: 158-158

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/(tabs)/profile/index.tsx at line 33, The code calls
Linking.openSettings() in the Profile component but Linking is not imported,
causing an unresolved identifier; fix by adding Linking to the React Native
imports so the symbol Linking is available (update the import statement that
currently imports Alert, Platform, TouchableOpacity, View to also import
Linking) and ensure any other usages of Linking in this file reference the same
imported symbol.

213-213: ⚠️ Potential issue | 🔴 Critical

Use a typed color token for the success icon.

Line 213 uses colors.green, which is not on the current theme type and triggers TS2339. Please switch to a valid token from your theme contract (for example colors.primary or another existing success token).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/(tabs)/profile/index.tsx at line 213, The success icon
currently uses an untyped color token (materialIcon: { name:
'check-circle-outline', color: colors.green }), which causes TS2339; update the
color to a valid theme token (for example colors.primary or your theme's success
token) so it matches the theme contract. Locate the materialIcon declaration in
the profile component (the object with name 'check-circle-outline') and replace
colors.green with an existing typed token (e.g., colors.primary or
colors.success) ensuring the imported colors type includes that token. Run
TypeScript to confirm the error is resolved.

140-142: ⚠️ Potential issue | 🔴 Critical

Remove the { size: true } option from getInfoAsync()—it's unsupported and unnecessary.

The size field is always included in the returned FileInfo object in expo-file-system/legacy (v19.0.21). The InfoOptions type only supports { md5?: boolean }, making { size: true } a TypeScript error. Simply call FileSystem.getInfoAsync(image.uri) without options; the size will still be available on the result.

🔧 Suggested fix
-      const info = await FileSystem.getInfoAsync(image.uri, { size: true });
+      const info = await FileSystem.getInfoAsync(image.uri);
       if (info.exists && info.size > AVATAR_MAX_BYTES) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/(tabs)/profile/index.tsx around lines 140 - 142, The
call to FileSystem.getInfoAsync in the profile screen passes an unsupported
options object ({ size: true }); remove the options so call
FileSystem.getInfoAsync(image.uri) instead — the returned FileInfo already
includes size. Update the check that uses info.size (and AVATAR_MAX_BYTES) to
remain the same and ensure TypeScript no longer errors; no other logic changes
are needed where info and image.uri are referenced.
apps/expo/features/weather/screens/LocationsScreen.tsx (1)

122-143: ⚠️ Potential issue | 🟠 Major

Double paddingTop: insets.top causes excessive top spacing.

Both SafeAreaView (line 122) and the search container View (line 143) apply paddingTop: insets.top. This pushes the search input down by 2× the safe area inset.

🐛 Proposed fix: Remove duplicate padding from search container
-      <View className="p-4" style={{ paddingTop: insets.top }}>
+      <View className="p-4">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/weather/screens/LocationsScreen.tsx` around lines 122 -
143, The search container View (the <View className="p-4" style={{ paddingTop:
insets.top }}>) is redundantly applying paddingTop already set on the
SafeAreaView; remove the duplicate by deleting the style paddingTop from that
inner View (leave className="p-4" intact) so only SafeAreaView provides
insets.top, ensuring LargeTitleHeader and the search input are not pushed down
twice.
packages/api/container_src/server.ts (1)

36-55: ⚠️ Potential issue | 🟡 Minor

Potential issue: GoogleGenAI client initialized before environment validation.

The googleAi client is initialized at line 37-39 using process.env.GOOGLE_GENAI_API_KEY directly, but environment validation via validateEnv() happens later (line 42). If GOOGLE_GENAI_API_KEY is missing, the client will be created with an undefined API key, and the error will only surface later when upload is attempted.

Consider deferring initialization or validating the key exists first.

Proposed fix: Defer GoogleGenAI initialization
-// GoogleGenAI client (for video upload)
-const googleAi = new GoogleGenAI({
-  apiKey: process.env.GOOGLE_GENAI_API_KEY,
-});
+// GoogleGenAI client (for video upload) - initialized after env validation
+let googleAi: GoogleGenAI | null = null;

 try {
   env = validateEnv();
   s3Client = new S3Client({
     region: 'auto',
     endpoint: `https://${env.CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`,
     credentials: {
       accessKeyId: env.R2_ACCESS_KEY_ID,
       secretAccessKey: env.R2_SECRET_ACCESS_KEY,
     },
   });
   console.log('R2 client initialized successfully');
+  googleAi = new GoogleGenAI({ apiKey: env.GOOGLE_GENAI_API_KEY });
+  console.log('GoogleGenAI client initialized successfully');
 } catch (error) {
   console.warn('R2 client initialization failed:', error);
-  console.warn('Image rehosting will be disabled');
+  console.warn('Image rehosting and video upload will be disabled');
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/container_src/server.ts` around lines 36 - 55, The GoogleGenAI
client (googleAi) is being constructed before environment validation; move or
defer initialization until after validateEnv() returns so the API key is
validated, or explicitly check env.GOOGLE_GENAI_API_KEY before creating the
GoogleGenAI instance; update the code to call validateEnv() first, then create
new GoogleGenAI({ apiKey: env.GOOGLE_GENAI_API_KEY }) (or guard creation with a
conditional and handle the missing-key case) so GoogleGenAI is never
instantiated with an undefined key.
packages/api/src/routes/packTemplates/generateFromOnlineContent.ts (1)

296-308: ⚠️ Potential issue | 🔴 Critical

TypeScript error: Invalid type for Sentry captureException second argument.

The pipeline reports TS2345: Argument of type 'unknown' is not assignable to parameter of type 'EventHint | undefined' at line 298. The as unknown cast is incorrect.

Proposed fix
     } catch (apiError) {
       console.error('TikTok service call failed:', apiError);
       c.get('sentry').captureException(apiError, {
         extra: { tiktokUrl: contentUrl, errorType: 'tiktok_service_error' },
-      } as unknown);
+      });
       return c.json(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts` around
lines 296 - 308, The Sentry capture call is being passed an invalid cast (as
unknown); instead construct a properly typed EventHint and pass it to
c.get('sentry').captureException: import the EventHint type from Sentry (e.g.,
'@sentry/types' or '@sentry/node'), create const hint: EventHint = { extra: {
tiktokUrl: contentUrl, errorType: 'tiktok_service_error' } }, and call
c.get('sentry').captureException(apiError, hint). This keeps the additional
context while satisfying TypeScript for captureException.
🟡 Minor comments (9)
apps/expo/features/ai-packs/screens/AIPacksScreen.tsx-80-80 (1)

80-80: ⚠️ Potential issue | 🟡 Minor

Top inset is applied twice.

Line 80 and Line 83 both add paddingTop: insets.top, which likely creates extra vertical spacing. Keeping it on the outer SafeAreaView only should avoid the double offset.

🔧 Suggested fix
-      <View className="px-4 py-6 space-y-6" style={{ paddingTop: insets.top }}>
+      <View className="px-4 py-6 space-y-6">

Also applies to: 83-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/ai-packs/screens/AIPacksScreen.tsx` at line 80, The outer
SafeAreaView (the one with className="flex-1" and style={{ paddingTop:
insets.top }}) already applies the top inset, so remove the duplicate
paddingTop: insets.top from the inner SafeAreaView in AIPacksScreen.tsx (leave
any other styles on the inner SafeAreaView intact); ensure only the outer
SafeAreaView uses paddingTop to avoid double vertical offset.
apps/expo/features/weather/screens/LocationsScreen.tsx-14-14 (1)

14-14: ⚠️ Potential issue | 🟡 Minor

Unused Platform import and headerPaddingTop variable.

Platform is imported (line 14) and used to compute headerPaddingTop (line 119), but this value is never applied anywhere in the component's render output. This appears to be leftover code from an incomplete implementation.

🧹 Proposed fix: Remove unused code
   Keyboard,
-  Platform,
   Pressable,
   const showLocationsList = filteredLocations.length > 0;
-  const headerPaddingTop = Platform.OS === 'ios' ? 80 : 24;

Also applies to: 119-119

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/weather/screens/LocationsScreen.tsx` at line 14, Remove
the unused Platform import and the unused headerPaddingTop calculation inside
the LocationsScreen component: delete the Platform import near the top and
remove the headerPaddingTop constant (and any related Platform.OS checks) around
where headerPaddingTop is defined so there is no dead code left; ensure
LocationsScreen compiles and no other references to headerPaddingTop remain.
apps/expo/features/weather/hooks/useWeatherAlert.ts-126-152 (1)

126-152: ⚠️ Potential issue | 🟡 Minor

Inner callbacks also use any type.

The forecast hour iteration callbacks at lines 129 and 142 use any typing for the hour objects. These should be typed according to the weather API response structure.

🔧 Proposed fix
-  const willRain = todayHours.some((h: any) => h.condition?.text?.toLowerCase().includes('rain'));
+  const willRain = todayHours.some((h: ForecastHour) => h.condition?.text?.toLowerCase().includes('rain'));
   
-  const highWindComing = todayHours.some((h: any) => h.wind_kph >= 30);
+  const highWindComing = todayHours.some((h: ForecastHour) => h.wind_kph >= 30);

As per coding guidelines: "Never use any in TypeScript — use proper types or unknown"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/weather/hooks/useWeatherAlert.ts` around lines 126 - 152,
The callbacks use (h: any) for forecast hour objects (used in todayHours,
willRain and highWindComing) which violates the no-any rule; define a proper
Hour type/interface matching the API (e.g., Hour { condition?: { text?: string
}; wind_kph?: number }) and type forecastDays/todayHours accordingly (e.g.,
todayHours: Hour[] = forecastDays[0]?.hour || []). Then replace (h: any) with
(h: Hour) and add lightweight runtime guards where needed (optional chaining and
typeof checks) in willRain and highWindComing to safely access condition.text
and wind_kph.
apps/expo/features/weather/screens/LocationSearchScreen.tsx-35-35 (1)

35-35: ⚠️ Potential issue | 🟡 Minor

Fix incorrect ref type annotation.

The ref should use explicit generic typing: useRef<SearchInputRef>(null) instead of const searchInputRef: SearchInputRef = useRef(null). The latter creates a type mismatch since useRef(null) returns a RefObject, not the component instance type directly.

🐛 Proposed fix
-  const searchInputRef: SearchInputRef = useRef(null);
+  const searchInputRef = useRef<SearchInputRef>(null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/weather/screens/LocationSearchScreen.tsx` at line 35, The
ref declaration for searchInputRef is typed incorrectly; change the declaration
to use React's generic useRef typing so the variable is a RefObject instead of
the raw instance type — replace the current line that declares searchInputRef
with a generic useRef usage: useRef<SearchInputRef>(null), referencing the
SearchInputRef type and the useRef hook to ensure the ref has the correct
RefObject type.
apps/expo/features/packs/components/AddPackItemActions.tsx-108-113 (1)

108-113: ⚠️ Potential issue | 🟡 Minor

Move recently-used tracking after a successful add.

Right now failures still persist items to “recently used” because tracking happens before the API call. Reorder it inside the try block after await addItemsToPack(...).

Suggested fix
 if (catalogItems.length > 0) {
-  trackRecentlyUsed(catalogItems);
   try {
     await addItemsToPack(packId, catalogItems as CatalogItemWithPackItemFields[]);
+    trackRecentlyUsed(catalogItems);
   } catch (error) {
     console.error('Error adding catalog items to pack:', error);
     Alert.alert(t('common.error'), t('catalog.somethingWentWrong'));
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/packs/components/AddPackItemActions.tsx` around lines 108
- 113, The call to trackRecentlyUsed currently runs before the API call so
failures still mark items as recently used; move the
trackRecentlyUsed(catalogItems) invocation into the try block immediately after
await addItemsToPack(packId, catalogItems as CatalogItemWithPackItemFields[]) so
it only runs on success, and remove the earlier pre-call invocation; keep the
existing catch behavior that logs the error and shows Alert.alert.
apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx-114-114 (1)

114-114: ⚠️ Potential issue | 🟡 Minor

Remove double top inset padding from SafeAreaView and child View.

SafeAreaView from react-native-safe-area-context automatically applies safe area insets as padding on all edges (including top) by default. The explicit paddingTop: insets.top on line 114 is added to (not replacing) this automatic padding, creating a double-padding effect that pushes content down unnecessarily. The same issue applies to the View at line 131, which should only add the 22px spacing without the redundant insets.top.

Suggested fix
-<SafeAreaView className="flex-1 " style={{ paddingTop: insets.top }}>
+<SafeAreaView className="flex-1">
@@
-<View className="bg-background gap-2 px-4 pb-2" style={{ paddingTop: insets.top + 22 }}>
+<View className="bg-background gap-2 px-4 pb-2" style={{ paddingTop: 22 }}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx` at line
114, The SafeAreaView in PackTemplateListScreen currently adds explicit
paddingTop: insets.top on top of the SafeAreaView's own automatic insets,
causing double top padding; remove the inline style paddingTop: insets.top from
the SafeAreaView and update the child View (the one adding spacing at the top)
to only add the fixed 22px (e.g., marginTop or paddingTop: 22) without
referencing insets.top so the safe-area padding is applied once by SafeAreaView.
apps/expo/app/(app)/weather-alerts.tsx-160-160 (1)

160-160: ⚠️ Potential issue | 🟡 Minor

Use i18n for user-facing strings.

The loading and empty-state messages are hardcoded in English. Use the translation hook for consistency.

🌐 Proposed fix
-          {loading && <Text className="mx-4">Loading alerts...</Text>}
+          {loading && <Text className="mx-4">{t('common.loading')}</Text>}

           {error && <Text className="mx-4 text-red-500">{error}</Text>}

           {!loading && alerts.length === 0 && (
             <Text className="mx-4 text-muted-foreground">
-              No active alerts for {activeLocation?.name ?? 'this location'}
+              {t('weather.noActiveAlerts', { location: activeLocation?.name ?? t('weather.thisLocation') })}
             </Text>
           )}

You may need to add the corresponding translation keys.

Also applies to: 165-167

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/weather-alerts.tsx at line 160, The hardcoded
user-facing strings in the WeatherAlerts component (the loading text rendered
when loading is true and the empty-state messages around lines where alerts are
rendered) must use the app i18n hook instead of literal English; import and call
the translation hook (e.g., useTranslation or t from your i18n util) at the top
of the weather-alerts component, replace "Loading alerts..." and any empty-state
Text values with t('weatherAlerts.loading') / t('weatherAlerts.empty') (or
chosen keys), and add those keys to the translation files for all locales;
update the JSX that checks the loading and alerts variables so it renders the
translated strings via the translation function.
apps/expo/app/(app)/weather-alerts.tsx-152-152 (1)

152-152: ⚠️ Potential issue | 🟡 Minor

Replace invalid icon name 'tune-vertical-variant' — this icon does not exist in MaterialCommunityIcons from @expo/vector-icons. Either use a valid icon name from the MaterialCommunityIcons set (check https://icons.expo.fyi/), switch to a different icon library that includes this icon, or use an alternative icon name that matches your UI requirements.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/weather-alerts.tsx at line 152, The JSX uses
<MaterialCommunityIcons name="tune-vertical-variant" ... /> which is an invalid
icon name; update the MaterialCommunityIcons usage in weather-alerts.tsx to a
valid icon name from the MaterialCommunityIcons set (check
https://icons.expo.fyi/) or switch to a different icon component/library that
contains the desired glyph, e.g., replace "tune-vertical-variant" with a
confirmed name like "tune" or another matching icon, and ensure the import of
MaterialCommunityIcons remains correct.
packages/api/src/routes/packTemplates/generateFromOnlineContent.ts-449-453 (1)

449-453: ⚠️ Potential issue | 🟡 Minor

Avoid using as any per coding guidelines.

Line 453 uses as any which violates the coding guideline "Never use any in TypeScript". The Sentry captureException extra parameter should be properly typed.

Proposed fix
     console.error('Error generating pack template:', error);
     c.get('sentry').captureException(error, {
       extra: { contentUrl, errorType: 'template_generation_error' },
-    } as any);
+    });

As per coding guidelines: "Never use any in TypeScript — use proper types or unknown"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts` around
lines 449 - 453, The current catch block uses an unsafe "as any" cast when
calling c.get('sentry').captureException(error, { extra: ... } as any); replace
that with a properly typed Sentry hint by importing the correct Sentry type
(e.g., Sentry.EventHint or Sentry.CaptureContext from the Sentry package you
use) and creating a typed variable for the second argument (e.g., const hint:
Sentry.EventHint = { extra: { contentUrl, errorType: 'template_generation_error'
} }) then pass that typed variable to c.get('sentry').captureException(error,
hint) so there is no use of any and the extra payload is correctly typed.
🧹 Nitpick comments (8)
apps/expo/features/weather/hooks/useWeatherAlert.ts (1)

184-216: Consider using React Query instead of manual useEffect/useState for data fetching.

Per coding guidelines for apps/expo/features/*/hooks/**/*.ts{,x}: "Use React Query hooks (useQuery, useMutation, useInfiniteQuery) for data fetching."

Using React Query would provide built-in caching, deduplication, refetching, and better loading/error state management.

♻️ Suggested refactor using React Query
import { useQuery } from '@tanstack/react-query';

export function useWeatherAlerts() {
  const activeLocation = useAtomValue(activeLocationAtom);

  const { data: alerts = [], isLoading: loading, error } = useQuery({
    queryKey: ['weatherAlerts', activeLocation?.id],
    queryFn: async () => {
      const data = await getWeatherData(activeLocation!.id);
      return generateAlerts(data, activeLocation);
    },
    enabled: !!activeLocation?.id,
  });

  return {
    alerts,
    loading,
    error: error?.message ?? null,
    activeLocation,
  };
}

As per coding guidelines: "Use React Query hooks for data fetching in Expo feature hooks"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/weather/hooks/useWeatherAlert.ts` around lines 184 - 216,
Replace the manual useEffect/useState fetch in useWeatherAlerts with a React
Query useQuery-based implementation: use the activeLocationAtom value for the
query key (e.g., ['weatherAlerts', activeLocation?.id]) and set enabled to
!!activeLocation?.id, call getWeatherData(activeLocation!.id) in the queryFn and
transform the result with generateAlerts before returning; map useQuery's
data/isLoading/error to alerts/loading/error and return activeLocation as
before. Ensure you import useQuery from `@tanstack/react-query` and convert error
to a string (error?.message ?? null).
apps/expo/app/(app)/weather-alert-preferences.tsx (1)

137-137: Avoid as never type casts; define proper types instead.

Using as never bypasses TypeScript's type checking entirely, which defeats the purpose of type safety. This pattern is fragile and will hide errors if icon names or translation keys become invalid.

♻️ Suggested approach for icon names

Import the icon type and use it in AlertTypeConfig:

+import type { MaterialCommunityIcons } from '@expo/vector-icons';
+
 type AlertTypeConfig = {
   key: keyof Omit<AlertPreferences, 'weatherNotifications' | 'locationMonitoring'>;
-  iconName: string;
+  iconName: keyof typeof MaterialCommunityIcons.glyphMap;
   iconColor: string;
 };

Then remove the as never cast on line 137:

-                      <Icon name={iconName as never} size={18} color="white" />
+                      <Icon name={iconName} size={18} color="white" />

For translation keys (lines 145, 148), consider defining a union type of valid weather translation keys.

Also applies to: 145-145, 148-148

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/weather-alert-preferences.tsx at line 137, Replace the
unsafe "as never" cast by giving iconName a proper type: import the icon name
type used by the Icon component (or define a union of allowed icon string
literals) and use that type in AlertTypeConfig so iconName is typed correctly;
update usages of Icon to accept iconName with the correct type instead of
casting. Likewise, replace the loose translation key usage by defining a union
type of valid weather translation keys (used where you build titles/subtitles)
and use it in AlertTypeConfig so the translation function receives a properly
typed key. Ensure AlertTypeConfig references these new types and remove all "as
never" casts (including the Icon invocation and translation key usages).
apps/expo/features/pack-templates/components/TemplateCreationOptions.tsx (1)

83-101: Stale comment: update to reflect the new functionality.

The comment on line 83 still references TikTok, but the code now handles generic online content import.

📝 Suggested fix
-            {/* Import from TikTok option (only for admins) */}
+            {/* Import from online content option (only for admins) */}
             {isAdmin && isAuthenticated && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/pack-templates/components/TemplateCreationOptions.tsx`
around lines 83 - 101, Update the stale inline comment that mentions "Import
from TikTok" to reflect the new generic online content import behavior; locate
the JSX block that renders the import option (the TouchableOpacity using
handleImportFromOnlineContent inside TemplateCreationOptions.tsx) and replace or
remove the outdated comment so it accurately describes the "Import from online
content" option for admins who are authenticated.
packages/api/src/routes/packTemplates/generateFromOnlineContent.ts (1)

362-364: Error message still references "TikTok post" but this endpoint now handles YouTube content too.

Consider updating the error message to be generic.

Proposed fix
     } else {
-      throw new Error('No content found in TikTok post (no images or video)');
+      throw new Error('No content found (no images, video, or transcript)');
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts` around
lines 362 - 364, The error thrown in the else branch of
generateFromOnlineContent still says "No content found in TikTok post (no images
or video)"; change that message to a generic one that covers YouTube and other
sources (e.g., "No content found in online post (no images or video)") by
updating the throw new Error(...) statement inside the else block of the
generateFromOnlineContent handler so it no longer references TikTok
specifically.
apps/expo/features/pack-templates/components/OnlineContentImportModal.tsx (1)

19-22: Interface name is inconsistent with the renamed component.

The interface is still named TikTokImportModalProps but the component was renamed to OnlineContentImportModal. Consider renaming for consistency.

Proposed fix
-interface TikTokImportModalProps {
+interface OnlineContentImportModalProps {
   visible: boolean;
   onClose: () => void;
 }

-export function OnlineContentImportModal({ visible, onClose }: TikTokImportModalProps) {
+export function OnlineContentImportModal({ visible, onClose }: OnlineContentImportModalProps) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/pack-templates/components/OnlineContentImportModal.tsx`
around lines 19 - 22, Rename the mismatched props interface to match the
component: change TikTokImportModalProps to OnlineContentImportModalProps and
update all references (the component declaration OnlineContentImportModal, any
prop annotations, and any exports/imports) to use the new name so the props type
and component name are consistent; search for occurrences of
TikTokImportModalProps and replace them with OnlineContentImportModalProps and
adjust any tests/types that reference the old name.
apps/expo/features/catalog/components/CatalogBrowserModal.tsx (1)

231-240: Type inconsistency: Returns items with quantity property but signature expects CatalogItem[].

The handleAddSelected function adds a quantity property to items at line 235, but onItemsSelected expects CatalogItem[] which doesn't include quantity (per apps/expo/features/catalog/types.ts:23-37). While this works at runtime because downstream code casts to CatalogItemWithPackItemFields[], it's not type-safe.

Consider using the existing CatalogItemWithQuantity type from the types file for the callback signature.

Proposed fix
// In types.ts or at the top of this file
import type { CatalogItem, CatalogItemWithQuantity } from '../types';

type CatalogBrowserModalProps = {
  visible: boolean;
  onClose: () => void;
-  onItemsSelected: (items: CatalogItem[]) => void;
+  onItemsSelected: (items: CatalogItemWithQuantity[]) => void;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/features/catalog/components/CatalogBrowserModal.tsx` around lines
231 - 240, The handler handleAddSelected builds items with a quantity field but
calls onItemsSelected typed as CatalogItem[], causing a type mismatch; update
the onItemsSelected callback signature (and any related uses) to accept
CatalogItemWithQuantity[] (the type defined in features/catalog/types.ts) and
ensure handleAddSelected returns that type by mapping to CatalogItemWithQuantity
(use itemQuantities.get(item.id) ?? 1 for quantity). Also update any upstream
prop types or callers of CatalogBrowserModal that provide onItemsSelected to
match the new CatalogItemWithQuantity[] signature.
packages/api/src/containers/AppContainer.ts (1)

9-15: Update the lifecycle log labels to AppContainer too.

The class rename stops at the declaration; onStart, onStop, and onError still emit TikTok container…, which makes log filtering and troubleshooting inconsistent with the new binding name.

🪵 Suggested log cleanup
   override onStart() {
-    console.log('TikTok container successfully started');
+    console.log('AppContainer successfully started');
   }

   override onStop() {
-    console.log('TikTok container successfully shut down');
+    console.log('AppContainer successfully shut down');
   }

   override onError(error: unknown) {
-    console.log('TikTok container error:', error);
+    console.log('AppContainer error:', error);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/containers/AppContainer.ts` around lines 9 - 15, The
lifecycle log messages still use the old "TikTok container…" label; update them
to "AppContainer" for consistency. In the AppContainer class, modify the logging
calls inside onStart, onStop, and onError to replace any "TikTok container" text
with "AppContainer" (or an equivalent exact label), and ensure any processLogger
or logger.error/info usages include the new label so log filtering works
consistently across those methods.
packages/api/test/generate-from-tiktok.test.ts (1)

41-47: Make the mock fail when the binding isn't passed.

getContainer ignores its first argument right now, so this suite still passes if APP_CONTAINER is undefined or the rename is miswired. That leaves the getEnv()getContainer() handoff in packages/api/src/routes/packTemplates/generateFromOnlineContent.ts:55-105 effectively untested.

🧪 Suggested assertion
 vi.mock('@cloudflare/containers', () => ({
   Container: class MockContainer {},
-  getContainer: vi.fn(() => ({
-    fetch: (...args: Parameters<typeof mockContainerFetch>) => mockContainerFetch(...args),
-  })),
+  getContainer: vi.fn((binding: unknown) => {
+    if (!binding) {
+      throw new Error('APP_CONTAINER binding was not provided');
+    }
+    return {
+      fetch: (...args: Parameters<typeof mockContainerFetch>) => mockContainerFetch(...args),
+    };
+  }),
 }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/test/generate-from-tiktok.test.ts` around lines 41 - 47, The
mock for getContainer currently ignores its first argument so tests don't verify
the binding is passed; update the vi.mock implementation for
'@cloudflare/containers' so getContainer examines its first parameter (the
binding name/identifier used by getEnv() → getContainer()) and throws or returns
a rejected promise when that argument is undefined or not the expected binding
(e.g., "APP_CONTAINER"), ensuring tests fail if the binding is missing or
misnamed; reference getContainer, MockContainer and mockContainerFetch in the
mock and then adjust the test to call getContainer with the correct binding name
so the suite verifies the handoff.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/expo/app/`(app)/(tabs)/profile/notifications.tsx:
- Around line 74-77: FormSection is being passed an invalid title prop causing
TS2322; remove the title prop from the FormSection instance (the one using
materialIconProps={{ name: 'weather-cloudy-alert' }}). If a visible heading is
required, render a separate Text (or Heading) component immediately above this
FormSection or move title-like content into an allowed prop such as footnote or
platform-specific ios={{ title: '...' }} consistent with how
weather-alert-preferences.tsx handles titles. Ensure only allowed props (e.g.,
materialIconProps, footnote, ios) are used on FormSection.
- Around line 100-107: Replace the invalid Icon name in the Notifications UI:
inside the Pressable block in notifications.tsx where Icon is rendered (the Icon
usage with name="tune-vertical-variant"), change the name to a valid
`@roninoss/icons` value such as "cog-outline" (the same icon used elsewhere) so
the prop matches the library's allowed union; note that "tune-vertical-variant"
is from MaterialCommunityIcons (used in weather-alerts.tsx) and should not be
used with this Icon component.

In `@apps/expo/app/`(app)/current-pack/[id].tsx:
- Around line 138-145: The inner View that renders the avatar row (the element
with className "flex-row items-center p-4") duplicates the safe-area padding
already applied to SafeAreaView; remove the duplicate paddingTop by deleting the
style entry or setting paddingTop to 0 on that View so only SafeAreaView applies
insets.top. Keep the SafeAreaView style={{ paddingTop: insets.top }} and ensure
no other parent/content containers also add insets.top.

In `@apps/expo/app/`(app)/weather-alert-preferences.tsx:
- Around line 51-62: Preferences in local state (preferences, setPreferences of
type AlertPreferences) are not persisted and will be lost on navigation;
implement persistence by creating a persisted atom (pattern like
recentlyUsedCatalogItemsAtom) or by reading/writing to AsyncStorage in this
component: load stored AlertPreferences into preferences on mount and save on
change/unmount (or when navigating away). Specifically, add a persisted atom or
utility that exposes get/set for AlertPreferences, replace the local
React.useState with that atom (or wrap setPreferences to also write to
AsyncStorage), and ensure you reference AlertPreferences, preferences,
setPreferences, and recentlyUsedCatalogItemsAtom pattern to locate where to
apply the fix. Ensure reads handle missing data (use the current defaults) and
writes debounce or batch updates to avoid excessive I/O.
- Around line 87-88: The Icon component is using an invalid name prop
'bell-ring-outline' causing a pipeline/type error; update the Icon usage (Icon
name="bell-ring-outline" ...) to use the valid icon name 'bell-outline' instead
so the component (Icon) renders a supported glyph and the TypeScript error
TS2820 is resolved.

In `@apps/expo/app/`(app)/weather-alerts.tsx:
- Around line 11-18: Remove the duplicate WeatherAlert type definition from
weather-alerts.tsx and import the exported WeatherAlert type from
expo-app/features/weather/hooks/useWeatherAlert instead; update the top of
weather-alerts.tsx to remove the local type block (the lines defining
WeatherAlert) and add an import for WeatherAlert from the hook module so all
references in this file use the single shared type.

In `@apps/expo/app/`(app)/weight-analysis/[id].tsx:
- Around line 51-58: The inner grid View and the SafeAreaView both apply
paddingTop: insets.top causing double top-padding; remove the duplicate by
deleting or setting paddingTop to 0 on the inner View (the <View className="grid
grid-cols-2 gap-3 p-4" ...> in weight-analysis/[id].tsx) so only SafeAreaView
applies insets.top; keep the rest of the View styling intact and ensure no other
nested element repeats insets.top.

In `@apps/expo/features/pack-templates/components/AddPackTemplateItemActions.tsx`:
- Around line 121-122: The code currently calls trackRecentlyUsed(catalogItems)
before the API write addItemsToPackTemplate(packTemplateId, catalogItems),
causing stale state if the add fails; change the flow so you await
addItemsToPackTemplate(...) first and only call trackRecentlyUsed(catalogItems)
after that promise resolves successfully, wrapping the operation in a try/catch
in the AddPackTemplateItemActions handler to prevent tracking on error and to
handle or rethrow the error (e.g., show a user-facing error) for consistent
client state.

In `@apps/expo/features/packs/components/HorizontalCatalogItemCard.tsx`:
- Around line 38-43: Remove the leftover debug class "bg-red" from the className
in the HorizontalCatalogItemCard component so it no longer forces a red
background; update the className expression that currently starts with
`rounded-lg flex-row gap-3 border p-4 bg-red` to match the pattern used in
PackItemCard.tsx (i.e., start without the unconditional bg class and rely solely
on the conditional expression using `isSelectable` and `restProps.selected` to
apply `border-primary bg-primary/5` or `border-border bg-card`).

In `@apps/expo/features/weather/hooks/useWeatherAlert.ts`:
- Around line 15-31: Change the function signature and map callback to use real
types: update generateAlerts to accept data: WeatherApiForecastResponse and
activeLocation: { name?: string } | undefined (instead of any), and when mapping
use the precise alert element type by declaring the mapper param as a:
WeatherApiForecastResponse["alerts"]["alert"][number], index: number; keep the
return type WeatherAlert[] unchanged and adjust any property accesses
accordingly so TypeScript type-checks the alert fields
(id/type/location/dates/severity/details) against the declared
WeatherApiForecastResponse shape.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts`:
- Around line 267-295: When handling the YouTube branch in the
generateFromOnlineContent flow, initialize the variables that the rest of the
pipeline expects (notably imageUrls, and optionally videoUrl and caption) so
they are defined for downstream usage; inside the isYouTubeUrl branch (after
setting contentId and youtubeVideoTranscript) set imageUrls = [] (and videoUrl =
undefined, caption = undefined if you want explicitness) and ensure
contentSource = 'youtube' remains. This ensures references to imageUrls later in
the code (and any use of videoUrl/caption) won't cause TypeScript or runtime
errors.

In `@packages/api/test/setup.ts`:
- Line 425: Remove the problematic cast to unknown when assigning testDb from
drizzle; call drizzle(testClient, { schema }) without casting so TypeScript can
infer the correct NodePgDatabase type for testDb, or if inference still fails
explicitly cast to the correct generic NodePgDatabase<typeof schema> type
(importing NodePgDatabase from 'drizzle-orm/node-postgres') and use that instead
of unknown; update the assignment where testDb = drizzle(testClient, { schema })
as unknown to one of these two safe approaches.

In `@packages/api/wrangler.jsonc`:
- Around line 180-186: The dev migration uses "new_sqlite_classes":
["AppContainer"] plus "deleted_classes": ["TikTokContainer"] which diverges from
production’s rename path and can drop existing Durable Object state; change the
dev migration to use a "renamed_classes" mapping from "TikTokContainer" to
"AppContainer" (replace the new_sqlite_classes/deleted_classes entries with a
single renamed_classes object) so the Durable Object rename preserves instances
and matches production behavior.

---

Outside diff comments:
In `@apps/expo/app/`(app)/(tabs)/profile/index.tsx:
- Line 33: The code calls Linking.openSettings() in the Profile component but
Linking is not imported, causing an unresolved identifier; fix by adding Linking
to the React Native imports so the symbol Linking is available (update the
import statement that currently imports Alert, Platform, TouchableOpacity, View
to also import Linking) and ensure any other usages of Linking in this file
reference the same imported symbol.
- Line 213: The success icon currently uses an untyped color token
(materialIcon: { name: 'check-circle-outline', color: colors.green }), which
causes TS2339; update the color to a valid theme token (for example
colors.primary or your theme's success token) so it matches the theme contract.
Locate the materialIcon declaration in the profile component (the object with
name 'check-circle-outline') and replace colors.green with an existing typed
token (e.g., colors.primary or colors.success) ensuring the imported colors type
includes that token. Run TypeScript to confirm the error is resolved.
- Around line 140-142: The call to FileSystem.getInfoAsync in the profile screen
passes an unsupported options object ({ size: true }); remove the options so
call FileSystem.getInfoAsync(image.uri) instead — the returned FileInfo already
includes size. Update the check that uses info.size (and AVATAR_MAX_BYTES) to
remain the same and ensure TypeScript no longer errors; no other logic changes
are needed where info and image.uri are referenced.

In `@apps/expo/features/weather/screens/LocationsScreen.tsx`:
- Around line 122-143: The search container View (the <View className="p-4"
style={{ paddingTop: insets.top }}>) is redundantly applying paddingTop already
set on the SafeAreaView; remove the duplicate by deleting the style paddingTop
from that inner View (leave className="p-4" intact) so only SafeAreaView
provides insets.top, ensuring LargeTitleHeader and the search input are not
pushed down twice.

In `@packages/api/container_src/server.ts`:
- Around line 36-55: The GoogleGenAI client (googleAi) is being constructed
before environment validation; move or defer initialization until after
validateEnv() returns so the API key is validated, or explicitly check
env.GOOGLE_GENAI_API_KEY before creating the GoogleGenAI instance; update the
code to call validateEnv() first, then create new GoogleGenAI({ apiKey:
env.GOOGLE_GENAI_API_KEY }) (or guard creation with a conditional and handle the
missing-key case) so GoogleGenAI is never instantiated with an undefined key.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts`:
- Around line 296-308: The Sentry capture call is being passed an invalid cast
(as unknown); instead construct a properly typed EventHint and pass it to
c.get('sentry').captureException: import the EventHint type from Sentry (e.g.,
'@sentry/types' or '@sentry/node'), create const hint: EventHint = { extra: {
tiktokUrl: contentUrl, errorType: 'tiktok_service_error' } }, and call
c.get('sentry').captureException(apiError, hint). This keeps the additional
context while satisfying TypeScript for captureException.

---

Minor comments:
In `@apps/expo/app/`(app)/weather-alerts.tsx:
- Line 160: The hardcoded user-facing strings in the WeatherAlerts component
(the loading text rendered when loading is true and the empty-state messages
around lines where alerts are rendered) must use the app i18n hook instead of
literal English; import and call the translation hook (e.g., useTranslation or t
from your i18n util) at the top of the weather-alerts component, replace
"Loading alerts..." and any empty-state Text values with
t('weatherAlerts.loading') / t('weatherAlerts.empty') (or chosen keys), and add
those keys to the translation files for all locales; update the JSX that checks
the loading and alerts variables so it renders the translated strings via the
translation function.
- Line 152: The JSX uses <MaterialCommunityIcons name="tune-vertical-variant"
... /> which is an invalid icon name; update the MaterialCommunityIcons usage in
weather-alerts.tsx to a valid icon name from the MaterialCommunityIcons set
(check https://icons.expo.fyi/) or switch to a different icon component/library
that contains the desired glyph, e.g., replace "tune-vertical-variant" with a
confirmed name like "tune" or another matching icon, and ensure the import of
MaterialCommunityIcons remains correct.

In `@apps/expo/features/ai-packs/screens/AIPacksScreen.tsx`:
- Line 80: The outer SafeAreaView (the one with className="flex-1" and style={{
paddingTop: insets.top }}) already applies the top inset, so remove the
duplicate paddingTop: insets.top from the inner SafeAreaView in
AIPacksScreen.tsx (leave any other styles on the inner SafeAreaView intact);
ensure only the outer SafeAreaView uses paddingTop to avoid double vertical
offset.

In `@apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx`:
- Line 114: The SafeAreaView in PackTemplateListScreen currently adds explicit
paddingTop: insets.top on top of the SafeAreaView's own automatic insets,
causing double top padding; remove the inline style paddingTop: insets.top from
the SafeAreaView and update the child View (the one adding spacing at the top)
to only add the fixed 22px (e.g., marginTop or paddingTop: 22) without
referencing insets.top so the safe-area padding is applied once by SafeAreaView.

In `@apps/expo/features/packs/components/AddPackItemActions.tsx`:
- Around line 108-113: The call to trackRecentlyUsed currently runs before the
API call so failures still mark items as recently used; move the
trackRecentlyUsed(catalogItems) invocation into the try block immediately after
await addItemsToPack(packId, catalogItems as CatalogItemWithPackItemFields[]) so
it only runs on success, and remove the earlier pre-call invocation; keep the
existing catch behavior that logs the error and shows Alert.alert.

In `@apps/expo/features/weather/hooks/useWeatherAlert.ts`:
- Around line 126-152: The callbacks use (h: any) for forecast hour objects
(used in todayHours, willRain and highWindComing) which violates the no-any
rule; define a proper Hour type/interface matching the API (e.g., Hour {
condition?: { text?: string }; wind_kph?: number }) and type
forecastDays/todayHours accordingly (e.g., todayHours: Hour[] =
forecastDays[0]?.hour || []). Then replace (h: any) with (h: Hour) and add
lightweight runtime guards where needed (optional chaining and typeof checks) in
willRain and highWindComing to safely access condition.text and wind_kph.

In `@apps/expo/features/weather/screens/LocationSearchScreen.tsx`:
- Line 35: The ref declaration for searchInputRef is typed incorrectly; change
the declaration to use React's generic useRef typing so the variable is a
RefObject instead of the raw instance type — replace the current line that
declares searchInputRef with a generic useRef usage:
useRef<SearchInputRef>(null), referencing the SearchInputRef type and the useRef
hook to ensure the ref has the correct RefObject type.

In `@apps/expo/features/weather/screens/LocationsScreen.tsx`:
- Line 14: Remove the unused Platform import and the unused headerPaddingTop
calculation inside the LocationsScreen component: delete the Platform import
near the top and remove the headerPaddingTop constant (and any related
Platform.OS checks) around where headerPaddingTop is defined so there is no dead
code left; ensure LocationsScreen compiles and no other references to
headerPaddingTop remain.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts`:
- Around line 449-453: The current catch block uses an unsafe "as any" cast when
calling c.get('sentry').captureException(error, { extra: ... } as any); replace
that with a properly typed Sentry hint by importing the correct Sentry type
(e.g., Sentry.EventHint or Sentry.CaptureContext from the Sentry package you
use) and creating a typed variable for the second argument (e.g., const hint:
Sentry.EventHint = { extra: { contentUrl, errorType: 'template_generation_error'
} }) then pass that typed variable to c.get('sentry').captureException(error,
hint) so there is no use of any and the extra payload is correctly typed.

---

Nitpick comments:
In `@apps/expo/app/`(app)/weather-alert-preferences.tsx:
- Line 137: Replace the unsafe "as never" cast by giving iconName a proper type:
import the icon name type used by the Icon component (or define a union of
allowed icon string literals) and use that type in AlertTypeConfig so iconName
is typed correctly; update usages of Icon to accept iconName with the correct
type instead of casting. Likewise, replace the loose translation key usage by
defining a union type of valid weather translation keys (used where you build
titles/subtitles) and use it in AlertTypeConfig so the translation function
receives a properly typed key. Ensure AlertTypeConfig references these new types
and remove all "as never" casts (including the Icon invocation and translation
key usages).

In `@apps/expo/features/catalog/components/CatalogBrowserModal.tsx`:
- Around line 231-240: The handler handleAddSelected builds items with a
quantity field but calls onItemsSelected typed as CatalogItem[], causing a type
mismatch; update the onItemsSelected callback signature (and any related uses)
to accept CatalogItemWithQuantity[] (the type defined in
features/catalog/types.ts) and ensure handleAddSelected returns that type by
mapping to CatalogItemWithQuantity (use itemQuantities.get(item.id) ?? 1 for
quantity). Also update any upstream prop types or callers of CatalogBrowserModal
that provide onItemsSelected to match the new CatalogItemWithQuantity[]
signature.

In `@apps/expo/features/pack-templates/components/OnlineContentImportModal.tsx`:
- Around line 19-22: Rename the mismatched props interface to match the
component: change TikTokImportModalProps to OnlineContentImportModalProps and
update all references (the component declaration OnlineContentImportModal, any
prop annotations, and any exports/imports) to use the new name so the props type
and component name are consistent; search for occurrences of
TikTokImportModalProps and replace them with OnlineContentImportModalProps and
adjust any tests/types that reference the old name.

In `@apps/expo/features/pack-templates/components/TemplateCreationOptions.tsx`:
- Around line 83-101: Update the stale inline comment that mentions "Import from
TikTok" to reflect the new generic online content import behavior; locate the
JSX block that renders the import option (the TouchableOpacity using
handleImportFromOnlineContent inside TemplateCreationOptions.tsx) and replace or
remove the outdated comment so it accurately describes the "Import from online
content" option for admins who are authenticated.

In `@apps/expo/features/weather/hooks/useWeatherAlert.ts`:
- Around line 184-216: Replace the manual useEffect/useState fetch in
useWeatherAlerts with a React Query useQuery-based implementation: use the
activeLocationAtom value for the query key (e.g., ['weatherAlerts',
activeLocation?.id]) and set enabled to !!activeLocation?.id, call
getWeatherData(activeLocation!.id) in the queryFn and transform the result with
generateAlerts before returning; map useQuery's data/isLoading/error to
alerts/loading/error and return activeLocation as before. Ensure you import
useQuery from `@tanstack/react-query` and convert error to a string
(error?.message ?? null).

In `@packages/api/src/containers/AppContainer.ts`:
- Around line 9-15: The lifecycle log messages still use the old "TikTok
container…" label; update them to "AppContainer" for consistency. In the
AppContainer class, modify the logging calls inside onStart, onStop, and onError
to replace any "TikTok container" text with "AppContainer" (or an equivalent
exact label), and ensure any processLogger or logger.error/info usages include
the new label so log filtering works consistently across those methods.

In `@packages/api/src/routes/packTemplates/generateFromOnlineContent.ts`:
- Around line 362-364: The error thrown in the else branch of
generateFromOnlineContent still says "No content found in TikTok post (no images
or video)"; change that message to a generic one that covers YouTube and other
sources (e.g., "No content found in online post (no images or video)") by
updating the throw new Error(...) statement inside the else block of the
generateFromOnlineContent handler so it no longer references TikTok
specifically.

In `@packages/api/test/generate-from-tiktok.test.ts`:
- Around line 41-47: The mock for getContainer currently ignores its first
argument so tests don't verify the binding is passed; update the vi.mock
implementation for '@cloudflare/containers' so getContainer examines its first
parameter (the binding name/identifier used by getEnv() → getContainer()) and
throws or returns a rejected promise when that argument is undefined or not the
expected binding (e.g., "APP_CONTAINER"), ensuring tests fail if the binding is
missing or misnamed; reference getContainer, MockContainer and
mockContainerFetch in the mock and then adjust the test to call getContainer
with the correct binding name so the suite verifies the handoff.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f5c5c8ab-158d-4269-809d-6c240e486f7e

📥 Commits

Reviewing files that changed from the base of the PR and between 23034ad and a482adf.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • packages/api/container_src/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (47)
  • apps/expo/app.config.ts
  • apps/expo/app/(app)/(tabs)/profile/index.tsx
  • apps/expo/app/(app)/(tabs)/profile/notifications.tsx
  • apps/expo/app/(app)/_layout.tsx
  • apps/expo/app/(app)/current-pack/[id].tsx
  • apps/expo/app/(app)/pack-categories/[id].tsx
  • apps/expo/app/(app)/weather-alert-preferences.tsx
  • apps/expo/app/(app)/weather-alerts.tsx
  • apps/expo/app/(app)/weight-analysis/[id].tsx
  • apps/expo/atoms/recentlyUsedCatalogItemsAtom.ts
  • apps/expo/features/ai-packs/screens/AIPacksScreen.tsx
  • apps/expo/features/catalog/components/CatalogBrowserModal.tsx
  • apps/expo/features/catalog/hooks/index.ts
  • apps/expo/features/catalog/hooks/usePopularCatalogItems.ts
  • apps/expo/features/catalog/hooks/useRecentlyUsedCatalogItems.ts
  • apps/expo/features/pack-templates/components/AddPackTemplateItemActions.tsx
  • apps/expo/features/pack-templates/components/OnlineContentImportModal.tsx
  • apps/expo/features/pack-templates/components/TemplateCreationOptions.tsx
  • apps/expo/features/pack-templates/hooks/index.ts
  • apps/expo/features/pack-templates/hooks/useGenerateTemplateFromOnlineContent.ts
  • apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx
  • apps/expo/features/packs/components/AddPackItemActions.tsx
  • apps/expo/features/packs/components/HorizontalCatalogItemCard.tsx
  • apps/expo/features/weather/components/LocationPicker.tsx
  • apps/expo/features/weather/components/WeatherAlertsTile.tsx
  • apps/expo/features/weather/hooks/useWeatherAlert.ts
  • apps/expo/features/weather/screens/LocationSearchScreen.tsx
  • apps/expo/features/weather/screens/LocationsScreen.tsx
  • apps/expo/lib/i18n/locales/en.json
  • apps/expo/package.json
  • apps/guides/package.json
  • apps/landing/package.json
  • package.json
  • packages/api/container_src/package.json
  • packages/api/container_src/server.ts
  • packages/api/package.json
  • packages/api/src/containers/AppContainer.ts
  • packages/api/src/containers/index.ts
  • packages/api/src/index.ts
  • packages/api/src/routes/packTemplates/generateFromOnlineContent.ts
  • packages/api/src/routes/packTemplates/index.ts
  • packages/api/src/schemas/packTemplates.ts
  • packages/api/src/utils/env-validation.ts
  • packages/api/test/generate-from-tiktok.test.ts
  • packages/api/test/setup.ts
  • packages/api/wrangler.jsonc
  • packages/ui/package.json

Comment thread apps/expo/app/(app)/(tabs)/profile/notifications.tsx
Comment thread apps/expo/app/(app)/(tabs)/profile/notifications.tsx
Comment thread apps/expo/app/(app)/current-pack/[id].tsx
Comment thread apps/expo/app/(app)/weather-alert-preferences.tsx
Comment thread apps/expo/app/(app)/weather-alert-preferences.tsx
Comment thread apps/expo/features/packs/components/HorizontalCatalogItemCard.tsx
Comment thread apps/expo/features/weather/hooks/useWeatherAlert.ts
Comment thread packages/api/src/routes/packTemplates/generateFromOnlineContent.ts
Comment thread packages/api/test/setup.ts
Comment thread packages/api/wrangler.jsonc
@mikib0 mikib0 merged commit 133a08f into main Apr 1, 2026
5 of 11 checks passed
@mikib0 mikib0 deleted the release/2.0.17 branch April 1, 2026 17:05
@coderabbitai coderabbitai Bot mentioned this pull request Apr 24, 2026
andrew-bierman pushed a commit that referenced this pull request May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants