@ccrf01/react-native-template 0.0.16

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 (233) hide show
  1. package/.github/workflows/npm-publish.yml +28 -0
  2. package/.vscode/settings.json +15 -0
  3. package/README.md +58 -0
  4. package/package.json +16 -0
  5. package/template/.bundle/config +2 -0
  6. package/template/.env.development +1 -0
  7. package/template/.env.production +1 -0
  8. package/template/.eslintrc.js +392 -0
  9. package/template/.java-version +1 -0
  10. package/template/.prettierrc.js +5 -0
  11. package/template/.ruby-version +1 -0
  12. package/template/.watchmanconfig +1 -0
  13. package/template/Gemfile +23 -0
  14. package/template/Gemfile.lock +330 -0
  15. package/template/README.md +97 -0
  16. package/template/ReactotronConfig.js +17 -0
  17. package/template/__tests__/App.test.tsx +13 -0
  18. package/template/_gitignore +75 -0
  19. package/template/_node-version +1 -0
  20. package/template/android/app/build.gradle +162 -0
  21. package/template/android/app/debug.keystore +0 -0
  22. package/template/android/app/proguard-rules.pro +10 -0
  23. package/template/android/app/src/debug/AndroidManifest.xml +9 -0
  24. package/template/android/app/src/main/AndroidManifest.xml +26 -0
  25. package/template/android/app/src/main/java/com/projectname/MainActivity.kt +30 -0
  26. package/template/android/app/src/main/java/com/projectname/MainApplication.kt +27 -0
  27. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  28. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  29. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  30. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  31. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  32. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  33. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  34. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  35. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  36. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  37. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  38. package/template/android/app/src/main/res/values/strings.xml +3 -0
  39. package/template/android/app/src/main/res/values/styles.xml +9 -0
  40. package/template/android/build.gradle +37 -0
  41. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  42. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  43. package/template/android/gradle.properties +48 -0
  44. package/template/android/gradlew +251 -0
  45. package/template/android/gradlew.bat +99 -0
  46. package/template/android/keystore/keystore.properties +4 -0
  47. package/template/android/settings.gradle +6 -0
  48. package/template/android/version.properties +2 -0
  49. package/template/app.json +4 -0
  50. package/template/babel.config.js +38 -0
  51. package/template/fastlane/Fastfile +136 -0
  52. package/template/fastlane/Pluginfile +9 -0
  53. package/template/fastlane/README.md +46 -0
  54. package/template/index.js +9 -0
  55. package/template/ios/.xcode.env +11 -0
  56. package/template/ios/Podfile +35 -0
  57. package/template/ios/Podfile.lock +3669 -0
  58. package/template/ios/ProjectName/AppDelegate.swift +48 -0
  59. package/template/ios/ProjectName/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  60. package/template/ios/ProjectName/Images.xcassets/Contents.json +6 -0
  61. package/template/ios/ProjectName/Info.plist +66 -0
  62. package/template/ios/ProjectName/LaunchScreen.storyboard +47 -0
  63. package/template/ios/ProjectName/PrivacyInfo.xcprivacy +47 -0
  64. package/template/ios/ProjectName.xcodeproj/project.pbxproj +482 -0
  65. package/template/ios/ProjectName.xcodeproj/xcshareddata/xcschemes/ProjectName.xcscheme +88 -0
  66. package/template/ios/ProjectName.xcworkspace/contents.xcworkspacedata +10 -0
  67. package/template/jest.config.js +3 -0
  68. package/template/metro.config.js +20 -0
  69. package/template/package-lock.json +17073 -0
  70. package/template/package.json +156 -0
  71. package/template/src/@types/emotion.d.ts +12 -0
  72. package/template/src/@types/env.d.ts +3 -0
  73. package/template/src/@types/redux-persist-transform-immutable.d.ts +1 -0
  74. package/template/src/@types/typing.d.ts +17 -0
  75. package/template/src/AppContainer.tsx +109 -0
  76. package/template/src/assets/images/143.png +0 -0
  77. package/template/src/assets/index.ts +13 -0
  78. package/template/src/components/basic/BackButton/index.tsx +34 -0
  79. package/template/src/components/basic/Body/index.tsx +68 -0
  80. package/template/src/components/basic/Button/index.tsx +181 -0
  81. package/template/src/components/basic/Button/utils.ts +78 -0
  82. package/template/src/components/basic/ButtonGroup/index.tsx +182 -0
  83. package/template/src/components/basic/Card/index.tsx +3 -0
  84. package/template/src/components/basic/Container/index.tsx +38 -0
  85. package/template/src/components/basic/Content/index.tsx +87 -0
  86. package/template/src/components/basic/DropDown/index.tsx +354 -0
  87. package/template/src/components/basic/ExpandableOverlay/index.tsx +113 -0
  88. package/template/src/components/basic/Header/index.tsx +216 -0
  89. package/template/src/components/basic/Header/styles.ts +0 -0
  90. package/template/src/components/basic/Icons/index.tsx +131 -0
  91. package/template/src/components/basic/InputLabel/index.tsx +19 -0
  92. package/template/src/components/basic/LoadingOverlay/index.tsx +68 -0
  93. package/template/src/components/basic/MaterialTextInput/index.tsx +153 -0
  94. package/template/src/components/basic/NumberInput/index.tsx +53 -0
  95. package/template/src/components/basic/Picker/PickerContext.ts +7 -0
  96. package/template/src/components/basic/Picker/PickerHeader.tsx +130 -0
  97. package/template/src/components/basic/Picker/PickerItem.tsx +105 -0
  98. package/template/src/components/basic/Picker/PickerItemsList.tsx +135 -0
  99. package/template/src/components/basic/Picker/PickerPresenter.ts +54 -0
  100. package/template/src/components/basic/Picker/hooks/useImperativePickerHandle.ts +27 -0
  101. package/template/src/components/basic/Picker/hooks/usePickerLabel.ts +74 -0
  102. package/template/src/components/basic/Picker/hooks/usePickerSearch.ts +37 -0
  103. package/template/src/components/basic/Picker/hooks/usePickerSelection.ts +57 -0
  104. package/template/src/components/basic/Picker/index.tsx +284 -0
  105. package/template/src/components/basic/Picker/types.tsx +229 -0
  106. package/template/src/components/basic/PressableOpacity/index.tsx +20 -0
  107. package/template/src/components/basic/RootDialog/Dialog.tsx +246 -0
  108. package/template/src/components/basic/RootDialog/Manager.tsx +110 -0
  109. package/template/src/components/basic/RootDialog/animations/Animation.ts +29 -0
  110. package/template/src/components/basic/RootDialog/animations/FadeAnimation.ts +40 -0
  111. package/template/src/components/basic/RootDialog/animations/ScaleAnimation.ts +37 -0
  112. package/template/src/components/basic/RootDialog/animations/SlideAnimation.ts +89 -0
  113. package/template/src/components/basic/RootDialog/components/Backdrop.tsx +60 -0
  114. package/template/src/components/basic/RootDialog/components/BaseDialog.tsx +564 -0
  115. package/template/src/components/basic/RootDialog/components/BottomDialog.tsx +32 -0
  116. package/template/src/components/basic/RootDialog/components/DialogButton.tsx +87 -0
  117. package/template/src/components/basic/RootDialog/components/DialogContent.tsx +26 -0
  118. package/template/src/components/basic/RootDialog/components/DialogContext.tsx +8 -0
  119. package/template/src/components/basic/RootDialog/components/DialogFooter.tsx +42 -0
  120. package/template/src/components/basic/RootDialog/components/DialogTitle.tsx +53 -0
  121. package/template/src/components/basic/RootDialog/components/DraggableView.tsx +271 -0
  122. package/template/src/components/basic/RootDialog/index.ts +21 -0
  123. package/template/src/components/basic/RootDialog/type.ts +102 -0
  124. package/template/src/components/basic/Text/index.tsx +8 -0
  125. package/template/src/components/basic/index.ts +35 -0
  126. package/template/src/configs/constants/type/APIStatus.type.ts +8 -0
  127. package/template/src/configs/constants/type/Locale.type.ts +7 -0
  128. package/template/src/configs/constants/type/StorageKey.type.ts +7 -0
  129. package/template/src/configs/constants/type/ThemeType.type.ts +6 -0
  130. package/template/src/configs/constants/type/index.ts +11 -0
  131. package/template/src/configs/index.ts +22 -0
  132. package/template/src/contexts/ThemeContext.ts +6 -0
  133. package/template/src/hooks/useAppLoading.ts +26 -0
  134. package/template/src/hooks/useAppState.ts +36 -0
  135. package/template/src/hooks/useArray.ts +47 -0
  136. package/template/src/hooks/useAsync.ts +42 -0
  137. package/template/src/hooks/useAsyncStorage.ts +41 -0
  138. package/template/src/hooks/useBoolean.ts +21 -0
  139. package/template/src/hooks/useBuildTheme.ts +249 -0
  140. package/template/src/hooks/useCountDown.ts +111 -0
  141. package/template/src/hooks/useCounter.ts +27 -0
  142. package/template/src/hooks/useDebounce.ts +25 -0
  143. package/template/src/hooks/useDebouncedValidate.ts +32 -0
  144. package/template/src/hooks/useDebugInformation.ts +38 -0
  145. package/template/src/hooks/useDeviceToken.ts +20 -0
  146. package/template/src/hooks/useEncryptedStorage.ts +41 -0
  147. package/template/src/hooks/useFontFamily.ts +13 -0
  148. package/template/src/hooks/useHttp.ts +18 -0
  149. package/template/src/hooks/useInterval.ts +24 -0
  150. package/template/src/hooks/useIsForeground.ts +17 -0
  151. package/template/src/hooks/useMMKVStorage.ts +0 -0
  152. package/template/src/hooks/usePrevious.ts +12 -0
  153. package/template/src/hooks/useRenderCount.ts +10 -0
  154. package/template/src/hooks/useTheme.ts +17 -0
  155. package/template/src/hooks/useTimeCountDown.ts +91 -0
  156. package/template/src/index.tsx +65 -0
  157. package/template/src/infrastructures/NetClient/AbstractClient.ts +66 -0
  158. package/template/src/infrastructures/NetClient/ApiResponse.ts +16 -0
  159. package/template/src/infrastructures/NetClient/ApisauceClient.ts +76 -0
  160. package/template/src/infrastructures/NetClient/AxiosClient.ts +80 -0
  161. package/template/src/infrastructures/NetClient/FetchNetClient.ts +120 -0
  162. package/template/src/infrastructures/NetClient/config.ts +3 -0
  163. package/template/src/infrastructures/NetClient/interfaces/INetClient.ts +6 -0
  164. package/template/src/infrastructures/Storage/IStorage.ts +7 -0
  165. package/template/src/infrastructures/Storage/MMKVStorage.ts +41 -0
  166. package/template/src/infrastructures/common/Timeout.ts +27 -0
  167. package/template/src/infrastructures/common/colorUtils.ts +82 -0
  168. package/template/src/infrastructures/common/dateUtils.ts +39 -0
  169. package/template/src/infrastructures/common/logger.ts +115 -0
  170. package/template/src/locales/en-US/general.json +26 -0
  171. package/template/src/locales/en-US/index.ts +9 -0
  172. package/template/src/locales/en-US/screens.json +4 -0
  173. package/template/src/locales/en-US/setting.json +3 -0
  174. package/template/src/locales/i18n.ts +109 -0
  175. package/template/src/locales/zh-TW/general.json +26 -0
  176. package/template/src/locales/zh-TW/index.ts +9 -0
  177. package/template/src/locales/zh-TW/screens.json +4 -0
  178. package/template/src/locales/zh-TW/setting.json +3 -0
  179. package/template/src/models/index.ts +5 -0
  180. package/template/src/models/request.model.ts +50 -0
  181. package/template/src/navigators/DrawerNav/DrawerContent.tsx +66 -0
  182. package/template/src/navigators/DrawerNav/DrawerItem.tsx +261 -0
  183. package/template/src/navigators/DrawerNav/index.tsx +39 -0
  184. package/template/src/navigators/DrawerNav/props.ts +12 -0
  185. package/template/src/navigators/DrawerNav/types.ts +8 -0
  186. package/template/src/navigators/MainBottomTabNav/index.tsx +83 -0
  187. package/template/src/navigators/MainBottomTabNav/props.ts +16 -0
  188. package/template/src/navigators/MainBottomTabNav/types.ts +6 -0
  189. package/template/src/navigators/RootStack.tsx +43 -0
  190. package/template/src/navigators/index.tsx +40 -0
  191. package/template/src/navigators/props.ts +14 -0
  192. package/template/src/navigators/types.ts +18 -0
  193. package/template/src/navigators/utils.ts +68 -0
  194. package/template/src/redux/api/api.ts +41 -0
  195. package/template/src/redux/reducers/appSlice.ts +26 -0
  196. package/template/src/redux/reducers/index.ts +21 -0
  197. package/template/src/redux/reducers/nonPersistSlice.ts +51 -0
  198. package/template/src/redux/reducers/settingSlice.ts +48 -0
  199. package/template/src/redux/reducers/themeSlice.ts +55 -0
  200. package/template/src/redux/saga/index.ts +5 -0
  201. package/template/src/redux/saga/settingSaga.ts +21 -0
  202. package/template/src/redux/selectors/app.ts +9 -0
  203. package/template/src/redux/selectors/nonPersist.ts +23 -0
  204. package/template/src/redux/selectors/setting.ts +29 -0
  205. package/template/src/redux/selectors/theme.ts +13 -0
  206. package/template/src/redux/store/index.ts +79 -0
  207. package/template/src/redux/store/types.d.ts +5 -0
  208. package/template/src/screens/Home/index.tsx +146 -0
  209. package/template/src/screens/Settings/components/Item.tsx +45 -0
  210. package/template/src/screens/Settings/index.tsx +97 -0
  211. package/template/src/screens/Splash/index.tsx +53 -0
  212. package/template/src/services/Dialogs.tsx +226 -0
  213. package/template/src/services/PermissionCheck.ts +257 -0
  214. package/template/src/theme/Common.ts +48 -0
  215. package/template/src/theme/Fonts.ts +196 -0
  216. package/template/src/theme/Gutters.ts +63 -0
  217. package/template/src/theme/Icons.ts +28 -0
  218. package/template/src/theme/Images.ts +13 -0
  219. package/template/src/theme/Layout.ts +106 -0
  220. package/template/src/theme/Variables.ts +167 -0
  221. package/template/src/theme/components/Buttons.ts +37 -0
  222. package/template/src/theme/index.ts +8 -0
  223. package/template/src/theme/metrics.ts +57 -0
  224. package/template/src/theme/themes/default_dark/Images.ts +7 -0
  225. package/template/src/theme/themes/default_dark/Variables.ts +84 -0
  226. package/template/src/theme/themes/default_dark/index.ts +2 -0
  227. package/template/src/theme/themes/index.ts +8 -0
  228. package/template/src/theme/types.ts +152 -0
  229. package/template/src/utils/encrypt-helper.ts +118 -0
  230. package/template/src/utils/index.ts +76 -0
  231. package/template/src/utils/sys-info-data.ts +17 -0
  232. package/template/tsconfig.json +44 -0
  233. package/template.config.js +8 -0
