@widergy/mobile-ui 0.32.4 → 0.34.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 (26) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/components/Capture/index.js +54 -0
  3. package/lib/components/Capture/propTypes.js +14 -0
  4. package/lib/components/Capture/styles.js +11 -0
  5. package/lib/components/FilePicker/index.js +10 -16
  6. package/lib/components/Label/utils.js +4 -1
  7. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/index.js +19 -0
  8. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/propTypes.js +7 -0
  9. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/styles.js +29 -0
  10. package/lib/components/PhotoAlbum/components/DeleteView/index.js +19 -0
  11. package/lib/components/PhotoAlbum/components/DeleteView/propTypes.js +6 -0
  12. package/lib/components/PhotoAlbum/components/DeleteView/styles.js +9 -0
  13. package/lib/components/PhotoAlbum/components/Photo/index.js +69 -0
  14. package/lib/components/PhotoAlbum/components/Photo/propTypes.js +10 -0
  15. package/lib/components/PhotoAlbum/components/Photo/styles.js +53 -0
  16. package/lib/components/PhotoAlbum/components/ReplaceView/index.js +18 -0
  17. package/lib/components/PhotoAlbum/components/ReplaceView/propTypes.js +6 -0
  18. package/lib/components/PhotoAlbum/components/ReplaceView/styles.js +15 -0
  19. package/lib/components/PhotoAlbum/components/SvgIconCheck/index.js +17 -0
  20. package/lib/components/PhotoAlbum/components/SvgIconCheck/propTypes.js +5 -0
  21. package/lib/components/PhotoAlbum/components/SvgIconCheck/styles.js +18 -0
  22. package/lib/components/PhotoAlbum/index.js +168 -0
  23. package/lib/components/PhotoAlbum/propTypes.js +17 -0
  24. package/lib/components/PhotoAlbum/styles.js +51 -0
  25. package/lib/index.js +4 -0
  26. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## [0.34.1](https://github.com/widergy/mobile-ui/compare/v0.34.0...v0.34.1) (2022-04-26)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * undefined is not a function ([#219](https://github.com/widergy/mobile-ui/issues/219)) ([ca80c4d](https://github.com/widergy/mobile-ui/commit/ca80c4d6b90176376f980234be432da87f6ed5ff))
