@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,6 @@
1
+ import APIResponse from '../ApiResponse'
2
+
3
+ export interface INetClient {
4
+ get<T>(path: string, params: Record<string, any>, headerParams: Record<string, string>): Promise<APIResponse<T>>
5
+ postJson<T>(path: string, json: Record<string, any>, headerParams: Record<string, string>): Promise<APIResponse<T>>
6
+ }
@@ -0,0 +1,7 @@
1
+ export interface IStorage {
2
+ getItem: (key: string) => Promise<string | null>
3
+ setItem: (key: string, value: string) => Promise<boolean>
4
+ removeItem: (key: string) => Promise<void>
5
+ getAllKeys: () => Promise<string[]>
6
+ clear: () => Promise<void>
7
+ }
@@ -0,0 +1,41 @@
1
+ import { MMKV } from 'react-native-mmkv'
2
+
3
+ import { IStorage } from '@/infrastructures/Storage/IStorage'
4
+
5
+ const storage = new MMKV()
6
+
7
+ export class MMKVStorage implements IStorage {
8
+ getItem = async (key: string) => {
9
+ const value = storage.getString(key)
10
+
11
+ return Promise.resolve(value ?? null)
12
+ }
13
+
14
+ setItem = async (key: string, value: string) => {
15
+ return new Promise<boolean>((resolve) => {
16
+ storage.set(key, value)
17
+
18
+ return resolve(true)
19
+ })
20
+ }
21
+
22
+ removeItem = async (key: string) => {
23
+ storage.delete(key)
24
+
25
+ return Promise.resolve()
26
+ }
27
+
28
+ getAllKeys = async () => {
29
+ const value = storage.getAllKeys()
30
+
31
+ return Promise.resolve(value)
32
+ }
33
+
34
+ clear = async () => {
35
+ storage.clearAll()
36
+
37
+ return Promise.resolve()
38
+ }
39
+ }
40
+
41
+ export { storage }
@@ -0,0 +1,27 @@
1
+ class Timeout<T> {
2
+ timeout: number
3
+ timeoutID: NodeJS.Timeout|undefined
4
+ constructor(config: { ms?: number } = {}) {
5
+ this.timeout = config.ms || 10000
6
+ this.timeoutID = undefined
7
+ }
8
+
9
+ public start() {
10
+ return new Promise<T>((resolve, reject) => {
11
+ this.timeoutID = setTimeout(() => {
12
+ reject('timeout')
13
+ // this.clear();
14
+ }, this.timeout)
15
+ })
16
+ }
17
+
18
+ public clear() {
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
20
+ if (this.timeoutID !== undefined) {
21
+ clearTimeout(this.timeoutID)
22
+ this.timeoutID = undefined
23
+ }
24
+ }
25
+ }
26
+
27
+ export default Timeout
@@ -0,0 +1,82 @@
1
+ import color from 'tinycolor2'
2
+
3
+ const hex2RGB = (hex: string): number[] => {
4
+ if (hex.charAt(0) === '#') {
5
+ hex = hex.substring(1)
6
+ }
7
+ if ((hex.length < 2) || (hex.length > 6)) {
8
+ return []
9
+ }
10
+ const values = hex.split('')
11
+ let r
12
+ let g
13
+ let b
14
+
15
+ if (hex.length === 2) {
16
+ r = parseInt(values[0].toString() + values[1].toString(), 16)
17
+ g = r
18
+ b = r
19
+ } else if (hex.length === 3) {
20
+ r = parseInt(values[0].toString() + values[0].toString(), 16)
21
+ g = parseInt(values[1].toString() + values[1].toString(), 16)
22
+ b = parseInt(values[2].toString() + values[2].toString(), 16)
23
+ } else if (hex.length === 6) {
24
+ r = parseInt(values[0].toString() + values[1].toString(), 16)
25
+ g = parseInt(values[2].toString() + values[3].toString(), 16)
26
+ b = parseInt(values[4].toString() + values[5].toString(), 16)
27
+ } else {
28
+ return []
29
+ }
30
+
31
+ return [r, g, b]
32
+ }
33
+
34
+ const hex2RGBColor = (hex: string, opacity: number = 1.0) => {
35
+ const rgb: number[] = hex2RGB(hex)
36
+ if (rgb.length === 3) {
37
+ return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`
38
+ }
39
+
40
+ return false
41
+ }
42
+
43
+ const isDark = ({ backgroundColor, dark }: {
44
+ dark?: boolean
45
+ backgroundColor?: string
46
+ }) => {
47
+ if (typeof dark === 'boolean') {
48
+ return dark
49
+ }
50
+
51
+ if (backgroundColor === 'transparent') {
52
+ return false
53
+ }
54
+
55
+ if (backgroundColor !== 'transparent') {
56
+ return !color(backgroundColor)
57
+ .isLight()
58
+ }
59
+
60
+ return false
61
+ }
62
+
63
+ const rgbToHex = (rgb: string, forceRemoveAlpha = false) => {
64
+ const rgbArray = rgb.split(',')
65
+ const r = parseInt(rgbArray[0].split('(')[1], 10)
66
+ const g = parseInt(rgbArray[1], 10)
67
+ const b = parseInt(rgbArray[2], 10)
68
+ const a = forceRemoveAlpha ? 1 : parseFloat(rgbArray[3])
69
+ const alpha = parseFloat(rgbArray[3])
70
+
71
+ return {
72
+ hex: color({ r, g, b }).toHex(),
73
+ alpha,
74
+ }
75
+ }
76
+
77
+ export {
78
+ hex2RGB,
79
+ hex2RGBColor,
80
+ isDark,
81
+ rgbToHex,
82
+ }
@@ -0,0 +1,39 @@
1
+ import moment from 'moment'
2
+
3
+ import { Locale } from '@/configs/constants/type'
4
+
5
+ const formatDate = (date: Date, format: string = 'YYYY-MM-DD HH:mm:ss') => {
6
+ const momentDate = moment(date)
7
+
8
+ return momentDate.format(format)
9
+ }
10
+
11
+ const parseDate = (dateText?: string, format: string = 'YYYY-MM-DD') => {
12
+ if (dateText === undefined) {
13
+ return undefined
14
+ }
15
+ const momentDate = moment(dateText, format)
16
+
17
+ return momentDate.toDate()
18
+ }
19
+
20
+
21
+ const convertDateTextObject = (dateText?: string, fromFormat: string = 'YYYY-MM-DD', lang: Locale = Locale.enUS, toEnMonthFormat = 'MMM') => {
22
+ if (dateText === undefined) {
23
+ return undefined
24
+ }
25
+ const momentDate = moment(dateText, fromFormat)
26
+ const monthFormat = lang === Locale.enUS ? toEnMonthFormat : 'M'
27
+
28
+ return {
29
+ year: momentDate.format('YYYY'),
30
+ month: momentDate.format(monthFormat),
31
+ day: momentDate.format('D'),
32
+ }
33
+ }
34
+
35
+ export {
36
+ convertDateTextObject,
37
+ formatDate,
38
+ parseDate,
39
+ }
@@ -0,0 +1,115 @@
1
+ /* eslint-disable @typescript-eslint/restrict-template-expressions */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
3
+ /* eslint-disable no-console */
4
+ import { REACT_APP_DEBUG } from '@env'
5
+ import { ApiResponse } from 'apisauce'
6
+ import { AxiosResponse } from 'axios'
7
+ import clc from 'cli-color'
8
+
9
+ import { ITypedMap } from '@/models'
10
+
11
+ import APIResponse from '../NetClient/ApiResponse'
12
+
13
+ const log = (message?: any, ...para: any[]) => {
14
+ if (REACT_APP_DEBUG === 'true') {
15
+ if (para === undefined || para === null || para.length === 0) {
16
+ console.log(`${clc.greenBright(message)}`)
17
+ } else if (para && para.length === 1) {
18
+ console.log(`${clc.greenBright(message)}`, para[0])
19
+ } else {
20
+ console.log(`${clc.greenBright(message)}`, para)
21
+ }
22
+ }
23
+ }
24
+ const debug = (message?: any, ...para: any[]): void => {
25
+ if (REACT_APP_DEBUG === 'true') {
26
+ if (para === undefined || para === null || para.length === 0) {
27
+ console.debug(`${clc.green(message)}`)
28
+ } else if (para && para.length === 1) {
29
+ console.debug(`${clc.green(message)}`, para[0])
30
+ } else {
31
+ console.debug(`${clc.green(message)}`, para)
32
+ }
33
+ }
34
+ }
35
+ const info = (message: string): void => {
36
+ if (REACT_APP_DEBUG === 'true') console.log(clc.greenBright(message))
37
+ }
38
+
39
+ const warn = (message: string): void => {
40
+ if (REACT_APP_DEBUG === 'true') console.log(clc.yellow(message))
41
+ }
42
+
43
+ const error = (message: string, errorObj?: any): void => {
44
+ if (REACT_APP_DEBUG === 'true') {
45
+ console.log(clc.red(message))
46
+ if (errorObj) {
47
+ console.log(errorObj)
48
+ }
49
+ }
50
+ }
51
+
52
+ const request = (method: string, headerParams: Record<string, unknown>, url: string, formBody?: string): void => {
53
+ if (REACT_APP_DEBUG === 'true') {
54
+ const bodyString = method !== 'GET' ? `${clc.greenBright('\nRequest [Body]')}${!formBody ? clc.greenBright(' <Empty>') : clc.greenBright(`\n${JSON.stringify(JSON.parse(formBody), [''], 2)}`)}` : ''
55
+ const requestSymbol = `${clc.greenBright('Request ==> ')}`
56
+
57
+ console.log(`\n
58
+ ${clc.blackBright('=============================< ')}${requestSymbol}${(clc.blackBright('>=================================\n'))}
59
+ ${clc.xterm(132)(`Request [Method]: ${method}`)}
60
+ ${clc.green(`Request [Url]: ${url}`)}
61
+ ${clc.cyan('Request [Header]')}${!headerParams ? clc.cyan(' <Empty>') : clc.cyan(`\n${JSON.stringify(headerParams, null, 2)}\n`)}${bodyString}
62
+ ${clc.blackBright('\n========================================================================')}
63
+ `)
64
+ }
65
+ }
66
+
67
+ const resp = (response: Response | AxiosResponse | ApiResponse<any>): void => {
68
+ if (REACT_APP_DEBUG === 'true') {
69
+ const responseSymbol = `${clc.greenBright('<== Response ')}`
70
+
71
+ const url = response instanceof Response ? response.url : response.config?.url
72
+
73
+ console.log(`\n
74
+ ${clc.blackBright('=============================< ')}${responseSymbol}${(clc.blackBright('>=================================\n'))}
75
+ ${clc.green(`Response [Url]: ${url}`)}
76
+ ${clc.yellow(`Response [Status Code]: ${response.status}`)}
77
+ ${clc.cyan('Response [Header]')}
78
+ ${clc.cyan(response.headers ? JSON.stringify(response.headers, null, 2) : '')} \n
79
+ ${clc.blackBright('========================================================================')}
80
+ `)
81
+ }
82
+ }
83
+
84
+ const responseBody = (respBody: Record<string, unknown>): void => {
85
+ if (REACT_APP_DEBUG === 'true') {
86
+ console.log(`\n
87
+ ${clc.greenBright('Response [Body]:')}
88
+ ${clc.greenBright(JSON.stringify(respBody, null, 2))} \n
89
+ ${clc.blackBright('========================================================================')}
90
+ `)
91
+ }
92
+ }
93
+
94
+ const object = (message: string, obj: Record<string, unknown> | ITypedMap<any>): void => {
95
+ if (REACT_APP_DEBUG === 'true') {
96
+ console.log(`\n
97
+ ${clc.blackBright('=============================< ')}${message}${(clc.blackBright('>=================================\n'))}
98
+ ${clc.greenBright(JSON.stringify(obj, null, 2))} \n
99
+ ${clc.blackBright('========================================================================')}
100
+ `)
101
+ }
102
+ }
103
+
104
+ export default {
105
+ log,
106
+ info,
107
+ debug,
108
+ warn,
109
+ error,
110
+ request,
111
+ resp,
112
+ responseBody,
113
+ object,
114
+ }
115
+
@@ -0,0 +1,26 @@
1
+ {
2
+ "app_name": "ProjectName",
3
+ "button": {
4
+ "cancel": "Cancel",
5
+ "choose": "Choose",
6
+ "confirm": "Confirm",
7
+ "done": "Done",
8
+ "edit": "Edit",
9
+ "learn_more": "Learn More",
10
+ "ok": "OK",
11
+ "redeem": "Redeem",
12
+ "reset": "Reset",
13
+ "retry": "Retry",
14
+ "show_more": "Show More",
15
+ "submit": "Submit",
16
+ "save": "Save"
17
+ },
18
+ "date_display": "{{day}} {{month}} {{year}}",
19
+ "loading": "Loading...",
20
+ "placeholder": {
21
+ "search": "Search"
22
+ },
23
+ "version": "App Version",
24
+ "version_string": "{{version_name}}",
25
+ "version_stringb": "{{version_name}} (Build {{build}})"
26
+ }
@@ -0,0 +1,9 @@
1
+ import * as general from './general.json'
2
+ import * as screens from './screens.json'
3
+ import * as setting from './setting.json'
4
+
5
+ export default {
6
+ general,
7
+ screens,
8
+ setting,
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "home": "Home",
3
+ "settings": "Settings"
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "language": "Language"
3
+ }
@@ -0,0 +1,109 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/naming-convention */
3
+ import 'intl-pluralrules'
4
+
5
+ import { REACT_APP_DEBUG as DEBUG } from '@env'
6
+ import AsyncStorage from '@react-native-async-storage/async-storage'
7
+ import i18n, { LanguageDetectorAsyncModule, Services } from 'i18next'
8
+ import { initReactI18next } from 'react-i18next'
9
+ import * as RNLocalize from 'react-native-localize'
10
+
11
+ import { Locale } from '@/configs/constants/type'
12
+ import { StorageKey } from '@/configs/constants/type/StorageKey.type'
13
+ import logger from '@/infrastructures/common/logger'
14
+
15
+ import en_US from './en-US/index'
16
+ // import zh_CN from './zh-CN/index'
17
+ import zh_TW from './zh-TW/index'
18
+
19
+ const i18nOptions: Record<any, any> = {
20
+ compatibilityJSON: 'v4',
21
+ lng: 'zh_TW',
22
+ fallbackLng: 'zh_TW',
23
+ debug: DEBUG === 'true',
24
+ keySeparator: '.',
25
+ nsSeparator: ':',
26
+ interpolation: { escapeValue: false }, // not needed for react as it escapes by default
27
+ resources: {
28
+ en_US: en_US,
29
+ // zh_CN: zh_CN,
30
+ zh_TW: zh_TW,
31
+ },
32
+ react: {
33
+ // wait: true,
34
+ useSuspense: true,
35
+ bindI18n: 'languageChanged loaded',
36
+ bindI18nStore: 'added removed',
37
+ nsMode: 'default',
38
+ },
39
+ }
40
+
41
+ export const findBestMatchedDeviceLanguage = (deviceLocale: string) => {
42
+ let appLang = Locale.enUS
43
+ switch (deviceLocale) {
44
+ case (new RegExp(/^en/).exec(deviceLocale) || {}).input:
45
+ appLang = Locale.enUS
46
+ break
47
+ case (new RegExp(/^zh-HK/).exec(deviceLocale) || new RegExp(/^zh-Hant/).exec(deviceLocale) || {}).input:
48
+ appLang = Locale.zhTW
49
+ break
50
+ // case (new RegExp(/^zh-CN/).exec(deviceLocale) || new RegExp(/^zh-Hans/).exec(deviceLocale) || {}).input:
51
+ // appLang = Locale.zhCN
52
+ // break
53
+ }
54
+
55
+ return appLang
56
+ }
57
+
58
+ const languageDetector: LanguageDetectorAsyncModule = {
59
+ type: 'languageDetector',
60
+ // If this is set to true, your detect function receives a callback function that you should call with your language,
61
+ // useful to retrieve your language stored in AsyncStorage for example
62
+ async: true,
63
+ init: (
64
+ _services: Services,
65
+ _detectorOptions: object,
66
+ _i18nextOptions: object,
67
+ ) => {
68
+ /* use services and options */
69
+ },
70
+ detect: (callback: (lng: string) => void) => {
71
+ void AsyncStorage.getItem(StorageKey.appLang)
72
+ .then((value: string | null) => {
73
+ if (value === undefined || value === null) {
74
+ const preferredLocale = RNLocalize.getLocales()[0]
75
+ const deviceLocale = preferredLocale.languageTag
76
+ const bestLng = findBestMatchedDeviceLanguage(deviceLocale)
77
+
78
+ logger.log('i18n detector bestLng', bestLng)
79
+ callback(bestLng)
80
+
81
+ return
82
+ } else {
83
+ logger.log('i18n detector AsyncStorage APP_LANG', value)
84
+ callback(value)
85
+
86
+ return
87
+ }
88
+ })
89
+ },
90
+ cacheUserLanguage: (lng: string) => {
91
+ void AsyncStorage.setItem(StorageKey.appLang, lng)
92
+ logger.log('i18n detector cacheUserLanguage', lng)
93
+
94
+ return
95
+ },
96
+ }
97
+
98
+ void i18n
99
+ .use(languageDetector)
100
+ .use(initReactI18next)
101
+ .init(i18nOptions)
102
+ .then(() => {
103
+ // init
104
+ })
105
+ .finally(() => {
106
+ // finally
107
+ })
108
+
109
+ export default i18n
@@ -0,0 +1,26 @@
1
+ {
2
+ "app_name": "ProjectName",
3
+ "button": {
4
+ "cancel": "取消",
5
+ "choose": "選擇",
6
+ "confirm": "確認",
7
+ "done": "完成",
8
+ "edit": "修改",
9
+ "learn_more": "查看詳情",
10
+ "ok": "好",
11
+ "redeem": "兌換",
12
+ "reset": "重設",
13
+ "retry": "重試",
14
+ "show_more": "顯示更多",
15
+ "submit": "提交",
16
+ "save": "儲存"
17
+ },
18
+ "date_display": "{{year}}年{{month}}月{{day}}日",
19
+ "loading": "載入中...",
20
+ "placeholder": {
21
+ "search": "搜尋"
22
+ },
23
+ "version": "版本",
24
+ "version_string": "{{version_name}}",
25
+ "version_stringb": "{{version_name}} (Build {{build}})"
26
+ }
@@ -0,0 +1,9 @@
1
+ import * as general from './general.json'
2
+ import * as screens from './screens.json'
3
+ import * as setting from './setting.json'
4
+
5
+ export default {
6
+ general,
7
+ screens,
8
+ setting,
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "home": "主頁",
3
+ "settings": "設定"
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "language": "語言"
3
+ }
@@ -0,0 +1,5 @@
1
+ import { List, Map } from 'immutable'
2
+
3
+ export interface ITypedMap<T> extends Map<string, any> {
4
+ get<I extends keyof T>(key: I & string): T[I]
5
+ }
@@ -0,0 +1,50 @@
1
+ import { SerializedError } from '@reduxjs/toolkit'
2
+ import { FetchBaseQueryError } from '@reduxjs/toolkit/query'
3
+
4
+ export interface IBaseResponse<T> {
5
+ timestamp: number
6
+ success: boolean
7
+ code: number
8
+ message: string
9
+ result: T
10
+ }
11
+
12
+ export interface IBaseRequestWithSign extends IBaseRequest {
13
+ noncr: number
14
+ timestamp: number
15
+ sign: string
16
+ }
17
+
18
+ export interface IBaseRequest {
19
+ language?: string
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ _ts?: number // use to refresh cache
22
+ }
23
+
24
+ export type IRequest<T> = T & IBaseRequest
25
+
26
+ type IPageable = {
27
+ pageIndex?: number
28
+ pageSize?: number
29
+ }
30
+ export type IPageableRequest<T> = IRequest<T> & IPageable
31
+
32
+ export type IResponseError = {
33
+ status: number
34
+ message: string
35
+ data: {
36
+ code: number
37
+ message: string
38
+ success: boolean
39
+ }
40
+ exception?: string
41
+ }
42
+
43
+ export type IUseFetchData<T> = {
44
+ isFetching: boolean
45
+ isLoading: boolean
46
+ isSuccess: boolean
47
+ refetch: () => any
48
+ data?: T
49
+ error: FetchBaseQueryError | SerializedError | undefined
50
+ }
@@ -0,0 +1,66 @@
1
+ import { DrawerContentComponentProps, DrawerContentScrollView, DrawerItemList } from '@react-navigation/drawer'
2
+ import React from 'react'
3
+ import { useTranslation } from 'react-i18next'
4
+ import { Linking, ScrollView, TouchableOpacity, View } from 'react-native'
5
+ import { Text } from 'react-native-paper'
6
+ import Icon from 'react-native-paper/src/components/Icon'
7
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
8
+
9
+ import { images } from '@/assets'
10
+ import { IconX, PressableOpacity } from '@/components/basic'
11
+ import useTheme from '@/hooks/useTheme'
12
+ import logger from '@/infrastructures/common/logger'
13
+ import { AppRoutes } from '@/navigators/types'
14
+
15
+ import DrawerItem from './DrawerItem'
16
+
17
+ const DrawerContent = (props: DrawerContentComponentProps) => {
18
+ const insets = useSafeAreaInsets()
19
+ const { Colors, Fonts, Gutters, Layout } = useTheme()
20
+ const { t } = useTranslation()
21
+
22
+ const { navigation, state } = props
23
+ const { index, routes } = state
24
+ const currentRouteName = routes[index].name
25
+
26
+ const gotoSettings = () => {
27
+ navigation.navigate(AppRoutes.SettingsScreen)
28
+ navigation.closeDrawer()
29
+ }
30
+
31
+ const navigateTo = (routeName: string) => {
32
+ navigation.navigate(routeName)
33
+ navigation.closeDrawer()
34
+ }
35
+
36
+ const closeDrawer = () => {
37
+ navigation.closeDrawer()
38
+ }
39
+
40
+ return (
41
+ <DrawerContentScrollView {...props}>
42
+ {/* <DrawerItemList {...props}/> */}
43
+ <View
44
+ style={[Layout.row, Layout.fill, Layout.justifyContentEnd, Gutters.smallHPadding]}
45
+ >
46
+ {/* <Icon size={40} source={images.menu_settings} /> */}
47
+ <PressableOpacity onPress={closeDrawer}>
48
+ <IconX size={40} color={Colors.text} origin={IconX.ANT_DESIGN} name="close" />
49
+ </PressableOpacity>
50
+ </View>
51
+ <DrawerItem
52
+ label={({ color, focused }) => <Text style={[{ color }]}>{`${t('screens:home')}`}</Text>}
53
+ icon={({ color, focused, size }) => <IconX size={40} color={color} origin={IconX.ANT_DESIGN} name={'home'} />}
54
+ // labelStyle={[Fonts.drawerItem, { color: currentRouteName === AppRoutes.DrawerMain ? Colors.primary : Colors.text }]}
55
+ focused={currentRouteName === `${AppRoutes.MainBottomTabNav}`}
56
+ activeTintColor={Colors.primary}
57
+ inactiveTintColor={Colors.text}
58
+ activeBackgroundColor={Colors.transparent}
59
+ onPress={() => navigateTo(AppRoutes.MainBottomTabNav)}
60
+ />
61
+ </DrawerContentScrollView>
62
+ )
63
+
64
+ }
65
+
66
+ export default DrawerContent