@grupalia/rn-ui-kit 0.17.0 → 0.19.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 (198) hide show
  1. package/README.md +27 -0
  2. package/lib/commonjs/UIKitProvider.js +41 -0
  3. package/lib/commonjs/UIKitProvider.js.map +1 -0
  4. package/lib/commonjs/assets/illustrations/warning.svg +1 -0
  5. package/lib/commonjs/components/AppView.js +64 -0
  6. package/lib/commonjs/components/AppView.js.map +1 -0
  7. package/lib/commonjs/components/BaseDatesScrollView.js +13 -7
  8. package/lib/commonjs/components/BaseDatesScrollView.js.map +1 -1
  9. package/lib/commonjs/components/BaseErrorBox.js +92 -0
  10. package/lib/commonjs/components/BaseErrorBox.js.map +1 -0
  11. package/lib/commonjs/components/BaseErrorScreen.js +41 -0
  12. package/lib/commonjs/components/BaseErrorScreen.js.map +1 -0
  13. package/lib/commonjs/components/BaseStickyFooter.js +19 -0
  14. package/lib/commonjs/components/BaseStickyFooter.js.map +1 -0
  15. package/lib/commonjs/components/DateSelector.js +10 -5
  16. package/lib/commonjs/components/DateSelector.js.map +1 -1
  17. package/lib/commonjs/components/DateTimeSelector.js +89 -48
  18. package/lib/commonjs/components/DateTimeSelector.js.map +1 -1
  19. package/lib/commonjs/components/NetworkBanner.js +73 -0
  20. package/lib/commonjs/components/NetworkBanner.js.map +1 -0
  21. package/lib/commonjs/components/index.js +21 -0
  22. package/lib/commonjs/components/index.js.map +1 -1
  23. package/lib/commonjs/components/svgs/Warning.js +15 -0
  24. package/lib/commonjs/components/svgs/Warning.js.map +1 -0
  25. package/lib/commonjs/hooks/index.js +22 -13
  26. package/lib/commonjs/hooks/index.js.map +1 -1
  27. package/lib/commonjs/hooks/useInternetConnectionStatus.js +24 -14
  28. package/lib/commonjs/hooks/useInternetConnectionStatus.js.map +1 -1
  29. package/lib/commonjs/hooks/useTimezonedDate.js +73 -0
  30. package/lib/commonjs/hooks/useTimezonedDate.js.map +1 -0
  31. package/lib/commonjs/index.js +36 -0
  32. package/lib/commonjs/index.js.map +1 -1
  33. package/lib/commonjs/test-setup.js +11 -0
  34. package/lib/commonjs/test-setup.js.map +1 -0
  35. package/lib/commonjs/utils/filters.js +52 -0
  36. package/lib/commonjs/utils/filters.js.map +1 -0
  37. package/lib/commonjs/utils/index.js +11 -0
  38. package/lib/commonjs/utils/index.js.map +1 -1
  39. package/lib/module/UIKitProvider.js +34 -0
  40. package/lib/module/UIKitProvider.js.map +1 -0
  41. package/lib/module/assets/illustrations/warning.svg +1 -0
  42. package/lib/module/components/AppView.js +59 -0
  43. package/lib/module/components/AppView.js.map +1 -0
  44. package/lib/module/components/BaseDatesScrollView.js +15 -9
  45. package/lib/module/components/BaseDatesScrollView.js.map +1 -1
  46. package/lib/module/components/BaseErrorBox.js +87 -0
  47. package/lib/module/components/BaseErrorBox.js.map +1 -0
  48. package/lib/module/components/BaseErrorScreen.js +36 -0
  49. package/lib/module/components/BaseErrorScreen.js.map +1 -0
  50. package/lib/module/components/BaseStickyFooter.js +15 -0
  51. package/lib/module/components/BaseStickyFooter.js.map +1 -0
  52. package/lib/module/components/DateSelector.js +11 -6
  53. package/lib/module/components/DateSelector.js.map +1 -1
  54. package/lib/module/components/DateTimeSelector.js +90 -48
  55. package/lib/module/components/DateTimeSelector.js.map +1 -1
  56. package/lib/module/components/NetworkBanner.js +67 -0
  57. package/lib/module/components/NetworkBanner.js.map +1 -0
  58. package/lib/module/components/index.js +3 -0
  59. package/lib/module/components/index.js.map +1 -1
  60. package/lib/module/components/svgs/Warning.js +10 -0
  61. package/lib/module/components/svgs/Warning.js.map +1 -0
  62. package/lib/module/hooks/index.js +2 -1
  63. package/lib/module/hooks/index.js.map +1 -1
  64. package/lib/module/hooks/useInternetConnectionStatus.js +23 -13
  65. package/lib/module/hooks/useInternetConnectionStatus.js.map +1 -1
  66. package/lib/module/hooks/useTimezonedDate.js +70 -0
  67. package/lib/module/hooks/useTimezonedDate.js.map +1 -0
  68. package/lib/module/index.js +3 -0
  69. package/lib/module/index.js.map +1 -1
  70. package/lib/module/test-setup.js +10 -0
  71. package/lib/module/test-setup.js.map +1 -0
  72. package/lib/module/utils/filters.js +48 -0
  73. package/lib/module/utils/filters.js.map +1 -0
  74. package/lib/module/utils/index.js +1 -0
  75. package/lib/module/utils/index.js.map +1 -1
  76. package/lib/typescript/commonjs/UIKitProvider.d.ts +15 -0
  77. package/lib/typescript/commonjs/UIKitProvider.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/__tests__/smoke.test.d.ts +2 -0
  79. package/lib/typescript/commonjs/__tests__/smoke.test.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/components/AppView.d.ts +19 -0
  81. package/lib/typescript/commonjs/components/AppView.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/components/BaseDatesScrollView.d.ts.map +1 -1
  83. package/lib/typescript/commonjs/components/BaseErrorBox.d.ts +14 -0
  84. package/lib/typescript/commonjs/components/BaseErrorBox.d.ts.map +1 -0
  85. package/lib/typescript/commonjs/components/BaseErrorScreen.d.ts +13 -0
  86. package/lib/typescript/commonjs/components/BaseErrorScreen.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/components/BaseStickyFooter.d.ts +11 -0
  88. package/lib/typescript/commonjs/components/BaseStickyFooter.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/components/DateSelector.d.ts.map +1 -1
  90. package/lib/typescript/commonjs/components/DateTimeSelector.d.ts +10 -4
  91. package/lib/typescript/commonjs/components/DateTimeSelector.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/components/FormikDateTimeSelector.d.ts +1 -1
  93. package/lib/typescript/commonjs/components/FormikDateTimeSelectorBottomSheet.d.ts +1 -1
  94. package/lib/typescript/commonjs/components/NetworkBanner.d.ts +10 -0
  95. package/lib/typescript/commonjs/components/NetworkBanner.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/components/index.d.ts +3 -0
  97. package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/components/svgs/Warning.d.ts +6 -0
  99. package/lib/typescript/commonjs/components/svgs/Warning.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/hooks/index.d.ts +2 -1
  101. package/lib/typescript/commonjs/hooks/index.d.ts.map +1 -1
  102. package/lib/typescript/commonjs/hooks/useInternetConnectionStatus.d.ts +4 -4
  103. package/lib/typescript/commonjs/hooks/useInternetConnectionStatus.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/hooks/useTimezonedDate.d.ts +59 -0
  105. package/lib/typescript/commonjs/hooks/useTimezonedDate.d.ts.map +1 -0
  106. package/lib/typescript/commonjs/index.d.ts +3 -0
  107. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/test-setup.d.ts +2 -0
  109. package/lib/typescript/commonjs/test-setup.d.ts.map +1 -0
  110. package/lib/typescript/commonjs/utils/filters.d.ts +4 -0
  111. package/lib/typescript/commonjs/utils/filters.d.ts.map +1 -0
  112. package/lib/typescript/commonjs/utils/index.d.ts +1 -0
  113. package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
  114. package/lib/typescript/module/UIKitProvider.d.ts +15 -0
  115. package/lib/typescript/module/UIKitProvider.d.ts.map +1 -0
  116. package/lib/typescript/module/__tests__/smoke.test.d.ts +2 -0
  117. package/lib/typescript/module/__tests__/smoke.test.d.ts.map +1 -0
  118. package/lib/typescript/module/components/AppView.d.ts +19 -0
  119. package/lib/typescript/module/components/AppView.d.ts.map +1 -0
  120. package/lib/typescript/module/components/BaseDatesScrollView.d.ts.map +1 -1
  121. package/lib/typescript/module/components/BaseErrorBox.d.ts +14 -0
  122. package/lib/typescript/module/components/BaseErrorBox.d.ts.map +1 -0
  123. package/lib/typescript/module/components/BaseErrorScreen.d.ts +13 -0
  124. package/lib/typescript/module/components/BaseErrorScreen.d.ts.map +1 -0
  125. package/lib/typescript/module/components/BaseStickyFooter.d.ts +11 -0
  126. package/lib/typescript/module/components/BaseStickyFooter.d.ts.map +1 -0
  127. package/lib/typescript/module/components/DateSelector.d.ts.map +1 -1
  128. package/lib/typescript/module/components/DateTimeSelector.d.ts +10 -4
  129. package/lib/typescript/module/components/DateTimeSelector.d.ts.map +1 -1
  130. package/lib/typescript/module/components/FormikDateTimeSelector.d.ts +1 -1
  131. package/lib/typescript/module/components/FormikDateTimeSelectorBottomSheet.d.ts +1 -1
  132. package/lib/typescript/module/components/NetworkBanner.d.ts +10 -0
  133. package/lib/typescript/module/components/NetworkBanner.d.ts.map +1 -0
  134. package/lib/typescript/module/components/index.d.ts +3 -0
  135. package/lib/typescript/module/components/index.d.ts.map +1 -1
  136. package/lib/typescript/module/components/svgs/Warning.d.ts +6 -0
  137. package/lib/typescript/module/components/svgs/Warning.d.ts.map +1 -0
  138. package/lib/typescript/module/hooks/index.d.ts +2 -1
  139. package/lib/typescript/module/hooks/index.d.ts.map +1 -1
  140. package/lib/typescript/module/hooks/useInternetConnectionStatus.d.ts +4 -4
  141. package/lib/typescript/module/hooks/useInternetConnectionStatus.d.ts.map +1 -1
  142. package/lib/typescript/module/hooks/useTimezonedDate.d.ts +59 -0
  143. package/lib/typescript/module/hooks/useTimezonedDate.d.ts.map +1 -0
  144. package/lib/typescript/module/index.d.ts +3 -0
  145. package/lib/typescript/module/index.d.ts.map +1 -1
  146. package/lib/typescript/module/test-setup.d.ts +2 -0
  147. package/lib/typescript/module/test-setup.d.ts.map +1 -0
  148. package/lib/typescript/module/utils/filters.d.ts +4 -0
  149. package/lib/typescript/module/utils/filters.d.ts.map +1 -0
  150. package/lib/typescript/module/utils/index.d.ts +1 -0
  151. package/lib/typescript/module/utils/index.d.ts.map +1 -1
  152. package/package.json +19 -9
  153. package/src/components/BaseAlert.tsx +0 -181
  154. package/src/components/BaseBadge.tsx +0 -192
  155. package/src/components/BaseBottomSheetModal.tsx +0 -50
  156. package/src/components/BaseButton.tsx +0 -317
  157. package/src/components/BaseConfirmationModal.tsx +0 -66
  158. package/src/components/BaseDateInput.tsx +0 -153
  159. package/src/components/BaseDatesScrollView.tsx +0 -123
  160. package/src/components/BaseHorizontalTabs.tsx +0 -225
  161. package/src/components/BaseIcon.tsx +0 -41
  162. package/src/components/BaseIconBox.tsx +0 -75
  163. package/src/components/BaseRadioGroup.tsx +0 -75
  164. package/src/components/BaseSelect.tsx +0 -170
  165. package/src/components/BaseSelectionItem.tsx +0 -85
  166. package/src/components/BaseSpinner.tsx +0 -21
  167. package/src/components/BaseStackedList.tsx +0 -146
  168. package/src/components/BaseSwitch.tsx +0 -48
  169. package/src/components/BaseText.tsx +0 -34
  170. package/src/components/CameraImageInput.tsx +0 -610
  171. package/src/components/CameraWrapperModal.tsx +0 -309
  172. package/src/components/DateSelector.tsx +0 -91
  173. package/src/components/DateTimeSelector.tsx +0 -267
  174. package/src/components/FormikCameraImageInput.tsx +0 -39
  175. package/src/components/FormikDateInput.tsx +0 -53
  176. package/src/components/FormikDateSelector.tsx +0 -36
  177. package/src/components/FormikDateTimeSelector.tsx +0 -49
  178. package/src/components/FormikDateTimeSelectorBottomSheet.tsx +0 -129
  179. package/src/components/FormikRadioGroup.tsx +0 -35
  180. package/src/components/FormikSelect.tsx +0 -49
  181. package/src/components/ImagePickerBottomSheet.tsx +0 -109
  182. package/src/components/PhotoPickerModal.tsx +0 -116
  183. package/src/components/PressableOpacity.tsx +0 -88
  184. package/src/components/Toasts.tsx +0 -200
  185. package/src/components/index.ts +0 -30
  186. package/src/components/svgs/Camera.tsx +0 -14
  187. package/src/hooks/index.ts +0 -3
  188. package/src/hooks/useBreakpoints.ts +0 -20
  189. package/src/hooks/useInternetConnectionStatus.ts +0 -221
  190. package/src/hooks/useIsAboveBreakpoint.ts +0 -8
  191. package/src/utils/clabe.ts +0 -31
  192. package/src/utils/date.ts +0 -1
  193. package/src/utils/fileDirectoryUtils.ts +0 -12
  194. package/src/utils/fonts.ts +0 -118
  195. package/src/utils/index.ts +0 -3
  196. package/src/utils/mx-banks.json +0 -492
  197. package/src/utils/mx-banks.ts +0 -9
  198. package/src/utils/timeConstants.ts +0 -19