7
+
8
+ # [0.34.0](https://github.com/widergy/mobile-ui/compare/v0.33.0...v0.34.0) (2022-04-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * photo album and capture component added ([08f0749](https://github.com/widergy/mobile-ui/commit/08f07498f274b36bfc2a3be901527bd73f338a7a))
14
+
15
+ # [0.33.0](https://github.com/widergy/mobile-ui/compare/v0.32.4...v0.33.0) (2022-03-25)
16
+
17
+
18
+ ### Features
19
+
20
+ * allow any mime type ([#217](https://github.com/widergy/mobile-ui/issues/217)) ([9b99614](https://github.com/widergy/mobile-ui/commit/9b99614b93d98e14a57c409f0e7674c5832d1b58))
21
+
1
22
  ## [0.32.4](https://github.com/widergy/mobile-ui/compare/v0.32.3...v0.32.4) (2022-03-07)
2
23
 
3
24
 
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+
3
+ import Label from '../Label';
4
+ import PhotoAlbum from '../PhotoAlbum';
5
+ import Portal from '../Portal';
6
+
7
+ import styles from './styles';
8
+ import propTypes from './propTypes';
9
+
10
+ const Capture = ({
11
+ label,
12
+ helpText,
13
+ maxImages,
14
+ images,
15
+ selectedImages,
16
+ setSelectedImages,
17
+ deletePhoto,
18
+ onPressAddAnotherPhoto,
19
+ onUnknownCameraError,
20
+ selectedMode,
21
+ sourceCameraImage,
22
+ sourceEditImage,
23
+ messageErrorPermissionCamera
24
+ }) => {
25
+ const isOnlyOnePicture = maxImages === 1 && images.length === 1;
26
+ const isItPossibleToAddAnotherPhoto = isOnlyOnePicture ? false : images.length <= maxImages;
27
+
28
+ return (
29
+ <Portal.Host>
30
+ <Label semiBold big style={styles.paddingText}>
31
+ {label}
32
+ </Label>
33
+ <PhotoAlbum
34
+ images={images}
35
+ selectedImages={selectedImages}
36
+ setSelectedImages={setSelectedImages}
37
+ deletePhoto={deletePhoto}
38
+ isItPossibleToAddAnotherPhoto={isItPossibleToAddAnotherPhoto}
39
+ onPressAddAnotherPhoto={onPressAddAnotherPhoto}
40
+ onUnknownCameraError={onUnknownCameraError}
41
+ selectedMode={selectedMode}
42
+ numberOfPhotosInTheAlbumHasExceeded={images.length === maxImages}
43
+ isOnlyOnePicture={isOnlyOnePicture}
44
+ sourceCameraImage={sourceCameraImage}
45
+ sourceEditImage={sourceEditImage}
46
+ messageErrorPermissionCamera={messageErrorPermissionCamera}
47
+ />
48
+ <Label style={styles.paddingText}>{helpText}</Label>
49
+ </Portal.Host>
50
+ );
51
+ };
52
+ Capture.propTypes = propTypes;
53
+
54
+ export default Capture;
@@ -0,0 +1,14 @@
1
+ import { bool, string, func, array, number } from 'prop-types';
2
+
3
+ export default {
4
+ label: string,
5
+ helpText: string,
6
+ maxImages: number,
7
+ images: array,
8
+ selectedImages: array,
9
+ setSelectedImages: func,
10
+ deletePhoto: func,
11
+ onPressAddAnotherPhoto: func,
12
+ onUnknownCameraError: func,
13
+ selectedMode: bool
14
+ };
@@ -0,0 +1,11 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale } from '../../utils/scaleUtils';
4
+
5
+ const styles = StyleSheet.create({
6
+ paddingText: {
7
+ paddingLeft: moderateHorizontalScale(5)
8
+ }
9
+ });
10
+
11
+ export default styles;
@@ -26,37 +26,31 @@ class FilePicker extends Component {
26
26
  onError,
27
27
  onChange,
28
28
  maxFileByteSize,
29
+ avoidRetrieveFile,
29
30
  fileTypeError,
30
31
  allowedPDFUploadSizes,
31
32
  pdfFormatError
32
33
  } = this.props;
33
- const promisePicker = new Promise(async (resolve, reject) => {
34
- try {
35
- const picker = await DocumentPicker.pick({
36
- type: allowedTypes && !onlyPDFAllowed(allowedTypes) ? allowedTypes : DocumentPicker.types.allFiles
37
- });
38
- return resolve(picker[0]);
39
- } catch (error) {
40
- return reject(error);
41
- }
42
- });
43
34
  try {
44
- const document = await promisePicker;
35
+ const documents = await DocumentPicker.pick({
36
+ type: allowedTypes && !onlyPDFAllowed(allowedTypes) ? allowedTypes : DocumentPicker.types.allFiles
37
+ });
38
+ const document = documents[0];
45
39
  const isPDF = document.type.includes('pdf');
46
40
  const isImage = document.type.includes('image');
47
41
  if (onlyPDFAllowed(allowedTypes) && !isPDF) {
48
42
  throw new Error(fileTypeError || 'El tipo de archivo debe ser PDF.');
49
43
  }
50
- if (!isImage && !isImageByUri(document.uri) && !isPDF) {
44
+ if (allowedTypes && !isImage && !isImageByUri(document.uri) && !isPDF) {
51
45
  throw new Error(fileTypeError || 'Tipo de archivo inválido.');
52
46
  }
53
- if (document.size > maxFileByteSize) {
47
+ if (maxFileByteSize && document.size > maxFileByteSize) {
54
48
  onMaxSizeError(document.size, maxFileByteSize);
55
49
  return;
56
50
  }
57
- const file = await retrieveFile(document.uri, document.type);
51
+ const file = !avoidRetrieveFile && (await retrieveFile(document.uri, document.type));
58
52
 
59
- if (isPDF && !isEmpty(allowedPDFUploadSizes)) {
53
+ if (file && isPDF && !isEmpty(allowedPDFUploadSizes)) {
60
54
  const isWrongFormat = await pdfAspectRatioValidation(file, allowedPDFUploadSizes);
61
55
  if (isWrongFormat) {
62
56
  throw new Error(
@@ -68,7 +62,7 @@ class FilePicker extends Component {
68
62
  }
69
63
  }
70
64
  if (onChange) {
71
- onChange({ file });
65
+ onChange(avoidRetrieveFile ? { document } : { file });
72
66
  }
73
67
  this.setState({ fileName: document.name });
74
68
  } catch (err) {
@@ -48,4 +48,7 @@ export const formatStyles = (useMarkdown, styles, newMarkdownStyles = {}) => {
48
48
  };
49
49
 
50
50
  export const markdownFormat = content =>
51
- content?.replace(/(<\s*br\s*\/?>|\n)/gi, '\n\n').replace(/(<\s*hr\s*\/?>)/gi, '\n\n---') || null;
51
+ content
52
+ ?.toString()
53
+ .replace(/(<\s*br\s*\/?>|\n)/gi, '\n\n')
54
+ .replace(/(<\s*hr\s*\/?>)/gi, '\n\n---') || null;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { Image, TouchableOpacity } from 'react-native';
3
+
4
+ import styles from './styles';
5
+ import propTypes from './propTypes';
6
+
7
+ const AddAnotherPhotoButton = ({ sourceCameraImage, onPress, disabled }) => (
8
+ <TouchableOpacity
9
+ onPress={onPress}
10
+ style={[styles.container, disabled && styles.disabledContainer]}
11
+ disabled={disabled}
12
+ >
13
+ <Image source={sourceCameraImage} style={[styles.image, disabled && styles.imageDisabled]} />
14
+ </TouchableOpacity>
15
+ );
16
+
17
+ AddAnotherPhotoButton.propTypes = propTypes;
18
+
19
+ export default AddAnotherPhotoButton;
@@ -0,0 +1,7 @@
1
+ import { bool, func, any } from 'prop-types';
2
+
3
+ export default {
4
+ source: any,
5
+ onPress: func,
6
+ disabled: bool
7
+ };
@@ -0,0 +1,29 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ width: IMAGE_SIZE,
9
+ height: IMAGE_SIZE,
10
+ paddingHorizontal: moderateHorizontalScale(10),
11
+ borderRadius: 5,
12
+ marginBottom: moderateVerticalScale(10),
13
+ backgroundColor: '#F7F8F9',
14
+ justifyContent: 'center',
15
+ alignItems: 'center'
16
+ },
17
+ disabledContainer: {
18
+ backgroundColor: 'rgba(247, 248, 249, 0.5)'
19
+ },
20
+ image: {
21
+ width: moderateHorizontalScale(48),
22
+ height: moderateHorizontalScale(48)
23
+ },
24
+ imageDisabled: {
25
+ opacity: 0.5
26
+ }
27
+ });
28
+
29
+ export default styles;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import Icon from '../../../Icon';
5
+ import Label from '../../../Label';
6
+
7
+ import styles from './styles';
8
+ import propTypes from './propTypes';
9
+
10
+ const DeleteView = ({ label, color }) => (
11
+ <View style={styles.buttonContainer}>
12
+ <Icon name="trash-2" type="feather" size={20} color={color} />
13
+ <Label color={color}>{label}</Label>
14
+ </View>
15
+ );
16
+
17
+ DeleteView.propTypes = propTypes;
18
+
19
+ export default DeleteView;
@@ -0,0 +1,6 @@
1
+ import { bool, string, oneOfType } from 'prop-types';
2
+
3
+ export default {
4
+ color: oneOfType([bool, string]),
5
+ label: string
6
+ };
@@ -0,0 +1,9 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ buttonContainer: {
5
+ alignItems: 'center'
6
+ }
7
+ });
8
+
9
+ export default styles;
@@ -0,0 +1,69 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Image, TouchableOpacity, Modal, ImageBackground } from 'react-native';
3
+
4
+ import SvgIconCheck from '../SvgIconCheck';
5
+ import Icon from '../../../Icon';
6
+ import DeleteView from '../DeleteView';
7
+
8
+ import styles from './styles';
9
+ import propTypes from './propTypes';
10
+
11
+ const Photo = ({ image, onError, onLongPressImage, selectedImages, deletePhoto, isSelectedMode }) => {
12
+ const uri = image.uri ?? image;
13
+ const [fullScreenPhotoModalVisible, setFullScreenPhotoModalVisible] = useState(false);
14
+
15
+ const wasTheImagePressed = selectedImages.includes(uri);
16
+
17
+ const deletePhotoInModal = () => {
18
+ setFullScreenPhotoModalVisible(false);
19
+ deletePhoto(uri);
20
+ };
21
+ return (
22
+ <View>
23
+ <TouchableOpacity
24
+ onPress={() => {
25
+ if (isSelectedMode) {
26
+ onLongPressImage(uri);
27
+ } else {
28
+ setFullScreenPhotoModalVisible(true);
29
+ }
30
+ }}
31
+ onLongPress={() => {
32
+ onLongPressImage(uri);
33
+ }}
34
+ >
35
+ {wasTheImagePressed ? (
36
+ <ImageBackground borderRadius={5} source={{ uri }} style={styles.image}>
37
+ <SvgIconCheck size={24} />
38
+ </ImageBackground>
39
+ ) : (
40
+ <Image onError={onError} source={{ uri }} style={styles.image} />
41
+ )}
42
+ </TouchableOpacity>
43
+ <Modal animationType="fade" visible={fullScreenPhotoModalVisible}>
44
+ <View style={styles.modalContainer}>
45
+ <View style={styles.headerContainerModal}>
46
+ <TouchableOpacity
47
+ onPress={() => {
48
+ setFullScreenPhotoModalVisible(!fullScreenPhotoModalVisible);
49
+ }}
50
+ style={styles.backButtonHeaderModal}
51
+ >
52
+ <Icon name="arrowleft" type="antdesign" size={24} color="white" />
53
+ </TouchableOpacity>
54
+ </View>
55
+ <Image onError={onError} source={{ uri }} style={styles.imageFullScreen} />
56
+ {deletePhoto && (
57
+ <TouchableOpacity onPress={deletePhotoInModal} style={styles.footerContainerModal}>
58
+ <DeleteView label="Eliminar" color="white" />
59
+ </TouchableOpacity>
60
+ )}
61
+ </View>
62
+ </Modal>
63
+ </View>
64
+ );
65
+ };
66
+
67
+ Photo.propTypes = propTypes;
68
+
69
+ export default Photo;
@@ -0,0 +1,10 @@
1
+ import { bool, func, array, any } from 'prop-types';
2
+
3
+ export default {
4
+ image: any,
5
+ onError: func,
6
+ onLongPressImage: func,
7
+ selectedImages: array,
8
+ deletePhoto: func,
9
+ isSelectedMode: bool
10
+ };
@@ -0,0 +1,53 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ image: {
8
+ width: IMAGE_SIZE,
9
+ height: IMAGE_SIZE,
10
+ borderRadius: 5,
11
+ marginBottom: moderateVerticalScale(10)
12
+ },
13
+ imageFullScreen: {
14
+ flex: 1,
15
+ width: '100%',
16
+ height: '100%',
17
+ resizeMode: 'cover'
18
+ },
19
+ selectedImageIcon: {
20
+ position: 'absolute',
21
+ alignItems: 'flex-start'
22
+ },
23
+ modalContainer: {
24
+ flex: 1,
25
+ justifyContent: 'space-between'
26
+ },
27
+ headerContainerModal: {
28
+ flexBasis: moderateHorizontalScale(54),
29
+ backgroundColor: '#3A3A3A',
30
+ flexDirection: 'row',
31
+ justifyContent: 'space-between',
32
+ alignItems: 'center',
33
+ paddingLeft: moderateHorizontalScale(15)
34
+ },
35
+ backButtonHeaderModal: {
36
+ width: moderateHorizontalScale(38),
37
+ height: moderateVerticalScale(38),
38
+ borderRadius: 50,
39
+ justifyContent: 'center',
40
+ alignItems: 'center'
41
+ },
42
+ footerContainerModal: {
43
+ flexBasis: moderateHorizontalScale(57),
44
+ backgroundColor: '#3A3A3A',
45
+ justifyContent: 'center',
46
+ alignItems: 'center'
47
+ },
48
+ buttonContainerFooterModal: {
49
+ alignItems: 'center'
50
+ }
51
+ });
52
+
53
+ export default styles;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { View, Image } from 'react-native';
3
+
4
+ import Label from '../../../Label';
5
+
6
+ import styles from './styles';
7
+ import propTypes from './propTypes';
8
+
9
+ const ReplaceView = ({ label, color, sourceEditImage }) => (
10
+ <View style={styles.buttonContainer}>
11
+ <Image source={sourceEditImage} style={styles.image} />
12
+ <Label color={color}>{label}</Label>
13
+ </View>
14
+ );
15
+
16
+ ReplaceView.propTypes = propTypes;
17
+
18
+ export default ReplaceView;
@@ -0,0 +1,6 @@
1
+ import { bool, string, oneOfType } from 'prop-types';
2
+
3
+ export default {
4
+ color: oneOfType([bool, string]),
5
+ label: string
6
+ };
@@ -0,0 +1,15 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale, moderateVerticalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const styles = StyleSheet.create({
6
+ buttonContainer: {
7
+ alignItems: 'center'
8
+ },
9
+ image: {
10
+ width: moderateHorizontalScale(24),
11
+ height: moderateVerticalScale(24)
12
+ }
13
+ });
14
+
15
+ export default styles;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import Icon from '../../../Icon';
5
+
6
+ import { styles, colorIcon } from './styles';
7
+ import propTypes from './propTypes';
8
+
9
+ const SvgIconCheck = ({ size }) => (
10
+ <View style={styles(size).backgroundIcon}>
11
+ <Icon color={colorIcon} name="check" size={16} />
12
+ </View>
13
+ );
14
+
15
+ SvgIconCheck.propTypes = propTypes;
16
+
17
+ export default SvgIconCheck;
@@ -0,0 +1,5 @@
1
+ import { number } from 'prop-types';
2
+
3
+ export default {
4
+ size: number
5
+ };
@@ -0,0 +1,18 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale } from '../../../../utils/scaleUtils';
4
+
5
+ export const styles = size =>
6
+ StyleSheet.create({
7
+ backgroundIcon: {
8
+ margin: moderateVerticalScale(10),
9
+ alignItems: 'center',
10
+ justifyContent: 'center',
11
+ backgroundColor: '#4D98FA',
12
+ borderRadius: 1000,
13
+ width: size,
14
+ height: size
15
+ }
16
+ });
17
+
18
+ export const colorIcon = 'white';
@@ -0,0 +1,168 @@
1
+ import React, { Fragment, useEffect, useState } from 'react';
2
+ // eslint-disable-next-line react-native/split-platform-components
3
+ import { View, TouchableOpacity, PermissionsAndroid } from 'react-native';
4
+ // eslint-disable-next-line import/no-unresolved
5
+ import { launchCamera } from 'react-native-image-picker';
6
+
7
+ import Label from '../Label';
8
+ import Portal from '../Portal';
9
+
10
+ import AddAnotherPhotoButton from './components/AddAnotherPhotoButton';
11
+ import DeleteView from './components/DeleteView';
12
+ import ReplaceView from './components/ReplaceView';
13
+ import Photo from './components/Photo';
14
+ import styles from './styles';
15
+ import propTypes from './propTypes';
16
+
17
+ const PhotoAlbum = ({
18
+ images,
19
+ selectedImages,
20
+ setSelectedImages,
21
+ deletePhoto,
22
+ selectedMode,
23
+ isItPossibleToAddAnotherPhoto,
24
+ onPressAddAnotherPhoto,
25
+ onError,
26
+ title,
27
+ subTitle,
28
+ onUnknownCameraError,
29
+ numberOfPhotosInTheAlbumHasExceeded,
30
+ isOnlyOnePicture,
31
+ sourceCameraImage,
32
+ sourceEditImage,
33
+ messageErrorPermissionCamera
34
+ }) => {
35
+ const requestPermission = async () => {
36
+ const permissionsResponse = await PermissionsAndroid.requestMultiple([
37
+ PermissionsAndroid.PERMISSIONS.CAMERA,
38
+ PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
39
+ ]);
40
+
41
+ const granted =
42
+ permissionsResponse[PermissionsAndroid.PERMISSIONS.CAMERA] === 'granted' &&
43
+ permissionsResponse[PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE] === 'granted';
44
+
45
+ if (!granted) {
46
+ throw messageErrorPermissionCamera;
47
+ }
48
+ };
49
+
50
+ const [isSelectedMode, setIsSelectedMode] = useState(false);
51
+ const onLongPressImage = uri => {
52
+ if (selectedImages.includes(uri)) {
53
+ setSelectedImages(selectedImages.filter(aPicUri => aPicUri !== uri));
54
+ } else {
55
+ setSelectedImages([...selectedImages, uri]);
56
+ }
57
+ };
58
+ const deleteSelectedPhotos = () => {
59
+ deletePhoto();
60
+ };
61
+
62
+ const openCamera = async () => {
63
+ await requestPermission();
64
+
65
+ const response = await launchCamera({});
66
+ const { didCancel, errorCode, errorMessage, assets } = response;
67
+ if (didCancel || errorCode) {
68
+ if (errorCode) {
69
+ onUnknownCameraError(`[${errorCode}] : ${errorMessage}`);
70
+ }
71
+ } else {
72
+ const { uri } = assets[0];
73
+ onPressAddAnotherPhoto({ newImage: { uri }, numberOfPhotosInTheAlbumHasExceeded });
74
+ }
75
+ };
76
+
77
+ const isDivisibleInModuleOfThree = () => {
78
+ const numberOfObjectsInView = isItPossibleToAddAnotherPhoto ? images.length + 1 : images.length;
79
+ return numberOfObjectsInView % 3 !== 0;
80
+ };
81
+
82
+ const cameraOnPress = () =>
83
+ openCamera().catch(error => {
84
+ if (typeof error === 'string') {
85
+ onError(error);
86
+ } else {
87
+ onUnknownCameraError(error);
88
+ }
89
+ });
90
+
91
+ const onPressAddAnotherPhotoButton = deleteSelectedImages => {
92
+ if (deleteSelectedImages) {
93
+ setSelectedImages([]);
94
+ }
95
+ cameraOnPress();
96
+ };
97
+
98
+ useEffect(() => {
99
+ if (selectedImages.length > 0) {
100
+ setIsSelectedMode(true);
101
+ } else {
102
+ setIsSelectedMode(false);
103
+ }
104
+ }, [selectedImages]);
105
+
106
+ return (
107
+ <Fragment>
108
+ {title && (
109
+ <Label big semiBold color="#666666" style={styles.title}>
110
+ {title}
111
+ </Label>
112
+ )}
113
+ {subTitle && (
114
+ <Label color="#3A3A3A" style={styles.subTitle}>
115
+ {subTitle}
116
+ </Label>
117
+ )}
118
+ <View style={styles.container}>
119
+ {images.length !== 0 &&
120
+ images.map(image => (
121
+ <Photo
122
+ key={image.uri ?? image}
123
+ image={image}
124
+ onLongPressImage={onLongPressImage}
125
+ selectedImages={selectedImages}
126
+ deletePhoto={deletePhoto}
127
+ isSelectedMode={isSelectedMode}
128
+ onError={onError}
129
+ />
130
+ ))}
131
+ {isItPossibleToAddAnotherPhoto && (
132
+ <AddAnotherPhotoButton
133
+ onPress={onPressAddAnotherPhotoButton}
134
+ disabled={numberOfPhotosInTheAlbumHasExceeded}
135
+ sourceCameraImage={sourceCameraImage}
136
+ />
137
+ )}
138
+ {isDivisibleInModuleOfThree() && <View style={styles.image} />}
139
+ {selectedMode && isSelectedMode && (
140
+ <Portal>
141
+ <View style={styles.selectedModeContainer}>
142
+ <View style={styles.selectionLabelContainer}>
143
+ <Label color="white">{`${selectedImages.length} selección`}</Label>
144
+ </View>
145
+ <View style={styles.buttonsContainer}>
146
+ {isOnlyOnePicture && (
147
+ <TouchableOpacity
148
+ onPress={() => onPressAddAnotherPhotoButton(numberOfPhotosInTheAlbumHasExceeded)}
149
+ style={styles.deleteSelectedPhotos}
150
+ >
151
+ <ReplaceView label="Remplazar" color="#3A3A3A" sourceEditImage={sourceEditImage} />
152
+ </TouchableOpacity>
153
+ )}
154
+ <TouchableOpacity onPress={deleteSelectedPhotos} style={styles.deleteSelectedPhotos}>
155
+ <DeleteView label="Eliminar" color="#3A3A3A" />
156
+ </TouchableOpacity>
157
+ </View>
158
+ </View>
159
+ </Portal>
160
+ )}
161
+ </View>
162
+ </Fragment>
163
+ );
164
+ };
165
+
166
+ PhotoAlbum.propTypes = propTypes;
167
+
168
+ export default PhotoAlbum;
@@ -0,0 +1,17 @@
1
+ import { bool, string, func, array } from 'prop-types';
2
+
3
+ export default {
4
+ images: array,
5
+ selectedImages: array,
6
+ setSelectedImages: func,
7
+ deletePhoto: func,
8
+ selectedMode: bool,
9
+ isItPossibleToAddAnotherPhoto: bool,
10
+ onPressAddAnotherPhoto: func,
11
+ onError: func,
12
+ title: string,
13
+ subTitle: string,
14
+ onUnknownCameraError: func,
15
+ numberOfPhotosInTheAlbumHasExceeded: bool,
16
+ isOnlyOnePicture: bool
17
+ };
@@ -0,0 +1,51 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale, moderateVerticalScale, WINDOW_WIDTH } from '../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ flexDirection: 'row',
9
+ flexWrap: 'wrap',
10
+ justifyContent: 'space-between',
11
+ paddingHorizontal: moderateHorizontalScale(5)
12
+ },
13
+ selectedModeContainer: {
14
+ width: WINDOW_WIDTH,
15
+ position: 'absolute',
16
+ bottom: 0
17
+ },
18
+ selectionLabelContainer: {
19
+ height: moderateVerticalScale(27),
20
+ alignItems: 'center',
21
+ backgroundColor: '#4D98FA'
22
+ },
23
+ buttonsContainer: {
24
+ flexDirection: 'row',
25
+ alignItems: 'center',
26
+ justifyContent: 'space-around',
27
+ backgroundColor: '#E4E6EA',
28
+ paddingHorizontal: 60
29
+ },
30
+ deleteSelectedPhotos: {
31
+ height: moderateVerticalScale(58),
32
+ justifyContent: 'center'
33
+ },
34
+ title: {
35
+ marginBottom: moderateVerticalScale(10),
36
+ paddingHorizontal: moderateHorizontalScale(5)
37
+ },
38
+ subTitle: {
39
+ marginBottom: moderateVerticalScale(5),
40
+ paddingHorizontal: moderateHorizontalScale(5)
41
+ },
42
+ image: {
43
+ width: IMAGE_SIZE,
44
+ height: IMAGE_SIZE,
45
+ borderRadius: 5,
46
+ marginBottom: moderateVerticalScale(10),
47
+ paddingHorizontal: moderateHorizontalScale(10)
48
+ }
49
+ });
50
+
51
+ export default styles;
package/lib/index.js CHANGED
@@ -69,3 +69,7 @@ export { default as withLoading } from './components/WithLoading';
69
69
  // Hooks
70
70
  export { default as useEffectOnlyOnUpdates } from './hooks/useEffectOnlyOnUpdates';
71
71
  export { default as useTogglableState } from './hooks/useTogglableState';
72
+
73
+ // Photo
74
+ export { default as PhotoAlbum } from './components/PhotoAlbum';
75
+ export { default as Capture } from './components/Capture';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@widergy/mobile-ui",
3
3
  "description": "Widergy Mobile Components",
4
4
  "author": "widergy",
5
- "version": "0.32.4",
5
+ "version": "0.34.1",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [
@@ -26,7 +26,7 @@
26
26
  "react": "*",
27
27
  "react-native": "*",
28
28
  "react-native-document-picker": "^3.4.0",
29
- "react-native-image-picker": "^0.28.0",
29
+ "react-native-image-picker": "4.x.x",
30
30
  "react-native-image-resizer": "^1.2.2",
31
31
  "react-native-svg": "*",
32
32
  "react-native-vector-icons": "*"