@umituz/react-native-notifications 1.1.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/package.json +18 -40
  2. package/src/index.ts +84 -13
  3. package/src/infrastructure/config/reminderPresets.ts +120 -0
  4. package/src/infrastructure/hooks/useQuietHoursActions.ts +52 -0
  5. package/src/infrastructure/hooks/useReminderActions.ts +147 -0
  6. package/src/infrastructure/services/types.ts +137 -44
  7. package/src/infrastructure/storage/RemindersStore.ts +150 -0
  8. package/src/presentation/components/FormButton.tsx +66 -0
  9. package/src/presentation/components/FrequencySelector.tsx +72 -0
  10. package/src/presentation/components/NotificationsSection.tsx +96 -159
  11. package/src/presentation/components/QuietHoursCard.tsx +105 -0
  12. package/src/presentation/components/ReminderForm.tsx +165 -0
  13. package/src/presentation/components/ReminderItem.tsx +124 -0
  14. package/src/presentation/components/TimePresetSelector.tsx +100 -0
  15. package/src/presentation/components/WeekdaySelector.tsx +61 -0
  16. package/src/presentation/screens/NotificationSettingsScreen.tsx +210 -0
  17. package/src/presentation/screens/ReminderListScreen.tsx +138 -0
  18. package/src/types/global.d.ts +11 -8
  19. package/lib/index.d.ts +0 -16
  20. package/lib/index.d.ts.map +0 -1
  21. package/lib/index.js +0 -23
  22. package/lib/index.js.map +0 -1
  23. package/lib/infrastructure/config/notificationsConfig.d.ts +0 -20
  24. package/lib/infrastructure/config/notificationsConfig.d.ts.map +0 -1
  25. package/lib/infrastructure/config/notificationsConfig.js +0 -81
  26. package/lib/infrastructure/config/notificationsConfig.js.map +0 -1
  27. package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts +0 -7
  28. package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts.map +0 -1
  29. package/lib/infrastructure/hooks/actions/useNotificationActions.js +0 -75
  30. package/lib/infrastructure/hooks/actions/useNotificationActions.js.map +0 -1
  31. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts +0 -8
  32. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts.map +0 -1
  33. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js +0 -78
  34. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js.map +0 -1
  35. package/lib/infrastructure/hooks/state/useNotificationsState.d.ts +0 -12
  36. package/lib/infrastructure/hooks/state/useNotificationsState.d.ts.map +0 -1
  37. package/lib/infrastructure/hooks/state/useNotificationsState.js +0 -30
  38. package/lib/infrastructure/hooks/state/useNotificationsState.js.map +0 -1
  39. package/lib/infrastructure/hooks/types.d.ts +0 -87
  40. package/lib/infrastructure/hooks/types.d.ts.map +0 -1
  41. package/lib/infrastructure/hooks/types.js +0 -8
  42. package/lib/infrastructure/hooks/types.js.map +0 -1
  43. package/lib/infrastructure/hooks/useNotificationSettings.d.ts +0 -10
  44. package/lib/infrastructure/hooks/useNotificationSettings.d.ts.map +0 -1
  45. package/lib/infrastructure/hooks/useNotificationSettings.js +0 -43
  46. package/lib/infrastructure/hooks/useNotificationSettings.js.map +0 -1
  47. package/lib/infrastructure/hooks/useNotifications.d.ts +0 -24
  48. package/lib/infrastructure/hooks/useNotifications.d.ts.map +0 -1
  49. package/lib/infrastructure/hooks/useNotifications.js +0 -72
  50. package/lib/infrastructure/hooks/useNotifications.js.map +0 -1
  51. package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts +0 -8
  52. package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts.map +0 -1
  53. package/lib/infrastructure/hooks/utils/useNotificationRefresh.js +0 -99
  54. package/lib/infrastructure/hooks/utils/useNotificationRefresh.js.map +0 -1
  55. package/lib/infrastructure/services/NotificationBadgeManager.d.ts +0 -5
  56. package/lib/infrastructure/services/NotificationBadgeManager.d.ts.map +0 -1
  57. package/lib/infrastructure/services/NotificationBadgeManager.js +0 -29
  58. package/lib/infrastructure/services/NotificationBadgeManager.js.map +0 -1
  59. package/lib/infrastructure/services/NotificationManager.d.ts +0 -59
  60. package/lib/infrastructure/services/NotificationManager.d.ts.map +0 -1
  61. package/lib/infrastructure/services/NotificationManager.js +0 -118
  62. package/lib/infrastructure/services/NotificationManager.js.map +0 -1
  63. package/lib/infrastructure/services/NotificationPermissions.d.ts +0 -6
  64. package/lib/infrastructure/services/NotificationPermissions.d.ts.map +0 -1
  65. package/lib/infrastructure/services/NotificationPermissions.js +0 -75
  66. package/lib/infrastructure/services/NotificationPermissions.js.map +0 -1
  67. package/lib/infrastructure/services/NotificationScheduler.d.ts +0 -8
  68. package/lib/infrastructure/services/NotificationScheduler.d.ts.map +0 -1
  69. package/lib/infrastructure/services/NotificationScheduler.js +0 -72
  70. package/lib/infrastructure/services/NotificationScheduler.js.map +0 -1
  71. package/lib/infrastructure/services/NotificationService.d.ts +0 -30
  72. package/lib/infrastructure/services/NotificationService.d.ts.map +0 -1
  73. package/lib/infrastructure/services/NotificationService.js +0 -41
  74. package/lib/infrastructure/services/NotificationService.js.map +0 -1
  75. package/lib/infrastructure/services/channels/ChannelManager.d.ts +0 -18
  76. package/lib/infrastructure/services/channels/ChannelManager.d.ts.map +0 -1
  77. package/lib/infrastructure/services/channels/ChannelManager.js +0 -87
  78. package/lib/infrastructure/services/channels/ChannelManager.js.map +0 -1
  79. package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts +0 -10
  80. package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts.map +0 -1
  81. package/lib/infrastructure/services/delivery/NotificationDelivery.js +0 -71
  82. package/lib/infrastructure/services/delivery/NotificationDelivery.js.map +0 -1
  83. package/lib/infrastructure/services/preferences/PreferencesManager.d.ts +0 -18
  84. package/lib/infrastructure/services/preferences/PreferencesManager.d.ts.map +0 -1
  85. package/lib/infrastructure/services/preferences/PreferencesManager.js +0 -65
  86. package/lib/infrastructure/services/preferences/PreferencesManager.js.map +0 -1
  87. package/lib/infrastructure/services/types.d.ts +0 -89
  88. package/lib/infrastructure/services/types.d.ts.map +0 -1
  89. package/lib/infrastructure/services/types.js +0 -7
  90. package/lib/infrastructure/services/types.js.map +0 -1
  91. package/lib/infrastructure/storage/NotificationsStore.d.ts +0 -23
  92. package/lib/infrastructure/storage/NotificationsStore.d.ts.map +0 -1
  93. package/lib/infrastructure/storage/NotificationsStore.js +0 -26
  94. package/lib/infrastructure/storage/NotificationsStore.js.map +0 -1
  95. package/lib/infrastructure/utils/dev.d.ts +0 -5
  96. package/lib/infrastructure/utils/dev.d.ts.map +0 -1
  97. package/lib/infrastructure/utils/dev.js +0 -24
  98. package/lib/infrastructure/utils/dev.js.map +0 -1
  99. package/lib/presentation/components/NotificationsSection.d.ts +0 -17
  100. package/lib/presentation/components/NotificationsSection.d.ts.map +0 -1
  101. package/lib/presentation/components/NotificationsSection.js +0 -132
  102. package/lib/presentation/components/NotificationsSection.js.map +0 -1
  103. package/lib/presentation/screens/NotificationsScreen.d.ts +0 -20
  104. package/lib/presentation/screens/NotificationsScreen.d.ts.map +0 -1
  105. package/lib/presentation/screens/NotificationsScreen.js +0 -74
  106. package/lib/presentation/screens/NotificationsScreen.js.map +0 -1
  107. package/src/__tests__/NotificationManager.test.ts +0 -215
  108. package/src/__tests__/useNotificationActions.test.ts +0 -189
  109. package/src/__tests__/useNotificationRefresh.test.ts +0 -213
  110. package/src/infrastructure/hooks/actions/useNotificationActions.ts +0 -131
  111. package/src/infrastructure/hooks/actions/useNotificationManagementActions.ts +0 -131
  112. package/src/infrastructure/hooks/state/useNotificationsState.ts +0 -46
  113. package/src/infrastructure/hooks/types.ts +0 -83
  114. package/src/infrastructure/hooks/useNotifications.ts +0 -96
  115. package/src/infrastructure/hooks/utils/useNotificationRefresh.ts +0 -131
  116. package/src/infrastructure/services/channels/ChannelManager.ts +0 -111
  117. package/src/infrastructure/services/delivery/NotificationDelivery.ts +0 -83
  118. package/src/infrastructure/services/preferences/PreferencesManager.ts +0 -77