@@ -1,309 +0,0 @@
1
- import { useAppState } from '@react-native-community/hooks';
2
- import { useIsFocused } from '@react-navigation/native';
3
- import { captureException } from '@sentry/react-native';
4
- import { useMutation } from '@tanstack/react-query';
5
- import clsx from 'clsx';
6
- import { styled } from 'nativewind';
7
- import {
8
- ComponentProps, useRef, useState, useCallback,
9
- } from 'react';
10
- import toast from 'react-hot-toast/headless';
11
- import { Linking } from 'react-native';
12
- import {
13
- ArrowLongLeftIcon, ArrowPathIcon, ArrowUturnLeftIcon, CheckIcon,
14
- } from 'react-native-heroicons/outline';
15
- import {
16
- PhotoFile,
17
- Camera as RNVisionCamera,
18
- useCameraPermission,
19
- useCameraDevice,
20
- useCameraFormat,
21
- FormatFilter,
22
- CameraPosition,
23
- } from 'react-native-vision-camera';
24
-
25
- import {
26
- View, Modal, Pressable, Image,
27
- } from '../hoc-components';
28
- import BaseButton from './BaseButton';
29
- import BaseIcon from './BaseIcon';
30
- import BaseText from './BaseText';
31
- import PressableOpacity from './PressableOpacity';
32
- import { useIsAboveBreakpoint } from '../hooks/useIsAboveBreakpoint';
33
- import { ensureDirExists } from '../utils/fileDirectoryUtils';
34
- import CameraSvg from './svgs/Camera';
35
- import Toasts from './Toasts';
36
-
37
- interface PermissionCardProps {
38
- onPermissionRequestPress: () => void;
39
- }
40
-
41
- export type CameraWrapperModalImage = PhotoFile & { uri: string };
42
-
43
- function PermissionCard({ onPermissionRequestPress }: PermissionCardProps) {
44
- const largePhone = useIsAboveBreakpoint('xs');
45
-
46
- return (
47
- <View className={clsx(
48
- 'w-full flex-col items-center rounded-lg bg-white p-4',
49
- largePhone ? 'mt-10 space-y-10' : 'space-y-4',
50
- )}
51
- >
52
- <BaseText className={clsx('text-center font-semibold', largePhone && 'text-xl')}>
53
- Necesitamos permiso para acceder a la camara
54
- </BaseText>
55
- <CameraSvg
56
- width="100%"
57
- height={largePhone ? 200 : 100}
58
- />
59
- <BaseButton
60
- className="w-full"
61
- size={largePhone ? 'md' : 'xs'}
62
- text="Permitir"
63
- onPress={onPermissionRequestPress}
64
- />
65
- </View>
66
- );
67
- }
68
-
69
- interface CameraPreviewProps {
70
- onCapture: (photoFile: CameraWrapperModalImage) => void;
71
- previewOverlay: JSX.Element | undefined;
72
- filters: FormatFilter[];
73
- allowDeviceSwitching: boolean;
74
- isActive: boolean;
75
- initialDevice: CameraPosition;
76
- pathToSave?: string;
77
- }
78
-
79
- function CameraPreview({
80
- onCapture,
81
- previewOverlay,
82
- filters,
83
- isActive,
84
- allowDeviceSwitching,
85
- initialDevice,
86
- pathToSave,
87
- }: CameraPreviewProps) {
88
- const cameraRef = useRef<RNVisionCamera>(null);
89
- const [selectedDevice, setSelectedDevice] = useState<CameraPosition>(initialDevice);
90
- const device = useCameraDevice(selectedDevice);
91
- const format = useCameraFormat(device, filters);
92
-
93
- const { mutate } = useMutation<PhotoFile, Error, void>({
94
- mutationFn: async () => {
95
- if (cameraRef.current) {
96
- if (pathToSave) await ensureDirExists(pathToSave);
97
-
98
- const file = await cameraRef.current.takePhoto({ path: pathToSave?.replace('file://', '') ?? undefined });
99
-
100
- return file;
101
- }
102
-
103
- return Promise.reject(new Error('Camera ref is not defined'));
104
- },
105
- networkMode: 'always',
106
- onSuccess: (photoFile) => onCapture({ ...photoFile, uri: `file://${photoFile.path}` }),
107
- onError: (error) => {
108
- captureException(error);
109
- toast.error('Ocurrió un error al tomar la foto');
110
- },
111
- });
112
-
113
- return (
114
- <View className="flex h-full w-full flex-col">
115
- {device ? (
116
- <View className="relative h-full w-full flex-1 overflow-hidden rounded-xl border-2">
117
- <RNVisionCamera
118
- style={{ flex: 1, width: '100%', height: '100%' }}
119
- ref={cameraRef}
120
- device={device}
121
- format={format}
122
- isActive={isActive}
123
- photo
124
- />
125
- {previewOverlay}
126
- {allowDeviceSwitching && (
127
- <PressableOpacity
128
- onPress={() => setSelectedDevice(selectedDevice === 'back' ? 'front' : 'back')}
129
- className="absolute bottom-8 right-8 flex h-12 w-12 items-center justify-center rounded-full bg-secondary"
130
- >
131
- <BaseIcon
132
- icon={ArrowPathIcon}
133
- className="h-full w-full"
134
- color="utility-gray-200"
135
- />
136
- </PressableOpacity>
137
- )}
138
- </View>
139
- ) : (
140
- <View className="flex h-full w-full items-center justify-center bg-utility-gray-200">
141
- <BaseText className="text-secondary">
142
- No fue posible acceder a la camara
143
- </BaseText>
144
- </View>
145
- )}
146
- <PressableOpacity
147
- onPress={() => mutate()}
148
- className="my-10 h-20 w-20 self-center rounded-full border-4 border-white bg-black p-1"
149
- >
150
- <View
151
- className="h-full w-full rounded-full bg-white"
152
- />
153
- </PressableOpacity>
154
- </View>
155
- );
156
- }
157
-
158
- interface PhotoFilePreviewProps {
159
- photoFile: CameraWrapperModalImage;
160
- onConfirm: () => void;
161
- onCancel: () => void;
162
- }
163
-
164
- function PhotoFilePreview({ photoFile, onConfirm, onCancel }: PhotoFilePreviewProps) {
165
- return (
166
- <View className="flex h-full w-full flex-col items-center pb-10">
167
- <View className="w-full flex-1 overflow-hidden rounded-xl">
168
- <Image
169
- style={{ width: 'auto', height: '100%' }}
170
- source={{ uri: photoFile.uri }}
171
- resizeMode="cover"
172
- />
173
- </View>
174
- <View className="mt-12 flex flex-row items-center space-x-16">
175
- <Pressable
176
- onPress={onCancel}
177
- >
178
- <BaseIcon
179
- icon={ArrowUturnLeftIcon}
180
- size={64}
181
- color="fg-error-primary"
182
- />
183
- </Pressable>
184
- <Pressable
185
- onPress={onConfirm}
186
- className="self-end"
187
- >
188
- <BaseIcon
189
- icon={CheckIcon}
190
- size={64}
191
- color="fg-success-primary"
192
- />
193
- </Pressable>
194
- </View>
195
- </View>
196
- );
197
- }
198
-
199
- interface Props extends ComponentProps<typeof Modal> {
200
- onCapture: (photoFile: CameraWrapperModalImage) => void;
201
- onClose: () => void;
202
- filters?: FormatFilter[];
203
- previewOverlay?: JSX.Element;
204
- allowDeviceSwitching?: boolean;
205
- initialDevice?: CameraPosition;
206
- pathToSave?: string;
207
- }
208
-
209
- function CameraWrapperModal({
210
- onCapture,
211
- onClose,
212
- filters = [{ photoResolution: { width: 720, height: 1280 } }],
213
- previewOverlay = undefined,
214
- allowDeviceSwitching = true,
215
- initialDevice = 'back',
216
- pathToSave = undefined,
217
- ...modalProps
218
- }: Props) {
219
- const [photoFile, setPhotoFile] = useState<CameraWrapperModalImage | null>(null);
220
- const [permissionRequested, setPermissionRequested] = useState(false);
221
-
222
- const isFocused = useIsFocused();
223
- const appState = useAppState();
224
- const isActive = isFocused && appState === 'active';
225
-
226
- const { hasPermission, requestPermission } = useCameraPermission();
227
-
228
- const handlePermissionRequestPress = useCallback(() => {
229
- if (!permissionRequested) {
230
- setPermissionRequested(true);
231
- requestPermission();
232
- } else {
233
- Linking.openSettings();
234
- }
235
- }, [permissionRequested, requestPermission]);
236
-
237
- const handleCaptureConfirm = useCallback(() => {
238
- if (photoFile) {
239
- onCapture({
240
- ...photoFile,
241
- uri: `file://${photoFile.path}`,
242
- });
243
- setPhotoFile(null);
244
- }
245
- }, [onCapture, photoFile]);
246
-
247
- const removePhotoFile = useCallback(() => {
248
- setPhotoFile(null);
249
- }, [setPhotoFile]);
250
-
251
- let content;
252
-
253
- if (!hasPermission) {
254
- content = (
255
- <PermissionCard
256
- onPermissionRequestPress={handlePermissionRequestPress}
257
- />
258
- );
259
- } else if (photoFile) {
260
- content = (
261
- <PhotoFilePreview
262
- photoFile={photoFile}
263
- onCancel={removePhotoFile}
264
- onConfirm={handleCaptureConfirm}
265
- />
266
- );
267
- } else {
268
- content = (
269
- <CameraPreview
270
- isActive={isActive}
271
- filters={filters}
272
- onCapture={setPhotoFile}
273
- previewOverlay={previewOverlay}
274
- allowDeviceSwitching={allowDeviceSwitching}
275
- initialDevice={initialDevice}
276
- pathToSave={pathToSave}
277
- />
278
- );
279
- }
280
-
281
- return (
282
- <Modal
283
- animationType="slide"
284
- statusBarTranslucent
285
- {...modalProps}
286
- >
287
- <Toasts />
288
- <View className="flex h-full w-full flex-col items-center bg-black px-4 pt-12">
289
- <View className="self-start py-4">
290
- <Pressable
291
- hitSlop={10}
292
- onPress={onClose}
293
- >
294
- <BaseIcon
295
- icon={ArrowLongLeftIcon}
296
- color="fg-brand-primary"
297
- size={32}
298
- />
299
- </Pressable>
300
- </View>
301
- <View className="mb-4 w-full flex-1">
302
- {content}
303
- </View>
304
- </View>
305
- </Modal>
306
- );
307
- }
308
-
309
- export default styled(CameraWrapperModal);
@@ -1,91 +0,0 @@
1
- import {
2
- eachDayOfInterval,
3
- isBefore,
4
- isAfter,
5
- getDay,
6
- addDays,
7
- startOfDay,
8
- } from 'date-fns';
9
- import { styled } from 'nativewind';
10
- import React, { useMemo, useCallback } from 'react';
11
- import { ViewProps } from 'react-native';
12
-
13
- import { View } from '../hoc-components';
14
- import BaseDatesScrollView from './BaseDatesScrollView';
15
- import BaseText from './BaseText';
16
-
17
- export interface DateSelectorProps extends ViewProps {
18
- value: Date | undefined;
19
- onChange: (date?: Date) => void;
20
- label?: string;
21
- description?: string;
22
- minDate?: Date;
23
- maxDate?: Date;
24
- disabledWeekDays?: number[];
25
- disabled?: boolean;
26
- error?: string;
27
- allowPastDates?: boolean;
28
- }
29
-
30
- function DateSelector({
31
- value,
32
- label,
33
- description,
34
- onChange,
35
- minDate,
36
- maxDate,
37
- disabledWeekDays = [],
38
- disabled = false,
39
- error,
40
- allowPastDates = false,
41
- ...props
42
- }: DateSelectorProps) {
43
- const minDateStartOfDay = useMemo(() => startOfDay(minDate || new Date()), [minDate]);
44
- const maxDateEndOfDay = useMemo(() => (maxDate ? startOfDay(maxDate) : null), [maxDate]);
45
-
46
- const dateRange = useMemo(() => {
47
- const startDate = minDateStartOfDay;
48
- const endDate = maxDateEndOfDay || addDays(startDate, 7);
49
-
50
- return eachDayOfInterval({ start: startDate, end: endDate });
51
- }, [minDateStartOfDay, maxDateEndOfDay]);
52
-
53
- const isDayDisabled = useCallback((day: Date) => {
54
- if (disabled) return true;
55
- if (minDateStartOfDay && isBefore(day, minDateStartOfDay)) return true;
56
- if (maxDateEndOfDay && isAfter(day, maxDateEndOfDay)) return true;
57
- if (disabledWeekDays.includes(getDay(day))) return true;
58
- if (!allowPastDates && isBefore(day, startOfDay(new Date()))) return true;
59
- return false;
60
- }, [disabled, minDateStartOfDay, maxDateEndOfDay, disabledWeekDays, allowPastDates]);
61
-
62
- const handleDayPress = useCallback((day: Date) => {
63
- if (isDayDisabled(day)) return;
64
-
65
- onChange?.(day);
66
- }, [isDayDisabled, onChange]);
67
-
68
- return (
69
- <View
70
- className="flex flex-col"
71
- {...props}
72
- >
73
- {label && <BaseText className="mb-2 font-semibold text-secondary">{label}</BaseText>}
74
- {description && <BaseText className="mb-2 text-tertiary">{description}</BaseText>}
75
- <BaseDatesScrollView
76
- dateRange={dateRange}
77
- selectedDate={value}
78
- isDayDisabled={isDayDisabled}
79
- onDayPress={handleDayPress}
80
- />
81
- {error && (
82
- <BaseText className="mt-2 text-error-primary">
83
- {error}
84
- </BaseText>
85
- )}
86
- </View>
87
- );
88
- }
89
-
90
- export default styled(DateSelector);
91
-
@@ -1,267 +0,0 @@
1
- import {
2
- format,
3
- eachDayOfInterval,
4
- isSameDay,
5
- isBefore,
6
- isAfter,
7
- getDay,
8
- addDays,
9
- startOfDay,
10
- isToday,
11
- } from 'date-fns';
12
- import { styled } from 'nativewind';
13
- import React, { useMemo, useCallback, useState } from 'react';
14
- import { ViewProps } from 'react-native';
15
-
16
- import { View, GestureScrollView, LinearGradient } from '../hoc-components';
17
- import BaseDatesScrollView from './BaseDatesScrollView';
18
- import BaseRadioGroup, { RadioOption } from './BaseRadioGroup';
19
- import BaseText from './BaseText';
20
-
21
- interface TimeSlot {
22
- hour: number;
23
- minute: number;
24
- endHour: number;
25
- endMinute: number;
26
- label: string;
27
- }
28
-
29
- interface TimeSlotsProps {
30
- timeSlots: TimeSlot[];
31
- selectedTime: { hour: number; minute: number } | null;
32
- handleTimePress: (time: { hour: number; minute: number }) => void;
33
- disabled: boolean;
34
- timeLabel?: string;
35
- }
36
-
37
- function TimeSlots({
38
- timeSlots,
39
- selectedTime,
40
- handleTimePress,
41
- disabled,
42
- timeLabel,
43
- }: TimeSlotsProps) {
44
- const radioOptions: RadioOption[] = timeSlots.map((slot) => ({
45
- label: slot.label,
46
- value: `${slot.hour}-${slot.minute}`,
47
- }));
48
-
49
- const selectedValue = selectedTime ? `${selectedTime.hour}-${selectedTime.minute}` : undefined;
50
-
51
- const handleRadioChange = (value: unknown) => {
52
- const [hour, minute] = (value as string).split('-').map(Number);
53
- handleTimePress({ hour, minute });
54
- };
55
-
56
- return (
57
- <View className="mt-4 flex-1">
58
- {timeLabel && (
59
- <BaseText className="mb-3 text-sm font-semibold text-secondary">
60
- {timeLabel}
61
- </BaseText>
62
- )}
63
- <View className="relative flex-1">
64
- <GestureScrollView
65
- style={{ flex: 1, minHeight: 200 }}
66
- showsVerticalScrollIndicator={false}
67
- nestedScrollEnabled
68
- >
69
- <BaseRadioGroup
70
- options={radioOptions}
71
- value={selectedValue}
72
- onChange={handleRadioChange}
73
- disabled={disabled}
74
- />
75
- <View className="h-20" />
76
- </GestureScrollView>
77
- {radioOptions.length > 3 && (
78
- <LinearGradient
79
- colors={[
80
- 'rgba(255, 255, 255, 0)',
81
- 'rgba(255, 255, 255, 1)',
82
- ]}
83
- start={{ x: 0, y: 0 }}
84
- end={{ x: 0, y: 1 }}
85
- className="absolute bottom-0 left-0 h-32 w-full"
86
- style={{ pointerEvents: 'none' }}
87
- />
88
- )}
89
- </View>
90
- </View>
91
- );
92
- }
93
-
94
- export interface DateTimeSelectorProps extends ViewProps {
95
- value: Date | undefined;
96
- onChange: (date?: Date) => void;
97
- minDate?: Date;
98
- maxDate?: Date;
99
- minHour?: number;
100
- maxHour?: number;
101
- timeSlotStepMinutes?: number;
102
- disabledWeekDays?: number[];
103
- disabledHours?: number[];
104
- dateLabel?: string;
105
- timeLabel?: string;
106
- description?: string;
107
- className?: string;
108
- disabled?: boolean;
109
- error?: string;
110
- allowPastDatetimes?: boolean;
111
- }
112
-
113
- function DateTimeSelector({
114
- value,
115
- onChange,
116
- minDate,
117
- maxDate,
118
- minHour = 0,
119
- maxHour = 23,
120
- timeSlotStepMinutes = 30,
121
- disabledWeekDays = [],
122
- disabledHours = [],
123
- dateLabel,
124
- timeLabel,
125
- description,
126
- disabled = false,
127
- error,
128
- allowPastDatetimes = false,
129
- ...props
130
- }: DateTimeSelectorProps) {
131
- const [selectedDate, setSelectedDate] = useState<Date | undefined>(value);
132
-
133
- const minDateStartOfDay = useMemo(() => startOfDay(minDate || new Date()), [minDate]);
134
- const maxDateEndOfDay = useMemo(() => (maxDate ? startOfDay(maxDate) : null), [maxDate]);
135
-
136
- const dateRange = useMemo(() => {
137
- const startDate = minDateStartOfDay;
138
- const endDate = maxDateEndOfDay || addDays(startDate, 7);
139
-
140
- return eachDayOfInterval({ start: startDate, end: endDate });
141
- }, [minDateStartOfDay, maxDateEndOfDay]);
142
-
143
- const getTimeSlotsForDate = useCallback((date: Date): TimeSlot[] => {
144
- const slots: TimeSlot[] = [];
145
- const now = new Date();
146
-
147
- for (let hour = minHour; hour <= maxHour; hour += 1) {
148
- if (disabledHours.includes(hour)) continue;
149
- if (!allowPastDatetimes && isToday(date) && hour < now.getHours()) continue;
150
-
151
- for (let minute = 0; minute < 60; minute += timeSlotStepMinutes) {
152
- if (
153
- !allowPastDatetimes
154
- && isToday(date)
155
- && hour === now.getHours()
156
- && minute <= now.getMinutes()
157
- ) continue;
158
-
159
- const endTime = new Date();
160
- endTime.setHours(hour, minute + timeSlotStepMinutes, 0, 0);
161
- const endHour = endTime.getHours();
162
- const endMinute = endTime.getMinutes();
163
-
164
- const startTime = new Date().setHours(hour, minute);
165
- const endTimeForLabel = new Date().setHours(endHour, endMinute);
166
- const startLabel = format(startTime, 'h:mm');
167
- const endLabel = format(endTimeForLabel, 'h:mm a');
168
- const hourLabel = `${startLabel} - ${endLabel}`;
169
-
170
- slots.push({
171
- hour, minute, endHour, endMinute, label: hourLabel,
172
- });
173
- }
174
- }
175
-
176
- return slots;
177
- }, [minHour, maxHour, timeSlotStepMinutes, disabledHours, allowPastDatetimes]);
178
-
179
- const timeSlots = useMemo<TimeSlot[]>(() => {
180
- if (!selectedDate) return [];
181
- return getTimeSlotsForDate(selectedDate);
182
- }, [selectedDate, getTimeSlotsForDate]);
183
-
184
- const isDayDisabled = useCallback((day: Date) => {
185
- if (disabled) return true;
186
- if (minDateStartOfDay && isBefore(day, minDateStartOfDay)) return true;
187
- if (maxDateEndOfDay && isAfter(day, maxDateEndOfDay)) return true;
188
- if (disabledWeekDays.includes(getDay(day))) return true;
189
- if (!allowPastDatetimes && isBefore(day, startOfDay(new Date()))) return true;
190
-
191
- // Check if there are available time slots for this day
192
- const availableSlots = getTimeSlotsForDate(day);
193
- if (availableSlots.length === 0) return true;
194
-
195
- return false;
196
- }, [
197
- disabled,
198
- minDateStartOfDay,
199
- maxDateEndOfDay,
200
- disabledWeekDays,
201
- allowPastDatetimes,
202
- getTimeSlotsForDate,
203
- ]);
204
-
205
- const handleDayPress = useCallback((day: Date) => {
206
- if (isDayDisabled(day)) return;
207
- setSelectedDate(day);
208
-
209
- if (value) {
210
- onChange(undefined);
211
- }
212
- }, [isDayDisabled, onChange, value]);
213
-
214
- const handleTimePress = useCallback((time: { hour: number; minute: number }) => {
215
- if (selectedDate) {
216
- const newDate = new Date(selectedDate);
217
- newDate.setHours(time.hour, time.minute, 0, 0);
218
- onChange(newDate);
219
- }
220
- }, [selectedDate, onChange]);
221
-
222
- const selectedTime = useMemo(() => {
223
- if (!value || !selectedDate || !isSameDay(value, selectedDate)) return null;
224
-
225
- return { hour: value.getHours(), minute: value.getMinutes() };
226
- }, [value, selectedDate]);
227
-
228
- return (
229
- <View
230
- className="flex flex-1 flex-col"
231
- {...props}
232
- >
233
- {dateLabel && (
234
- <BaseText className="mb-2 font-semibold text-secondary">
235
- {dateLabel}
236
- </BaseText>
237
- )}
238
- {description && (
239
- <BaseText className="mb-4 text-tertiary">
240
- {description}
241
- </BaseText>
242
- )}
243
- <BaseDatesScrollView
244
- dateRange={dateRange}
245
- selectedDate={selectedDate}
246
- isDayDisabled={isDayDisabled}
247
- onDayPress={handleDayPress}
248
- />
249
- {selectedDate && (
250
- <TimeSlots
251
- timeSlots={timeSlots}
252
- selectedTime={selectedTime}
253
- handleTimePress={handleTimePress}
254
- disabled={disabled}
255
- timeLabel={timeLabel}
256
- />
257
- )}
258
- {error && (
259
- <BaseText className="mt-2 text-error-primary">
260
- {error}
261
- </BaseText>
262
- )}
263
- </View>
264
- );
265
- }
266
-
267
- export default styled(DateTimeSelector);
@@ -1,39 +0,0 @@
1
- import { ErrorMessage, useField } from 'formik';
2
- import { styled } from 'nativewind';
3
- import React from 'react';
4
- import { ViewProps } from 'react-native';
5
-
6
- import BaseText from './BaseText';
7
- import CameraImageInput, { CameraImageInputProps } from './CameraImageInput';
8
-
9
- interface FormikCameraImageInputProps extends Omit<CameraImageInputProps, 'value' | 'onValueChange' | 'hasError'>, ViewProps {
10
- name: string;
11
- }
12
-
13
- function FormikCameraImageInput({
14
- name,
15
- ...props
16
- }: FormikCameraImageInputProps) {
17
- const [field, meta, helpers] = useField(name);
18
-
19
- const hasError = !!(meta.error && meta.touched);
20
-
21
- return (
22
- <>
23
- <CameraImageInput
24
- value={field.value}
25
- onValueChange={helpers.setValue}
26
- hasError={hasError}
27
- showImages
28
- {...props}
29
- />
30
- {hasError && (
31
- <ErrorMessage name={name}>
32
- {(msg) => <BaseText className="mt-1 text-sm text-error-primary">{msg}</BaseText>}
33
- </ErrorMessage>
34
- )}
35
- </>
36
- );
37
- }
38
-
39
- export default styled(FormikCameraImageInput);