ota-components-module 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 (36) hide show
  1. package/README.md +179 -0
  2. package/assets/images/ic_camera.svg +3 -0
  3. package/assets/images/ic_close.svg +8 -0
  4. package/assets/images/ic_folder.svg +3 -0
  5. package/assets/images/placeholder.png +0 -0
  6. package/expo-env.d.ts +7 -0
  7. package/mri-manifest.json +10 -0
  8. package/package.json +28 -0
  9. package/src/button/ThemedButton.tsx +120 -0
  10. package/src/feedback/ActivityLoader.tsx +84 -0
  11. package/src/feedback/CustomAlert.tsx +143 -0
  12. package/src/feedback/DeleteImageConfirmationDialog.tsx +58 -0
  13. package/src/feedback/ProgressBar.tsx +58 -0
  14. package/src/image/ImagePickerBottomSheet.tsx +61 -0
  15. package/src/image/ImagePickerView.tsx +103 -0
  16. package/src/image/MultipleImagePreview.tsx +424 -0
  17. package/src/image/StackedImage.tsx +155 -0
  18. package/src/index.ts +68 -0
  19. package/src/input/CustomDropdown.tsx +142 -0
  20. package/src/input/CustomInput.tsx +101 -0
  21. package/src/input/FormField.tsx +358 -0
  22. package/src/input/KeyboardScrollView.tsx +131 -0
  23. package/src/input/SearchViewInput.tsx +183 -0
  24. package/src/layout/BottomSheetDialog.tsx +208 -0
  25. package/src/layout/BottomTwoButtonLayoutComponent.tsx +153 -0
  26. package/src/layout/CardView.tsx +101 -0
  27. package/src/layout/PropertyHeaderComponent.tsx +110 -0
  28. package/src/list/SearchableList.tsx +273 -0
  29. package/src/models/PropertyImage.ts +20 -0
  30. package/src/typography/Label.tsx +225 -0
  31. package/src/utils/BaseStyle.ts +46 -0
  32. package/src/utils/Strings.ts +1 -0
  33. package/src/utils/TextConstants.ts +24 -0
  34. package/src/utils/Utils.ts +11 -0
  35. package/src/webbaseview/WebBaseView.tsx +26 -0
  36. package/tsconfig.json +9 -0
