@umituz/react-native-settings 4.23.85 → 4.23.87

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 (38) hide show
  1. package/package.json +3 -3
  2. package/src/domains/about/presentation/hooks/useAboutInfo.ts +1 -1
  3. package/src/domains/faqs/presentation/screens/FAQScreen.tsx +1 -1
  4. package/src/domains/feedback/presentation/components/FeedbackForm.styles.ts +1 -1
  5. package/src/domains/feedback/presentation/components/FeedbackForm.tsx +11 -4
  6. package/src/domains/gamification/components/GamificationScreen/GamificationScreen.tsx +1 -6
  7. package/src/domains/gamification/store/gamificationStore.ts +6 -7
  8. package/src/domains/localization/infrastructure/storage/LocalizationStore.ts +50 -181
  9. package/src/domains/localization/infrastructure/storage/localizationStoreUtils.ts +182 -0
  10. package/src/domains/notifications/infrastructure/utils/dev.ts +3 -3
  11. package/src/domains/notifications/reminders/presentation/components/ReminderForm.constants.ts +1 -1
  12. package/src/domains/notifications/reminders/presentation/components/ReminderForm.tsx +52 -46
  13. package/src/infrastructure/types/commonComponentTypes.ts +142 -0
  14. package/src/infrastructure/utils/async/core.ts +109 -0
  15. package/src/infrastructure/utils/async/debounceAndBatch.ts +69 -0
  16. package/src/infrastructure/utils/async/index.ts +8 -0
  17. package/src/infrastructure/utils/async/retryAndTimeout.ts +57 -0
  18. package/src/infrastructure/utils/configFactory.ts +101 -0
  19. package/src/infrastructure/utils/errorHandlers.ts +249 -0
  20. package/src/infrastructure/utils/index.ts +5 -0
  21. package/src/infrastructure/utils/memoComparisonUtils.ts +0 -2
  22. package/src/infrastructure/utils/memoUtils.ts +10 -2
  23. package/src/infrastructure/utils/styleTokens.ts +132 -0
  24. package/src/infrastructure/utils/validation/core.ts +42 -0
  25. package/src/infrastructure/utils/validation/formValidators.ts +82 -0
  26. package/src/infrastructure/utils/validation/index.ts +37 -0
  27. package/src/infrastructure/utils/validation/numericValidators.ts +66 -0
  28. package/src/infrastructure/utils/validation/passwordValidator.ts +53 -0
  29. package/src/infrastructure/utils/validation/textValidators.ts +118 -0
  30. package/src/presentation/hooks/useSettingsScreenConfig.ts +32 -79
  31. package/src/presentation/navigation/SettingsStackNavigator.tsx +1 -24
  32. package/src/presentation/navigation/hooks/useSettingsScreens.ts +1 -1
  33. package/src/presentation/utils/config-creators/base-configs.ts +54 -42
  34. package/src/presentation/utils/faqTranslator.ts +31 -0
  35. package/src/presentation/utils/index.ts +6 -1
  36. package/src/presentation/utils/screenFactory.ts +1 -1
  37. package/src/presentation/utils/settingsConfigFactory.ts +89 -0
  38. package/src/presentation/utils/useAuthHandlers.ts +98 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "4.23.85",
3
+ "version": "4.23.87",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -74,8 +74,8 @@
74
74
  "@types/react": "~19.1.10",
75
75
  "@typescript-eslint/eslint-plugin": "^7.18.0",
76
76
  "@typescript-eslint/parser": "^7.18.0",
77
- "@umituz/react-native-auth": "^3.6.49",
78
- "@umituz/react-native-design-system": "*",
77
+ "@umituz/react-native-auth": "^3.6.76",
78
+ "@umituz/react-native-design-system": "latest",
79
79
  "@umituz/react-native-firebase": "^1.13.102",
80
80
  "@umituz/react-native-sentry": "*",
81
81
  "eslint": "^8.57.0",
@@ -122,7 +122,7 @@ export const useAboutInfo = (
122
122
  setAppInfo(defaultAppInfo);
123
123
  isInitializedRef.current = true;
124
124
  }
