@umituz/react-native-notifications 1.1.7 → 1.3.1

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 (119) 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 +95 -160
  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/NotificationsScreen.tsx +1 -1
  18. package/src/presentation/screens/ReminderListScreen.tsx +138 -0
  19. package/src/types/global.d.ts +11 -8
  20. package/lib/index.d.ts +0 -16
  21. package/lib/index.d.ts.map +0 -1
  22. package/lib/index.js +0 -23
  23. package/lib/index.js.map +0 -1
  24. package/lib/infrastructure/config/notificationsConfig.d.ts +0 -20
  25. package/lib/infrastructure/config/notificationsConfig.d.ts.map +0 -1
  26. package/lib/infrastructure/config/notificationsConfig.js +0 -81
  27. package/lib/infrastructure/config/notificationsConfig.js.map +0 -1
  28. package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts +0 -7
  29. package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts.map +0 -1
  30. package/lib/infrastructure/hooks/actions/useNotificationActions.js +0 -75
  31. package/lib/infrastructure/hooks/actions/useNotificationActions.js.map +0 -1
  32. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts +0 -8
  33. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts.map +0 -1
  34. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js +0 -78
  35. package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js.map +0 -1
  36. package/lib/infrastructure/hooks/state/useNotificationsState.d.ts +0 -12
  37. package/lib/infrastructure/hooks/state/useNotificationsState.d.ts.map +0 -1
  38. package/lib/infrastructure/hooks/state/useNotificationsState.js +0 -30
  39. package/lib/infrastructure/hooks/state/useNotificationsState.js.map +0 -1
  40. package/lib/infrastructure/hooks/types.d.ts +0 -87
  41. package/lib/infrastructure/hooks/types.d.ts.map +0 -1
  42. package/lib/infrastructure/hooks/types.js +0 -8
  43. package/lib/infrastructure/hooks/types.js.map +0 -1
  44. package/lib/infrastructure/hooks/useNotificationSettings.d.ts +0 -10
  45. package/lib/infrastructure/hooks/useNotificationSettings.d.ts.map +0 -1
  46. package/lib/infrastructure/hooks/useNotificationSettings.js +0 -43
  47. package/lib/infrastructure/hooks/useNotificationSettings.js.map +0 -1
  48. package/lib/infrastructure/hooks/useNotifications.d.ts +0 -24
  49. package/lib/infrastructure/hooks/useNotifications.d.ts.map +0 -1
  50. package/lib/infrastructure/hooks/useNotifications.js +0 -72
  51. package/lib/infrastructure/hooks/useNotifications.js.map +0 -1
  52. package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts +0 -8
  53. package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts.map +0 -1
  54. package/lib/infrastructure/hooks/utils/useNotificationRefresh.js +0 -99
  55. package/lib/infrastructure/hooks/utils/useNotificationRefresh.js.map +0 -1
  56. package/lib/infrastructure/services/NotificationBadgeManager.d.ts +0 -5
  57. package/lib/infrastructure/services/NotificationBadgeManager.d.ts.map +0 -1
  58. package/lib/infrastructure/services/NotificationBadgeManager.js +0 -29
  59. package/lib/infrastructure/services/NotificationBadgeManager.js.map +0 -1
  60. package/lib/infrastructure/services/NotificationManager.d.ts +0 -59
  61. package/lib/infrastructure/services/NotificationManager.d.ts.map +0 -1
  62. package/lib/infrastructure/services/NotificationManager.js +0 -118
  63. package/lib/infrastructure/services/NotificationManager.js.map +0 -1
  64. package/lib/infrastructure/services/NotificationPermissions.d.ts +0 -6
  65. package/lib/infrastructure/services/NotificationPermissions.d.ts.map +0 -1
  66. package/lib/infrastructure/services/NotificationPermissions.js +0 -75
  67. package/lib/infrastructure/services/NotificationPermissions.js.map +0 -1
  68. package/lib/infrastructure/services/NotificationScheduler.d.ts +0 -8
  69. package/lib/infrastructure/services/NotificationScheduler.d.ts.map +0 -1
  70. package/lib/infrastructure/services/NotificationScheduler.js +0 -72
  71. package/lib/infrastructure/services/NotificationScheduler.js.map +0 -1
  72. package/lib/infrastructure/services/NotificationService.d.ts +0 -30
  73. package/lib/infrastructure/services/NotificationService.d.ts.map +0 -1
  74. package/lib/infrastructure/services/NotificationService.js +0 -41
  75. package/lib/infrastructure/services/NotificationService.js.map +0 -1
  76. package/lib/infrastructure/services/channels/ChannelManager.d.ts +0 -18
  77. package/lib/infrastructure/services/channels/ChannelManager.d.ts.map +0 -1
  78. package/lib/infrastructure/services/channels/ChannelManager.js +0 -87
  79. package/lib/infrastructure/services/channels/ChannelManager.js.map +0 -1
  80. package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts +0 -10
  81. package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts.map +0 -1
  82. package/lib/infrastructure/services/delivery/NotificationDelivery.js +0 -71
  83. package/lib/infrastructure/services/delivery/NotificationDelivery.js.map +0 -1
  84. package/lib/infrastructure/services/preferences/PreferencesManager.d.ts +0 -18
  85. package/lib/infrastructure/services/preferences/PreferencesManager.d.ts.map +0 -1
  86. package/lib/infrastructure/services/preferences/PreferencesManager.js +0 -65
  87. package/lib/infrastructure/services/preferences/PreferencesManager.js.map +0 -1
  88. package/lib/infrastructure/services/types.d.ts +0 -89
  89. package/lib/infrastructure/services/types.d.ts.map +0 -1
  90. package/lib/infrastructure/services/types.js +0 -7
  91. package/lib/infrastructure/services/types.js.map +0 -1
  92. package/lib/infrastructure/storage/NotificationsStore.d.ts +0 -23
  93. package/lib/infrastructure/storage/NotificationsStore.d.ts.map +0 -1
  94. package/lib/infrastructure/storage/NotificationsStore.js +0 -26
  95. package/lib/infrastructure/storage/NotificationsStore.js.map +0 -1
  96. package/lib/infrastructure/utils/dev.d.ts +0 -5
  97. package/lib/infrastructure/utils/dev.d.ts.map +0 -1
  98. package/lib/infrastructure/utils/dev.js +0 -24
  99. package/lib/infrastructure/utils/dev.js.map +0 -1
  100. package/lib/presentation/components/NotificationsSection.d.ts +0 -17
  101. package/lib/presentation/components/NotificationsSection.d.ts.map +0 -1
  102. package/lib/presentation/components/NotificationsSection.js +0 -133
  103. package/lib/presentation/components/NotificationsSection.js.map +0 -1
  104. package/lib/presentation/screens/NotificationsScreen.d.ts +0 -20
  105. package/lib/presentation/screens/NotificationsScreen.d.ts.map +0 -1
  106. package/lib/presentation/screens/NotificationsScreen.js +0 -74
  107. package/lib/presentation/screens/NotificationsScreen.js.map +0 -1
  108. package/src/__tests__/NotificationManager.test.ts +0 -215
  109. package/src/__tests__/useNotificationActions.test.ts +0 -189
  110. package/src/__tests__/useNotificationRefresh.test.ts +0 -213
  111. package/src/infrastructure/hooks/actions/useNotificationActions.ts +0 -131
  112. package/src/infrastructure/hooks/actions/useNotificationManagementActions.ts +0 -131
  113. package/src/infrastructure/hooks/state/useNotificationsState.ts +0 -46
  114. package/src/infrastructure/hooks/types.ts +0 -83
  115. package/src/infrastructure/hooks/useNotifications.ts +0 -96
  116. package/src/infrastructure/hooks/utils/useNotificationRefresh.ts +0 -131
  117. package/src/infrastructure/services/channels/ChannelManager.ts +0 -111
  118. package/src/infrastructure/services/delivery/NotificationDelivery.ts +0 -83
  119. package/src/infrastructure/services/preferences/PreferencesManager.ts +0 -77
