@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.
- package/.github/workflows/npm-publish.yml +28 -0
- package/.vscode/settings.json +15 -0
- package/README.md +58 -0
- package/package.json +16 -0
- package/template/.bundle/config +2 -0
- package/template/.env.development +1 -0
- package/template/.env.production +1 -0
- package/template/.eslintrc.js +392 -0
- package/template/.java-version +1 -0
- package/template/.prettierrc.js +5 -0
- package/template/.ruby-version +1 -0
- package/template/.watchmanconfig +1 -0
- package/template/Gemfile +23 -0
- package/template/Gemfile.lock +330 -0
- package/template/README.md +97 -0
- package/template/ReactotronConfig.js +17 -0
- package/template/__tests__/App.test.tsx +13 -0
- package/template/_gitignore +75 -0
- package/template/_node-version +1 -0
- package/template/android/app/build.gradle +162 -0
- package/template/android/app/debug.keystore +0 -0
- package/template/android/app/proguard-rules.pro +10 -0
- package/template/android/app/src/debug/AndroidManifest.xml +9 -0
- package/template/android/app/src/main/AndroidManifest.xml +26 -0
- package/template/android/app/src/main/java/com/projectname/MainActivity.kt +30 -0
- package/template/android/app/src/main/java/com/projectname/MainApplication.kt +27 -0
- package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/values/strings.xml +3 -0
- package/template/android/app/src/main/res/values/styles.xml +9 -0
- package/template/android/build.gradle +37 -0
- package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/template/android/gradle.properties +48 -0
- package/template/android/gradlew +251 -0
- package/template/android/gradlew.bat +99 -0
- package/template/android/keystore/keystore.properties +4 -0
- package/template/android/settings.gradle +6 -0
- package/template/android/version.properties +2 -0
- package/template/app.json +4 -0
- package/template/babel.config.js +38 -0
- package/template/fastlane/Fastfile +136 -0
- package/template/fastlane/Pluginfile +9 -0
- package/template/fastlane/README.md +46 -0
- package/template/index.js +9 -0
- package/template/ios/.xcode.env +11 -0
- package/template/ios/Podfile +35 -0
- package/template/ios/Podfile.lock +3669 -0
- package/template/ios/ProjectName/AppDelegate.swift +48 -0
- package/template/ios/ProjectName/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/template/ios/ProjectName/Images.xcassets/Contents.json +6 -0
- package/template/ios/ProjectName/Info.plist +66 -0
- package/template/ios/ProjectName/LaunchScreen.storyboard +47 -0
- package/template/ios/ProjectName/PrivacyInfo.xcprivacy +47 -0
- package/template/ios/ProjectName.xcodeproj/project.pbxproj +482 -0
- package/template/ios/ProjectName.xcodeproj/xcshareddata/xcschemes/ProjectName.xcscheme +88 -0
- package/template/ios/ProjectName.xcworkspace/contents.xcworkspacedata +10 -0
- package/template/jest.config.js +3 -0
- package/template/metro.config.js +20 -0
- package/template/package-lock.json +17073 -0
- package/template/package.json +156 -0
- package/template/src/@types/emotion.d.ts +12 -0
- package/template/src/@types/env.d.ts +3 -0
- package/template/src/@types/redux-persist-transform-immutable.d.ts +1 -0
- package/template/src/@types/typing.d.ts +17 -0
- package/template/src/AppContainer.tsx +109 -0
- package/template/src/assets/images/143.png +0 -0
- package/template/src/assets/index.ts +13 -0
- package/template/src/components/basic/BackButton/index.tsx +34 -0
- package/template/src/components/basic/Body/index.tsx +68 -0
- package/template/src/components/basic/Button/index.tsx +181 -0
- package/template/src/components/basic/Button/utils.ts +78 -0
- package/template/src/components/basic/ButtonGroup/index.tsx +182 -0
- package/template/src/components/basic/Card/index.tsx +3 -0
- package/template/src/components/basic/Container/index.tsx +38 -0
- package/template/src/components/basic/Content/index.tsx +87 -0
- package/template/src/components/basic/DropDown/index.tsx +354 -0
- package/template/src/components/basic/ExpandableOverlay/index.tsx +113 -0
- package/template/src/components/basic/Header/index.tsx +216 -0
- package/template/src/components/basic/Header/styles.ts +0 -0
- package/template/src/components/basic/Icons/index.tsx +131 -0
- package/template/src/components/basic/InputLabel/index.tsx +19 -0
- package/template/src/components/basic/LoadingOverlay/index.tsx +68 -0
- package/template/src/components/basic/MaterialTextInput/index.tsx +153 -0
- package/template/src/components/basic/NumberInput/index.tsx +53 -0
- package/template/src/components/basic/Picker/PickerContext.ts +7 -0
- package/template/src/components/basic/Picker/PickerHeader.tsx +130 -0
- package/template/src/components/basic/Picker/PickerItem.tsx +105 -0
- package/template/src/components/basic/Picker/PickerItemsList.tsx +135 -0
- package/template/src/components/basic/Picker/PickerPresenter.ts +54 -0
- package/template/src/components/basic/Picker/hooks/useImperativePickerHandle.ts +27 -0
- package/template/src/components/basic/Picker/hooks/usePickerLabel.ts +74 -0
- package/template/src/components/basic/Picker/hooks/usePickerSearch.ts +37 -0
- package/template/src/components/basic/Picker/hooks/usePickerSelection.ts +57 -0
- package/template/src/components/basic/Picker/index.tsx +284 -0
- package/template/src/components/basic/Picker/types.tsx +229 -0
- package/template/src/components/basic/PressableOpacity/index.tsx +20 -0
- package/template/src/components/basic/RootDialog/Dialog.tsx +246 -0
- package/template/src/components/basic/RootDialog/Manager.tsx +110 -0
- package/template/src/components/basic/RootDialog/animations/Animation.ts +29 -0
- package/template/src/components/basic/RootDialog/animations/FadeAnimation.ts +40 -0
- package/template/src/components/basic/RootDialog/animations/ScaleAnimation.ts +37 -0
- package/template/src/components/basic/RootDialog/animations/SlideAnimation.ts +89 -0
- package/template/src/components/basic/RootDialog/components/Backdrop.tsx +60 -0
- package/template/src/components/basic/RootDialog/components/BaseDialog.tsx +564 -0
- package/template/src/components/basic/RootDialog/components/BottomDialog.tsx +32 -0
- package/template/src/components/basic/RootDialog/components/DialogButton.tsx +87 -0
- package/template/src/components/basic/RootDialog/components/DialogContent.tsx +26 -0
- package/template/src/components/basic/RootDialog/components/DialogContext.tsx +8 -0
- package/template/src/components/basic/RootDialog/components/DialogFooter.tsx +42 -0
- package/template/src/components/basic/RootDialog/components/DialogTitle.tsx +53 -0
- package/template/src/components/basic/RootDialog/components/DraggableView.tsx +271 -0
- package/template/src/components/basic/RootDialog/index.ts +21 -0
- package/template/src/components/basic/RootDialog/type.ts +102 -0
- package/template/src/components/basic/Text/index.tsx +8 -0
- package/template/src/components/basic/index.ts +35 -0
- package/template/src/configs/constants/type/APIStatus.type.ts +8 -0
- package/template/src/configs/constants/type/Locale.type.ts +7 -0
- package/template/src/configs/constants/type/StorageKey.type.ts +7 -0
- package/template/src/configs/constants/type/ThemeType.type.ts +6 -0
- package/template/src/configs/constants/type/index.ts +11 -0
- package/template/src/configs/index.ts +22 -0
- package/template/src/contexts/ThemeContext.ts +6 -0
- package/template/src/hooks/useAppLoading.ts +26 -0
- package/template/src/hooks/useAppState.ts +36 -0
- package/template/src/hooks/useArray.ts +47 -0
- package/template/src/hooks/useAsync.ts +42 -0
- package/template/src/hooks/useAsyncStorage.ts +41 -0
- package/template/src/hooks/useBoolean.ts +21 -0
- package/template/src/hooks/useBuildTheme.ts +249 -0
- package/template/src/hooks/useCountDown.ts +111 -0
- package/template/src/hooks/useCounter.ts +27 -0
- package/template/src/hooks/useDebounce.ts +25 -0
- package/template/src/hooks/useDebouncedValidate.ts +32 -0
- package/template/src/hooks/useDebugInformation.ts +38 -0
- package/template/src/hooks/useDeviceToken.ts +20 -0
- package/template/src/hooks/useEncryptedStorage.ts +41 -0
- package/template/src/hooks/useFontFamily.ts +13 -0
- package/template/src/hooks/useHttp.ts +18 -0
- package/template/src/hooks/useInterval.ts +24 -0
- package/template/src/hooks/useIsForeground.ts +17 -0
- package/template/src/hooks/useMMKVStorage.ts +0 -0
- package/template/src/hooks/usePrevious.ts +12 -0
- package/template/src/hooks/useRenderCount.ts +10 -0
- package/template/src/hooks/useTheme.ts +17 -0
- package/template/src/hooks/useTimeCountDown.ts +91 -0
- package/template/src/index.tsx +65 -0
- package/template/src/infrastructures/NetClient/AbstractClient.ts +66 -0
- package/template/src/infrastructures/NetClient/ApiResponse.ts +16 -0
- package/template/src/infrastructures/NetClient/ApisauceClient.ts +76 -0
- package/template/src/infrastructures/NetClient/AxiosClient.ts +80 -0
- package/template/src/infrastructures/NetClient/FetchNetClient.ts +120 -0
- package/template/src/infrastructures/NetClient/config.ts +3 -0
- package/template/src/infrastructures/NetClient/interfaces/INetClient.ts +6 -0
- package/template/src/infrastructures/Storage/IStorage.ts +7 -0
- package/template/src/infrastructures/Storage/MMKVStorage.ts +41 -0
- package/template/src/infrastructures/common/Timeout.ts +27 -0
- package/template/src/infrastructures/common/colorUtils.ts +82 -0
- package/template/src/infrastructures/common/dateUtils.ts +39 -0
- package/template/src/infrastructures/common/logger.ts +115 -0
- package/template/src/locales/en-US/general.json +26 -0
- package/template/src/locales/en-US/index.ts +9 -0
- package/template/src/locales/en-US/screens.json +4 -0
- package/template/src/locales/en-US/setting.json +3 -0
- package/template/src/locales/i18n.ts +109 -0
- package/template/src/locales/zh-TW/general.json +26 -0
- package/template/src/locales/zh-TW/index.ts +9 -0
- package/template/src/locales/zh-TW/screens.json +4 -0
- package/template/src/locales/zh-TW/setting.json +3 -0
- package/template/src/models/index.ts +5 -0
- package/template/src/models/request.model.ts +50 -0
- package/template/src/navigators/DrawerNav/DrawerContent.tsx +66 -0
- package/template/src/navigators/DrawerNav/DrawerItem.tsx +261 -0
- package/template/src/navigators/DrawerNav/index.tsx +39 -0
- package/template/src/navigators/DrawerNav/props.ts +12 -0
- package/template/src/navigators/DrawerNav/types.ts +8 -0
- package/template/src/navigators/MainBottomTabNav/index.tsx +83 -0
- package/template/src/navigators/MainBottomTabNav/props.ts +16 -0
- package/template/src/navigators/MainBottomTabNav/types.ts +6 -0
- package/template/src/navigators/RootStack.tsx +43 -0
- package/template/src/navigators/index.tsx +40 -0
- package/template/src/navigators/props.ts +14 -0
- package/template/src/navigators/types.ts +18 -0
- package/template/src/navigators/utils.ts +68 -0
- package/template/src/redux/api/api.ts +41 -0
- package/template/src/redux/reducers/appSlice.ts +26 -0
- package/template/src/redux/reducers/index.ts +21 -0
- package/template/src/redux/reducers/nonPersistSlice.ts +51 -0
- package/template/src/redux/reducers/settingSlice.ts +48 -0
- package/template/src/redux/reducers/themeSlice.ts +55 -0
- package/template/src/redux/saga/index.ts +5 -0
- package/template/src/redux/saga/settingSaga.ts +21 -0
- package/template/src/redux/selectors/app.ts +9 -0
- package/template/src/redux/selectors/nonPersist.ts +23 -0
- package/template/src/redux/selectors/setting.ts +29 -0
- package/template/src/redux/selectors/theme.ts +13 -0
- package/template/src/redux/store/index.ts +79 -0
- package/template/src/redux/store/types.d.ts +5 -0
- package/template/src/screens/Home/index.tsx +146 -0
- package/template/src/screens/Settings/components/Item.tsx +45 -0
- package/template/src/screens/Settings/index.tsx +97 -0
- package/template/src/screens/Splash/index.tsx +53 -0
- package/template/src/services/Dialogs.tsx +226 -0
- package/template/src/services/PermissionCheck.ts +257 -0
- package/template/src/theme/Common.ts +48 -0
- package/template/src/theme/Fonts.ts +196 -0
- package/template/src/theme/Gutters.ts +63 -0
- package/template/src/theme/Icons.ts +28 -0
- package/template/src/theme/Images.ts +13 -0
- package/template/src/theme/Layout.ts +106 -0
- package/template/src/theme/Variables.ts +167 -0
- package/template/src/theme/components/Buttons.ts +37 -0
- package/template/src/theme/index.ts +8 -0
- package/template/src/theme/metrics.ts +57 -0
- package/template/src/theme/themes/default_dark/Images.ts +7 -0
- package/template/src/theme/themes/default_dark/Variables.ts +84 -0
- package/template/src/theme/themes/default_dark/index.ts +2 -0
- package/template/src/theme/themes/index.ts +8 -0
- package/template/src/theme/types.ts +152 -0
- package/template/src/utils/encrypt-helper.ts +118 -0
- package/template/src/utils/index.ts +76 -0
- package/template/src/utils/sys-info-data.ts +17 -0
- package/template/tsconfig.json +44 -0
- package/template.config.js +8 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
type GetIdFunc<T> = (item: T) => string|number
|
|
4
|
+
const useArray = <T>(defaultValue: T[] = [], getId?: GetIdFunc<T>|undefined) => {
|
|
5
|
+
const [array, setArray] = useState(defaultValue)
|
|
6
|
+
|
|
7
|
+
const removeByIndex = (index: number) => {
|
|
8
|
+
const copy = [...array]
|
|
9
|
+
copy.splice(index, 1)
|
|
10
|
+
setArray(copy)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
array,
|
|
15
|
+
set: setArray,
|
|
16
|
+
add: (item: any, index?: number) => {
|
|
17
|
+
if (index === undefined) {
|
|
18
|
+
setArray([...array, item])
|
|
19
|
+
} else {
|
|
20
|
+
setArray(a => {
|
|
21
|
+
return [
|
|
22
|
+
...a.slice(0, index),
|
|
23
|
+
item,
|
|
24
|
+
...a.slice(index + 1, a.length),
|
|
25
|
+
] as T[]
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
clear: () => setArray([]),
|
|
30
|
+
filter: (fn: (item: T) => boolean) => {
|
|
31
|
+
setArray(defaultValue.filter(fn))
|
|
32
|
+
},
|
|
33
|
+
reset: () => setArray([...defaultValue]),
|
|
34
|
+
remove: removeByIndex,
|
|
35
|
+
removeById: (id: string|number) => {
|
|
36
|
+
if (getId === undefined) {
|
|
37
|
+
throw new Error('getId is undefined')
|
|
38
|
+
}
|
|
39
|
+
const index = array.findIndex(item => getId(item) === id)
|
|
40
|
+
if (index !== -1) {
|
|
41
|
+
removeByIndex(index)
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default useArray
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
const useAsync = <T, E = string>(
|
|
4
|
+
asyncFunction: () => Promise<T>,
|
|
5
|
+
immediate = true
|
|
6
|
+
) => {
|
|
7
|
+
const [status, setStatus] = useState<
|
|
8
|
+
'idle' | 'pending' | 'success' | 'error'
|
|
9
|
+
>('idle')
|
|
10
|
+
const [value, setValue] = useState<T | null>(null)
|
|
11
|
+
const [error, setError] = useState<E | null>(null)
|
|
12
|
+
// The execute function wraps asyncFunction and
|
|
13
|
+
// handles setting state for pending, value, and error.
|
|
14
|
+
// useCallback ensures the below useEffect is not called
|
|
15
|
+
// on every render, but only if asyncFunction changes.
|
|
16
|
+
const execute = useCallback(() => {
|
|
17
|
+
setStatus('pending')
|
|
18
|
+
setValue(null)
|
|
19
|
+
setError(null)
|
|
20
|
+
|
|
21
|
+
return asyncFunction()
|
|
22
|
+
.then((response: any) => {
|
|
23
|
+
setValue(response)
|
|
24
|
+
setStatus('success')
|
|
25
|
+
})
|
|
26
|
+
.catch((asyncError: any) => {
|
|
27
|
+
setError(asyncError)
|
|
28
|
+
setStatus('error')
|
|
29
|
+
})
|
|
30
|
+
}, [asyncFunction])
|
|
31
|
+
// Call execute if we want to fire it right away.
|
|
32
|
+
// Otherwise, execute can be called later, such as
|
|
33
|
+
// in an onClick handler.
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (immediate) {
|
|
36
|
+
void execute()
|
|
37
|
+
}
|
|
38
|
+
}, [execute, immediate])
|
|
39
|
+
|
|
40
|
+
return { execute, status, value, error }
|
|
41
|
+
}
|
|
42
|
+
export default useAsync
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
2
|
+
import { MutableRefObject, useEffect } from 'react'
|
|
3
|
+
import useState from 'react-usestateref'
|
|
4
|
+
|
|
5
|
+
import logger from '@/infrastructures/common/logger'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const useAsyncStorage = <T = string>(key: string, initialValue: T): [data: T, setNewData: (value: any) => Promise<void>, retrivedFromStorage: boolean, dataRef: MutableRefObject<T>] => {
|
|
9
|
+
const [data, setData, dataRef] = useState(initialValue)
|
|
10
|
+
const [retrievedFromStorage, setRetrievedFromStorage] = useState(false)
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const init = async () => {
|
|
14
|
+
try {
|
|
15
|
+
const value = await AsyncStorage.getItem(key)
|
|
16
|
+
if (typeof value === 'string') {
|
|
17
|
+
setData((JSON.parse(value) as T) || initialValue)
|
|
18
|
+
} else {
|
|
19
|
+
setData(initialValue)
|
|
20
|
+
}
|
|
21
|
+
setRetrievedFromStorage(true)
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// console.error('useAsyncStorage getItem error:', error)
|
|
24
|
+
logger.error('useAsyncStorage getItem error:', error)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
void init()
|
|
28
|
+
}, [key, initialValue])
|
|
29
|
+
|
|
30
|
+
const setNewData = async (value: T) => {
|
|
31
|
+
try {
|
|
32
|
+
await AsyncStorage.setItem(key, JSON.stringify(value))
|
|
33
|
+
setData(value)
|
|
34
|
+
} catch (error) {
|
|
35
|
+
logger.error('useAsyncStorage setItem error:', error)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return [data, setNewData, retrievedFromStorage, dataRef]
|
|
40
|
+
}
|
|
41
|
+
export default useAsyncStorage
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Dispatch, SetStateAction, useCallback, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
type UseBooleanOutput = {
|
|
4
|
+
value: boolean
|
|
5
|
+
setValue: Dispatch<SetStateAction<boolean>>
|
|
6
|
+
setTrue: () => void
|
|
7
|
+
setFalse: () => void
|
|
8
|
+
toggle: () => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const useBoolean = (defaultValue?: boolean): UseBooleanOutput => {
|
|
12
|
+
const [value, setValue] = useState(!!defaultValue)
|
|
13
|
+
|
|
14
|
+
const setTrue = useCallback(() => setValue(true), [])
|
|
15
|
+
const setFalse = useCallback(() => setValue(false), [])
|
|
16
|
+
const toggle = useCallback(() => setValue(x => !x), [])
|
|
17
|
+
|
|
18
|
+
return { value, setValue, setTrue, setFalse, toggle }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default useBoolean
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { DarkTheme as NavigationDarkTheme, DefaultTheme as NavigationDefaultTheme, Theme as NavigationThemeType } from '@react-navigation/native'
|
|
2
|
+
import merge from 'deepmerge'
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
|
+
import { useColorScheme } from 'react-native'
|
|
5
|
+
import { adaptNavigationTheme, configureFonts, DefaultTheme as PaperDefaultTheme, MD3DarkTheme as PaperDarkTheme } from 'react-native-paper'
|
|
6
|
+
import { useSelector } from 'react-redux'
|
|
7
|
+
|
|
8
|
+
import { Locale } from '@/configs/constants/type'
|
|
9
|
+
import { ThemeState } from '@/redux/reducers/themeSlice'
|
|
10
|
+
import { selectLocale } from '@/redux/selectors/setting'
|
|
11
|
+
import {
|
|
12
|
+
Common,
|
|
13
|
+
DefaultVariables,
|
|
14
|
+
Fonts,
|
|
15
|
+
Gutters,
|
|
16
|
+
Images,
|
|
17
|
+
Layout,
|
|
18
|
+
themes,
|
|
19
|
+
} from '@/theme'
|
|
20
|
+
import Icons from '@/theme/Icons'
|
|
21
|
+
import {
|
|
22
|
+
CustomPaperThemeType,
|
|
23
|
+
FontScale,
|
|
24
|
+
MD3Fonts,
|
|
25
|
+
Theme,
|
|
26
|
+
ThemeCommon,
|
|
27
|
+
ThemeFonts,
|
|
28
|
+
ThemeNavigationColors,
|
|
29
|
+
ThemeNavigationFonts,
|
|
30
|
+
ThemeNavigationTheme,
|
|
31
|
+
ThemeNavigationThemeWithOwn,
|
|
32
|
+
ThemeVariables,
|
|
33
|
+
} from '@/theme/types'
|
|
34
|
+
|
|
35
|
+
const { DarkTheme, LightTheme } = adaptNavigationTheme({
|
|
36
|
+
reactNavigationLight: NavigationDefaultTheme,
|
|
37
|
+
reactNavigationDark: NavigationDarkTheme,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const CombinedDefaultTheme = merge(PaperDefaultTheme, LightTheme)
|
|
41
|
+
const CombinedDarkTheme = merge(PaperDarkTheme, DarkTheme)
|
|
42
|
+
|
|
43
|
+
const useBuildTheme = () => {
|
|
44
|
+
const colorScheme = useColorScheme()
|
|
45
|
+
|
|
46
|
+
// Get current theme from the store
|
|
47
|
+
const currentTheme = useSelector(
|
|
48
|
+
(state: { theme: ThemeState }) => state.theme.theme || 'default',
|
|
49
|
+
)
|
|
50
|
+
const isDark = useSelector(
|
|
51
|
+
(state: { theme: ThemeState }) => state.theme.darkMode,
|
|
52
|
+
)
|
|
53
|
+
const darkMode = useMemo(() => {
|
|
54
|
+
// use system color scheme if isDark is null
|
|
55
|
+
return isDark === null ? colorScheme === 'dark' : isDark
|
|
56
|
+
}, [colorScheme, isDark])
|
|
57
|
+
const fontScaleType = useSelector(
|
|
58
|
+
(state: { theme: ThemeState }) => state.theme.fontScale,
|
|
59
|
+
)
|
|
60
|
+
const fontScale = FontScale[fontScaleType || 'MEDIUM']
|
|
61
|
+
|
|
62
|
+
const createTheme = useCallback((): Theme & { PaperTheme: CustomPaperThemeType } & { NavigationTheme: NavigationThemeType } & { darkMode: boolean } => {
|
|
63
|
+
// Select the right theme light theme ({} if not exist)
|
|
64
|
+
const { Variables: themeConfigVars = {} as Partial<ThemeVariables>, ...themeConfig } = themes[currentTheme] || {}
|
|
65
|
+
|
|
66
|
+
const { Variables: darkThemeConfigVars = {} as Partial<ThemeVariables>, ...darkThemeConfig } = darkMode ? themes[`${currentTheme}_dark`] || {} : {}
|
|
67
|
+
|
|
68
|
+
const themeVariables: ThemeVariables = mergeVariables(
|
|
69
|
+
DefaultVariables as ThemeVariables,
|
|
70
|
+
themeConfigVars,
|
|
71
|
+
darkThemeConfigVars,
|
|
72
|
+
)
|
|
73
|
+
// const defaultNavTheme = darkMode ? Object.assign(DarkTheme, PaperDarkTheme) : Object.assign(DefaultTheme, PaperDefaultTheme)
|
|
74
|
+
const defaultNavTheme = darkMode ? CombinedDarkTheme : CombinedDefaultTheme
|
|
75
|
+
|
|
76
|
+
// Build the default theme
|
|
77
|
+
const baseTheme: Theme = {
|
|
78
|
+
Fonts: Fonts(themeVariables, fontScale),
|
|
79
|
+
Icons: Icons(themeVariables),
|
|
80
|
+
Gutters: Gutters(themeVariables),
|
|
81
|
+
Images: Images(themeVariables),
|
|
82
|
+
Layout: Layout(themeVariables),
|
|
83
|
+
Common: Common({
|
|
84
|
+
...themeVariables,
|
|
85
|
+
Layout: Layout(themeVariables),
|
|
86
|
+
Gutters: Gutters(themeVariables),
|
|
87
|
+
Fonts: Fonts(themeVariables, fontScale),
|
|
88
|
+
Images: Images(themeVariables),
|
|
89
|
+
}),
|
|
90
|
+
...themeVariables,
|
|
91
|
+
FontSize: themeVariables.ScaledFontSize[fontScale],
|
|
92
|
+
darkMode: !!darkMode,
|
|
93
|
+
Param: themeVariables.Param,
|
|
94
|
+
PaperTheme: PaperDefaultTheme as CustomPaperThemeType,
|
|
95
|
+
NavigationTheme: defaultNavTheme,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Merge and return the current Theme
|
|
99
|
+
return buildTheme(
|
|
100
|
+
!!darkMode,
|
|
101
|
+
baseTheme,
|
|
102
|
+
formatTheme(themeVariables, themeConfig || {}),
|
|
103
|
+
formatTheme(themeVariables, darkThemeConfig || {}),
|
|
104
|
+
)
|
|
105
|
+
}, [currentTheme, darkMode, fontScale])
|
|
106
|
+
|
|
107
|
+
return createTheme()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default useBuildTheme
|
|
111
|
+
|
|
112
|
+
const formatTheme = (
|
|
113
|
+
variables: ThemeVariables,
|
|
114
|
+
theme: Partial<Theme>,
|
|
115
|
+
): Partial<Theme> => {
|
|
116
|
+
return Object.entries(theme).reduce((acc, [name, generate]) => {
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...acc,
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
123
|
+
[name]: (generate)(variables),
|
|
124
|
+
}
|
|
125
|
+
}, {})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Merge all variables for building the theme
|
|
130
|
+
* baseTheme <- currentTheme <- currentDarkTheme
|
|
131
|
+
*
|
|
132
|
+
* @param variables : {MetricsSizes?: {small: number, large: number, tiny: number, regular: number}, NavigationColors?: {primary: string}, FontSize?: {small: number, large: number, regular: number}, Colors?: {white: string, success: string, text: string, error: string, transparent: string, primary: string}} variables from @Theme/Variables
|
|
133
|
+
* @param themeConfig : currentTheme form @Theme/themes
|
|
134
|
+
* @param darkThemeConfig : currentDarkTheme from @Theme/themes
|
|
135
|
+
* @return {{}|{[p: string]: *}}
|
|
136
|
+
*/
|
|
137
|
+
const mergeVariables = (
|
|
138
|
+
variables: ThemeVariables,
|
|
139
|
+
themeConfig: Partial<ThemeVariables>,
|
|
140
|
+
darkThemeConfig: Partial<ThemeVariables>,
|
|
141
|
+
): ThemeVariables =>
|
|
142
|
+
Object.entries(variables).reduce((acc, [group, vars]) => {
|
|
143
|
+
return {
|
|
144
|
+
...acc,
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
146
|
+
[group]: {
|
|
147
|
+
...vars,
|
|
148
|
+
...((themeConfig as any)[group] || {}),
|
|
149
|
+
...((darkThemeConfig as any)[group] || {}),
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
}, {} as ThemeVariables)
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Provide all the theme exposed with useTheme()
|
|
156
|
+
*
|
|
157
|
+
* @param darkMode : boolean
|
|
158
|
+
* @param baseTheme
|
|
159
|
+
* @param themeConfig
|
|
160
|
+
* @param darkThemeConfig
|
|
161
|
+
* @return {{[p: string]: *, NavigationTheme: {colors}, darkMode: *}}
|
|
162
|
+
*/
|
|
163
|
+
const buildTheme = (
|
|
164
|
+
darkMode: boolean,
|
|
165
|
+
baseTheme: Theme,
|
|
166
|
+
themeConfig: Partial<Theme>,
|
|
167
|
+
darkThemeConfig: Partial<Theme>,
|
|
168
|
+
): Theme & { PaperTheme: CustomPaperThemeType } & { NavigationTheme: NavigationThemeType } & { darkMode: boolean } => {
|
|
169
|
+
|
|
170
|
+
const paperTheme = mergeNavigationTheme(
|
|
171
|
+
darkMode ? PaperDarkTheme : PaperDefaultTheme,
|
|
172
|
+
baseTheme.Colors,
|
|
173
|
+
baseTheme.Fonts as any,
|
|
174
|
+
baseTheme.Param.roundness,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
const adaptedNavigationTheme = adaptNavigationTheme({
|
|
178
|
+
materialLight: paperTheme,
|
|
179
|
+
reactNavigationLight: NavigationDefaultTheme,
|
|
180
|
+
materialDark: paperTheme,
|
|
181
|
+
reactNavigationDark: NavigationDarkTheme,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
...mergeTheme(baseTheme, themeConfig, darkThemeConfig),
|
|
186
|
+
darkMode,
|
|
187
|
+
PaperTheme: paperTheme,
|
|
188
|
+
NavigationTheme: darkMode ? adaptedNavigationTheme.DarkTheme : adaptedNavigationTheme.LightTheme,
|
|
189
|
+
// NavigationTheme: mergeNavigationTheme(
|
|
190
|
+
// darkMode ? Object.assign(NavigationDarkTheme, PaperDarkTheme) : Object.assign(NavigationDefaultTheme, PaperDefaultTheme),
|
|
191
|
+
// baseTheme.Colors,
|
|
192
|
+
// baseTheme.Fonts as any,
|
|
193
|
+
// baseTheme.Param.roundness,
|
|
194
|
+
// ),
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Merge theme from baseTheme <- currentTheme <- currentDarkTheme
|
|
201
|
+
*
|
|
202
|
+
* @param baseTheme
|
|
203
|
+
* @param theme
|
|
204
|
+
* @param darkTheme
|
|
205
|
+
* @return {{[p: string]: *}}
|
|
206
|
+
*/
|
|
207
|
+
const mergeTheme = (
|
|
208
|
+
baseTheme: Theme,
|
|
209
|
+
theme: Partial<Theme>,
|
|
210
|
+
darkTheme: Partial<Theme>,
|
|
211
|
+
): Theme =>
|
|
212
|
+
Object.entries(baseTheme).reduce(
|
|
213
|
+
(acc, [key, value]) => ({
|
|
214
|
+
...acc,
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
216
|
+
[key]: {
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
...value,
|
|
220
|
+
...((theme as any)[key] || {}),
|
|
221
|
+
...((darkTheme as any)[key] || {}),
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
{} as Theme,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
const mergeNavigationTheme = (
|
|
228
|
+
reactNavigationTheme: ThemeNavigationTheme,
|
|
229
|
+
overrideColors: ThemeNavigationColors,
|
|
230
|
+
overrideFonts: ThemeNavigationFonts,
|
|
231
|
+
roundness: number,
|
|
232
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
233
|
+
): ThemeNavigationThemeWithOwn => ({
|
|
234
|
+
...reactNavigationTheme,
|
|
235
|
+
colors: {
|
|
236
|
+
...reactNavigationTheme.colors,
|
|
237
|
+
...overrideColors,
|
|
238
|
+
},
|
|
239
|
+
fonts: {
|
|
240
|
+
...reactNavigationTheme.fonts,
|
|
241
|
+
...configureFonts({
|
|
242
|
+
config: {
|
|
243
|
+
...overrideFonts,
|
|
244
|
+
},
|
|
245
|
+
}),
|
|
246
|
+
...overrideFonts,
|
|
247
|
+
},
|
|
248
|
+
roundness: roundness,
|
|
249
|
+
})
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
|
|
3
|
+
import logger from '@/infrastructures/common/logger'
|
|
4
|
+
|
|
5
|
+
import useBoolean from './useBoolean'
|
|
6
|
+
import useCounter from './useCounter'
|
|
7
|
+
import useInterval from './useInterval'
|
|
8
|
+
|
|
9
|
+
// New interface IN & OUT
|
|
10
|
+
type CountdownOption = {
|
|
11
|
+
countStart: number
|
|
12
|
+
intervalMs?: number
|
|
13
|
+
isIncrement?: boolean
|
|
14
|
+
countStop?: number
|
|
15
|
+
}
|
|
16
|
+
type CountdownControllers = {
|
|
17
|
+
startCountdown: () => void
|
|
18
|
+
stopCountdown: () => void
|
|
19
|
+
resetCountdown: () => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* New interface with default value
|
|
24
|
+
*
|
|
25
|
+
* @param {CountdownOption} countdownOption
|
|
26
|
+
* @param {number} countdownOption.countStart - the countdown's starting number, initial value of the returned number.
|
|
27
|
+
* @param {?number} countdownOption.countStop - `0` by default, the countdown's stopping number. Pass `-Infinity` to decrease forever.
|
|
28
|
+
* @param {?number} countdownOption.intervalMs - `1000` by default, the countdown's interval, in milliseconds.
|
|
29
|
+
* @param {?boolean} countdownOption.isIncrement - `false` by default, true if the countdown is increment.
|
|
30
|
+
* @returns [counter, CountdownControllers]
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const useCountdown = (
|
|
34
|
+
countdownOption: CountdownOption,
|
|
35
|
+
): [number, CountdownControllers] => {
|
|
36
|
+
/**
|
|
37
|
+
* Use to determine the API call is a deprecated version.
|
|
38
|
+
*/
|
|
39
|
+
let isDeprecated = false
|
|
40
|
+
|
|
41
|
+
let countStart
|
|
42
|
+
let intervalMs
|
|
43
|
+
let isIncrement: boolean | undefined
|
|
44
|
+
let countStop: number | undefined
|
|
45
|
+
|
|
46
|
+
if ('seconds' in countdownOption) {
|
|
47
|
+
logger.warn(
|
|
48
|
+
'[useCountdown:DEPRECATED] new interface is already available (see https://usehooks-ts.com/react-hook/use-countdown), the old version will retire on usehooks-ts@3.',
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
isDeprecated = true
|
|
52
|
+
countStart = countdownOption.countStart
|
|
53
|
+
intervalMs = countdownOption.intervalMs
|
|
54
|
+
isIncrement = countdownOption.isIncrement
|
|
55
|
+
} else {
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-extra-semi
|
|
57
|
+
;({ countStart, countStop, intervalMs, isIncrement } = countdownOption)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// default values
|
|
61
|
+
intervalMs = intervalMs ?? 1000
|
|
62
|
+
isIncrement = isIncrement ?? false
|
|
63
|
+
countStop = countStop ?? 0
|
|
64
|
+
|
|
65
|
+
const { count, decrement, increment, reset: resetCounter } = useCounter(countStart)
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Note: used to control the useInterval
|
|
69
|
+
* running: If true, the interval is running
|
|
70
|
+
* start: Should set running true to trigger interval
|
|
71
|
+
* stop: Should set running false to remove interval
|
|
72
|
+
*/
|
|
73
|
+
const { setFalse: stopCountdown, setTrue: startCountdown, value: isCountdownRunning } = useBoolean(false)
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Will set running false and reset the seconds to initial value
|
|
77
|
+
*/
|
|
78
|
+
const resetCountdown = () => {
|
|
79
|
+
stopCountdown()
|
|
80
|
+
resetCounter()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const countdownCallback = useCallback(() => {
|
|
84
|
+
if (count === countStop) {
|
|
85
|
+
stopCountdown()
|
|
86
|
+
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isIncrement) {
|
|
91
|
+
increment()
|
|
92
|
+
} else {
|
|
93
|
+
decrement()
|
|
94
|
+
}
|
|
95
|
+
}, [
|
|
96
|
+
count, countStop, decrement, increment, isIncrement, stopCountdown,
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
useInterval(countdownCallback, isCountdownRunning ? intervalMs : null)
|
|
100
|
+
|
|
101
|
+
return [
|
|
102
|
+
count,
|
|
103
|
+
{
|
|
104
|
+
startCountdown,
|
|
105
|
+
stopCountdown,
|
|
106
|
+
resetCountdown,
|
|
107
|
+
} as CountdownControllers,
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default useCountdown
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Dispatch, SetStateAction, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
type UseCounterOutput = {
|
|
4
|
+
count: number
|
|
5
|
+
increment: () => void
|
|
6
|
+
decrement: () => void
|
|
7
|
+
reset: () => void
|
|
8
|
+
setCount: Dispatch<SetStateAction<number>>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const useCounter = (initialValue?: number): UseCounterOutput => {
|
|
12
|
+
const [count, setCount] = useState(initialValue || 0)
|
|
13
|
+
|
|
14
|
+
const increment = () => setCount(x => x + 1)
|
|
15
|
+
const decrement = () => setCount(x => x - 1)
|
|
16
|
+
const reset = () => setCount(initialValue || 0)
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
count,
|
|
20
|
+
increment,
|
|
21
|
+
decrement,
|
|
22
|
+
reset,
|
|
23
|
+
setCount,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default useCounter
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
const useDebounce = <T>(value: T, delay: number): T => {
|
|
4
|
+
// State and setters for debounced value
|
|
5
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
|
6
|
+
useEffect(
|
|
7
|
+
() => {
|
|
8
|
+
// Update debounced value after delay
|
|
9
|
+
const handler = setTimeout(() => {
|
|
10
|
+
setDebouncedValue(value)
|
|
11
|
+
}, delay)
|
|
12
|
+
|
|
13
|
+
// Cancel the timeout if value changes (also on delay change or unmount)
|
|
14
|
+
// This is how we prevent debounced value from updating if value is changed ...
|
|
15
|
+
// .. within the delay period. Timeout gets cleared and restarted.
|
|
16
|
+
return () => {
|
|
17
|
+
clearTimeout(handler)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
[value, delay] // Only re-call effect if value or delay changes
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
return debouncedValue
|
|
24
|
+
}
|
|
25
|
+
export default useDebounce
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FormikValues } from 'formik'
|
|
2
|
+
import { FormikConfig } from 'formik/dist/types'
|
|
3
|
+
import { debounce } from 'lodash'
|
|
4
|
+
import { useCallback, useEffect, useRef } from 'react'
|
|
5
|
+
|
|
6
|
+
const useDebouncedValidate = <T extends FormikValues>({ debounceTime = 200, validate, values }: {
|
|
7
|
+
values: T
|
|
8
|
+
validate: FormikConfig<T>['validate']
|
|
9
|
+
debounceTime?: number
|
|
10
|
+
}) => {
|
|
11
|
+
const debouncedFunction = useRef(
|
|
12
|
+
debounce((validateFunc: FormikConfig<T>['validate'], data: T) => {
|
|
13
|
+
return validateFunc ? validateFunc(data) : () => {}
|
|
14
|
+
}, debounceTime),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const debounceValidate = useCallback((data: T) => {
|
|
18
|
+
return debouncedFunction.current(validate, data)
|
|
19
|
+
}, [])
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
debounceValidate(values)
|
|
23
|
+
}, [values])
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
return () => {
|
|
27
|
+
debouncedFunction.current.cancel()
|
|
28
|
+
}
|
|
29
|
+
}, [])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default useDebouncedValidate
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import logger from '@/infrastructures/common/logger'
|
|
4
|
+
|
|
5
|
+
import useRenderCount from './useRenderCount'
|
|
6
|
+
|
|
7
|
+
const useDebugInformation = (componentName: string, props: Record<string, unknown>) => {
|
|
8
|
+
const count = useRenderCount()
|
|
9
|
+
const changedProps = useRef({})
|
|
10
|
+
const previousProps = useRef(props)
|
|
11
|
+
const lastRenderTimestamp = useRef(Date.now())
|
|
12
|
+
|
|
13
|
+
const propKeys = Object.keys({ ...props, ...previousProps })
|
|
14
|
+
changedProps.current = propKeys.reduce((obj, key) => {
|
|
15
|
+
if (props[key] === previousProps.current[key]) return obj
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
...obj,
|
|
19
|
+
[key]: { previous: previousProps.current[key], current: props[key] },
|
|
20
|
+
}
|
|
21
|
+
}, {})
|
|
22
|
+
const info = {
|
|
23
|
+
count,
|
|
24
|
+
changedProps: changedProps.current,
|
|
25
|
+
timeSinceLastRender: Date.now() - lastRenderTimestamp.current,
|
|
26
|
+
lastRenderTimestamp: lastRenderTimestamp.current,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
previousProps.current = props
|
|
31
|
+
lastRenderTimestamp.current = Date.now()
|
|
32
|
+
logger.log('[debug-info] - ' + componentName, info)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return info
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default useDebugInformation
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MutableRefObject, useCallback, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { StorageKey } from '@/configs/constants/type'
|
|
4
|
+
import useEncryptedStorage from '@/hooks/useEncryptedStorage'
|
|
5
|
+
|
|
6
|
+
const useDeviceToken = ():[string, (value: string) => void, boolean, MutableRefObject<string>] => {
|
|
7
|
+
const [
|
|
8
|
+
deviceToken,
|
|
9
|
+
setDeviceToken,
|
|
10
|
+
retrievedDeviceTokenFromStorage,
|
|
11
|
+
tokenRef,
|
|
12
|
+
] = useEncryptedStorage(StorageKey.deviceToken, '')
|
|
13
|
+
const setNewDeviceToken = useCallback((newDeviceToken: string) => {
|
|
14
|
+
void setDeviceToken(newDeviceToken)
|
|
15
|
+
}, [setDeviceToken])
|
|
16
|
+
|
|
17
|
+
return [deviceToken, setNewDeviceToken, retrievedDeviceTokenFromStorage, tokenRef]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default useDeviceToken
|