@umituz/react-native-settings 5.4.9 → 5.4.11

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 (31) hide show
  1. package/package.json +1 -1
  2. package/src/core/base/BaseService.ts +141 -0
  3. package/src/core/index.ts +60 -0
  4. package/src/core/patterns/Modal/ModalConfig.ts +282 -0
  5. package/src/core/patterns/Modal/useModalState.ts +128 -0
  6. package/src/core/patterns/Screen/ScreenConfig.ts +375 -0
  7. package/src/core/patterns/Screen/useScreenData.ts +201 -0
  8. package/src/core/utils/logger.ts +138 -0
  9. package/src/core/utils/validators.ts +203 -0
  10. package/src/domains/disclaimer/index.ts +0 -3
  11. package/src/domains/disclaimer/presentation/components/DisclaimerSetting.tsx +18 -43
  12. package/src/domains/disclaimer/presentation/screens/DisclaimerScreen.tsx +42 -92
  13. package/src/domains/feedback/index.ts +2 -1
  14. package/src/domains/feedback/presentation/components/SupportSection.tsx +16 -43
  15. package/src/domains/feedback/presentation/screens/FeatureRequestScreen.tsx +4 -4
  16. package/src/domains/feedback/presentation/screens/FeedbackScreen.tsx +75 -0
  17. package/src/domains/notifications/infrastructure/services/NotificationService.ts +16 -13
  18. package/src/domains/rating/application/services/RatingService.ts +115 -79
  19. package/src/domains/rating/index.ts +3 -3
  20. package/src/domains/rating/presentation/hooks/useAppRating.tsx +42 -65
  21. package/src/domains/rating/presentation/screens/RatingPromptScreen.tsx +162 -0
  22. package/src/index.ts +12 -0
  23. package/src/infrastructure/services/SettingsService.ts +23 -19
  24. package/src/presentation/components/GenericModal.tsx +208 -0
  25. package/src/presentation/components/GenericScreen.tsx +273 -0
  26. package/src/presentation/components/index.ts +27 -0
  27. package/src/presentation/navigation/hooks/useSettingsScreens.ts +26 -1
  28. package/src/presentation/navigation/types.ts +6 -0
  29. package/src/domains/disclaimer/presentation/components/DisclaimerModal.tsx +0 -103
  30. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +0 -99
  31. package/src/domains/rating/presentation/components/RatingPromptModal.tsx +0 -152
