nx-react-native-cli 1.0.7 → 1.0.8

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 (113) hide show
  1. package/README.md +1 -1
  2. package/contents/.eslintrc.json +293 -0
  3. package/contents/.husky/pre-commit +5 -0
  4. package/contents/.husky/pre-push +15 -0
  5. package/contents/.nvmrc +1 -0
  6. package/contents/.prettierignore +8 -0
  7. package/contents/.prettierrc +13 -0
  8. package/contents/.ruby-version +1 -0
  9. package/contents/.vscode/extensions.json +10 -0
  10. package/contents/.vscode/settings.json +18 -0
  11. package/contents/apps/mobile/.env.template +3 -0
  12. package/contents/apps/mobile/.eslintrc.json +34 -0
  13. package/contents/apps/mobile/Gemfile +11 -0
  14. package/contents/apps/mobile/android/app/build.gradle +164 -0
  15. package/contents/apps/mobile/android/app/src/dev/res/values/strings.xml +3 -0
  16. package/contents/apps/mobile/android/app/src/production/res/values/strings.xml +3 -0
  17. package/contents/apps/mobile/android/build.gradle +34 -0
  18. package/contents/apps/mobile/babel.config.json +14 -0
  19. package/contents/apps/mobile/fastlane/.env.template +24 -0
  20. package/contents/apps/mobile/fastlane/Fastfile +303 -0
  21. package/contents/apps/mobile/fastlane/Matchfile +5 -0
  22. package/contents/apps/mobile/fastlane/Pluginfile +6 -0
  23. package/contents/apps/mobile/fastlane/README.md +65 -0
  24. package/contents/apps/mobile/package.json +77 -0
  25. package/contents/apps/mobile/project.json +102 -0
  26. package/contents/apps/mobile/src/app/index.tsx +68 -0
  27. package/contents/apps/mobile/src/components/atoms/BottomSheet/bottom-sheet.component.tsx +145 -0
  28. package/contents/apps/mobile/src/components/atoms/BottomSheet/index.ts +1 -0
  29. package/contents/apps/mobile/src/components/atoms/Button/button.component.tsx +55 -0
  30. package/contents/apps/mobile/src/components/atoms/Button/index.ts +2 -0
  31. package/contents/apps/mobile/src/components/atoms/Button/outlined-button.component.tsx +59 -0
  32. package/contents/apps/mobile/src/components/atoms/Divider/divider-component.tsx +13 -0
  33. package/contents/apps/mobile/src/components/atoms/Divider/index.ts +1 -0
  34. package/contents/apps/mobile/src/components/atoms/InputLayout/index.ts +1 -0
  35. package/contents/apps/mobile/src/components/atoms/InputLayout/input-layout.component.tsx +34 -0
  36. package/contents/apps/mobile/src/components/atoms/ListLoadingItem/index.ts +1 -0
  37. package/contents/apps/mobile/src/components/atoms/ListLoadingItem/list-loading-item.component.tsx +56 -0
  38. package/contents/apps/mobile/src/components/atoms/Modal/index.ts +1 -0
  39. package/contents/apps/mobile/src/components/atoms/Modal/modal.component.tsx +58 -0
  40. package/contents/apps/mobile/src/components/atoms/ScreenLoader/index.ts +1 -0
  41. package/contents/apps/mobile/src/components/atoms/ScreenLoader/screen-loader.component.tsx +17 -0
  42. package/contents/apps/mobile/src/components/atoms/Skeleton/index.ts +1 -0
  43. package/contents/apps/mobile/src/components/atoms/Skeleton/skeleton.component.tsx +42 -0
  44. package/contents/apps/mobile/src/components/atoms/Text/index.ts +1 -0
  45. package/contents/apps/mobile/src/components/atoms/Text/text.component.tsx +23 -0
  46. package/contents/apps/mobile/src/components/atoms/TextInput/constants.ts +43 -0
  47. package/contents/apps/mobile/src/components/atoms/TextInput/index.ts +2 -0
  48. package/contents/apps/mobile/src/components/atoms/TextInput/text-input.component.tsx +137 -0
  49. package/contents/apps/mobile/src/components/atoms/index.ts +10 -0
  50. package/contents/apps/mobile/src/components/index.ts +3 -0
  51. package/contents/apps/mobile/src/components/molecules/BackButton/back-button.component.tsx +58 -0
  52. package/contents/apps/mobile/src/components/molecules/BackButton/index.ts +1 -0
  53. package/contents/apps/mobile/src/components/molecules/BottomActionsContainer/BottomActionsContainer.component.tsx +28 -0
  54. package/contents/apps/mobile/src/components/molecules/BottomActionsContainer/index.ts +1 -0
  55. package/contents/apps/mobile/src/components/molecules/ScreenContainer/index.ts +1 -0
  56. package/contents/apps/mobile/src/components/molecules/ScreenContainer/screen-container.component.tsx +100 -0
  57. package/contents/apps/mobile/src/components/molecules/ScreenHeader/index.ts +1 -0
  58. package/contents/apps/mobile/src/components/molecules/ScreenHeader/screen-header.component.tsx +71 -0
  59. package/contents/apps/mobile/src/components/molecules/StorageManager/StorageManager.component.tsx +18 -0
  60. package/contents/apps/mobile/src/components/molecules/StorageManager/index.ts +1 -0
  61. package/contents/apps/mobile/src/components/molecules/index.ts +5 -0
  62. package/contents/apps/mobile/src/components/organisms/index.ts +1 -0
  63. package/contents/apps/mobile/src/config/index.ts +13 -0
  64. package/contents/apps/mobile/src/dimens/index.ts +1 -0
  65. package/contents/apps/mobile/src/env.d.ts +17 -0
  66. package/contents/apps/mobile/src/hooks/index.ts +9 -0
  67. package/contents/apps/mobile/src/hooks/useAppState.hook.tsx +20 -0
  68. package/contents/apps/mobile/src/hooks/useApplicationDimensions.hook.tsx +10 -0
  69. package/contents/apps/mobile/src/hooks/useDebounce.hook.ts +11 -0
  70. package/contents/apps/mobile/src/hooks/useGetLayoutHeight.hook.tsx +27 -0
  71. package/contents/apps/mobile/src/hooks/useGetLayoutWidth.hook.tsx +27 -0
  72. package/contents/apps/mobile/src/hooks/useNavigation.hook.tsx +8 -0
  73. package/contents/apps/mobile/src/hooks/useShakeAnimation.hook.tsx +32 -0
  74. package/contents/apps/mobile/src/hooks/useTextInputChangeFocus.hook.tsx +12 -0
  75. package/contents/apps/mobile/src/hooks/useThrottle.hook.ts +11 -0
  76. package/contents/apps/mobile/src/icons/arrow-left.svg +3 -0
  77. package/contents/apps/mobile/src/icons/checkbox-active.svg +4 -0
  78. package/contents/apps/mobile/src/icons/checkbox-unactive.svg +4 -0
  79. package/contents/apps/mobile/src/icons/close.svg +3 -0
  80. package/contents/apps/mobile/src/icons/download.svg +4 -0
  81. package/contents/apps/mobile/src/icons/email.svg +10 -0
  82. package/contents/apps/mobile/src/icons/eye-slash.svg +11 -0
  83. package/contents/apps/mobile/src/icons/eye.svg +4 -0
  84. package/contents/apps/mobile/src/icons/gear.svg +4 -0
  85. package/contents/apps/mobile/src/icons/home.svg +3 -0
  86. package/contents/apps/mobile/src/icons/index.ts +33 -0
  87. package/contents/apps/mobile/src/icons/pencil.svg +3 -0
  88. package/contents/apps/mobile/src/icons/phone.svg +3 -0
  89. package/contents/apps/mobile/src/icons/user-circle.svg +3 -0
  90. package/contents/apps/mobile/src/icons/user.svg +4 -0
  91. package/contents/apps/mobile/src/icons/warning.svg +3 -0
  92. package/contents/apps/mobile/src/main.tsx +5 -0
  93. package/contents/apps/mobile/src/routes/index.tsx +65 -0
  94. package/contents/apps/mobile/src/routes/privateRoutes.tsx +32 -0
  95. package/contents/apps/mobile/src/routes/publicRoutes.tsx +26 -0
  96. package/contents/apps/mobile/src/routes/routes.enum.ts +5 -0
  97. package/contents/apps/mobile/src/routes/screen-options.ts +9 -0
  98. package/contents/apps/mobile/src/routes/screens.enum.ts +4 -0
  99. package/contents/apps/mobile/src/screens/HomeScreen/home.screen.tsx +12 -0
  100. package/contents/apps/mobile/src/screens/LoginScreen/login.screen.tsx +13 -0
  101. package/contents/apps/mobile/src/stores/index.ts +1 -0
  102. package/contents/apps/mobile/src/stores/local-storage.store.ts +60 -0
  103. package/contents/apps/mobile/src/stores/mmkvStorage.ts +19 -0
  104. package/contents/apps/mobile/src/tailwind/index.ts +24 -0
  105. package/contents/apps/mobile/src/types/component.type.ts +13 -0
  106. package/contents/apps/mobile/src/types/index.ts +1 -0
  107. package/contents/apps/mobile/tailwind.config.js +80 -0
  108. package/contents/apps/mobile/tsconfig.app.json +11 -0
  109. package/contents/check-env.sh +44 -0
  110. package/contents/clean-generated-outputs.sh +32 -0
  111. package/lib/index.cjs +39 -39
  112. package/package.json +3 -2
  113. package/lib/index.js +0 -75
