@umituz/react-native-design-system 4.25.67 → 4.25.69

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.25.67",
3
+ "version": "4.25.69",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -37,13 +37,15 @@ export class ValidationManager {
37
37
  return this.validateMultipleChoice(answer, validation);
38
38
  case "text_input":
39
39
  return this.validateTextInput(answer, validation);
40
+ case "date":
41
+ return this.validateDate(answer, validation);
40
42
  case "rating":
41
43
  return this.validateNumeric(answer, validation);
42
44
  default:
43
45
  break;
44
46
  }
45
47
 
46
- // Custom validator
48
+ // Custom validator (for types not covered by switch, e.g. default)
47
49
  if (validation.customValidator) {
48
50
  const customResult = validation.customValidator(answer);
49
51
  return customResult === true;
@@ -85,10 +87,20 @@ export class ValidationManager {
85
87
  ): boolean {
86
88
  if (!validation) return true;
87
89
 
90
+ // If no answer yet (undefined/null), valid only when not required
91
+ if (answer === undefined || answer === null) {
92
+ return !validation.required;
93
+ }
94
+
88
95
  if (typeof answer !== "string") {
89
96
  return false;
90
97
  }
91
98
 
99
+ // Empty string: valid only when not required
100
+ if (!answer.trim() && validation.required) {
101
+ return false;
102
+ }
103
+
92
104
  if (validation.minLength && answer.length < validation.minLength) {
93
105
  return false;
94
106
  }
@@ -97,9 +109,36 @@ export class ValidationManager {
97
109
  return false;
98
110
  }
99
111
 
112
+ // Run custom validator if provided
113
+ if (validation.customValidator) {
114
+ const customResult = validation.customValidator(answer);
115
+ return customResult === true;
116
+ }
117
+
100
118
  return true;
101
119
  }
102
120
 
121
+ /**
122
+ * Validate date answer (ISO string from date picker)
123
+ */
124
+ private static validateDate(
125
+ answer: OnboardingAnswerValue,
126
+ validation: OnboardingQuestion["validation"],
127
+ ): boolean {
128
+ if (!validation) return true;
129
+
130
+ if (answer === undefined || answer === null) {
131
+ return !validation.required;
132
+ }
133
+
134
+ if (typeof answer !== "string" || !answer) {
135
+ return !validation.required;
136
+ }
137
+
138
+ const d = new Date(answer);
139
+ return !isNaN(d.getTime());
140
+ }
141
+
103
142
  /**
104
143
  * Validate numeric answer (rating)
105
144
  */
@@ -9,6 +9,7 @@ import { SingleChoiceQuestion } from "./questions/SingleChoiceQuestion";
9
9
  import { MultipleChoiceQuestion } from "./questions/MultipleChoiceQuestion";
10
10
  import { TextInputQuestion } from "./questions/TextInputQuestion";
11
11
  import { RatingQuestion } from "./questions/RatingQuestion";
12
+ import { DateQuestion } from "./questions/DateQuestion";
12
13
 
13
14
  export interface QuestionRendererProps {
14
15
  question: OnboardingQuestion;
@@ -54,6 +55,14 @@ export const QuestionRenderer = ({
54
55
  onChange={onChange as (value: number) => void}
55
56
  />
56
57
  );
58
+ case "date":
59
+ return (
60
+ <DateQuestion
61
+ question={question}
62
+ value={value as string | undefined}
63
+ onChange={onChange as (value: string) => void}
64
+ />
65
+ );
57
66
  default:
58
67
  return null;
59
68
  }
@@ -16,19 +16,21 @@ export const QuestionSlideHeader = ({ slide }: QuestionSlideHeaderProps) => {
16
16
 
17
17
  return (
18
18
  <View style={styles.container}>
19
- <View style={[
20
- styles.iconContainer,
21
- {
22
- backgroundColor: colors.iconBg,
23
- borderColor: colors.iconBorder,
24
- }
25
- ]}>
26
- {isEmoji ? (
27
- <AtomicText style={{ fontSize: 48 }}>{slide.icon}</AtomicText>
28
- ) : (
29
- <AtomicIcon name={slide.icon} customSize={48} customColor={colors.textColor} />
30
- )}
31
- </View>
19
+ {!slide.hideIcon && (
20
+ <View style={[
21
+ styles.iconContainer,
22
+ {
23
+ backgroundColor: colors.iconBg,
24
+ borderColor: colors.iconBorder,
25
+ }
26
+ ]}>
27
+ {isEmoji ? (
28
+ <AtomicText style={{ fontSize: 48 }}>{slide.icon}</AtomicText>
29
+ ) : (
30
+ <AtomicIcon name={slide.icon} customSize={48} customColor={colors.textColor} />
31
+ )}
32
+ </View>
33
+ )}
32
34
 
33
35
  <AtomicText type="headlineMedium" style={[styles.title, { color: colors.textColor }]}>
34
36
  {slide.title}
@@ -0,0 +1,58 @@
1
+ import React, { useCallback } from "react";
2
+ import { View, StyleSheet } from "react-native";
3
+ import { AtomicDatePicker } from "../../../../atoms/AtomicDatePicker";
4
+ import { useOnboardingProvider } from "../../providers/OnboardingProvider";
5
+ import type { OnboardingQuestion } from "../../../domain/entities/OnboardingQuestion";
6
+
7
+ export interface DateQuestionProps {
8
+ question: OnboardingQuestion;
9
+ value: string | undefined;
10
+ onChange: (value: string) => void;
11
+ }
12
+
13
+ export const DateQuestion = ({
14
+ question,
15
+ value,
16
+ onChange,
17
+ }: DateQuestionProps) => {
18
+ const {
19
+ theme: { colors },
20
+ } = useOnboardingProvider();
21
+
22
+ const dateValue = value ? new Date(value) : null;
23
+
24
+ const handleChange = useCallback(
25
+ (date: Date) => {
26
+ onChange(date.toISOString());
27
+ },
28
+ [onChange],
29
+ );
30
+
31
+ return (
32
+ <View style={styles.container}>
33
+ <AtomicDatePicker
34
+ value={dateValue}
35
+ onChange={handleChange}
36
+ placeholder={question.placeholder}
37
+ maximumDate={new Date()}
38
+ style={[
39
+ styles.picker,
40
+ {
41
+ borderColor: dateValue ? colors.iconColor : colors.headerButtonBorder,
42
+ },
43
+ ]}
44
+ />
45
+ </View>
46
+ );
47
+ };
48
+
49
+ const styles = StyleSheet.create({
50
+ container: {
51
+ width: "100%",
52
+ },
53
+ picker: {
54
+ borderRadius: 16,
55
+ borderWidth: 2,
56
+ overflow: "hidden",
57
+ },
58
+ });