@@ -1,81 +1,174 @@
1
1
  /**
2
2
  * Offline-First Notification Types
3
3
  * Uses expo-notifications for local device notifications
4
- * NO backend, NO user IDs, NO push notifications
5
4
  */
6
5
 
7
- /**
8
- * Notification channel for managing notification delivery
9
- */
6
+ // ============================================================================
7
+ // NOTIFICATION CHANNEL TYPES
8
+ // ============================================================================
9
+
10
10
  export interface NotificationChannel {
11
11
  id: string;
12
12
  channel_type: 'push' | 'in_app';
13
13
  channel_address: string;
14
- preferences: Record<string, any>;
14
+ preferences: Record<string, unknown>;
15
15
  is_verified: boolean;
16
16
  is_active: boolean;
17
17
  created_at: string;
18
18
  }
19
19
 
20
- /**
21
- * Notification data structure
22
- */
23
- export interface Notification {
24
- id: string;
25
- title: string;
26
- body: string;
27
- scheduled_for?: string;
28
- data?: Record<string, any>;
29
- }
20
+ // ============================================================================
21
+ // NOTIFICATION TRIGGER TYPES
22
+ // ============================================================================
30
23
 
31
- /**
32
- * User notification preferences
33
- */
34
- export interface NotificationPreferences {
35
- push_enabled: boolean;
36
- quiet_hours: {
37
- enabled: boolean;
38
- start_time: string;
39
- end_time: string;
40
- timezone: string;
41
- };
42
- categories: Record<string, {
43
- push: boolean;
44
- in_app: boolean;
45
- }>;
46
- }
47
-
48
- /**
49
- * Trigger types for scheduling notifications
50
- */
51
24
  export type NotificationTrigger =
