Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6c51b65
Initial plan
Copilot Mar 9, 2026
9979ed6
Add iOS Weather Alerts feature parity with customizable preferences
Copilot Mar 9, 2026
0c96419
Add catalog browser enhancements: Popular Items, Recently Used, per-i…
Copilot Mar 9, 2026
9971b6d
Fix profile name screen: trim whitespace in canSave, route handleSave…
Copilot Mar 9, 2026
9acaa8b
Address CodeRabbit review feedback on catalog browser
andrew-bierman Mar 9, 2026
d616941
fix: resolve biome lint errors
andrew-bierman Mar 9, 2026
9427cef
Merge remote-tracking branch 'origin/development' into copilot/add-ch…
claude Mar 17, 2026
e3ebffd
Fix missing Share import in TripDetailScreen
andrew-bierman Mar 18, 2026
27fbe21
improve responsiveness
Isthisanmol Mar 18, 2026
5271716
chore(wrangler): add migrations for TikTokContainer to match deletion…
mikib0 Mar 22, 2026
79148b7
Merge pull request #1994 from PackRat-AI/chore/DO-migrations
mikib0 Mar 22, 2026
85b4337
chore(api): refactor container name to AppContainer
mikib0 Mar 22, 2026
ec269ef
chore(wrangler): update migrations
mikib0 Mar 22, 2026
8e7fb07
chore(wrangler): update migrations for prod environment
mikib0 Mar 22, 2026
f277a24
refactor(api): update comments to match the new container binding name
mikib0 Mar 22, 2026
9f3b4c9
Merge branch 'development' into chore/change-container-name
mikib0 Mar 22, 2026
ae1e401
Merge pull request #1995 from PackRat-AI/chore/change-container-name
mikib0 Mar 22, 2026
09b737e
Merge main into development
github-actions[bot] Mar 22, 2026
9870023
correct import
Isthisanmol Mar 23, 2026
fc8a83e
fix-profile-image
Isthisanmol Mar 23, 2026
a13db5c
merge development
Isthisanmol Mar 23, 2026
8b7d4de
add-choose-from-catalog-option-again
Isthisanmol Mar 23, 2026
a9f8ab9
fix(api): address memory limit issue in video to pack template genera…
mikib0 Mar 24, 2026
f3cfef8
Merge pull request #1997 from PackRat-AI/fix/memory-limit-video-pack-…
mikib0 Mar 24, 2026
31cbff8
merge development
Isthisanmol Mar 25, 2026
ef42a8b
feat: support generating of pack template from youtube videos
mikib0 Mar 26, 2026
6570536
Merge pull request #2000 from PackRat-AI/feat/generate-pack-template-…
mikib0 Mar 26, 2026
7392548
fix(expo/pack-categories): misaligned empty state text (closes #1981)
mikib0 Mar 26, 2026
6afff73
fix(expo/LocationPicker): add SafeAreaView (closes #1992)
mikib0 Mar 26, 2026
0534a1b
fix(expo/LocationSearchScreen): adjust search input focus timing (clo…
mikib0 Mar 26, 2026
6440a9d
Merge pull request #2001 from PackRat-AI/fix/bug-fixes-26.03.26
mikib0 Mar 26, 2026
fd8ff18
add real-time weather-alert and back button to weather screen
Isthisanmol Mar 26, 2026
c175e35
revert change
Isthisanmol Mar 26, 2026
1d36d8d
Merge branch 'development' into copilot/add-weather-alerts-feature-ios
Isthisanmol Mar 29, 2026
ff134f4
add-weather-alerts-feature
Isthisanmol Mar 29, 2026
d774b2c
prevent content from overlapping header on iOS using safe area insets
Isthisanmol Mar 29, 2026
5080b38
safe-area-header-overlap
Isthisanmol Mar 29, 2026
e32e492
prevent content from overlapping header on iOS using safe area insets
Isthisanmol Mar 29, 2026
c870ddd
safe-area-header-overlap-pack-template
Isthisanmol Mar 29, 2026
a482adf
chore: bump version to v2.0.17
mikib0 Mar 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/expo/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default (): ExpoConfig =>
{
name: getAppName(),
slug: 'packrat',
version: '2.0.16',
version: '2.0.17',
scheme: 'packrat',
web: {
bundler: 'metro',
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/app/(app)/(tabs)/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { cn } from 'expo-app/lib/cn';
import { hasUnsyncedChanges } from 'expo-app/lib/hasUnsyncedChanges';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { buildPackTemplateItemImageUrl } from 'expo-app/lib/utils/buildPackTemplateItemImageUrl';
import * as FileSystem from 'expo-file-system';
import * as FileSystem from 'expo-file-system/legacy';
import { router, Stack } from 'expo-router';
import * as Updates from 'expo-updates';
import { useRef, useState } from 'react';
Expand Down
44 changes: 42 additions & 2 deletions apps/expo/app/(app)/(tabs)/profile/notifications.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Button, Form, FormItem, FormSection, Text, Toggle } from '@packrat/ui/nativewindui';
import { Icon } from '@roninoss/icons';
import { cn } from 'expo-app/lib/cn';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { router, Stack } from 'expo-router';
import * as React from 'react';
import { Platform, ScrollView, View } from 'react-native';
import { Platform, Pressable, ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export default function NotificationsScreen() {
Expand All @@ -12,9 +13,10 @@ export default function NotificationsScreen() {
const [notifications, setNotifications] = React.useState({
push: true,
email: false,
weatherAlerts: true,
});

function onValueChange(type: 'push' | 'email') {
function onValueChange(type: 'push' | 'email' | 'weatherAlerts') {
return (value: boolean) => {
setNotifications((prev) => ({ ...prev, [type]: value }));
};
Expand Down Expand Up @@ -68,6 +70,44 @@ export default function NotificationsScreen() {
<Toggle value={notifications.email} onValueChange={onValueChange('email')} />
</FormItem>
</FormSection>

<FormSection
materialIconProps={{ name: 'weather-cloudy-alert' }}
title={t('profile.weatherAlerts')}
>
Comment thread
mikib0 marked this conversation as resolved.
<FormItem className="ios:px-4 ios:pb-2 ios:pt-2 flex-row items-center justify-between px-2 pb-4">
<View className="flex-1 flex-row items-center gap-2">
<View className="h-8 w-8 items-center justify-center rounded-lg bg-amber-500">
<Icon name="weather-rainy" size={18} color="white" />
</View>
<View className="flex-1">
<Text className="font-medium">{t('profile.weatherAlerts')}</Text>
<Text variant="caption1" className="text-muted-foreground">
{t('profile.weatherAlertsNotif')}
</Text>
</View>
</View>
<Toggle
value={notifications.weatherAlerts}
onValueChange={onValueChange('weatherAlerts')}
/>
</FormItem>
<FormItem className="ios:px-4 ios:pb-2 ios:pt-2 px-2 pb-4">
<Pressable
className="flex-row items-center justify-between"
onPress={() => router.push('/weather-alert-preferences')}
>
<View className="flex-1 flex-row items-center gap-2">
<View className="h-8 w-8 items-center justify-center rounded-lg bg-blue-500">
<Icon name="tune-vertical-variant" size={18} color="white" />
</View>
<Text className="font-medium">{t('profile.configureAlertTypes')}</Text>
</View>
<Icon name="chevron-right" size={17} color="#8E8E93" />
</Pressable>
Comment thread
mikib0 marked this conversation as resolved.
</FormItem>
</FormSection>

{Platform.OS !== 'ios' && (
<View className="items-end">
<Button
Expand Down
8 changes: 8 additions & 0 deletions apps/expo/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ export default function AppLayout() {
/>
<Stack.Screen
name="weather-alerts"
options={{
headerShown: false,
presentation: 'card',
animation: 'slide_from_bottom',
}}
/>
<Stack.Screen
name="weather-alert-preferences"
options={{
headerShown: false,
presentation: 'modal',
Expand Down
7 changes: 4 additions & 3 deletions apps/expo/app/(app)/current-pack/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { PackItem } from 'expo-app/types';
import { useLocalSearchParams } from 'expo-router';
import type React from 'react';
import { ScrollView, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';

function WeightCard({
title,
Expand Down Expand Up @@ -132,16 +132,17 @@ export default function CurrentPackScreen() {

const pack = usePackDetailsFromStore(params.id as string);
const uniqueCategories = computeCategorySummaries(pack);
const insets = useSafeAreaInsets();

return (
<SafeAreaView className="flex-1">
<SafeAreaView className="flex-1" style={{ paddingTop: insets.top }}>
<LargeTitleHeader title={t('packs.currentPack')} />
<ScrollView
className="flex-1"
contentContainerStyle={{ paddingBottom: 32 }}
removeClippedSubviews={false}
>
<View className="flex-row items-center p-4">
<View className="flex-row items-center p-4" style={{ paddingTop: insets.top }}>
Comment thread
mikib0 marked this conversation as resolved.
<Avatar className="mr-4 h-16 w-16" alt="">
<AvatarImage source={{ uri: pack.image }} />
<AvatarFallback>
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/app/(app)/pack-categories/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default function PackCategoriesScreen() {
</ScrollView>
) : (
<View className="flex-1 items-center justify-center">
<Text>{t('packs.noCategorizedItems')}</Text>
<Text className="text-center">{t('packs.noCategorizedItems')}</Text>
</View>
)}
</>
Expand Down
161 changes: 161 additions & 0 deletions apps/expo/app/(app)/weather-alert-preferences.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
Form,
FormItem,
FormSection,
LargeTitleHeader,
Text,
Toggle,
} from '@packrat/ui/nativewindui';
import { Icon } from '@roninoss/icons';
import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import * as React from 'react';
import { ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

type AlertPreferences = {
weatherNotifications: boolean;
locationMonitoring: boolean;
severeStorms: boolean;
tornadoWarnings: boolean;
floodAlerts: boolean;
fireDanger: boolean;
winterWeather: boolean;
extremeTemperature: boolean;
highWinds: boolean;
fogAlerts: boolean;
};

type AlertTypeConfig = {
key: keyof Omit<AlertPreferences, 'weatherNotifications' | 'locationMonitoring'>;
iconName: string;
iconColor: string;
};

const ALERT_TYPE_CONFIGS: AlertTypeConfig[] = [
{ key: 'severeStorms', iconName: 'weather-lightning-rainy', iconColor: '#FFCE56' },
{ key: 'tornadoWarnings', iconName: 'weather-tornado', iconColor: '#FF6384' },
{ key: 'floodAlerts', iconName: 'waves', iconColor: '#36A2EB' },
{ key: 'fireDanger', iconName: 'fire', iconColor: '#FF5722' },
{ key: 'winterWeather', iconName: 'weather-snowy-heavy', iconColor: '#90CAF9' },
{ key: 'extremeTemperature', iconName: 'thermometer-alert', iconColor: '#EF5350' },
{ key: 'highWinds', iconName: 'weather-windy', iconColor: '#4BC0C0' },
{ key: 'fogAlerts', iconName: 'weather-fog', iconColor: '#B0BEC5' },
];

export default function WeatherAlertPreferencesScreen() {
const insets = useSafeAreaInsets();
const { colors } = useColorScheme();
const { t } = useTranslation();

const [preferences, setPreferences] = React.useState<AlertPreferences>({
weatherNotifications: true,
locationMonitoring: true,
severeStorms: true,
tornadoWarnings: true,
floodAlerts: true,
fireDanger: true,
winterWeather: true,
extremeTemperature: true,
highWinds: false,
fogAlerts: false,
});
Comment thread
mikib0 marked this conversation as resolved.

function onToggle(key: keyof AlertPreferences) {
return (value: boolean) => {
setPreferences((prev) => ({ ...prev, [key]: value }));
};
}

const alertTypesDisabled = !preferences.weatherNotifications;

return (
<>
<LargeTitleHeader title={t('weather.alertPreferencesTitle')} />
<ScrollView
contentInsetAdjustmentBehavior="automatic"
contentContainerStyle={{ paddingBottom: insets.bottom + 16 }}
>
<Form className="gap-5 px-4 pt-4">
<FormSection
materialIconProps={{ name: 'bell-outline' }}
footnote={t('weather.alertPreferencesDesc')}
>
<FormItem className="ios:px-4 ios:pb-2 ios:pt-2 flex-row items-center justify-between px-2 pb-4">
<View className="flex-1 flex-row items-center gap-3">
<View className="h-8 w-8 items-center justify-center rounded-lg bg-amber-500">
<Icon name="bell-ring-outline" size={18} color="white" />
</View>
Comment thread
mikib0 marked this conversation as resolved.
<View className="flex-1">
<Text className="font-medium">{t('weather.weatherNotifications')}</Text>
<Text variant="caption1" className="text-muted-foreground">
{t('weather.weatherNotificationsDesc')}
</Text>
</View>
</View>
<Toggle
value={preferences.weatherNotifications}
onValueChange={onToggle('weatherNotifications')}
/>
</FormItem>
<FormItem className="ios:px-4 ios:pb-2 ios:pt-2 flex-row items-center justify-between px-2 pb-4">
<View className="flex-1 flex-row items-center gap-3">
<View className="h-8 w-8 items-center justify-center rounded-lg bg-blue-500">
<Icon name="map-marker-radius-outline" size={18} color="white" />
</View>
<View className="flex-1">
<Text className="font-medium">{t('weather.locationMonitoring')}</Text>
<Text variant="caption1" className="text-muted-foreground">
{t('weather.locationMonitoringDesc')}
</Text>
</View>
</View>
<Toggle
value={preferences.locationMonitoring}
onValueChange={onToggle('locationMonitoring')}
/>
</FormItem>
</FormSection>

<FormSection
ios={{ title: t('weather.alertTypes') }}
materialIconProps={{ name: 'alert-outline' }}
footnote={alertTypesDisabled ? t('weather.weatherNotificationsDesc') : undefined}
>
{ALERT_TYPE_CONFIGS.map(({ key, iconName, iconColor }) => (
<View
key={key}
style={{ opacity: alertTypesDisabled ? 0.5 : 1 }}
pointerEvents={alertTypesDisabled ? 'none' : 'auto'}
>
<FormItem className="ios:px-4 ios:pb-2 ios:pt-2 flex-row items-center justify-between px-2 pb-4">
<View className="flex-1 flex-row items-center gap-3">
<View
className="h-8 w-8 items-center justify-center rounded-lg"
style={{ backgroundColor: alertTypesDisabled ? colors.grey3 : iconColor }}
>
<Icon name={iconName as never} size={18} color="white" />
</View>
<View className="flex-1">
<Text
className={
alertTypesDisabled ? 'font-medium text-muted-foreground' : 'font-medium'
}
>
{t(`weather.${key}` as never)}
</Text>
<Text variant="caption1" className="text-muted-foreground">
{t(`weather.${key}Desc` as never)}
</Text>
</View>
</View>
<Toggle value={preferences[key]} onValueChange={onToggle(key)} />
</FormItem>
</View>
))}
</FormSection>
</Form>
</ScrollView>
</>
);
}
Loading
Loading