@@ -0,0 +1,137 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import {
3
+ TextInput as RNTextInput,
4
+ TextInputProps as RNTextInputProps,
5
+ StyleProp,
6
+ TextStyle,
7
+ View,
8
+ } from 'react-native';
9
+
10
+ import {
11
+ colors,
12
+ defaultInputContainerStyle,
13
+ defaultInputTextStyle,
14
+ disabledInputStyle,
15
+ focusedInputStyle,
16
+ } from '../../../tailwind';
17
+ import { DefaultInputComponentProps } from '../../../types';
18
+
19
+ import { DefaultNameInputProps, DefaultTextAreaInputProps } from './constants';
20
+
21
+ export const TEXT_INPUT_MIN_HEIGHT = 100;
22
+ export const TEXT_INPUT_LINE_HEIGHT = 21;
23
+
24
+ export function getTextInputHeightAdjustment(numberOfNewLines: number) {
25
+ if (numberOfNewLines < 2) {
26
+ return TEXT_INPUT_MIN_HEIGHT;
27
+ }
28
+
29
+ return TEXT_INPUT_MIN_HEIGHT + (numberOfNewLines - 2) * TEXT_INPUT_LINE_HEIGHT;
30
+ }
31
+
32
+ export type TextInputProps = DefaultInputComponentProps<string> &
33
+ RNTextInputProps & {
34
+ textInputRef?: React.RefObject<RNTextInput>;
35
+ textStyle?: StyleProp<TextStyle>;
36
+ };
37
+
38
+ export function TextInput(props: TextInputProps) {
39
+ const {
40
+ isDisabled = false,
41
+ multiline = false,
42
+ onChangeText,
43
+ placeholder,
44
+ style,
45
+ textInputRef,
46
+ textStyle,
47
+ value,
48
+ ...extraProps
49
+ } = props;
50
+ const [isFocused, setFocused] = useState<boolean>(false);
51
+
52
+ function handleOnChangeText(text: string) {
53
+ onChangeText?.(text);
54
+ }
55
+
56
+ function handleOnFocus() {
57
+ setFocused(true);
58
+ }
59
+
60
+ function handleOnBlur() {
61
+ setFocused(false);
62
+ }
63
+
64
+ return (
65
+ <View
66
+ style={[
67
+ defaultInputContainerStyle,
68
+ focusedInputStyle(isFocused),
69
+ disabledInputStyle(isDisabled),
70
+ style,
71
+ ]}
72
+ >
73
+ <RNTextInput
74
+ {...DefaultNameInputProps}
75
+ ref={textInputRef}
76
+ editable={!isDisabled}
77
+ multiline={multiline}
78
+ placeholder={placeholder}
79
+ placeholderTextColor={colors.gray[600]}
80
+ selectionColor={colors.primary[400]}
81
+ style={[defaultInputTextStyle, textStyle]}
82
+ value={value}
83
+ onBlur={handleOnBlur}
84
+ onChangeText={handleOnChangeText}
85
+ onFocus={handleOnFocus}
86
+ {...extraProps}
87
+ />
88
+ </View>
89
+ );
90
+ }
91
+
92
+ export function TextInputArea(props: TextInputProps) {
93
+ const {
94
+ numberOfLines = DefaultTextAreaInputProps.numberOfLines as number,
95
+ onChangeText,
96
+ textStyle,
97
+ value,
98
+ ...extraProps
99
+ } = props;
100
+ const [numberOfNewLines, setNumberOfNewLines] = useState<number>(numberOfLines);
101
+
102
+ function handleOnChangeText(text: string) {
103
+ onChangeText?.(text);
104
+ }
105
+ useEffect(() => {
106
+ if (!value) {
107
+ return;
108
+ }
109
+
110
+ const newLines = value.split(/\r\n|\r|\n/).length;
111
+
112
+ if (numberOfNewLines !== newLines) {
113
+ setNumberOfNewLines(newLines);
114
+ }
115
+
116
+ // eslint-disable-next-line react-hooks/exhaustive-deps
117
+ }, [value]);
118
+
119
+ return (
120
+ <TextInput
121
+ {...DefaultTextAreaInputProps}
122
+ multiline
123
+ numberOfLines={numberOfLines}
124
+ textStyle={[
125
+ textStyle,
126
+ {
127
+ height: getTextInputHeightAdjustment(numberOfNewLines),
128
+ minHeight: TEXT_INPUT_MIN_HEIGHT,
129
+ textAlignVertical: 'top',
130
+ },
131
+ ]}
132
+ value={value}
133
+ onChangeText={handleOnChangeText}
134
+ {...extraProps}
135
+ />
136
+ );
137
+ }
@@ -0,0 +1,10 @@
1
+ export * from './BottomSheet';
2
+ export * from './Button';
3
+ export * from './Divider';
4
+ export * from './InputLayout';
5
+ export * from './ListLoadingItem';
6
+ export * from './Modal';
7
+ export * from './ScreenLoader';
8
+ export * from './Skeleton';
9
+ export * from './Text';
10
+ export * from './TextInput';
@@ -0,0 +1,3 @@
1
+ export * from './atoms';
2
+ export * from './molecules';
3
+ export * from './organisms';
@@ -0,0 +1,58 @@
1
+ import { useBackHandler } from '@react-native-community/hooks';
2
+ import { ParamListBase } from '@react-navigation/native';
3
+ import React from 'react';
4
+ import {
5
+ GestureResponderEvent,
6
+ PressableProps,
7
+ StyleProp,
8
+ TouchableOpacity,
9
+ View,
10
+ ViewStyle,
11
+ } from 'react-native';
12
+
13
+ import { useNavigation } from '../../../hooks';
14
+ import { ArrowLeftIcon } from '../../../icons';
15
+ import { Screens } from '../../../routes';
16
+ import { tw } from '../../../tailwind';
17
+ import { DefaultComponentProps } from '../../../types/component.type';
18
+
19
+ type Props = DefaultComponentProps &
20
+ PressableProps & {
21
+ fallbackRoute?: Screens;
22
+ onPress?: (event?: GestureResponderEvent) => void;
23
+ style?: StyleProp<ViewStyle>;
24
+ };
25
+
26
+ const ACTIVE_OPACITY = 0.5;
27
+ export function BackButton(props: Props): JSX.Element {
28
+ const { fallbackRoute, onPress, style } = props;
29
+ const navigation = useNavigation<ParamListBase>();
30
+
31
+ useBackHandler(() => {
32
+ handleOnPress();
33
+
34
+ return true;
35
+ });
36
+
37
+ const handleOnPress = (event?: GestureResponderEvent) => {
38
+ if (onPress) {
39
+ onPress(event);
40
+ } else if (navigation.canGoBack()) {
41
+ navigation.goBack();
42
+ } else if (fallbackRoute) {
43
+ navigation.replace(fallbackRoute);
44
+ }
45
+ };
46
+
47
+ return (
48
+ <TouchableOpacity
49
+ activeOpacity={ACTIVE_OPACITY}
50
+ style={[tw`h-[48px] w-[48px]`, style]}
51
+ onPress={handleOnPress}
52
+ >
53
+ <View style={[tw`flex-1 items-center justify-center rounded-full`, style]}>
54
+ <ArrowLeftIcon style={tw`text-gray-950`} />
55
+ </View>
56
+ </TouchableOpacity>
57
+ );
58
+ }
@@ -0,0 +1 @@
1
+ export * from './back-button.component';
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { ViewProps } from 'react-native';
3
+ import { SafeAreaView } from 'react-native-safe-area-context';
4
+
5
+ import { tw } from '../../../tailwind';
6
+ import { DefaultComponentProps } from '../../../types';
7
+
8
+ type Props = DefaultComponentProps &
9
+ ViewProps & {
10
+ children: React.ReactNode;
11
+ };
12
+
13
+ export function BottomActionsContainer(props: Props) {
14
+ const { children, style, ...rest } = props;
15
+
16
+ return (
17
+ <SafeAreaView
18
+ edges={['left', 'right', 'bottom']}
19
+ style={[
20
+ tw`border-geyser-200 absolute bottom-0 left-0 right-0 flex flex-col gap-y-2 border-b-0 border-t bg-gray-50 p-4`,
21
+ style,
22
+ ]}
23
+ {...rest}
24
+ >
25
+ {children}
26
+ </SafeAreaView>
27
+ );
28
+ }
@@ -0,0 +1 @@
1
+ export * from './BottomActionsContainer.component';
@@ -0,0 +1 @@
1
+ export * from './screen-container.component';
@@ -0,0 +1,100 @@
1
+ import { useFocusEffect } from '@react-navigation/core';
2
+ import React, { ReactElement, useEffect } from 'react';
3
+ import {
4
+ NativeScrollEvent,
5
+ NativeSyntheticEvent,
6
+ Platform,
7
+ StatusBar,
8
+ StyleProp,
9
+ View,
10
+ ViewStyle,
11
+ } from 'react-native';
12
+ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
13
+ import Animated from 'react-native-reanimated';
14
+ import { Edge, SafeAreaProviderProps, SafeAreaView } from 'react-native-safe-area-context';
15
+
16
+ import CONFIG from '../../../config';
17
+ import { tw } from '../../../tailwind';
18
+
19
+ type Props = SafeAreaProviderProps & {
20
+ containerStyle?: StyleProp<ViewStyle>;
21
+ excludedEdges?: Edge[];
22
+ extraBottomPadding?: number;
23
+ hasScroll?: boolean;
24
+ refreshControl?: ReactElement;
25
+ shouldShowStatusBar?: boolean;
26
+ shouldBeTranslucent?: boolean;
27
+ statusBarColor?: string;
28
+ onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
29
+ };
30
+
31
+ const defaultStyle = tw.style('grow', {
32
+ paddingTop: StatusBar.currentHeight ? StatusBar.currentHeight - 1 : 0,
33
+ });
34
+
35
+ const safeAreaViewEdges: Edge[] = Platform.select({
36
+ android: ['left', 'right', 'bottom'],
37
+ default: [],
38
+ ios: ['left', 'right', 'bottom', 'top'],
39
+ });
40
+
41
+ const AnimatedKeyboardAwareScrollView = Animated.createAnimatedComponent(KeyboardAwareScrollView);
42
+
43
+ export function ScreenContainer(props: Props): JSX.Element {
44
+ const {
45
+ children,
46
+ containerStyle,
47
+ excludedEdges = [],
48
+ extraBottomPadding = 0,
49
+ hasScroll = true,
50
+ onScroll,
51
+ refreshControl,
52
+ shouldBeTranslucent = false,
53
+ shouldShowStatusBar = true,
54
+ statusBarColor = 'transparent',
55
+ style,
56
+ } = props;
57
+ const edges =
58
+ excludedEdges.length > 0
59
+ ? safeAreaViewEdges.filter((edge) => !excludedEdges.includes(edge))
60
+ : safeAreaViewEdges;
61
+
62
+ useEffect(() => {
63
+ if (CONFIG.IS_ANDROID) {
64
+ StatusBar.setBackgroundColor(statusBarColor);
65
+ }
66
+ }, [statusBarColor]);
67
+
68
+ useFocusEffect(() => {
69
+ StatusBar.setHidden(!shouldShowStatusBar);
70
+ if (CONFIG.IS_ANDROID) {
71
+ StatusBar.setBackgroundColor(statusBarColor);
72
+ StatusBar.setTranslucent(!shouldBeTranslucent);
73
+ }
74
+ });
75
+
76
+ const defaultContainerStyle = [
77
+ defaultStyle,
78
+ containerStyle,
79
+ // eslint-disable-next-line no-magic-numbers
80
+ extraBottomPadding && tw`pb-[${extraBottomPadding + 50}px]`,
81
+ ];
82
+
83
+ return (
84
+ <SafeAreaView edges={edges} style={[tw`flex-1 bg-gray-50`, style]}>
85
+ {hasScroll ? (
86
+ <AnimatedKeyboardAwareScrollView
87
+ contentContainerStyle={defaultContainerStyle}
88
+ keyboardShouldPersistTaps="handled"
89
+ refreshControl={refreshControl}
90
+ scrollEventThrottle={16}
91
+ onScroll={onScroll}
92
+ >
93
+ {children}
94
+ </AnimatedKeyboardAwareScrollView>
95
+ ) : (
96
+ <View style={defaultContainerStyle}>{children}</View>
97
+ )}
98
+ </SafeAreaView>
99
+ );
100
+ }
@@ -0,0 +1 @@
1
+ export * from './screen-header.component';
@@ -0,0 +1,71 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { StyleProp, TouchableOpacity, View, ViewStyle } from 'react-native';
3
+
4
+ import { GearIcon } from '../../../icons';
5
+ import { tw } from '../../../tailwind';
6
+ import { DefaultComponentProps } from '../../../types/component.type';
7
+ import { Text } from '../../atoms/Text';
8
+ import { BackButton } from '../BackButton';
9
+
10
+ type Props = DefaultComponentProps & {
11
+ hasBackButton?: boolean;
12
+ extraActionComponent?: ReactNode;
13
+ shouldShowBorder?: boolean;
14
+ title: string;
15
+ titleStyle?: StyleProp<ViewStyle>;
16
+ onBackPress?: () => void;
17
+ onExtraActionPress?: () => void;
18
+ };
19
+
20
+ const ACTIVE_OPACITY = 0.5;
21
+ export function ScreenHeader(props: Props) {
22
+ const {
23
+ extraActionComponent,
24
+ hasBackButton = true,
25
+ onBackPress,
26
+ onExtraActionPress,
27
+ shouldShowBorder = false,
28
+ style,
29
+ title,
30
+ titleStyle,
31
+ } = props;
32
+
33
+ const hasExtraActionComponent = onExtraActionPress;
34
+ const extraActionComponentDisplay = hasExtraActionComponent && (
35
+ <TouchableOpacity
36
+ activeOpacity={ACTIVE_OPACITY}
37
+ style={tw`z-10 h-[48px] w-[48px]`}
38
+ onPress={onExtraActionPress}
39
+ >
40
+ <View style={[tw`flex-1 items-center justify-center rounded-full`, style]}>
41
+ {extraActionComponent ? (
42
+ extraActionComponent
43
+ ) : (
44
+ <GearIcon height={25} style={tw`text-black-950`} width={25} />
45
+ )}
46
+ </View>
47
+ </TouchableOpacity>
48
+ );
49
+
50
+ return (
51
+ <View style={[tw`h-[64px] border border-transparent bg-gray-50`, style]}>
52
+ <View
53
+ style={[
54
+ tw`flex-row items-center justify-between border border-transparent p-4 pt-2`,
55
+ shouldShowBorder && tw`elevation-2 -m-[5px]`,
56
+ ]}
57
+ >
58
+ {hasBackButton && <BackButton style={tw`z-10`} onPress={onBackPress} />}
59
+ <Text
60
+ style={[
61
+ tw`text-primary-700 absolute inset-x-0 top-4 text-center text-xl font-medium`,
62
+ titleStyle,
63
+ ]}
64
+ >
65
+ {title}
66
+ </Text>
67
+ {extraActionComponentDisplay}
68
+ </View>
69
+ </View>
70
+ );
71
+ }
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { useLocalStorageState } from '../../../stores';
4
+
5
+ type Props = {
6
+ children: ReactNode;
7
+ };
8
+
9
+ export function StorageManager(props: Props) {
10
+ const { children } = props;
11
+ const hasHydrated = useLocalStorageState((state) => state._hasHydrated);
12
+
13
+ if (!hasHydrated) {
14
+ return null;
15
+ }
16
+
17
+ return children;
18
+ }
@@ -0,0 +1 @@
1
+ export * from './StorageManager.component';
@@ -0,0 +1,5 @@
1
+ export * from './BackButton';
2
+ export * from './BottomActionsContainer';
3
+ export * from './ScreenContainer';
4
+ export * from './ScreenHeader';
5
+ export * from './StorageManager';
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,13 @@
1
+ /* eslint-disable import/no-unresolved */
2
+ import { API_BASE_URL, IS_LIVE, STORAGE_KEY } from '@env';
3
+ import { Platform } from 'react-native';
4
+
5
+ const CONFIG = {
6
+ API_BASE_URL: API_BASE_URL,
7
+ IS_ANDROID: Platform.OS === 'android',
8
+ IS_IOS: Platform.OS === 'ios',
9
+ IS_LIVE: IS_LIVE,
10
+ STORAGE_KEY: STORAGE_KEY,
11
+ };
12
+
13
+ export default CONFIG;
@@ -0,0 +1 @@
1
+ export const HEADER_HEIGHT = 110;
@@ -0,0 +1,17 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ declare module '@env' {
3
+ export const IS_LIVE: any;
4
+ export const STORAGE_KEY: any;
5
+ export const API_BASE_URL: any;
6
+ }
7
+ declare module '*.svg' {
8
+ import React from 'react';
9
+ import { SvgProps } from 'react-native-svg';
10
+ const content: React.FC<SvgProps>;
11
+ export default content;
12
+ }
13
+
14
+ declare module '*.png';
15
+ declare module '*.jpg';
16
+ declare module '*.config';
17
+ declare module 'twrnc';
@@ -0,0 +1,9 @@
1
+ export * from './useAppState.hook';
2
+ export * from './useApplicationDimensions.hook';
3
+ export * from './useDebounce.hook';
4
+ export * from './useGetLayoutHeight.hook';
5
+ export * from './useGetLayoutWidth.hook';
6
+ export * from './useNavigation.hook';
7
+ export * from './useShakeAnimation.hook';
8
+ export * from './useTextInputChangeFocus.hook';
9
+ export * from './useThrottle.hook';
@@ -0,0 +1,20 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { AppState } from 'react-native';
3
+
4
+ export function useAppState() {
5
+ const appState = useRef(AppState.currentState);
6
+ const [appStateVisible, setAppStateVisible] = useState<boolean>(appState.current === 'active');
7
+
8
+ useEffect(() => {
9
+ const subscription = AppState.addEventListener('change', (nextAppState) => {
10
+ appState.current = nextAppState;
11
+ setAppStateVisible(appState.current === 'active');
12
+ });
13
+
14
+ return () => {
15
+ subscription.remove();
16
+ };
17
+ }, []);
18
+
19
+ return appStateVisible;
20
+ }
@@ -0,0 +1,10 @@
1
+ import { StatusBar, useWindowDimensions } from 'react-native';
2
+
3
+ export function useApplicationDimensions() {
4
+ const { height, width } = useWindowDimensions();
5
+
6
+ return {
7
+ height: height + (StatusBar?.currentHeight || 0),
8
+ width,
9
+ };
10
+ }
@@ -0,0 +1,11 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { debounce, DebouncedFunc } from 'lodash';
3
+ import { useCallback } from 'react';
4
+
5
+ export function useDebounce<T extends (...args: any[]) => any>(
6
+ func: T,
7
+ delay: number,
8
+ ): DebouncedFunc<T> {
9
+ // eslint-disable-next-line react-hooks/exhaustive-deps
10
+ return useCallback(debounce<T>(func, delay), []);
11
+ }
@@ -0,0 +1,27 @@
1
+ import { useState } from 'react';
2
+ import { LayoutChangeEvent } from 'react-native';
3
+
4
+ import { useDebounce } from './useDebounce.hook';
5
+
6
+ export function useGetLayoutHeight(
7
+ initialHeight = 0,
8
+ ): [number, (event: LayoutChangeEvent) => void, number] {
9
+ const [actualHeight, setLayoutActualHeight] = useState<number>(0);
10
+ const debouncedOnSetActualHeight = useDebounce(setLayoutActualHeight, 1);
11
+
12
+ const [layoutHeight, setLayoutHeight] = useState<number>(initialHeight);
13
+ const debouncedOnSetHeight = useDebounce(setLayoutHeight, 1);
14
+
15
+ function onLayout(event: LayoutChangeEvent) {
16
+ const { height } = event.nativeEvent.layout;
17
+
18
+ if (height === 0 && height <= initialHeight) {
19
+ return;
20
+ }
21
+
22
+ debouncedOnSetActualHeight(Math.round(height));
23
+ debouncedOnSetHeight(Math.round(height));
24
+ }
25
+
26
+ return [layoutHeight, onLayout, actualHeight];
27
+ }
@@ -0,0 +1,27 @@
1
+ import { useState } from 'react';
2
+ import { LayoutChangeEvent } from 'react-native';
3
+
4
+ import { useDebounce } from './useDebounce.hook';
5
+
6
+ export function useGetLayoutWidth(
7
+ initialWidth = 0,
8
+ ): [number, (event: LayoutChangeEvent) => void, number] {
9
+ const [actualWidth, setLayoutActualWidth] = useState<number>(0);
10
+ const debouncedOnSetActualWidth = useDebounce(setLayoutActualWidth, 1);
11
+
12
+ const [layoutWidth, setLayoutWidth] = useState<number>(initialWidth);
13
+ const debouncedOnSetWidth = useDebounce(setLayoutWidth, 1);
14
+
15
+ function onLayout(event: LayoutChangeEvent) {
16
+ const { width } = event.nativeEvent.layout;
17
+
18
+ if (width === 0 && width <= initialWidth) {
19
+ return;
20
+ }
21
+
22
+ debouncedOnSetActualWidth(Math.round(width));
23
+ debouncedOnSetWidth(Math.round(width));
24
+ }
25
+
26
+ return [layoutWidth, onLayout, actualWidth];
27
+ }
@@ -0,0 +1,8 @@
1
+ import { ParamListBase, useNavigation as RNUseNavigation } from '@react-navigation/native';
2
+ import { StackNavigationProp } from '@react-navigation/stack';
3
+
4
+ import { PrivateStackParams, PublicStackParams } from '../routes';
5
+
6
+ export function useNavigation<T extends PublicStackParams | PrivateStackParams | ParamListBase>() {
7
+ return RNUseNavigation<StackNavigationProp<T, keyof T>>();
8
+ }
@@ -0,0 +1,32 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ import {
3
+ useSharedValue,
4
+ withRepeat,
5
+ withSequence,
6
+ withTiming,
7
+ useAnimatedStyle,
8
+ } from 'react-native-reanimated';
9
+
10
+ export function useShakeAnimation() {
11
+ const shake = useSharedValue(0);
12
+
13
+ const startAnimation = () => {
14
+ shake.value = withRepeat(
15
+ withSequence(
16
+ withTiming(-10, { duration: 50 }),
17
+ withTiming(10, { duration: 50 }),
18
+ withTiming(-10, { duration: 50 }),
19
+ withTiming(10, { duration: 50 }),
20
+ withTiming(0, { duration: 50 }),
21
+ ),
22
+ 1,
23
+ false,
24
+ );
25
+ };
26
+
27
+ const animatedStyle = useAnimatedStyle(() => ({
28
+ transform: [{ translateX: shake.value }],
29
+ }));
30
+
31
+ return { animatedStyle, startAnimation };
32
+ }
@@ -0,0 +1,12 @@
1
+ import React, { useRef } from 'react';
2
+ import { TextInput } from 'react-native';
3
+
4
+ export function useTextInputChangeFocus(): [React.MutableRefObject<TextInput>, () => void] {
5
+ const ref = useRef() as React.MutableRefObject<TextInput>;
6
+
7
+ function changeFocus() {
8
+ ref?.current?.focus();
9
+ }
10
+
11
+ return [ref, changeFocus];
12
+ }
@@ -0,0 +1,11 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { throttle, DebouncedFunc } from 'lodash';
3
+ import { useCallback } from 'react';
4
+
5
+ export function useThrottle<T extends (...args: any[]) => any>(
6
+ func: T,
7
+ delay: number,
8
+ ): DebouncedFunc<T> {
9
+ // eslint-disable-next-line react-hooks/exhaustive-deps
10
+ return useCallback(throttle<T>(func, delay), []);
11
+ }