52
25
  | { type: 'date'; date: Date }
53
26
  | { type: 'daily'; hour: number; minute: number }
54
27
  | { type: 'weekly'; weekday: number; hour: number; minute: number }
55
28
  | { type: 'monthly'; day: number; hour: number; minute: number };
56
29
 
57
- /**
58
- * Options for scheduling a notification
59
- */
60
30
  export interface ScheduleNotificationOptions {
61
31
  title: string;
62
32
  body: string;
63
- data?: Record<string, any>;
33
+ data?: Record<string, unknown>;
64
34
  trigger: NotificationTrigger;
65
35
  sound?: boolean | string;
66
36
  badge?: number;
67
37
  categoryIdentifier?: string;
68
38
  }
69
39
 
70
- /**
71
- * Scheduled notification details
72
- */
73
40
  export interface ScheduledNotification {
74
41
  identifier: string;
75
42
  content: {
76
43
  title: string;
77
44
  body: string;
78
- data: Record<string, any>;
45
+ data: Record<string, unknown>;
79
46
  };
80
- trigger: any;
47
+ trigger: unknown;
48
+ }
49
+
50
+ // ============================================================================
51
+ // TIME PRESET TYPES
52
+ // ============================================================================
53
+
54
+ export interface TimePreset {
55
+ id: string;
56
+ hour: number;
57
+ minute: number;
58
+ labelKey: string;
59
+ iconName: string;
60
+ }
61
+
62
+ // ============================================================================
63
+ // REMINDER TYPES
64
+ // ============================================================================
65
+
66
+ export type ReminderFrequency = 'once' | 'daily' | 'weekly' | 'monthly';
67
+
68
+ export interface Reminder {
69
+ id: string;
70
+ title: string;
71
+ body: string;
72
+ frequency: ReminderFrequency;
73
+ timePresetId?: string;
74
+ hour: number;
75
+ minute: number;
76
+ weekday?: number;
77
+ dayOfMonth?: number;
78
+ enabled: boolean;
79
+ notificationId?: string;
80
+ createdAt: string;
81
+ updatedAt: string;
82
+ }
83
+
84
+ export interface CreateReminderInput {
85
+ title: string;
86
+ body: string;
87
+ frequency: ReminderFrequency;
88
+ timePresetId?: string;
89
+ hour: number;
90
+ minute: number;
91
+ weekday?: number;
92
+ dayOfMonth?: number;
93
+ }
94
+
95
+ export interface UpdateReminderInput {
96
+ title?: string;
97
+ body?: string;
98
+ frequency?: ReminderFrequency;
99
+ timePresetId?: string;
100
+ hour?: number;
101
+ minute?: number;
102
+ weekday?: number;
103
+ dayOfMonth?: number;
104
+ enabled?: boolean;
105
+ }
106
+
107
+ // ============================================================================
108
+ // QUIET HOURS TYPES
109
+ // ============================================================================
110
+
111
+ export interface QuietHoursConfig {
112
+ enabled: boolean;
113
+ startHour: number;
114
+ startMinute: number;
115
+ endHour: number;
116
+ endMinute: number;
117
+ }
118
+
119
+ // ============================================================================
120
+ // NOTIFICATION PREFERENCES
121
+ // ============================================================================
122
+
123
+ export interface NotificationPreferences {
124
+ enabled: boolean;
125
+ sound: boolean;
126
+ vibration: boolean;
127
+ quietHours: QuietHoursConfig;
128
+ }
129
+
130
+ // ============================================================================
131
+ // SCREEN CONFIGURATION TYPES
132
+ // ============================================================================
133
+
134
+ export interface ReminderTranslations {
135
+ screenTitle: string;
136
+ emptyTitle: string;
137
+ emptyDescription: string;
138
+ addButtonLabel: string;
139
+ editButtonLabel: string;
140
+ deleteButtonLabel: string;
141
+ enabledLabel: string;
142
+ disabledLabel: string;
143
+ frequencyOnce: string;
144
+ frequencyDaily: string;
145
+ frequencyWeekly: string;
146
+ frequencyMonthly: string;
147
+ timeLabel: string;
148
+ titlePlaceholder: string;
149
+ bodyPlaceholder: string;
150
+ saveButtonLabel: string;
151
+ cancelButtonLabel: string;
152
+ }
153
+
154
+ export interface QuietHoursTranslations {
155
+ title: string;
156
+ description: string;
157
+ startTimeLabel: string;
158
+ endTimeLabel: string;
159
+ enabledLabel: string;
160
+ }
161
+
162
+ export interface NotificationSettingsTranslations {
163
+ screenTitle: string;
164
+ masterToggleTitle: string;
165
+ masterToggleDescription: string;
166
+ soundTitle: string;
167
+ soundDescription: string;
168
+ vibrationTitle: string;
169
+ vibrationDescription: string;
170
+ remindersTitle: string;
171
+ remindersDescription: string;
172
+ quietHoursTitle: string;
173
+ quietHoursDescription: string;
81
174
  }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Reminders Store - Zustand State Management
