Add streaks, scheduled releases, and notification settings

- Couple streaks with milestone notifications
- Scheduled pack releases with admin UI
- Notification preferences screen
- Refactored profile settings screens
- Partner activity notifications
This commit is contained in:
jjbrunton committed 2026-01-17 16:38:47 +00:00
1 parent 12f312421b
commit 494ed17fe2
82 files changed
+4189 -725

No files matched your search

@@ -1,5 +1,8 @@
import React from 'react';
import React, { useEffect, useMemo } from 'react';
import { View, StyleSheet, Text } from 'react-native';
import { colors, spacing, typography } from '../../../theme';
import { useNotificationPreferencesStore } from '../../../store';
import { useAuthStore } from '../../../store';
import { SettingsSection } from './SettingsSection';
import { SwitchItem } from './SwitchItem';
@@ -16,16 +19,132 @@ export const NotificationSettings: React.FC<NotificationSettingsProps> = ({
onPushToggle,
delay = 360,
}) => {
const { user } = useAuthStore();
const { preferences, isUpdating, fetchPreferences, updatePreference } = useNotificationPreferencesStore();
// Fetch notification preferences on mount when user is available
useEffect(() => {
if (user?.id && !preferences) {
fetchPreferences();
}
}, [user?.id, preferences, fetchPreferences]);
// Memoize handlers to prevent unnecessary re-renders
const handlers = useMemo(() => ({
onMatchesToggle: (value: boolean) => updatePreference('matches_enabled', value),
onMessagesToggle: (value: boolean) => updatePreference('messages_enabled', value),
onPartnerActivityToggle: (value: boolean) => updatePreference('partner_activity_enabled', value),
onPackChangesToggle: (value: boolean) => updatePreference('pack_changes_enabled', value),
onNewPacksToggle: (value: boolean) => updatePreference('new_packs_enabled', value),
onStreakMilestonesToggle: (value: boolean) => updatePreference('streak_milestones_enabled', value),
}), [updatePreference]);
return (
<SettingsSection title="Notifications" delay={delay}>
{/* Master push toggle */}
<SwitchItem
icon="notifications-outline"
label="Push Notifications"
description="Get alerts for matches and messages"
description="Enable notifications on this device"
value={pushEnabled}
onValueChange={onPushToggle}
disabled={isUpdatingPush}
/>
{/* Granular settings - only show when push is enabled and preferences are loaded */}
{pushEnabled && preferences && (
<>
<View style={styles.sectionDivider}>
<Text style={styles.subsectionLabel}>Notification Types</Text>
</View>
<SwitchItem
icon="heart-outline"
label="Matches"
description="When you and your partner match"
value={preferences.matches_enabled}
onValueChange={handlers.onMatchesToggle}
disabled={isUpdating}
/>
<View style={styles.itemDivider} />
<SwitchItem
icon="chatbubble-outline"
label="Messages"
description="When your partner sends you a message"
value={preferences.messages_enabled}
onValueChange={handlers.onMessagesToggle}
disabled={isUpdating}
/>
<View style={styles.itemDivider} />
<SwitchItem
icon="person-outline"
label="Partner Activity"
description="When your partner answers questions"
value={preferences.partner_activity_enabled}
onValueChange={handlers.onPartnerActivityToggle}
disabled={isUpdating}
/>
<View style={styles.itemDivider} />
<SwitchItem
icon="layers-outline"
label="Pack Updates"
description="When your partner enables new packs"
value={preferences.pack_changes_enabled}
onValueChange={handlers.onPackChangesToggle}
disabled={isUpdating}
/>
<View style={styles.itemDivider} />
<SwitchItem
icon="sparkles-outline"
label="New Packs"
description="When new question packs are available"
value={preferences.new_packs_enabled}
onValueChange={handlers.onNewPacksToggle}
disabled={isUpdating}
/>
<View style={styles.itemDivider} />
<SwitchItem
icon="flame-outline"
label="Streak Milestones"
description="Celebrate your streak achievements"
value={preferences.streak_milestones_enabled}
onValueChange={handlers.onStreakMilestonesToggle}
disabled={isUpdating}
/>
</>
)}
</SettingsSection>
);
};
const styles = StyleSheet.create({
sectionDivider: {
marginTop: spacing.lg,
marginBottom: spacing.md,
paddingTop: spacing.md,
borderTopWidth: 1,
borderTopColor: colors.glass.border,
},
subsectionLabel: {
...typography.caption1,
color: colors.textTertiary,
fontWeight: '600',
letterSpacing: 1,
textTransform: 'uppercase',
},
itemDivider: {
height: 1,
backgroundColor: colors.glass.border,
marginVertical: spacing.sm,
},
});