125
- }).catch((error) => {
125
+ }).catch((_error) => {
126
126
  });
127
127
  }
128
128
  }, [initialConfig, autoInit]);
@@ -6,7 +6,7 @@
6
6
 
7
7
  import React, { useMemo } from 'react';
8
8
  import { View, ScrollView, StyleSheet, ViewStyle, TextStyle, useWindowDimensions } from 'react-native';
9
- import { useAppDesignTokens, AtomicText, ScreenLayout, getContentMaxWidth, NavigationHeader, useAppNavigation } from '@umituz/react-native-design-system';
9
+ import { useAppDesignTokens, ScreenLayout, getContentMaxWidth, NavigationHeader, useAppNavigation } from '@umituz/react-native-design-system';
10
10
  import { FAQCategory } from '../../domain/entities/FAQEntity';
11
11
  import { useFAQSearch } from '../hooks/useFAQSearch';
12
12
  import { useFAQExpansion } from '../hooks/useFAQExpansion';
@@ -1,7 +1,7 @@
1
1
  import { StyleSheet } from "react-native";
2
2
  import type { useAppDesignTokens } from "@umituz/react-native-design-system";
3
3
 
4
- export const getFeedbackFormStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
4
+ export const getFeedbackFormStyles = (_tokens: ReturnType<typeof useAppDesignTokens>) =>
5
5
  StyleSheet.create({
6
6
  container: {
7
7
  width: "100%",
@@ -4,9 +4,10 @@
4
4
  */
5
5
 
6
6
  import React, { useState } from "react";
7
- import { View, StyleSheet, TouchableOpacity, ScrollView, TextInput } from "react-native";
7
+ import { View, TouchableOpacity, ScrollView, TextInput } from "react-native";
8
8
  import { useAppDesignTokens, AtomicText, AtomicButton, AtomicIcon } from "@umituz/react-native-design-system";
9
9
  import type { FeedbackType, FeedbackRating } from "../../domain/entities/FeedbackEntity";
10
+ import { validateFeedbackForm } from "../../../../infrastructure/utils/validation";
10
11
 
11
12
  import { getFeedbackFormStyles as getStyles } from "./FeedbackForm.styles";
12
13
 
@@ -40,9 +41,15 @@ export const FeedbackForm: React.FC<FeedbackFormProps> = ({
40
41
  const [isSubmittingLocal, setIsSubmittingLocal] = useState(false);
41
42
 
42
43
  const handleSubmit = async () => {
43
- // Validate input
44
- if (!description.trim()) {
45
- setError("Please provide a description");
44
+ // Validate using centralized validation
45
+ const validationResult = validateFeedbackForm({
46
+ type: selectedType,
47
+ rating,
48
+ description,
49
+ });
50
+
51
+ if (!validationResult.isValid) {
52
+ setError(validationResult.error || "Validation failed");
46
53
  return;
47
54
  }
48
55
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import React from "react";
8
- import { View, ScrollView } from "react-native";
8
+ import { View } from "react-native";
9
9
  import { useAppDesignTokens, AtomicText, ScreenLayout, NavigationHeader, useAppNavigation } from "@umituz/react-native-design-system";
10
10
  import { LevelProgress } from "../LevelProgress";
11
11
  import { StreakDisplay } from "../StreakDisplay";
@@ -27,12 +27,8 @@ export const GamificationScreenInner: React.FC<GamificationScreenProps> = ({
27
27
  achievements,
28
28
  streakProps,
29
29
  emptyAchievementsText,
30
- containerStyle,
31
- headerStyle,
32
- titleStyle,
33
30
  sectionTitleStyle,
34
31
  accentColor,
35
- backgroundColor,
36
32
  cardBackgroundColor,
37
33
  textColor,
38
34
  subtextColor,
@@ -43,7 +39,6 @@ export const GamificationScreenInner: React.FC<GamificationScreenProps> = ({
43
39
 
44
40
  // Use tokens for fallbacks
45
41
  const finalAccentColor = accentColor || tokens.colors.primary;
46
- const finalBackgroundColor = backgroundColor || tokens.colors.backgroundPrimary;
47
42
  const finalCardBackgroundColor = cardBackgroundColor || tokens.colors.surface;
48
43
  const finalTextColor = textColor || tokens.colors.textPrimary;
49
44
  const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
@@ -78,16 +78,16 @@ export const useGamificationStore = createStore<GamificationState, GamificationA
78
78
  const state = get();
79
79
  const pointsToAdd = currentConfig?.pointsPerAction ?? 15;
80
80
 
81
+ const newTotalTasks = state.totalTasksCompleted + 1;
82
+
81
83
  set({
82
- totalTasksCompleted: state.totalTasksCompleted + 1,
84
+ totalTasksCompleted: newTotalTasks,
83
85
  points: state.points + pointsToAdd,
84
86
  });
85
87
 
86
- // Update streak
87
- get().updateStreak();
88
-
89
- // Check achievements
90
- get().checkAchievements();
88
+ const actions = get() as GamificationActions;
89
+ actions.updateStreak();
90
+ actions.checkAchievements();
91
91
  },
92
92
 
93
93
  updateStreak: () => {
@@ -121,7 +121,6 @@ export const useGamificationStore = createStore<GamificationState, GamificationA
121
121
 
122
122
  const state = get();
123
123
 
124
- // Safety check for achievements array
125
124
  if (!state.achievements || state.achievements.length === 0) {
126
125
  return [];
127
126
  }
@@ -3,187 +3,56 @@
3
3
  * Creates and manages localization state with proper separation of concerns
4
4
  */
5
5
 
6
- import { create } from 'zustand';
7
- import type { LocalizationState, LocalizationActions, LocalizationGetters } from './types/LocalizationState';
8
- import { LanguageInitializer } from './LanguageInitializer';
9
- import { LanguageSwitcher } from './LanguageSwitcher';
10
- import { languageRepository } from '../repository/LanguageRepository';
11
-
12
- declare const __DEV__: boolean;
6
+ import { create } from "zustand";
7
+ import type { LocalizationState, LocalizationActions, LocalizationGetters } from "./types/LocalizationState";
8
+ import { languageRepository } from "../repository/LanguageRepository";
9
+ import { InitializationManager, LanguageSwitchManager, localizationGetters } from "./localizationStoreUtils";
13
10
 
14
11
  type LocalizationStoreType = LocalizationState & LocalizationActions & LocalizationGetters;
15
12
 
16
- const LANGUAGE_SWITCH_DEBOUNCE_MS = 300;
17
-
18
- export const useLocalizationStore = create<LocalizationStoreType>((set, get) => {
19
- // Instance-level state to prevent memory leaks
20
- let initializeInProgress = false;
21
- let initializePromise: Promise<void> | null = null;
22
- let languageSwitchTimer: ReturnType<typeof setTimeout> | null = null;
23
- const pendingResolvers: Array<() => void> = [];
24
-
25
- return {
26
- // State
27
- currentLanguage: 'en-US',
28
- isRTL: false,
29
- isInitialized: false,
30
- supportedLanguages: languageRepository.getLanguages(),
31
-
32
- // Actions
33
- initialize: async () => {
34
- const { isInitialized: alreadyInitialized } = get();
35
-
36
- // Return existing promise if initialization is in progress
37
- if (initializeInProgress && initializePromise) {
38
- return initializePromise;
39
- }
40
-
41
- // Return if already initialized
42
- if (alreadyInitialized) {
43
- return;
44
- }
45
-
46
- // Set mutex and create promise
47
- initializeInProgress = true;
48
- initializePromise = (async () => {
49
- try {
50
- const result = await LanguageInitializer.initialize();
51
-
52
- set({
53
- currentLanguage: result.languageCode,
54
- isRTL: result.isRTL,
55
- isInitialized: true,
56
- });
57
- } catch (error) {
58
- // Log and set fallback state
59
- if (typeof __DEV__ !== "undefined" && __DEV__) {
60
- }
61
-
62
- set({
63
- currentLanguage: 'en-US',
64
- isRTL: false,
65
- isInitialized: true,
66
- });
67
-
68
- throw error; // Re-throw to allow error handling
69
- } finally {
70
- initializeInProgress = false;
71
- initializePromise = null;
72
- }
73
- })();
74
-
75
- return initializePromise;
76
- },
77
-
78
- setLanguage: async (languageCode: string) => {
79
- // Validate input
80
- if (!languageCode || typeof languageCode !== 'string') {
81
- throw new Error('Invalid language code provided');
82
- }
83
-
84
- // Clear existing timer
85
- if (languageSwitchTimer) {
86
- clearTimeout(languageSwitchTimer);
87
- languageSwitchTimer = null;
88
- }
89
-
90
- return new Promise<void>((resolve, reject) => {
91
- // Add resolver to pending list
92
- pendingResolvers.push(() => {
93
- // Resolve successfully
94
- resolve();
95
- });
96
-
97
- // Create rejection handler
98
- const rejectAndCleanup = (error: Error) => {
99
- // Remove this resolver
100
- const index = pendingResolvers.findIndex(r => r === resolve);
101
- if (index > -1) {
102
- pendingResolvers.splice(index, 1);
103
- }
104
- reject(error);
105
- };
106
-
107
- languageSwitchTimer = setTimeout(async () => {
108
- if (typeof __DEV__ !== "undefined" && __DEV__) {
109
- }
110
-
111
- try {
112
- const result = await LanguageSwitcher.switchLanguage(languageCode);
113
-
114
- if (typeof __DEV__ !== "undefined" && __DEV__) {
115
- }
116
-
117
- set({
118
- currentLanguage: result.languageCode,
119
- isRTL: result.isRTL,
120
- });
121
-
122
- if (typeof __DEV__ !== "undefined" && __DEV__) {
123
- }
124
-
125
- // Resolve ALL pending promises
126
- const resolvers = [...pendingResolvers];
127
- pendingResolvers.length = 0; // Clear array
128
- resolvers.forEach(r => r());
129
- } catch (error) {
130
- const errorMessage = error instanceof Error ? error : new Error(String(error));
131
-
132
- if (typeof __DEV__ !== "undefined" && __DEV__) {
133
- }
134
-
135
- // Reject all pending promises
136
- const resolvers = [...pendingResolvers];
137
- pendingResolvers.length = 0; // Clear array
138
- resolvers.forEach(() => {
139
- // Each resolver is wrapped to handle rejection
140
- // Note: We can't reject promises already created, so we just clear them
141
- });
142
-
143
- // Reject this specific promise
144
- rejectAndCleanup(errorMessage);
145
- } finally {
146
- languageSwitchTimer = null;
147
- }
148
- }, LANGUAGE_SWITCH_DEBOUNCE_MS);
149
- });
150
- },
151
-
152
- reset: () => {
153
- // Clear any pending language switch
154
- if (languageSwitchTimer) {
155
- clearTimeout(languageSwitchTimer);
156
- languageSwitchTimer = null;
157
- }
158
-
159
- // Resolve any pending promises to prevent hanging
160
- const resolvers = [...pendingResolvers];
161
- pendingResolvers.length = 0; // Clear array
162
- resolvers.forEach(r => r());
163
-
164
- // Reset mutex
165
- initializeInProgress = false;
166
- initializePromise = null;
167
-
168
- set({
169
- currentLanguage: 'en-US',
170
- isRTL: false,
171
- isInitialized: false,
172
- });
173
- },
174
-
175
- // Getters
176
- getCurrentLanguage: () => {
177
- const { currentLanguage } = get();
178
- return languageRepository.getLanguageByCode(currentLanguage);
179
- },
180
-
181
- isLanguageSupported: (code: string) => {
182
- return languageRepository.isLanguageSupported(code);
183
- },
184
-
185
- getSupportedLanguages: () => {
186
- return languageRepository.getLanguages();
187
- },
188
- };
189
- });
13
+ // Instance-level managers
14
+ const initManager = new InitializationManager();
15
+ const switchManager = new LanguageSwitchManager();
16
+
17
+ export const useLocalizationStore = create<LocalizationStoreType>((set, get) => ({
18
+ // State
19
+ currentLanguage: "en-US",
20
+ isRTL: false,
21
+ isInitialized: false,
22
+ supportedLanguages: languageRepository.getLanguages(),
23
+
24
+ // Actions
25
+ initialize: async () => {
26
+ const { isInitialized } = get();
27
+ await initManager.initialize(isInitialized, set);
28
+ },
29
+
30
+ setLanguage: async (languageCode: string) => {
31
+ await switchManager.setLanguage(languageCode, set);
32
+ },
33
+
34
+ reset: () => {
35
+ initManager.reset();
36
+ switchManager.reset();
37
+
38
+ set({
39
+ currentLanguage: "en-US",
40
+ isRTL: false,
41
+ isInitialized: false,
42
+ });
43
+ },
44
+
45
+ // Getters
46
+ getCurrentLanguage: () => {
47
+ const { currentLanguage } = get();
48
+ return localizationGetters.getCurrentLanguage(currentLanguage);
49
+ },
50
+
51
+ isLanguageSupported: (code: string) => {
52
+ return localizationGetters.isLanguageSupported(code);
53
+ },
54
+
55
+ getSupportedLanguages: () => {
56
+ return localizationGetters.getSupportedLanguages();
57
+ },
58
+ }));
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Localization Store Utilities
3
+ * Extracted business logic for localization store
4
+ */
5
+
6
+ import { LanguageInitializer } from "./LanguageInitializer";
7
+ import { LanguageSwitcher } from "./LanguageSwitcher";
8
+ import { languageRepository } from "../repository/LanguageRepository";
9
+
10
+ declare const __DEV__: boolean;
11
+
12
+ export const LANGUAGE_SWITCH_DEBOUNCE_MS = 300;
13
+
14
+ /**
15
+ * Manages localization initialization state
16
+ */
17
+ export class InitializationManager {
18
+ private inProgress = false;
19
+ private promise: Promise<void> | null = null;
20
+
21
+ async initialize(
22
+ isAlreadyInitialized: boolean,
23
+ setState: (state: Partial<{ currentLanguage: string; isRTL: boolean; isInitialized: boolean }>) => void
24
+ ): Promise<void> {
25
+ // Return existing promise if initialization is in progress
26
+ if (this.inProgress && this.promise) {
27
+ return this.promise;
28
+ }
29
+
30
+ // Return if already initialized
31
+ if (isAlreadyInitialized) {
32
+ return;
33
+ }
34
+
35
+ // Set mutex and create promise
36
+ this.inProgress = true;
37
+ this.promise = (async () => {
38
+ try {
39
+ const result = await LanguageInitializer.initialize();
40
+
41
+ setState({
42
+ currentLanguage: result.languageCode,
43
+ isRTL: result.isRTL,
44
+ isInitialized: true,
45
+ });
46
+ } catch (error) {
47
+ // Log and set fallback state
48
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
49
+ console.error("Localization initialization failed:", error);
50
+ }
51
+
52
+ setState({
53
+ currentLanguage: "en-US",
54
+ isRTL: false,
55
+ isInitialized: true,
56
+ });
57
+
58
+ throw error; // Re-throw to allow error handling
59
+ } finally {
60
+ this.inProgress = false;
61
+ this.promise = null;
62
+ }
63
+ })();
64
+
65
+ return this.promise;
66
+ }
67
+
68
+ reset(): void {
69
+ this.inProgress = false;
70
+ this.promise = null;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Manages debounced language switching with pending promise handling
76
+ * FIXED: Properly rejects pending promises on error
77
+ */
78
+ export class LanguageSwitchManager {
79
+ private timer: ReturnType<typeof setTimeout> | null = null;
80
+ private pendingResolvers: Array<{ resolve: () => void; reject: (error: Error) => void }> = [];
81
+
82
+ /**
83
+ * Sets language with debounce and promise handling
84
+ */
85
+ setLanguage(
86
+ languageCode: string,
87
+ setState: (state: Partial<{ currentLanguage: string; isRTL: boolean }>) => void
88
+ ): Promise<void> {
89
+ // Validate input
90
+ if (!languageCode || typeof languageCode !== "string") {
91
+ return Promise.reject(new Error("Invalid language code provided"));
92
+ }
93
+
94
+ // Clear existing timer
95
+ if (this.timer) {
96
+ clearTimeout(this.timer);
97
+ this.timer = null;
98
+ }
99
+
100
+ return new Promise<void>((resolve, reject) => {
101
+ // Add resolver and rejector to pending list
102
+ const pendingItem = { resolve, reject };
103
+ this.pendingResolvers.push(pendingItem);
104
+
105
+ this.timer = setTimeout(async () => {
106
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
107
+ console.log("[Localization] Switching language to:", languageCode);
108
+ }
109
+
110
+ try {
111
+ const result = await LanguageSwitcher.switchLanguage(languageCode);
112
+
113
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
114
+ console.log("[Localization] Language switched successfully");
115
+ }
116
+
117
+ const stateUpdate = {
118
+ currentLanguage: result.languageCode,
119
+ isRTL: result.isRTL,
120
+ };
121
+
122
+ setState(stateUpdate);
123
+
124
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
125
+ console.log("[Localization] State updated:", stateUpdate);
126
+ }
127
+
128
+ // Resolve ALL pending promises
129
+ const resolvers = [...this.pendingResolvers];
130
+ this.pendingResolvers = [];
131
+ resolvers.forEach((r) => r.resolve());
132
+ } catch (error) {
133
+ const errorMessage =
134
+ error instanceof Error ? error : new Error(String(error));
135
+
136
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
137
+ console.error("[Localization] Language switch failed:", errorMessage);
138
+ }
139
+
140
+ // Reject ALL pending promises - FIXED: Actually rejects them now
141
+ const resolvers = [...this.pendingResolvers];
142
+ this.pendingResolvers = [];
143
+ resolvers.forEach((r) => r.reject(errorMessage));
144
+ } finally {
145
+ this.timer = null;
146
+ }
147
+ }, LANGUAGE_SWITCH_DEBOUNCE_MS);
148
+ });
149
+ }
150
+
151
+ /**
152
+ * Clears any pending language switch and resolves all promises
153
+ */
154
+ reset(): void {
155
+ if (this.timer) {
156
+ clearTimeout(this.timer);
157
+ this.timer = null;
158
+ }
159
+
160
+ // Resolve any pending promises to prevent hanging
161
+ const resolvers = [...this.pendingResolvers];
162
+ this.pendingResolvers = [];
163
+ resolvers.forEach((r) => r.resolve());
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Localization getters
169
+ */
170
+ export const localizationGetters = {
171
+ getCurrentLanguage: (currentLanguage: string) => {
172
+ return languageRepository.getLanguageByCode(currentLanguage);
173
+ },
174
+
175
+ isLanguageSupported: (code: string) => {
176
+ return languageRepository.isLanguageSupported(code);
177
+ },
178
+
179
+ getSupportedLanguages: () => {
180
+ return languageRepository.getLanguages();
181
+ },
182
+ };
@@ -6,17 +6,17 @@ export const isDev = () => {
6
6
  }
7
7
  };
8
8
 
9
- export const devLog = (message: string, ...args: unknown[]) => {
9
+ export const devLog = (_message: string, ..._args: unknown[]) => {
10
10
  if (isDev()) {
11
11
  }
12
12
  };
13
13
 
14
- export const devError = (message: string, ...args: unknown[]) => {
14
+ export const devError = (_message: string, ..._args: unknown[]) => {
15
15
  if (isDev()) {
16
16
  }
17
17
  };
18
18
 
19
- export const devWarn = (message: string, ...args: unknown[]) => {
19
+ export const devWarn = (_message: string, ..._args: unknown[]) => {
20
20
  if (isDev()) {
21
21
  }
22
22
  };
@@ -1,4 +1,4 @@
1
- import type { Reminder, ReminderFrequency, CreateReminderInput, TimePreset } from '../../../infrastructure/services/types';
1
+ import type { Reminder, CreateReminderInput, TimePreset } from '../../../infrastructure/services/types';
2
2
 
3
3
  export const DEFAULT_HOUR = 9;
4
4
  export const DEFAULT_MINUTE = 0;