@@ -0,0 +1,100 @@
1
+ /**
2
+ * TimePresetSelector Component
3
+ * Allows selection of preset times or custom time
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 { TimePreset } from '../../infrastructure/services/types';
11
+
12
+ export interface TimePresetSelectorProps {
13
+ presets: TimePreset[];
14
+ selectedPresetId?: string;
15
+ customTime?: { hour: number; minute: number };
16
+ onSelectPreset: (preset: TimePreset) => void;
17
+ onSelectCustom: () => void;
18
+ getPresetLabel: (labelKey: string) => string;
19
+ customLabel: string;
20
+ isCustomSelected: boolean;
21
+ }
22
+
23
+ const formatTime = (hour: number, minute: number): string => {
24
+ return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
25
+ };
26
+
27
+ export const TimePresetSelector: React.FC<TimePresetSelectorProps> = ({
28
+ presets,
29
+ selectedPresetId,
30
+ customTime,
31
+ onSelectPreset,
32
+ onSelectCustom,
33
+ getPresetLabel,
34
+ customLabel,
35
+ isCustomSelected,
36
+ }) => {
37
+ const tokens = useAppDesignTokens();
38
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
39
+
40
+ return (
41
+ <View style={styles.container}>
42
+ {presets.map(preset => {
43
+ const isSelected = selectedPresetId === preset.id && !isCustomSelected;
44
+ return (
45
+ <TouchableOpacity
46
+ key={preset.id}
47
+ style={[styles.button, isSelected ? styles.selectedButton : undefined]}
48
+ onPress={() => onSelectPreset(preset)}
49
+ activeOpacity={0.7}
50
+ >
51
+ <AtomicIcon
52
+ name={preset.iconName}
53
+ size="md"
54
+ color={isSelected ? 'surface' : 'textSecondary'}
55
+ />
56
+ <AtomicText type="bodySmall" style={isSelected ? styles.selectedText : styles.text}>
57
+ {getPresetLabel(preset.labelKey)}
58
+ </AtomicText>
59
+ <AtomicText type="bodySmall" style={isSelected ? styles.selectedText : styles.subText}>
60
+ {formatTime(preset.hour, preset.minute)}
61
+ </AtomicText>
62
+ </TouchableOpacity>
63
+ );
64
+ })}
65
+
66
+ <TouchableOpacity
67
+ style={[styles.button, isCustomSelected ? styles.selectedButton : undefined]}
68
+ onPress={onSelectCustom}
69
+ activeOpacity={0.7}
70
+ >
71
+ <AtomicIcon name="time" size="md" color={isCustomSelected ? 'surface' : 'textSecondary'} />
72
+ <AtomicText type="bodySmall" style={isCustomSelected ? styles.selectedText : styles.text}>
73
+ {customLabel}
74
+ </AtomicText>
75
+ {customTime ? (
76
+ <AtomicText type="bodySmall" style={isCustomSelected ? styles.selectedText : styles.subText}>
77
+ {formatTime(customTime.hour, customTime.minute)}
78
+ </AtomicText>
79
+ ) : null}
80
+ </TouchableOpacity>
81
+ </View>
82
+ );
83
+ };
84
+
85
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
86
+ StyleSheet.create({
87
+ container: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
88
+ button: {
89
+ paddingVertical: 8,
90
+ paddingHorizontal: 12,
91
+ borderRadius: 8,
92
+ backgroundColor: tokens.colors.surfaceSecondary,
93
+ alignItems: 'center',
94
+ minWidth: 72,
95
+ },
96
+ selectedButton: { backgroundColor: tokens.colors.primary },
97
+ text: { color: tokens.colors.textSecondary, marginTop: 4 },
98
+ subText: { color: tokens.colors.textSecondary, marginTop: 2, opacity: 0.7 },
99
+ selectedText: { color: tokens.colors.surface, marginTop: 4 },
100
+ });
@@ -0,0 +1,61 @@
1
+ /**
2
+ * WeekdaySelector Component
3
+ * Allows selection of a weekday for weekly reminders
4
+ */
5
+
6
+ import React, { useMemo } from 'react';
7
+ import { View, 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
+ import { WEEKDAY_OPTIONS } from '../../infrastructure/config/reminderPresets';
11
+
12
+ export interface WeekdaySelectorProps {
13
+ selectedWeekday: number;
14
+ onSelect: (weekday: number) => void;
15
+ getLabel: (key: string) => string;
16
+ }
17
+
18
+ export const WeekdaySelector: React.FC<WeekdaySelectorProps> = ({
19
+ selectedWeekday,
20
+ onSelect,
21
+ getLabel,
22
+ }) => {
23
+ const tokens = useAppDesignTokens();
24
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
25
+
26
+ return (
27
+ <View style={styles.container}>
28
+ {WEEKDAY_OPTIONS.map(option => {
29
+ const isSelected = selectedWeekday === option.id;
30
+ return (
31
+ <TouchableOpacity
32
+ key={option.id}
33
+ style={[styles.button, isSelected ? styles.selectedButton : undefined]}
34
+ onPress={() => onSelect(option.id)}
35
+ activeOpacity={0.7}
36
+ >
37
+ <AtomicText type="bodySmall" style={isSelected ? styles.selectedText : styles.text}>
38
+ {getLabel(option.shortLabelKey)}
39
+ </AtomicText>
40
+ </TouchableOpacity>
41
+ );
42
+ })}
43
+ </View>
44
+ );
45
+ };
46
+
47
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
48
+ StyleSheet.create({
49
+ container: { flexDirection: 'row', justifyContent: 'space-between', gap: 4 },
50
+ button: {
51
+ flex: 1,
52
+ paddingVertical: 10,
53
+ paddingHorizontal: 4,
54
+ borderRadius: 8,
55
+ backgroundColor: tokens.colors.surfaceSecondary,
56
+ alignItems: 'center',
57
+ },
58
+ selectedButton: { backgroundColor: tokens.colors.primary },
59
+ text: { color: tokens.colors.textSecondary, fontWeight: '500' },
60
+ selectedText: { color: tokens.colors.surface, fontWeight: '500' },
61
+ });
@@ -0,0 +1,210 @@
1
+ /**
2
+ * NotificationSettingsScreen
3
+ * Professional notification settings with all options
4
+ */
5
+
6
+ import React, { useEffect, useMemo, useCallback } from 'react';
7
+ import { View, StyleSheet, ActivityIndicator, ScrollView, TouchableOpacity } from 'react-native';
8
+ import { AtomicText, AtomicIcon, AtomicSwitch, AtomicCard, ScreenLayout } from '@umituz/react-native-design-system';
9
+ import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
10
+ import { QuietHoursCard } from '../components/QuietHoursCard';
11
+ import { useRemindersStore, useNotificationPreferences, useQuietHours, useReminders } from '../../infrastructure/storage/RemindersStore';
12
+ import { notificationService } from '../../infrastructure/services/NotificationService';
13
+ import type { NotificationSettingsTranslations, QuietHoursTranslations } from '../../infrastructure/services/types';
14
+
15
+ export interface NotificationSettingsScreenProps {
16
+ translations: NotificationSettingsTranslations;
17
+ quietHoursTranslations: QuietHoursTranslations;
18
+ onRemindersPress: () => void;
19
+ onStartTimePress: () => void;
20
+ onEndTimePress: () => void;
21
+ }
22
+
23
+ export const NotificationSettingsScreen: React.FC<NotificationSettingsScreenProps> = ({
24
+ translations,
25
+ quietHoursTranslations,
26
+ onRemindersPress,
27
+ onStartTimePress,
28
+ onEndTimePress,
29
+ }) => {
30
+ const tokens = useAppDesignTokens();
31
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
32
+
33
+ const preferences = useNotificationPreferences();
34
+ const quietHours = useQuietHours();
35
+ const reminders = useReminders();
36
+ const { loadPreferences, updatePreferences, updateQuietHours, isLoading } = useRemindersStore();
37
+
38
+ useEffect(() => {
39
+ loadPreferences();
40
+ }, [loadPreferences]);
41
+
42
+ const handleMasterToggle = useCallback(async (value: boolean) => {
43
+ if (value) {
44
+ const hasPermission = await notificationService.hasPermissions();
45
+ if (!hasPermission) {
46
+ const granted = await notificationService.requestPermissions();
47
+ if (!granted) return;
48
+ }
49
+ }
50
+ await updatePreferences({ enabled: value });
51
+ }, [updatePreferences]);
52
+
53
+ const handleSoundToggle = useCallback(async (value: boolean) => {
54
+ await updatePreferences({ sound: value });
55
+ }, [updatePreferences]);
56
+
57
+ const handleVibrationToggle = useCallback(async (value: boolean) => {
58
+ await updatePreferences({ vibration: value });
59
+ }, [updatePreferences]);
60
+
61
+ const handleQuietHoursToggle = useCallback(async (value: boolean) => {
62
+ await updateQuietHours({ ...quietHours, enabled: value });
63
+ }, [quietHours, updateQuietHours]);
64
+
65
+ if (isLoading) {
66
+ return (
67
+ <ScreenLayout>
68
+ <View style={styles.loadingContainer}>
69
+ <ActivityIndicator size="large" color={tokens.colors.primary} />
70
+ </View>
71
+ </ScreenLayout>
72
+ );
73
+ }
74
+
75
+ return (
76
+ <ScreenLayout hideScrollIndicator>
77
+ <ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
78
+ <AtomicCard style={styles.card}>
79
+ <SettingRow
80
+ iconName="notifications"
81
+ title={translations.masterToggleTitle}
82
+ description={translations.masterToggleDescription}
83
+ value={preferences.enabled}
84
+ onToggle={handleMasterToggle}
85
+ tokens={tokens}
86
+ />
87
+ </AtomicCard>
88
+
89
+ {preferences.enabled && (
90
+ <>
91
+ <AtomicCard style={styles.card}>
92
+ <SettingRow
93
+ iconName="volume-high"
94
+ title={translations.soundTitle}
95
+ description={translations.soundDescription}
96
+ value={preferences.sound}
97
+ onToggle={handleSoundToggle}
98
+ tokens={tokens}
99
+ />
100
+ <View style={styles.divider} />
101
+ <SettingRow
102
+ iconName="phone-portrait"
103
+ title={translations.vibrationTitle}
104
+ description={translations.vibrationDescription}
105
+ value={preferences.vibration}
106
+ onToggle={handleVibrationToggle}
107
+ tokens={tokens}
108
+ />
109
+ </AtomicCard>
110
+
111
+ <AtomicCard style={styles.card}>
112
+ <TouchableOpacity style={styles.navRow} onPress={onRemindersPress} activeOpacity={0.7}>
113
+ <View style={styles.iconContainer}>
114
+ <AtomicIcon name="time" size="md" color="primary" />
115
+ </View>
116
+ <View style={styles.textContainer}>
117
+ <AtomicText type="bodyLarge">{translations.remindersTitle}</AtomicText>
118
+ <AtomicText type="bodySmall" style={styles.description}>{translations.remindersDescription}</AtomicText>
119
+ </View>
120
+ {reminders.length > 0 && (
121
+ <View style={styles.badge}>
122
+ <AtomicText type="bodySmall" style={styles.badgeText}>{reminders.length}</AtomicText>
123
+ </View>
124
+ )}
125
+ <AtomicIcon name="chevron-forward" size="md" color="textSecondary" />
126
+ </TouchableOpacity>
127
+ </AtomicCard>
128
+
129
+ <QuietHoursCard
130
+ config={quietHours}
131
+ translations={quietHoursTranslations}
132
+ onToggle={handleQuietHoursToggle}
133
+ onStartTimePress={onStartTimePress}
134
+ onEndTimePress={onEndTimePress}
135
+ />
136
+ </>
137
+ )}
138
+ </ScrollView>
139
+ </ScreenLayout>
140
+ );
141
+ };
142
+
143
+ interface SettingRowProps {
144
+ iconName: string;
145
+ title: string;
146
+ description: string;
147
+ value: boolean;
148
+ onToggle: (value: boolean) => void;
149
+ tokens: ReturnType<typeof useAppDesignTokens>;
150
+ }
151
+
152
+ const SettingRow: React.FC<SettingRowProps> = ({ iconName, title, description, value, onToggle, tokens }) => {
153
+ const styles = useMemo(() => createRowStyles(tokens), [tokens]);
154
+ return (
155
+ <View style={styles.container}>
156
+ <View style={styles.iconContainer}>
157
+ <AtomicIcon name={iconName} size="md" color="primary" />
158
+ </View>
159
+ <View style={styles.textContainer}>
160
+ <AtomicText type="bodyLarge">{title}</AtomicText>
161
+ <AtomicText type="bodySmall" style={styles.description}>{description}</AtomicText>
162
+ </View>
163
+ <AtomicSwitch value={value} onValueChange={onToggle} />
164
+ </View>
165
+ );
166
+ };
167
+
168
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
169
+ StyleSheet.create({
170
+ loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
171
+ scrollView: { flex: 1, padding: 16 },
172
+ card: { marginBottom: 16, padding: 16, backgroundColor: tokens.colors.surface },
173
+ divider: { height: 1, backgroundColor: tokens.colors.surfaceSecondary, marginVertical: 12 },
174
+ navRow: { flexDirection: 'row', alignItems: 'center' },
175
+ iconContainer: {
176
+ width: 44,
177
+ height: 44,
178
+ borderRadius: 22,
179
+ backgroundColor: tokens.colors.surfaceSecondary,
180
+ justifyContent: 'center',
181
+ alignItems: 'center',
182
+ marginRight: 12,
183
+ },
184
+ textContainer: { flex: 1, marginRight: 12 },
185
+ description: { color: tokens.colors.textSecondary, marginTop: 2 },
186
+ badge: {
187
+ backgroundColor: tokens.colors.primary,
188
+ paddingHorizontal: 8,
189
+ paddingVertical: 2,
190
+ borderRadius: 10,
191
+ marginRight: 8,
192
+ },
193
+ badgeText: { color: tokens.colors.surface, fontWeight: '600' },
194
+ });
195
+
196
+ const createRowStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
197
+ StyleSheet.create({
198
+ container: { flexDirection: 'row', alignItems: 'center' },
199
+ iconContainer: {
200
+ width: 44,
201
+ height: 44,
202
+ borderRadius: 22,
203
+ backgroundColor: tokens.colors.surfaceSecondary,
204
+ justifyContent: 'center',
205
+ alignItems: 'center',
206
+ marginRight: 12,
207
+ },
208
+ textContainer: { flex: 1, marginRight: 12 },
209
+ description: { color: tokens.colors.textSecondary, marginTop: 2 },
210
+ });
@@ -25,7 +25,7 @@ export interface NotificationsScreenProps {
25
25
 
26
26
  export const NotificationsScreen: React.FC<NotificationsScreenProps> = ({
27
27
  translations,
28
- iconName = 'bell',
28
+ iconName = 'notifications',
29
29
  iconColor = 'primary',
30
30
  testID = 'notifications-screen',
31
31
  }) => {
@@ -0,0 +1,138 @@
1
+ /**
2
+ * ReminderListScreen
3
+ * Displays list of reminders with add, edit, delete functionality
4
+ */
5
+
6
+ import React, { useEffect, useMemo, useCallback } from 'react';
7
+ import { View, FlatList, StyleSheet, ActivityIndicator, TouchableOpacity } from 'react-native';
8
+ import { AtomicText, AtomicIcon, ScreenLayout } from '@umituz/react-native-design-system';
9
+ import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
10
+ import { ReminderItem } from '../components/ReminderItem';
11
+ import { useRemindersStore, useReminders, useRemindersLoading } from '../../infrastructure/storage/RemindersStore';
12
+ import { useReminderActions } from '../../infrastructure/hooks/useReminderActions';
13
+ import type { Reminder, ReminderTranslations } from '../../infrastructure/services/types';
14
+
15
+ export interface ReminderListScreenProps {
16
+ translations: ReminderTranslations;
17
+ onAddPress: () => void;
18
+ onEditPress: (reminder: Reminder) => void;
19
+ maxReminders?: number;
20
+ }
21
+
22
+ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
23
+ translations,
24
+ onAddPress,
25
+ onEditPress,
26
+ maxReminders = 20,
27
+ }) => {
28
+ const tokens = useAppDesignTokens();
29
+ const styles = useMemo(() => createStyles(tokens), [tokens]);
30
+
31
+ const reminders = useReminders();
32
+ const isLoading = useRemindersLoading();
33
+ const { loadReminders } = useRemindersStore();
34
+ const { toggleReminderEnabled, removeReminder } = useReminderActions();
35
+
36
+ useEffect(() => {
37
+ loadReminders();
38
+ }, [loadReminders]);
39
+
40
+ const handleToggle = useCallback(async (id: string) => {
41
+ await toggleReminderEnabled(id);
42
+ }, [toggleReminderEnabled]);
43
+
44
+ const handleDelete = useCallback(async (id: string) => {
45
+ await removeReminder(id);
46
+ }, [removeReminder]);
47
+
48
+ const canAddMore = reminders.length < maxReminders;
49
+
50
+ const renderItem = useCallback(({ item }: { item: Reminder }) => (
51
+ <ReminderItem
52
+ reminder={item}
53
+ translations={{
54
+ frequencyOnce: translations.frequencyOnce,
55
+ frequencyDaily: translations.frequencyDaily,
56
+ frequencyWeekly: translations.frequencyWeekly,
57
+ frequencyMonthly: translations.frequencyMonthly,
58
+ }}
59
+ onToggle={handleToggle}
60
+ onEdit={onEditPress}
61
+ onDelete={handleDelete}
62
+ />
63
+ ), [translations, handleToggle, onEditPress, handleDelete]);
64
+
65
+ const renderEmpty = useCallback(() => (
66
+ <View style={styles.emptyContainer}>
67
+ <View style={styles.emptyIconContainer}>
68
+ <AtomicIcon name="notifications-off" size="xl" color="textSecondary" />
69
+ </View>
70
+ <AtomicText type="bodyLarge" style={styles.emptyTitle}>{translations.emptyTitle}</AtomicText>
71
+ <AtomicText type="bodySmall" style={styles.emptyDescription}>{translations.emptyDescription}</AtomicText>
72
+ </View>
73
+ ), [translations, styles]);
74
+
75
+ const keyExtractor = useCallback((item: Reminder) => item.id, []);
76
+
77
+ if (isLoading) {
78
+ return (
79
+ <ScreenLayout>
80
+ <View style={styles.loadingContainer}>
81
+ <ActivityIndicator size="large" color={tokens.colors.primary} />
82
+ </View>
83
+ </ScreenLayout>
84
+ );
85
+ }
86
+
87
+ return (
88
+ <ScreenLayout hideScrollIndicator>
89
+ <FlatList
90
+ data={reminders}
91
+ renderItem={renderItem}
92
+ keyExtractor={keyExtractor}
93
+ ListEmptyComponent={renderEmpty}
94
+ contentContainerStyle={styles.listContent}
95
+ showsVerticalScrollIndicator={false}
96
+ />
97
+
98
+ {canAddMore && (
99
+ <TouchableOpacity style={styles.fab} onPress={onAddPress} activeOpacity={0.8}>
100
+ <AtomicIcon name="add" size="md" color="surface" />
101
+ <AtomicText type="bodyMedium" style={styles.fabText}>{translations.addButtonLabel}</AtomicText>
102
+ </TouchableOpacity>
103
+ )}
104
+ </ScreenLayout>
105
+ );
106
+ };
107
+
108
+ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
109
+ StyleSheet.create({
110
+ loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
111
+ listContent: { padding: 16, paddingBottom: 100, flexGrow: 1 },
112
+ emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 32 },
113
+ emptyIconContainer: {
114
+ width: 80,
115
+ height: 80,
116
+ borderRadius: 40,
117
+ backgroundColor: tokens.colors.surfaceSecondary,
118
+ justifyContent: 'center',
119
+ alignItems: 'center',
120
+ marginBottom: 16,
121
+ },
122
+ emptyTitle: { color: tokens.colors.textPrimary, textAlign: 'center', marginBottom: 8 },
123
+ emptyDescription: { color: tokens.colors.textSecondary, textAlign: 'center' },
124
+ fab: {
125
+ position: 'absolute',
126
+ bottom: 24,
127
+ left: 16,
128
+ right: 16,
129
+ backgroundColor: tokens.colors.primary,
130
+ borderRadius: 12,
131
+ paddingVertical: 14,
132
+ flexDirection: 'row',
133
+ alignItems: 'center',
134
+ justifyContent: 'center',
135
+ gap: 8,
136
+ },
137
+ fabText: { color: tokens.colors.surface, fontWeight: '600' },
138
+ });
@@ -161,15 +161,18 @@ declare module 'react-native' {
161
161
  }