@@ -0,0 +1,41 @@
1
+ import { MutableRefObject, useEffect } from 'react'
2
+ import EncryptedStorage from 'react-native-encrypted-storage'
3
+ import useState from 'react-usestateref'
4
+
5
+ import logger from '@/infrastructures/common/logger'
6
+
7
+ const useEncryptedStorage = <T = string>(key: string, initialValue: T): [data: T, setNewData: (value: any) => Promise<void>, retrivedFromStorage: boolean, dataRef: MutableRefObject<T>] => {
8
+ const [data, setData, dataRef] = useState(initialValue)
9
+ const [retrievedFromStorage, setRetrievedFromStorage] = useState(false)
10
+
11
+ useEffect(() => {
12
+ const init = async () => {
13
+ try {
14
+ const value = await EncryptedStorage.getItem(key)
15
+ if (typeof value === 'string') {
16
+ setData((JSON.parse(value) as T) || initialValue)
17
+ } else {
18
+ setData(initialValue)
19
+ }
20
+ setRetrievedFromStorage(true)
21
+ } catch (error) {
22
+ // console.error('useAsyncStorage getItem error:', error)
23
+ logger.error('useEncryptedStorage getItem error:', error)
24
+ }
25
+ }
26
+ void init()
27
+ }, [key, initialValue])
28
+
29
+ const setNewData = async (value: T) => {
30
+ try {
31
+ await EncryptedStorage.setItem(key, JSON.stringify(value))
32
+ setData(value)
33
+ } catch (error) {
34
+ logger.error('useAsyncStorage setItem error:', error)
35
+ }
36
+ }
37
+
38
+ return [data, setNewData, retrievedFromStorage, dataRef]
39
+ }
40
+
41
+ export default useEncryptedStorage
@@ -0,0 +1,13 @@
1
+ import { useSelector } from 'react-redux'
2
+
3
+ import { FONT_FAMILY } from '@/configs'
4
+ import { Locale } from '@/configs/constants/type'
5
+ import { selectLocale } from '@/redux/selectors/setting'
6
+
7
+ const useFontFamily = () => {
8
+ const lang = useSelector(selectLocale)
9
+
10
+ return lang === Locale.zhTW ? FONT_FAMILY.CHI : FONT_FAMILY.ENG
11
+ }
12
+
13
+ export default useFontFamily
@@ -0,0 +1,18 @@
1
+ import { useCallback, useState } from 'react'
2
+
3
+ import AxiosClient from '@/infrastructures/NetClient/AxiosClient'
4
+ import { INetClient } from '@/infrastructures/NetClient/interfaces/INetClient'
5
+
6
+ const makeHttpClinet = (netClientType: string, endpoint: string) => {
7
+ const netClient = new AxiosClient(endpoint)
8
+
9
+ return (path: string) => {
10
+
11
+
12
+ return [{}]
13
+ }
14
+
15
+ }
16
+ export const useHttp = () => {
17
+
18
+ }
@@ -0,0 +1,24 @@
1
+ import { useEffect, useRef } from 'react'
2
+ const useInterval = (callback: () => void, delay: number | null) => {
3
+ const savedCallback = useRef(callback)
4
+
5
+ // Remember the latest callback if it changes.
6
+ useEffect(() => {
7
+ savedCallback.current = callback
8
+ }, [callback])
9
+
10
+ // Set up the interval.
11
+ useEffect(() => {
12
+ // Don't schedule if no delay is specified.
13
+ // Note: 0 is a valid value for delay.
14
+ if (!delay && delay !== 0) {
15
+ return
16
+ }
17
+
18
+ const id = setInterval(() => savedCallback.current(), delay)
19
+
20
+ return () => clearInterval(id)
21
+ }, [delay])
22
+ }
23
+
24
+ export default useInterval
@@ -0,0 +1,17 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { AppState, AppStateStatus } from 'react-native'
3
+
4
+ export const useIsForeground = (): boolean => {
5
+ const [isForeground, setIsForeground] = useState(true)
6
+
7
+ useEffect(() => {
8
+ const onChange = (state: AppStateStatus): void => {
9
+ setIsForeground(state === 'active')
10
+ }
11
+ const listener = AppState.addEventListener('change', onChange)
12
+
13
+ return () => listener.remove()
14
+ }, [setIsForeground])
15
+
16
+ return isForeground
17
+ }
File without changes
@@ -0,0 +1,12 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ const usePrevious = <T>(value: T): T | undefined => {
4
+ const ref = useRef<T>()
5
+ useEffect(() => {
6
+ ref.current = value
7
+ })
8
+
9
+ return ref.current
10
+ }
11
+
12
+ export default usePrevious
@@ -0,0 +1,10 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ const useRenderCount = () => {
4
+ const count = useRef<number>(1)
5
+ useEffect(() => { count.current++ })
6
+
7
+ return count.current
8
+ }
9
+
10
+ export default useRenderCount
@@ -0,0 +1,17 @@
1
+ import _ from 'lodash'
2
+ import { useContext } from 'react'
3
+
4
+ import { ThemeContext } from '@/contexts/ThemeContext'
5
+
6
+ const useTheme = () => {
7
+ const themeContext = _.cloneDeep(useContext(ThemeContext))
8
+ if (!themeContext) {
9
+ throw new Error(
10
+ 'No ThemeContext.Provider found when calling useTheme.'
11
+ )
12
+ }
13
+
14
+ return themeContext
15
+ }
16
+
17
+ export default useTheme
@@ -0,0 +1,91 @@
1
+ import React, { useCallback, useEffect, useState } from 'react'
2
+
3
+ import useBoolean from '@/hooks/useBoolean'
4
+ import useInterval from '@/hooks/useInterval'
5
+ import logger from '@/infrastructures/common/logger'
6
+
7
+ type CountdownControllers = {
8
+ isCountdownRunning: boolean
9
+ startCountdown: () => void
10
+ stopCountdown: () => void
11
+ resetCountdown: () => void
12
+ }
13
+ type CountdownOption = {
14
+ /*
15
+ * The initial value of the countdown in seconds
16
+ */
17
+ countStart: number
18
+ intervalMs?: number
19
+ isIncrement?: boolean
20
+ countStop?: number
21
+ }
22
+
23
+ const useTimeCountDown = (
24
+ countdownOption: CountdownOption,
25
+ ): [number, CountdownControllers] => {
26
+
27
+ const { countStart, countStop = 0, intervalMs = 1000, isIncrement = false } = countdownOption
28
+
29
+ const [count, setCount] = useState(countStart)
30
+ const [timestampStart, setTimestampStart] = useState(0)
31
+ // const [lastTimestamp, setLastTimestamp] = useState(0)
32
+ const { setFalse: stopCountdown, setTrue: startCountdown, value: isCountdownRunning } = useBoolean(false)
33
+
34
+ // const runStart = () => {
35
+ // const startTime = Date.now()
36
+ // setTimestampStart(startTime)
37
+ // // setLastTimestamp(startTime)
38
+ // }
39
+
40
+ useEffect(() => {
41
+ if (isCountdownRunning) {
42
+ const startTime = Date.now()
43
+ setTimestampStart(startTime)
44
+ } else {
45
+ // TODO:
46
+ }
47
+ }, [isCountdownRunning])
48
+
49
+ const resetCounter = () => {
50
+ setCount(countStart)
51
+ }
52
+
53
+ const countdownCallback = useCallback(() => {
54
+ const timeDiff = Date.now() - timestampStart
55
+ const nextCount = Math.round(!isIncrement ? countStart - timeDiff / 1000 : count + timeDiff / 1000)
56
+ if (!isIncrement) {
57
+ if (nextCount <= countStop) {
58
+ setCount(countStop)
59
+ stopCountdown()
60
+
61
+ return
62
+ }
63
+ } else {
64
+ if (nextCount >= countStop) {
65
+ setCount(countStop)
66
+ stopCountdown()
67
+
68
+ return
69
+ }
70
+ }
71
+ setCount(nextCount)
72
+ }, [count, countStop, timestampStart, isIncrement, stopCountdown])
73
+
74
+ useInterval(countdownCallback, isCountdownRunning ? intervalMs : null)
75
+
76
+ const resetCountdown = () => {
77
+ stopCountdown()
78
+ resetCounter()
79
+ }
80
+
81
+ return [
82
+ count, {
83
+ isCountdownRunning,
84
+ stopCountdown,
85
+ startCountdown,
86
+ resetCountdown,
87
+ },
88
+ ]
89
+ }
90
+
91
+ export default useTimeCountDown
@@ -0,0 +1,65 @@
1
+ import { NewAppScreen } from '@react-native/new-app-screen'
2
+ import React, { Suspense, useEffect } from 'react'
3
+ import { I18nextProvider } from 'react-i18next'
4
+ import { StatusBar, StyleSheet, useColorScheme, View } from 'react-native'
5
+ import { MD2Colors } from 'react-native-paper'
6
+ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
7
+ import { Provider } from 'react-redux'
8
+ import { PersistGate } from 'redux-persist/integration/react'
9
+
10
+ import { persistor, store } from '@/redux/store'
11
+
12
+ import AppContainer from './AppContainer'
13
+ import i18n from './locales/i18n'
14
+
15
+ function App() {
16
+ const isDarkMode = useColorScheme() === 'dark'
17
+
18
+ return (
19
+ <SafeAreaProvider>
20
+ <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
21
+ <I18nextProvider i18n={i18n}>
22
+ <Suspense fallback={'is loading'}>
23
+ <Provider store={store}>
24
+ <PersistGate
25
+ loading={
26
+ <View
27
+ style={{
28
+ flex: 1,
29
+ width: '100%',
30
+ height: '100%',
31
+ backgroundColor: MD2Colors.grey700,
32
+ }}
33
+ />
34
+ }
35
+ persistor={persistor}
36
+ >
37
+ <AppContainer />
38
+ </PersistGate>
39
+ </Provider>
40
+ </Suspense>
41
+ </I18nextProvider>
42
+ </SafeAreaProvider>
43
+ )
44
+ }
45
+
46
+ function AppContent() {
47
+ const safeAreaInsets = useSafeAreaInsets()
48
+
49
+ return (
50
+ <View style={styles.container}>
51
+ <NewAppScreen
52
+ templateFileName="App.tsx"
53
+ safeAreaInsets={safeAreaInsets}
54
+ />
55
+ </View>
56
+ )
57
+ }
58
+
59
+ const styles = StyleSheet.create({
60
+ container: {
61
+ flex: 1,
62
+ },
63
+ })
64
+
65
+ export default App
@@ -0,0 +1,66 @@
1
+ import { ApisauceInstance } from 'apisauce'
2
+ import { AxiosInstance } from 'axios'
3
+
4
+ import { IFetchNetClientInstance } from './FetchNetClient'
5
+ export default class AbstractClient<T extends AxiosInstance|ApisauceInstance|IFetchNetClientInstance> {
6
+ instance: T
7
+ endpoint: string
8
+ constructor(endpoint: string) {
9
+ this.endpoint = endpoint
10
+ this.instance = this.createInstance()
11
+ }
12
+
13
+ createInstance():T {
14
+ throw new Error()
15
+ }
16
+
17
+ protected paramsToQueryString = (
18
+ params: Record<string, unknown>,
19
+ skipEmpty = false,
20
+ encodeToken = false,
21
+ ) => {
22
+ const paramKeys = Object.keys(params)
23
+ let query = ''
24
+ // const formBody:string[] = [];
25
+ paramKeys.sort()
26
+ paramKeys.forEach((key) => {
27
+ if (
28
+ params[key] !== null &&
29
+ ((skipEmpty && params[key] !== '') || !skipEmpty)
30
+ ) {
31
+ if (query !== '') {
32
+ query += '&'
33
+ }
34
+
35
+ if (params[key] instanceof Array) {
36
+ const paramsArray: any[] = params[key] as any[]
37
+ paramsArray.sort()
38
+ paramsArray.forEach((param: any) => {
39
+ query +=
40
+ '&' +
41
+ key +
42
+ '=' +
43
+ (encodeToken
44
+ ? encodeURI(encodeURIComponent(param))
45
+ : encodeURIComponent(param))
46
+ // query += '&' + key + '=' + encodeURI(encodeURIComponent(param));
47
+ })
48
+ } else {
49
+ const value: string = params[key] as string
50
+ query +=
51
+ key +
52
+ '=' +
53
+ (encodeToken
54
+ ? encodeURI(encodeURIComponent(value))
55
+ : encodeURIComponent(value))
56
+ // query += key + '=' + encodeURI(encodeURIComponent(params[key]));
57
+ }
58
+ }
59
+ })
60
+ if (query.startsWith('&')) {
61
+ query = query.substring(1)
62
+ }
63
+
64
+ return query
65
+ }
66
+ }
@@ -0,0 +1,16 @@
1
+ export default class APIResponse<T = any> {
2
+ origResp: unknown
3
+ ok:boolean
4
+ status: number
5
+ headers?: Record<string, unknown>
6
+ data?: T
7
+ error?: Error
8
+ // problem?: string;
9
+ constructor(status: number, headers?: Record<string, unknown>, data?: T, error?: Error, origResp?: unknown) {
10
+ this.status = status
11
+ this.headers = headers
12
+ this.data = data as T
13
+ this.error = error
14
+ this.ok = status >= 200 && status <= 299
15
+ }
16
+ }
@@ -0,0 +1,76 @@
1
+ /* eslint-disable no-console */
2
+ import { ApiResponse, ApisauceInstance, create } from 'apisauce'
3
+ import { AxiosError, AxiosResponse } from 'axios'
4
+
5
+ import logger from '../common/logger'
6
+ import AbstractClient from './AbstractClient'
7
+ import APIResponse from './ApiResponse'
8
+ import { API } from './config'
9
+
10
+ export default class ApiSauceClient extends AbstractClient<ApisauceInstance>{
11
+ constructor(endpoint: string) {
12
+ super(endpoint)
13
+ }
14
+
15
+ createInstance(): ApisauceInstance {
16
+ return create({
17
+ baseURL: this.endpoint,
18
+ timeout: API.Timeout,
19
+ })
20
+ }
21
+
22
+ public get<T>(path: string, params: Record<string, any>, headerParams: Record<string, string>): Promise<APIResponse<T>> {
23
+ return new Promise<APIResponse<T>>((resolve) => {
24
+ const paramString = this.paramsToQueryString(params)
25
+ const finalPath = path + (paramString.length > 0 ? `?${paramString}` : '')
26
+ logger.request('GET', headerParams, finalPath)
27
+ this.instance.get<T>(finalPath, { headers: headerParams }).then((response: ApiResponse<T>) => {
28
+ logger.resp(response)
29
+ logger.responseBody(response.data as Record<string, unknown>)
30
+ if (response.status && response.status >= 200 && response.status <= 299) {
31
+ const apiResponse = new APIResponse<T>(response.status, response.headers, response.data)
32
+ resolve(apiResponse)
33
+ } else {
34
+ const apiErrorResponse = new APIResponse<T>(response.status ? response.status : -1, response.headers, response.data)
35
+ resolve(apiErrorResponse)
36
+ }
37
+ })
38
+ .catch((error: Error) => {
39
+ const axiosErrorResponse = error.hasOwnProperty('response') ? (error as AxiosError<T>).response : undefined
40
+ if (axiosErrorResponse !== undefined) {
41
+ const errorResponse = new APIResponse<T>(axiosErrorResponse.status, axiosErrorResponse.headers, axiosErrorResponse.data, error)
42
+ resolve(errorResponse)
43
+ } else {
44
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
45
+ }
46
+ })
47
+ })
48
+ }
49
+
50
+ public postJson<T>(path: string, json: Record<string, any>, headerParams: Record<string, string>): Promise<APIResponse<T>> {
51
+ return new Promise<APIResponse<T>>((resolve) => {
52
+ const finalPath = path
53
+ this.instance.post<T>(finalPath, json, { headers: headerParams }).then((response: ApiResponse<T>) => {
54
+ logger.resp(response)
55
+ logger.responseBody(response.data as Record<string, unknown>)
56
+ if (response.status && response.status >= 200 && response.status <= 299) {
57
+ const apiResponse = new APIResponse<T>(response.status, response.headers, response.data)
58
+ resolve(apiResponse)
59
+ } else {
60
+ const apiErrorResponse = new APIResponse<T>(response.status ? response.status : -1, response.headers, response.data)
61
+ resolve(apiErrorResponse)
62
+ }
63
+ })
64
+ .catch((error: AxiosError|Error) => {
65
+ const axiosErrorResponse = error.hasOwnProperty('response') ? (error as AxiosError<T>).response : undefined
66
+ if (axiosErrorResponse !== undefined) {
67
+ const errorResponse = new APIResponse<T>(axiosErrorResponse.status, axiosErrorResponse.headers, axiosErrorResponse.data, error)
68
+ resolve(errorResponse)
69
+ } else {
70
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
71
+ }
72
+ })
73
+ })
74
+ }
75
+ }
76
+
@@ -0,0 +1,80 @@
1
+ import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios'
2
+
3
+ import logger from '../common/logger'
4
+ import AbstractClient from './AbstractClient'
5
+ import APIResponse from './ApiResponse'
6
+ import { API } from './config'
7
+ import { INetClient } from './interfaces/INetClient'
8
+
9
+ class AxiosClient extends AbstractClient<AxiosInstance> implements INetClient {
10
+ constructor(endpoint: string) {
11
+ super(endpoint)
12
+ }
13
+
14
+ createInstance(): AxiosInstance {
15
+ return axios.create({
16
+ baseURL: this.endpoint,
17
+ timeout: API.Timeout,
18
+ })
19
+ }
20
+
21
+ public get<T>(path: string, params: Record<string, unknown>, headerParams: Record<string, string>): Promise<APIResponse<T>> {
22
+ return new Promise<APIResponse<T>>((resolve) => {
23
+ const paramString = this.paramsToQueryString(params)
24
+ const finalPath = path + (paramString.length > 0 ? `?${paramString}` : '')
25
+ logger.request('GET', headerParams, finalPath)
26
+ this.instance.get<T>(finalPath, { headers: headerParams }).then((response: AxiosResponse<T>) => {
27
+ logger.resp(response)
28
+ // logger.responseBody(response.data as Record<string, unknown>)
29
+ if (response.status >= 200 && response.status <= 299) {
30
+ const apiResponse = new APIResponse<T>(response.status, response.headers as Record<string, unknown>, response.data)
31
+ resolve(apiResponse)
32
+ } else {
33
+ const apiErrorResponse = new APIResponse<T>(response.status, response.headers as Record<string, unknown>, response.data)
34
+ resolve(apiErrorResponse)
35
+ }
36
+ })
37
+ .catch((error: AxiosError<T>|Error) => {
38
+ logger.log('request error', error)
39
+ const axiosErrorResponse:AxiosResponse<T>|undefined = error.hasOwnProperty('response') ? (error as AxiosError<T>).response : undefined
40
+
41
+ logger.log('request axiosErrorResponse', axiosErrorResponse)
42
+ if (axiosErrorResponse !== undefined) {
43
+ const errorResponse = new APIResponse<T>(axiosErrorResponse.status, axiosErrorResponse.headers as Record<string, unknown>, axiosErrorResponse.data, error)
44
+ resolve(errorResponse)
45
+ } else {
46
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
47
+ }
48
+ })
49
+ })
50
+ }
51
+
52
+ public postJson<T>(path: string, json: Record<string, unknown>, headerParams: Record<string, string>): Promise<APIResponse<T>> {
53
+ return new Promise<APIResponse<T>>((resolve) => {
54
+ const finalPath = path
55
+ logger.request('POST', headerParams, finalPath)
56
+ this.instance.post<T>(finalPath, json, { headers: headerParams }).then((response: AxiosResponse<T>) => {
57
+ logger.resp(response)
58
+ // logger.responseBody(response.data as Record<string, unknown>)
59
+ if (response.status >= 200 && response.status <= 299) {
60
+ const apiResponse = new APIResponse<T>(response.status, response.headers as Record<string, unknown>, response.data)
61
+ resolve(apiResponse)
62
+ } else {
63
+ const apiErrorResponse = new APIResponse<T>(response.status, response.headers as Record<string, unknown>, response.data)
64
+ resolve(apiErrorResponse)
65
+ }
66
+ })
67
+ .catch((error: AxiosError<T>|Error) => {
68
+ const axiosErrorResponse: AxiosResponse<T>|undefined = error.hasOwnProperty('response') ? (error as AxiosError<T>).response : undefined
69
+ if (axiosErrorResponse !== undefined) {
70
+ const errorResponse = new APIResponse<T>(axiosErrorResponse.status, axiosErrorResponse.headers as Record<string, unknown>, axiosErrorResponse.data, error)
71
+ resolve(errorResponse)
72
+ } else {
73
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
74
+ }
75
+ })
76
+ })
77
+ }
78
+ }
79
+
80
+ export default AxiosClient
@@ -0,0 +1,120 @@
1
+ import logger from '../common/logger'
2
+ import Timeout from '../common/Timeout'
3
+ import AbstractClient from './AbstractClient'
4
+ import APIResponse from './ApiResponse'
5
+ import { API } from './config'
6
+
7
+ export interface IFetchNetClientInstance {
8
+ create: () => void
9
+ }
10
+
11
+ export default class FetchNetClient extends AbstractClient<IFetchNetClientInstance> {
12
+ constructor(endpoint: string) {
13
+ super(endpoint)
14
+ }
15
+
16
+ private _request = async (url: string, options: RequestInit): Promise<Response> => {
17
+ return fetch(url, options)
18
+ }
19
+
20
+ private _headersToRecord = (headers: Headers) => {
21
+ const result:Record<string, string> = {}
22
+ headers.forEach((k: string, v: string) => {
23
+ Object.assign(result, { [k]: v })
24
+ })
25
+
26
+ return result
27
+ }
28
+
29
+ private _fetchWithTimeout = async (path: string, options: RequestInit, timeout = API.Timeout): Promise<Response> => {
30
+ const timeoutObj = new Timeout<Response>({ ms: timeout })
31
+
32
+ return new Promise((resolve, reject) => {
33
+
34
+ Promise
35
+ .race([
36
+ this._request(path, options),
37
+ timeoutObj.start(),
38
+ ])
39
+ .then((success: Response) => {
40
+ timeoutObj.clear()
41
+ // handle response
42
+ resolve(success)
43
+ }, (error: any) => {
44
+ timeoutObj.clear()
45
+ // handle error
46
+ reject(error)
47
+ })
48
+ })
49
+ }
50
+
51
+ createInstance(): IFetchNetClientInstance {
52
+ return {
53
+ create: () => {
54
+ // TODO:
55
+ },
56
+ }
57
+ }
58
+
59
+ /**
60
+ * REST - GET
61
+ *
62
+ * @param path API Path
63
+ * @param params Query Param
64
+ * @param header API Header
65
+ */
66
+ public get<T>(path: string, params: Record<string, any>, headerParams: Record<string, string>):Promise<APIResponse<T>> {
67
+ return new Promise<APIResponse<T>>((resolve) => {
68
+ let paramString = '?' + this.paramsToQueryString(params)
69
+ if (paramString.startsWith('&')) paramString = paramString.substring(1)
70
+ if (paramString !== '') paramString = '?' + paramString
71
+ const finalPath = path + paramString
72
+
73
+ logger.request('GET', headerParams, finalPath)
74
+ void this._fetchWithTimeout(finalPath, {
75
+ method: 'GET',
76
+ headers: headerParams,
77
+ })
78
+ .then(async (response) => {
79
+ logger.resp(response)
80
+ const headers = this._headersToRecord(response.headers)
81
+ const data: T = await response.json() as T
82
+
83
+ resolve(new APIResponse(response.status, headers, data))
84
+ })
85
+ .catch((error: Error) => {
86
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
87
+ })
88
+ })
89
+ }
90
+
91
+ /**
92
+ * REST - POST => [JSON Body]
93
+ *
94
+ * @param path API Path
95
+ * @param params Body in json format
96
+ * @param header API Header
97
+ */
98
+ public postJson<T>(path: string, json: Record<string, any>, headerParams: Record<string, string>): Promise<APIResponse<T>> {
99
+ return new Promise((resolve) => {
100
+ headerParams['Content-Type'] = 'application/json'
101
+ const jsonString = JSON.stringify(json)
102
+
103
+ logger.request('POST', headerParams, path, jsonString)
104
+ void this._fetchWithTimeout(path, {
105
+ method: 'POST',
106
+ headers: headerParams,
107
+ body: jsonString,
108
+ })
109
+ .then(async (response) => {
110
+ logger.resp(response)
111
+ const headers = this._headersToRecord(response.headers)
112
+ const data: T = await response.json() as T
113
+ resolve(new APIResponse<T>(response.status, headers, data))
114
+ })
115
+ .catch((error: Error) => {
116
+ resolve(new APIResponse<T>(-1, undefined, undefined, error))
117
+ })
118
+ })
119
+ }
120
+ }
@@ -0,0 +1,3 @@
1
+ export const API = {
2
+ Timeout: 6000,
3
+ }