3
+ * Manages reminder state with AsyncStorage persistence
4
+ */
5
+
6
+ import { create } from 'zustand';
7
+ import AsyncStorage from '@react-native-async-storage/async-storage';
8
+ import type { Reminder, QuietHoursConfig, NotificationPreferences } from '../services/types';
9
+
10
+ const STORAGE_KEYS = {
11
+ REMINDERS: '@notifications:reminders',
12
+ PREFERENCES: '@notifications:preferences',
13
+ QUIET_HOURS: '@notifications:quiet_hours',
14
+ } as const;
15
+
16
+ // ============================================================================
17
+ // STORE INTERFACE
18
+ // ============================================================================
19
+
20
+ interface RemindersState {
21
+ reminders: Reminder[];
22
+ preferences: NotificationPreferences;
23
+ isLoading: boolean;
24
+ isInitialized: boolean;
25
+ }
26
+
27
+ interface RemindersActions {
28
+ loadReminders: () => Promise<void>;
29
+ addReminder: (reminder: Reminder) => Promise<void>;
30
+ updateReminder: (id: string, updates: Partial<Reminder>) => Promise<void>;
31
+ deleteReminder: (id: string) => Promise<void>;
32
+ toggleReminder: (id: string) => Promise<void>;
33
+ loadPreferences: () => Promise<void>;
34
+ updatePreferences: (updates: Partial<NotificationPreferences>) => Promise<void>;
35
+ updateQuietHours: (quietHours: QuietHoursConfig) => Promise<void>;
36
+ reset: () => Promise<void>;
37
+ }
38
+
39
+ type RemindersStore = RemindersState & RemindersActions;
40
+
41
+ // ============================================================================
42
+ // DEFAULT VALUES
43
+ // ============================================================================
44
+
45
+ const DEFAULT_PREFERENCES: NotificationPreferences = {
46
+ enabled: false,
47
+ sound: false,
48
+ vibration: false,
49
+ quietHours: {
50
+ enabled: false,
51
+ startHour: 22,
52
+ startMinute: 0,
53
+ endHour: 7,
54
+ endMinute: 0,
55
+ },
56
+ };
57
+
58
+ // ============================================================================
59
+ // STORE IMPLEMENTATION
60
+ // ============================================================================
61
+
62
+ export const useRemindersStore = create<RemindersStore>((set, get) => ({
63
+ reminders: [],
64
+ preferences: DEFAULT_PREFERENCES,
65
+ isLoading: true,
66
+ isInitialized: false,
67
+
68
+ loadReminders: async () => {
69
+ try {
70
+ const data = await AsyncStorage.getItem(STORAGE_KEYS.REMINDERS);
71
+ const reminders = data ? JSON.parse(data) : [];
72
+ set({ reminders, isLoading: false, isInitialized: true });
73
+ } catch {
74
+ set({ reminders: [], isLoading: false, isInitialized: true });
75
+ }
76
+ },
77
+
78
+ addReminder: async (reminder: Reminder) => {
79
+ const { reminders } = get();
80
+ const updated = [...reminders, reminder];
81
+ set({ reminders: updated });
82
+ await AsyncStorage.setItem(STORAGE_KEYS.REMINDERS, JSON.stringify(updated));
83
+ },
84
+
85
+ updateReminder: async (id: string, updates: Partial<Reminder>) => {
86
+ const { reminders } = get();
87
+ const updated = reminders.map(r =>
88
+ r.id === id ? { ...r, ...updates, updatedAt: new Date().toISOString() } : r
89
+ );
90
+ set({ reminders: updated });
91
+ await AsyncStorage.setItem(STORAGE_KEYS.REMINDERS, JSON.stringify(updated));
92
+ },
93
+
94
+ deleteReminder: async (id: string) => {
95
+ const { reminders } = get();
96
+ const updated = reminders.filter(r => r.id !== id);
97
+ set({ reminders: updated });
98
+ await AsyncStorage.setItem(STORAGE_KEYS.REMINDERS, JSON.stringify(updated));
99
+ },
100
+
101
+ toggleReminder: async (id: string) => {
102
+ const { reminders } = get();
103
+ const updated = reminders.map(r =>
104
+ r.id === id ? { ...r, enabled: !r.enabled, updatedAt: new Date().toISOString() } : r
105
+ );
106
+ set({ reminders: updated });
107
+ await AsyncStorage.setItem(STORAGE_KEYS.REMINDERS, JSON.stringify(updated));
108
+ },
109
+
110
+ loadPreferences: async () => {
111
+ try {
112
+ const data = await AsyncStorage.getItem(STORAGE_KEYS.PREFERENCES);
113
+ const preferences = data ? { ...DEFAULT_PREFERENCES, ...JSON.parse(data) } : DEFAULT_PREFERENCES;
114
+ set({ preferences });
115
+ } catch {
116
+ set({ preferences: DEFAULT_PREFERENCES });
117
+ }
118
+ },
119
+
120
+ updatePreferences: async (updates: Partial<NotificationPreferences>) => {
121
+ const { preferences } = get();
122
+ const updated = { ...preferences, ...updates };
123
+ set({ preferences: updated });
124
+ await AsyncStorage.setItem(STORAGE_KEYS.PREFERENCES, JSON.stringify(updated));
125
+ },
126
+
127
+ updateQuietHours: async (quietHours: QuietHoursConfig) => {
128
+ const { preferences } = get();
129
+ const updated = { ...preferences, quietHours };
130
+ set({ preferences: updated });
131
+ await AsyncStorage.setItem(STORAGE_KEYS.PREFERENCES, JSON.stringify(updated));
132
+ },
133
+
134
+ reset: async () => {
135
+ set({ reminders: [], preferences: DEFAULT_PREFERENCES });
136
+ await AsyncStorage.multiRemove([STORAGE_KEYS.REMINDERS, STORAGE_KEYS.PREFERENCES]);
137
+ },
138
+ }));
139
+
140
+ // ============================================================================
141
+ // SELECTOR HOOKS
142
+ // ============================================================================
143
+
144
+ export const useReminders = () => useRemindersStore(state => state.reminders);
145
+ export const useEnabledReminders = () => useRemindersStore(state => state.reminders.filter(r => r.enabled));
146
+ export const useReminderById = (id: string) => useRemindersStore(state => state.reminders.find(r => r.id === id));
147
+ export const useNotificationPreferences = () => useRemindersStore(state => state.preferences);
148
+ export const useQuietHours = () => useRemindersStore(state => state.preferences.quietHours);
149
+ export const useRemindersLoading = () => useRemindersStore(state => state.isLoading);
150
+ export const useRemindersInitialized = () => useRemindersStore(state => state.isInitialized);
@@ -0,0 +1,66 @@
1
+ /**
2
+ * FormButton Component
3
+ * Simple button for forms
4
+ */
5
+
6
+ import React, { useMemo } from 'react';
7
+ import { TouchableOpacity, StyleSheet } from 'react-native';
8
+ import { AtomicText } from '@umituz/react-native-design-system';
9
+ import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
10
+
11
+ export interface FormButtonProps {
12
+ label: string;
13
+ onPress: () => void;
14
+ variant?: 'primary' | 'secondary';
15
+ disabled?: boolean;
16
+ }
17
+
18
+ export const FormButton: React.FC<FormButtonProps> = ({
19
+ label,
20
+ onPress,
21
+ variant = 'primary',
22
+ disabled = false,
23
+ }) => {
24
+ const tokens = useAppDesignTokens();
25
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
26
+
27
+ const isPrimary = variant === 'primary';
28
+
29
+ return (
30
+ <TouchableOpacity
31
+ style={[
32
+ styles.button,
33
+ isPrimary ? styles.primaryButton : styles.secondaryButton,
34
+ disabled ? styles.disabled : undefined,
35
+ ]}
36
+ onPress={onPress}
37
+ disabled={disabled}
38
+ activeOpacity={0.7}
39
+ >
40
+ <AtomicText
41
+ type="bodyMedium"
42
+ style={[styles.label, isPrimary ? styles.primaryLabel : styles.secondaryLabel]}
43
+ >
44
+ {label}
45
+ </AtomicText>
46
+ </TouchableOpacity>
47
+ );
48
+ };
49
+
50
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
51
+ StyleSheet.create({
52
+ button: {
53
+ flex: 1,
54
+ paddingVertical: 14,
55
+ paddingHorizontal: 16,
56
+ borderRadius: 10,
57
+ alignItems: 'center',
58
+ justifyContent: 'center',
59
+ },
60
+ primaryButton: { backgroundColor: tokens.colors.primary },
61
+ secondaryButton: { backgroundColor: tokens.colors.surfaceSecondary },
62
+ disabled: { opacity: 0.5 },
63
+ label: { fontWeight: '600' },
64
+ primaryLabel: { color: tokens.colors.surface },
65
+ secondaryLabel: { color: tokens.colors.textPrimary },
66
+ });
@@ -0,0 +1,72 @@
1
+ /**
2
+ * FrequencySelector Component
3
+ * Allows selection of reminder frequency
4
+ */
5
+
6
+ import React, { useMemo } from 'react';
7
+ import { View, TouchableOpacity, StyleSheet } from 'react-native';
8
+ import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
9
+ import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
10
+ import type { ReminderFrequency } from '../../infrastructure/services/types';
11
+ import type { FrequencyOption } from '../../infrastructure/config/reminderPresets';
12
+
13
+ export interface FrequencySelectorProps {
14
+ options: FrequencyOption[];
15
+ selectedFrequency: ReminderFrequency;
16
+ onSelect: (frequency: ReminderFrequency) => void;
17
+ getLabel: (labelKey: string) => string;
18
+ }
19
+
20
+ export const FrequencySelector: React.FC<FrequencySelectorProps> = ({
21
+ options,
22
+ selectedFrequency,
23
+ onSelect,
24
+ getLabel,
25
+ }) => {
26
+ const tokens = useAppDesignTokens();
27
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
28
+
29
+ return (
30
+ <View style={styles.container}>
31
+ {options.map(option => {
32
+ const isSelected = selectedFrequency === option.id;
33
+ return (
34
+ <TouchableOpacity
35
+ key={option.id}
36
+ style={[styles.button, isSelected ? styles.selectedButton : undefined]}
37
+ onPress={() => onSelect(option.id)}
38
+ activeOpacity={0.7}
39
+ >
40
+ <AtomicIcon
41
+ name={option.iconName}
42
+ size="sm"
43
+ color={isSelected ? 'surface' : 'textSecondary'}
44
+ />
45
+ <AtomicText type="bodySmall" style={isSelected ? styles.selectedText : styles.text}>
46
+ {getLabel(option.labelKey)}
47
+ </AtomicText>
48
+ </TouchableOpacity>
49
+ );
50
+ })}
51
+ </View>
52
+ );
53
+ };
54
+
55
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
56
+ StyleSheet.create({
57
+ container: { flexDirection: 'row', gap: 8 },
58
+ button: {
59
+ flex: 1,
60
+ flexDirection: 'row',
61
+ alignItems: 'center',
62
+ justifyContent: 'center',
63
+ paddingVertical: 10,
64
+ paddingHorizontal: 8,
65
+ borderRadius: 8,
66
+ backgroundColor: tokens.colors.surfaceSecondary,
67
+ gap: 6,
68
+ },
69
+ selectedButton: { backgroundColor: tokens.colors.primary },
70
+ text: { color: tokens.colors.textSecondary },
71
+ selectedText: { color: tokens.colors.surface },
72
+ });