@@ -1,103 +0,0 @@
1
- /**
2
- * Disclaimer Modal Component
3
- * Extracted from DisclaimerSetting to follow single responsibility and 200-line rules
4
- */
5
-
6
- import React from 'react';
7
- import {
8
- View,
9
- StyleSheet,
10
- TouchableOpacity,
11
- ScrollView,
12
- } from 'react-native';
13
-
14
- import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system/atoms';
15
- import { BaseModal } from '@umituz/react-native-design-system/molecules';
16
- import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
17
-
18
- export interface DisclaimerModalProps {
19
- visible: boolean;
20
- title: string;
21
- content: string;
22
- onClose: () => void;
23
- }
24
-
25
- export const DisclaimerModal: React.FC<DisclaimerModalProps> = ({
26
- visible,
27
- title,
28
- content,
29
- onClose,
30
- }) => {
31
- const tokens = useAppDesignTokens();
32
- const styles = getStyles(tokens);
33
-
34
- return (
35
- <BaseModal visible={visible} onClose={onClose}>
36
- <View style={styles.modalContentWrapper}>
37
- {/* Modal Header */}
38
- <View
39
- style={[
40
- styles.modalHeader,
41
- { borderBottomColor: tokens.colors.border },
42
- ]}
43
- >
44
- <AtomicText type="headlineMedium" color="primary">
45
- {title}
46
- </AtomicText>
47
- <TouchableOpacity
48
- onPress={onClose}
49
- testID="close-disclaimer-modal"
50
- >
51
- <AtomicIcon name="close" color="primary" size="md" />
52
- </TouchableOpacity>
53
- </View>
54
-
55
- {/* Scrollable Content */}
56
- <ScrollView
57
- style={styles.modalContent}
58
- contentContainerStyle={styles.modalContentContainer}
59
- >
60
- <AtomicText
61
- type="bodyMedium"
62
- color="textPrimary"
63
- style={styles.modalText}
64
- >
65
- {content}
66
- </AtomicText>
67
- </ScrollView>
68
- </View>
69
- </BaseModal>
70
- );
71
- };
72
-
73
-
74
- const getStyles = (_tokens: ReturnType<typeof useAppDesignTokens>) =>
75
- StyleSheet.create({
76
- modalContainer: {
77
- flex: 1,
78
- },
79
- modalContentWrapper: {
80
- flex: 1,
81
- },
82
- modalHeader: {
83
- flexDirection: 'row',
84
- justifyContent: 'space-between',
85
- alignItems: 'center',
86
- paddingHorizontal: 20,
87
- paddingVertical: 16,
88
- borderBottomWidth: 1,
89
- },
90
-
91
- modalContent: {
92
- flex: 1,
93
- },
94
-
95
- modalContentContainer: {
96
- padding: 20,
97
- },
98
-
99
- modalText: {
100
- lineHeight: 24,
101
- fontSize: 15, // or tokens.typography.bodyMedium.responsiveFontSize
102
- },
103
- });
@@ -1,99 +0,0 @@
1
- /**
2
- * Feedback Modal Component
3
- * Modal wrapper for providing feedback
4
- */
5
-
6
- import React from "react";
7
- import { View, StyleSheet, TouchableOpacity } from "react-native";
8
- import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
9
- import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
10
- import { BaseModal } from "@umituz/react-native-design-system/molecules";
11
- import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
12
- import { FeedbackForm } from "./FeedbackForm";
13
- import type { FeedbackType, FeedbackRating } from "../../domain/entities/FeedbackEntity";
14
- import type { FeedbackFormProps } from "./FeedbackFormProps";
15
-
16
- export interface FeedbackModalProps {
17
- visible: boolean;
18
- onClose: () => void;
19
- onSubmit: (data: { type: FeedbackType; rating: FeedbackRating; description: string; title: string }) => Promise<void>;
20
- initialType?: FeedbackType;
21
- isSubmitting?: boolean;
22
- title?: string;
23
- subtitle?: string;
24
- texts: FeedbackFormProps['texts'];
25
- }
26
-
27
- export const FeedbackModal: React.FC<FeedbackModalProps> = ({
28
- visible,
29
- onClose,
30
- onSubmit,
31
- initialType,
32
- isSubmitting,
33
- title,
34
- subtitle,
35
- texts,
36
- }) => {
37
- const tokens = useAppDesignTokens();
38
- const styles = getStyles(tokens);
39
-
40
- const header = (
41
- <View style={styles.header}>
42
- <View style={styles.headerText}>
43
- {title && <AtomicText style={{ fontSize: 20, fontWeight: '600' }}>{title}</AtomicText>}
44
- {subtitle && <AtomicText style={{ fontSize: 14, marginTop: 4 }}>{subtitle}</AtomicText>}
45
- </View>
46
- <TouchableOpacity
47
- onPress={onClose}
48
- style={[styles.closeButton, { backgroundColor: tokens.colors.surfaceVariant }]}
49
- >
50
- <AtomicIcon name="close" size="sm" color="onSurface" />
51
- </TouchableOpacity>
52
- </View>
53
- );
54
-
55
- return (
56
- <BaseModal visible={visible} onClose={onClose}>
57
- <ScreenLayout
58
- header={header}
59
- scrollable={true}
60
- edges={[]}
61
- keyboardAvoiding={true}
62
- contentContainerStyle={styles.content}
63
- hideScrollIndicator={false}
64
- >
65
- <FeedbackForm
66
- onSubmit={onSubmit}
67
- initialType={initialType}
68
- isSubmitting={isSubmitting}
69
- texts={texts}
70
- />
71
- </ScreenLayout>
72
- </BaseModal>
73
- );
74
- };
75
-
76
-
77
- const getStyles = (_tokens: ReturnType<typeof useAppDesignTokens>) =>
78
- StyleSheet.create({
79
- header: {
80
- flexDirection: "row",
81
- justifyContent: "space-between",
82
- alignItems: "center",
83
- padding: 16,
84
- borderBottomWidth: 1,
85
- },
86
- headerText: {
87
- flex: 1,
88
- },
89
- closeButton: {
90
- width: 36,
91
- height: 36,
92
- borderRadius: 18,
93
- justifyContent: "center",
94
- alignItems: "center",
95
- },
96
- content: {
97
- padding: 20,
98
- },
99
- });
@@ -1,152 +0,0 @@
1
- /**
2
- * Rating Prompt Modal
3
- * 2-step rating prompt: Custom modal → Native review prompt
4
- */
5
-
6
- import React from "react";
7
- import { Modal, View, StyleSheet } from "react-native";
8
- import { AtomicText, AtomicButton, AtomicIcon } from "@umituz/react-native-design-system/atoms";
9
- import { useResponsive } from "@umituz/react-native-design-system/responsive";
10
- import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
11
- import type { RatingTranslations } from "../../domain/entities/RatingConfig";
12
-
13
- export interface RatingPromptModalProps {
14
- visible: boolean;
15
- onPositive: () => void;
16
- onNegative: () => void;
17
- onLater: () => void;
18
- onDismiss: () => void;
19
- translations?: RatingTranslations;
20
- appName?: string;
21
- }
22
-
23
- export const RatingPromptModal: React.FC<RatingPromptModalProps> = ({
24
- visible,
25
- onPositive,
26
- onNegative,
27
- onLater,
28
- onDismiss,
29
- translations,
30
- appName = "this app",
31
- }) => {
32
- const tokens = useAppDesignTokens();
33
- const responsive = useResponsive();
34
-
35
- const defaultTranslations: RatingTranslations = {
36
- title: translations?.title ?? "Enjoying the app?",
37
- message:
38
- translations?.message ??
39
- `If you love using ${appName}, would you mind taking a moment to rate it?`,
40
- positiveButton: translations?.positiveButton ?? "Yes, I love it!",
41
- negativeButton: translations?.negativeButton ?? "Not really",
42
- laterButton: translations?.laterButton ?? "Maybe later",
43
- };
44
-
45
- return (
46
- <Modal
47
- visible={visible}
48
- transparent
49
- animationType="none"
50
- onRequestClose={onDismiss}
51
- statusBarTranslucent
52
- >
53
- <View
54
- style={[
55
- styles.overlay,
56
- { backgroundColor: "rgba(0, 0, 0, 0.5)" },
57
- ]}
58
- >
59
- <View
60
- style={[
61
- styles.container,
62
- {
63
- backgroundColor: tokens.colors.surface,
64
- borderRadius: tokens.borders.radius.xl,
65
- padding: tokens.spacing.lg,
66
- maxWidth: responsive.maxContentWidth * 0.85,
67
- width: "90%",
68
- },
69
- ]}
70
- >
71
- <View style={styles.iconContainer}>
72
- <AtomicIcon name="star" size="xl" color="primary" />
73
- </View>
74
-
75
- <AtomicText
76
- type="headlineMedium"
77
- color="onSurface"
78
- style={[
79
- styles.title,
80
- { marginBottom: tokens.spacing.sm },
81
- ]}
82
- >
83
- {defaultTranslations.title}
84
- </AtomicText>
85
-
86
- <AtomicText
87
- type="bodyMedium"
88
- color="onSurfaceVariant"
89
- style={[
90
- styles.message,
91
- { marginBottom: tokens.spacing.lg },
92
- ]}
93
- >
94
- {defaultTranslations.message}
95
- </AtomicText>
96
-
97
- <View style={[styles.buttonContainer, { gap: tokens.spacing.sm }]}>
98
- <AtomicButton
99
- variant="primary"
100
- onPress={onPositive}
101
- style={styles.button}
102
- >
103
- {defaultTranslations.positiveButton}
104
- </AtomicButton>
105
-
106
- <AtomicButton
107
- variant="outline"
108
- onPress={onNegative}
109
- style={styles.button}
110
- >
111
- {defaultTranslations.negativeButton}
112
- </AtomicButton>
113
-
114
- <AtomicButton
115
- variant="text"
116
- onPress={onLater}
117
- style={styles.button}
118
- >
119
- {defaultTranslations.laterButton}
120
- </AtomicButton>
121
- </View>
122
- </View>
123
- </View>
124
- </Modal>
125
- );
126
- };
127
-
128
- const styles = StyleSheet.create({
129
- overlay: {
130
- flex: 1,
131
- justifyContent: "center",
132
- alignItems: "center",
133
- },
134
- container: {
135
- alignItems: "center",
136
- },
137
- iconContainer: {
138
- marginBottom: 16,
139
- },
140
- title: {
141
- textAlign: "center",
142
- },
143
- message: {
144
- textAlign: "center",
145
- },
146
- buttonContainer: {
147
- width: "100%",
148
- },
149
- button: {
150
- width: "100%",
151
- },
152
- });