@@ -0,0 +1,155 @@
1
+ import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
2
+ import React, {ReactElement} from 'react';
3
+ import { Colors } from '../utils/BaseStyle';
4
+ import { PropertyImage } from '../models/PropertyImage';
5
+ import { Image } from 'expo-image';
6
+
7
+ type StackedImageProps = {
8
+ photos: PropertyImage[];
9
+ onPress?: (photos: any) => void;
10
+ };
11
+
12
+ type Size = {
13
+ width: number;
14
+ height: number;
15
+ };
16
+
17
+ const MAX_COUNT = 3;
18
+
19
+ // Spacing constants
20
+ const Spacing = {
21
+ mini: 4,
22
+ sm: 8,
23
+ smd: 12,
24
+ md: 16,
25
+ lg: 24,
26
+ xl: 32,
27
+ xxl: 40,
28
+ xxxl: 80,
29
+ };
30
+
31
+ // Border constants
32
+ const Border = {
33
+ br_mini: 15,
34
+ br_mini2: 5,
35
+ border_10: 10,
36
+ border_20: 20,
37
+ border_25: 25,
38
+ border_40: 40,
39
+ };
40
+
41
+ /**
42
+ * A component for displaying stacked images
43
+ */
44
+ const StackedImage: React.FC<StackedImageProps> = ({
45
+ photos,
46
+ onPress,
47
+ }): ReactElement => {
48
+ const photoCount = photos?.length > MAX_COUNT ? MAX_COUNT : photos.length;
49
+ const style = StackPhotoStyle(photoCount);
50
+
51
+ const getHeight = (index: number) => {
52
+ if ((photoCount - 1) == index) {
53
+ return {width: 120, height: 120};
54
+ } else {
55
+ return {width: 100 + (index * 8), height: 100 + (index * 8)};
56
+ }
57
+ };
58
+
59
+ const getRight = (index: number) => {
60
+ if (photoCount == 1) {
61
+ return undefined;
62
+ } else {
63
+ return index * Spacing.smd;
64
+ }
65
+ };
66
+
67
+ const getLeft = (index: number) => {
68
+ if (photoCount == 1) {
69
+ return 0;
70
+ } else {
71
+ return undefined;
72
+ }
73
+ };
74
+
75
+ const onPressStack = () => {
76
+ if (onPress) {
77
+ onPress(photos);
78
+ }
79
+ };
80
+
81
+ return (
82
+ <TouchableOpacity onPress={onPressStack}>
83
+ <View style={style.imageStack}>
84
+ {photos
85
+ .slice(0, photoCount)
86
+ .reverse()
87
+ .map((image: PropertyImage, index: number) => (
88
+ <Image
89
+ key={index}
90
+ source={image.imageBlobUrl}
91
+ contentFit="cover"
92
+ placeholderContentFit='cover'
93
+ transition={500}
94
+ cachePolicy="disk"
95
+ placeholder={require("../../assets/images/placeholder.png")}
96
+ style={[
97
+ style.image,
98
+ {
99
+ width: getHeight(index).width,
100
+ height: getHeight(index).height,
101
+ borderColor: Colors.whiteColor,
102
+ borderWidth: 1,
103
+ shadowColor: Colors.shadowColor,
104
+ shadowOffset: { width: 0, height: 2 },
105
+ shadowOpacity: 0.1,
106
+ shadowRadius: 4,
107
+ bottom: 0,
108
+ left: getLeft(index),
109
+ right: getRight(index),
110
+ },
111
+ ]}
112
+ />
113
+ ))}
114
+ </View>
115
+
116
+ {photos.length >= 1 && (
117
+ <View style={style.countOverlay}>
118
+ <Text style={style.countText}>{photos.length}</Text>
119
+ </View>
120
+ )}
121
+ </TouchableOpacity>
122
+ );
123
+ };
124
+
125
+ const StackPhotoStyle = (photoCount: number) =>
126
+ StyleSheet.create({
127
+ imageStack: {
128
+ position: 'relative',
129
+ width: Spacing.xxxl + 60,
130
+ height: Spacing.xxxl + 60,
131
+ },
132
+ image: {
133
+ position: 'absolute',
134
+ borderRadius: Border.border_10,
135
+ },
136
+ countOverlay: {
137
+ position: 'absolute',
138
+ borderColor: Colors.whiteColor,
139
+ borderWidth: 1,
140
+ backgroundColor: Colors.lightThemePrimaryColor,
141
+ borderRadius: Border.br_mini,
142
+ width: Spacing.lg,
143
+ height: Spacing.lg,
144
+ alignItems: 'center',
145
+ bottom: 10,
146
+ left: (photoCount > 0 && photoCount % 2 == 0) ? 18 : 8,
147
+ },
148
+ countText: {
149
+ color: Colors.whiteColor,
150
+ fontFamily: 'OpenSans-Regular',
151
+ includeFontPadding: false,
152
+ },
153
+ });
154
+
155
+ export default StackedImage;
package/src/index.ts ADDED
@@ -0,0 +1,68 @@
1
+ // import all components from their respective folders
2
+
3
+ // Button Components
4
+ import ThemedButton from "./button/ThemedButton";
5
+
6
+ // Image Components
7
+ import MultipleImagePreview from "./image/MultipleImagePreview";
8
+ import ImagePickerView from "./image/ImagePickerView";
9
+ import ImagePickerBottomSheet from "./image/ImagePickerBottomSheet";
10
+ import StackedImage from "./image/StackedImage";
11
+
12
+ // Input Components
13
+ import CustomInput from "./input/CustomInput";
14
+ import FormField from "./input/FormField";
15
+ import CustomDropdown from "./input/CustomDropdown";
16
+ import SearchViewInput from "./input/SearchViewInput";
17
+ import KeyboardScrollView from "./input/KeyboardScrollView";
18
+
19
+ // Layout Components
20
+ import BottomTwoButtonLayoutComponent from "./layout/BottomTwoButtonLayoutComponent";
21
+ import PropertyHeaderComponent from "./layout/PropertyHeaderComponent";
22
+ import BottomSheetDialog from "./layout/BottomSheetDialog";
23
+ import { BottomSheetDialogRef } from "./layout/BottomSheetDialog";
24
+ import CardView from "./layout/CardView";
25
+
26
+
27
+ // Feedback Components
28
+ import ActivityLoader from "./feedback/ActivityLoader";
29
+ import ProgressBar from "./feedback/ProgressBar";
30
+ import CustomAlert from "./feedback/CustomAlert";
31
+ import DeleteImageConfirmationDialog from "./feedback/DeleteImageConfirmationDialog";
32
+
33
+ // Typography Components
34
+ import Label from "./typography/Label";
35
+
36
+ // List Components
37
+ import SearchableList from "./list/SearchableList";
38
+
39
+ // Common utilities and types
40
+ import * as BaseStyle from "./utils/BaseStyle";
41
+ import * as TextConstants from "./utils/TextConstants";
42
+
43
+ export {
44
+ ThemedButton,
45
+ MultipleImagePreview,
46
+ ImagePickerView,
47
+ ImagePickerBottomSheet,
48
+ StackedImage,
49
+ CustomInput,
50
+ FormField,
51
+ CustomDropdown,
52
+ SearchViewInput,
53
+ KeyboardScrollView,
54
+ BottomTwoButtonLayoutComponent,
55
+ PropertyHeaderComponent,
56
+ BottomSheetDialog,
57
+ ActivityLoader,
58
+ ProgressBar,
59
+ CustomAlert,
60
+ DeleteImageConfirmationDialog,
61
+ Label,
62
+ SearchableList,
63
+ BaseStyle,
64
+ TextConstants,
65
+ CardView,
66
+ };
67
+
68
+ export type { BottomSheetDialogRef };
@@ -0,0 +1,142 @@
1
+ import React from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import { Dropdown } from 'react-native-element-dropdown';
4
+ import { Colors } from '../utils/BaseStyle';
5
+
6
+ type DropdownItem = {
7
+ label?: string;
8
+ value: string;
9
+ };
10
+
11
+ interface CustomDropdownProps {
12
+ /**
13
+ * Test ID for the component
14
+ */
15
+ testID?: string;
16
+
17
+ /**
18
+ * Array of items to display in the dropdown
19
+ */
20
+ items: DropdownItem[];
21
+
22
+ /**
23
+ * Currently selected value
24
+ */
25
+ value: string;
26
+
27
+ /**
28
+ * Z-index for the dropdown (important for positioning)
29
+ */
30
+ zIndex: number;
31
+
32
+ /**
33
+ * Function to call when selection changes
34
+ */
35
+ onChange: (item: DropdownItem) => void;
36
+
37
+ /**
38
+ * Placeholder text to display when no item is selected
39
+ */
40
+ placeHolder: string;
41
+
42
+ /**
43
+ * Whether the dropdown is disabled
44
+ */
45
+ disabled?: boolean;
46
+ }
47
+
48
+ /**
49
+ * A customizable dropdown component
50
+ */
51
+ const CustomDropdown: React.FC<CustomDropdownProps> = ({
52
+ testID,
53
+ items,
54
+ value,
55
+ onChange,
56
+ zIndex,
57
+ placeHolder,
58
+ disabled = false
59
+ }) => {
60
+ // Find the selected item in the items array
61
+ const findSelectedItem = () => {
62
+ if (!value || !items || items.length === 0) return null;
63
+
64
+ // Try to find an item where the 'value' property matches the provided value
65
+ return items.find(item => item.value === value) || null;
66
+ };
67
+
68
+ const selectedItem = findSelectedItem();
69
+
70
+ // Create styles for disabled state
71
+ const dropdownStyle = [
72
+ styles.dropdown,
73
+ disabled && styles.disabledDropdown
74
+ ];
75
+
76
+ return (
77
+ <View style={[styles.container, { zIndex }]}>
78
+ <Dropdown
79
+ testID={testID}
80
+ style={dropdownStyle}
81
+ containerStyle={styles.dropdownContainer}
82
+ data={items}
83
+ labelField="value"
84
+ valueField="value"
85
+ value={selectedItem?.value || ''}
86
+ onChange={(item: DropdownItem) => !disabled ? onChange(item) : null}
87
+ placeholder={placeHolder}
88
+ autoScroll={true}
89
+ dropdownPosition='auto'
90
+ itemTextStyle={styles.itemText}
91
+ disable={disabled}
92
+ placeholderStyle={styles.placeholder}
93
+ selectedTextStyle={styles.selectedText}
94
+ />
95
+ </View>
96
+ );
97
+ };
98
+
99
+ const styles = StyleSheet.create({
100
+ container: {
101
+ position: 'relative',
102
+ overflow: 'visible',
103
+ },
104
+ dropdown: {
105
+ paddingHorizontal: 0,
106
+ paddingVertical: 10,
107
+ paddingBottom: 10,
108
+ borderBottomWidth: 1.0,
109
+ borderBottomColor: Colors.borderColor,
110
+ },
111
+ disabledDropdown: {
112
+ opacity: 0.5,
113
+ },
114
+ dropdownContainer: {
115
+ zIndex: 100,
116
+ borderRadius: 8,
117
+ borderWidth: 1,
118
+ borderColor: Colors.borderColor,
119
+ shadowColor: Colors.shadowColor,
120
+ shadowOffset: { width: 0, height: 2 },
121
+ shadowOpacity: 0.1,
122
+ shadowRadius: 4,
123
+ elevation: 3,
124
+ },
125
+ itemText: {
126
+ padding: 0,
127
+ fontSize: 16,
128
+ fontWeight: '500',
129
+ color: Colors.primaryTextColor,
130
+ },
131
+ placeholder: {
132
+ color: Colors.secondaryTextColor,
133
+ fontSize: 16,
134
+ },
135
+ selectedText: {
136
+ color: Colors.primaryTextColor,
137
+ fontSize: 16,
138
+ fontWeight: '500',
139
+ },
140
+ });
141
+
142
+ export default CustomDropdown;
@@ -0,0 +1,101 @@
1
+ import {
2
+ TextInput,
3
+ KeyboardType,
4
+ StyleSheet,
5
+ StyleProp,
6
+ TextStyle,
7
+ View,
8
+ Text,
9
+ ViewStyle,
10
+ } from "react-native";
11
+ import React, { useState } from "react";
12
+ import { Colors } from "../utils/BaseStyle";
13
+
14
+ const CustomInput = ({
15
+ onChangeText,
16
+ placeholder,
17
+ keyBoardType = "default",
18
+ textStyle,
19
+ customStyle,
20
+ placeholderTextColor,
21
+ text,
22
+ isEditable,
23
+ inputType,
24
+ validationPattern,
25
+ errorMessage,
26
+ onSubmitEditing,
27
+ returnKeyType
28
+ }: {
29
+ onChangeText: (text: string) => void;
30
+ placeholder: string;
31
+ keyBoardType?: KeyboardType;
32
+ customStyle?: StyleProp<ViewStyle>;
33
+ textStyle?: StyleProp<TextStyle>;
34
+ placeholderTextColor?: string;
35
+ text?: string;
36
+ isEditable?: boolean;
37
+ inputType?: 'email' | 'text' | 'number';
38
+ validationPattern?: RegExp;
39
+ errorMessage?: string;
40
+ onSubmitEditing?: () => void;
41
+ returnKeyType?: 'default' | 'done' | 'go' | 'next' | 'search' | 'send';
42
+ }) => {
43
+ const [isValid, setIsValid] = useState(true);
44
+
45
+ const validateInput = (text: string) => {
46
+ if (inputType === 'email') {
47
+ const emailRegex = validationPattern || /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
48
+ setIsValid(emailRegex.test(text));
49
+ } else if (validationPattern) {
50
+ setIsValid(validationPattern.test(text));
51
+ } else {
52
+ setIsValid(true);
53
+ }
54
+ };
55
+
56
+ const onChange = (text: string) => {
57
+ onChangeText(text);
58
+ validateInput(text);
59
+ };
60
+
61
+ const styles = inputStyles(isEditable!!, !isValid);
62
+
63
+ return (
64
+ <View style={[styles.inputcontainer, customStyle]}>
65
+ <TextInput
66
+ placeholder={placeholder}
67
+ placeholderTextColor={placeholderTextColor}
68
+ style={[styles.input, textStyle]}
69
+ value={text}
70
+ onChangeText={onChange}
71
+ keyboardType={keyBoardType}
72
+ editable={isEditable}
73
+ onSubmitEditing={onSubmitEditing}
74
+ returnKeyType={returnKeyType}
75
+ />
76
+ {!isValid && isEditable && errorMessage && (
77
+ <Text style={styles.errorText}>{errorMessage}</Text>
78
+ )}
79
+ </View>
80
+ );
81
+ };
82
+
83
+ const inputStyles = (isEditable: boolean, isError: boolean) =>
84
+ StyleSheet.create({
85
+ inputcontainer: {
86
+
87
+ },
88
+ input: {
89
+ borderBottomWidth: isEditable ? 1 : 0,
90
+ borderBottomColor: isError ? "red" : Colors.darkGrayColor,
91
+ outlineColor: "transparent",
92
+ paddingVertical: 10
93
+ },
94
+ errorText: {
95
+ color: 'red',
96
+ fontSize: 12,
97
+ marginTop: 5,
98
+ },
99
+ });
100
+
101
+ export default CustomInput;