162
162
  export const StyleSheet: StyleSheetStatic;
163
163
 
164
- export interface ViewStatic {
165
- new (props: any): any;
166
- }
167
- export const View: ViewStatic;
164
+ export type StyleProp<T> = T | T[] | null | undefined;
165
+ export interface ViewStyle { [key: string]: any; }
166
+ export interface TextStyle { [key: string]: any; }
168
167
 
169
- export interface ActivityIndicatorStatic {
170
- new (props: any): any;
171
- }
172
- export const ActivityIndicator: ActivityIndicatorStatic;
168
+ export const View: React.FC<any>;
169
+ export const Text: React.FC<any>;
170
+ export const TouchableOpacity: React.FC<any>;
171
+ export const TextInput: React.FC<any>;
172
+ export const ScrollView: React.FC<any>;
173
+ export const FlatList: React.FC<any>;
174
+ export const Switch: React.FC<any>;
175
+ export const ActivityIndicator: React.FC<any>;
173
176
  }
174
177
 
175
178
  declare module 'zustand' {
package/lib/index.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Notifications Domain - Public API
3
- * Offline-first local notifications using expo-notifications
4
- * NO backend, NO user IDs, NO push notifications
5
- */
6
- export type { NotificationTrigger, ScheduleNotificationOptions, ScheduledNotification, } from './infrastructure/services/types';
7
- export { notificationsConfig } from './infrastructure/config/notificationsConfig';
8
- export type { NotificationSetting, NotificationSection, NotificationsConfig, } from './infrastructure/config/notificationsConfig';
9
- export { useNotificationsStore, useNotifications } from './infrastructure/storage/NotificationsStore';
10
- export { NotificationService, notificationService } from './infrastructure/services/NotificationService';
11
- export { NotificationManager } from './infrastructure/services/NotificationManager';
12
- export { useNotificationSettings } from './infrastructure/hooks/useNotificationSettings';
13
- export { NotificationsScreen } from './presentation/screens/NotificationsScreen';
14
- export { NotificationsSection } from './presentation/components/NotificationsSection';
15
- export type { NotificationsSectionProps, NotificationsSectionConfig } from './presentation/components/NotificationsSection';
16
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,YAAY,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAClF,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAGtG,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAGpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAQzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAGjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,YAAY,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC"}
package/lib/index.js DELETED
@@ -1,23 +0,0 @@
1
- /**
2
- * Notifications Domain - Public API
3
- * Offline-first local notifications using expo-notifications
4
- * NO backend, NO user IDs, NO push notifications
5
- */
6
- // Configuration
7
- export { notificationsConfig } from './infrastructure/config/notificationsConfig';
8
- // State Store (Zustand)
9
- export { useNotificationsStore, useNotifications } from './infrastructure/storage/NotificationsStore';
10
- // Services
11
- export { NotificationService, notificationService } from './infrastructure/services/NotificationService';
12
- export { NotificationManager } from './infrastructure/services/NotificationManager';
13
- // Hooks
14
- export { useNotificationSettings } from './infrastructure/hooks/useNotificationSettings';
15
- // ============================================================================
16
- // PRESENTATION LAYER EXPORTS
17
- // ============================================================================
18
- // Screens
19
- // Screens
20
- export { NotificationsScreen } from './presentation/screens/NotificationsScreen';
21
- // Components
22
- export { NotificationsSection } from './presentation/components/NotificationsSection';
23
- //# sourceMappingURL=index.js.map
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAOlF,wBAAwB;AACxB,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAEtG,WAAW;AACX,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAEpF,QAAQ;AACR,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAEzF,+EAA+E;AAC/E,6BAA6B;AAC7B,+EAA+E;AAE/E,UAAU;AACV,UAAU;AACV,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAEjF,aAAa;AACb,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC"}
@@ -1,20 +0,0 @@
1
- /**
2
- * Notifications Configuration
3
- * Defines notification settings structure
4
- */
5
- export interface NotificationSetting {
6
- id: string;
7
- titleKey: string;
8
- descKey: string;
9
- icon: string;
10
- }
11
- export interface NotificationSection {
12
- id: string;
13
- titleKey: string;
14
- settings: NotificationSetting[];
15
- }
16
- export interface NotificationsConfig {
17
- sections: NotificationSection[];
18
- }
19
- export declare const notificationsConfig: NotificationsConfig;
20
- //# sourceMappingURL=notificationsConfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"notificationsConfig.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/config/notificationsConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,eAAO,MAAM,mBAAmB,EAAE,mBA2EjC,CAAC"}