diff --git a/babel.config.js b/babel.config.js
index 8408012a5..8029e1c0f 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -20,16 +20,14 @@ const baseConfig = {
'@helium/crypto': './node_modules/@helium/crypto-react-native',
'@assets': './src/assets',
'@components': './src/components',
- '@constants': './src/constants',
'@hooks': './src/hooks',
- '@theme': './src/theme',
'@utils': './src/utils',
- '@storage': './src/storage',
+ '@config': './src/config',
'@types': './src/types',
'@features': './src/features',
- '@services': './src/services',
+ '@services': './src/app/services',
'@store': './src/store',
- '@/solana': './src/solana',
+ '@app': './src/app',
},
extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
root: ['./src'],
diff --git a/index.js b/index.js
index 172ef565a..0807a1438 100644
--- a/index.js
+++ b/index.js
@@ -8,12 +8,12 @@ import 'react-native-url-polyfill/auto'
import { Provider as ReduxProvider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import { name as appName } from './app.json'
-import App from './src/App'
+import App from './src/app/App'
import { GlobalError } from './src/components/GlobalError'
-import AccountStorageProvider from './src/storage/AccountStorageProvider'
-import AppStorageProvider from './src/storage/AppStorageProvider'
-import LanguageProvider from './src/storage/LanguageProvider'
-import NotificationStorageProvider from './src/storage/NotificationStorageProvider'
+import AccountStorageProvider from './src/config/storage/AccountStorageProvider'
+import AppStorageProvider from './src/config/storage/AppStorageProvider'
+import LanguageProvider from './src/config/storage/LanguageProvider'
+import NotificationStorageProvider from './src/config/storage/NotificationStorageProvider'
import { persistor } from './src/store/persistence'
import store from './src/store/store'
import './src/utils/i18n'
diff --git a/ios/Podfile b/ios/Podfile
index 0d64adb7d..6349f49dd 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -56,8 +56,11 @@ target 'HeliumWallet' do
permissions_path = '../node_modules/react-native-permissions/ios'
setup_permissions(['BluetoothPeripheral'])
+ $RNMapboxMapsImpl = 'mapbox'
+ $RNMapboxMapsVersion = '= 11.4.0'
+
post_install do |installer|
- $RNMBGL.post_install(installer)
+ $RNMapboxMaps.post_install(installer)
# https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
react_native_post_install(
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index cbfaf840e..4a38b3db0 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -22,6 +22,8 @@ PODS:
- EXImageLoader (4.7.0):
- ExpoModulesCore
- React-Core
+ - EXLocation (17.0.1):
+ - ExpoModulesCore
- Expo (51.0.24):
- ExpoModulesCore
- ExpoAsset (10.0.10):
@@ -118,13 +120,13 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - maplibre-react-native (9.1.0):
- - maplibre-react-native/DynamicLibrary (= 9.1.0)
- - React
- - React-Core
- - maplibre-react-native/DynamicLibrary (9.1.0):
- - React
- - React-Core
+ - MapboxCommon (24.4.0)
+ - MapboxCoreMaps (11.4.0):
+ - MapboxCommon (~> 24.4)
+ - MapboxMaps (11.4.0):
+ - MapboxCommon (= 24.4.0)
+ - MapboxCoreMaps (= 11.4.0)
+ - Turf (= 2.8.0)
- MultiplatformBleAdapter (0.1.9)
- OneSignalXCFramework (5.2.2):
- OneSignalXCFramework/OneSignalComplete (= 5.2.2)
@@ -1109,6 +1111,8 @@ PODS:
- Charts (= 4.1.0)
- React
- SwiftyJSON (= 5.0)
+ - react-native-compass-heading (1.5.0):
+ - React-Core
- react-native-config (1.4.6):
- react-native-config/App (= 1.4.6)
- react-native-config/App (1.4.6):
@@ -1421,6 +1425,27 @@ PODS:
- React-Core
- RNCClipboard (1.5.1):
- React-Core
+ - RNCMaskedView (0.3.2):
+ - DoubleConversion
+ - glog
+ - hermes-engine
+ - RCT-Folly (= 2024.01.01.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon/turbomodule/bridging
+ - ReactCommon/turbomodule/core
+ - Yoga
- RNDeviceInfo (8.7.1):
- React-Core
- RNGestureHandler (2.18.1):
@@ -1448,6 +1473,17 @@ PODS:
- React
- RNLocalize (2.2.3):
- React-Core
+ - rnmapbox-maps (10.1.31):
+ - MapboxMaps (= 11.4.0)
+ - React
+ - React-Core
+ - rnmapbox-maps/DynamicLibrary (= 10.1.31)
+ - Turf
+ - rnmapbox-maps/DynamicLibrary (10.1.31):
+ - MapboxMaps (= 11.4.0)
+ - React
+ - React-Core
+ - Turf
- RNOS (1.2.6):
- React
- RNPermissions (3.9.2):
@@ -1509,6 +1545,13 @@ PODS:
- TcpSockets (3.3.2):
- React
- Toast (4.0.0)
+ - Turf (2.8.0)
+ - VisionCamera (4.5.3):
+ - VisionCamera/Core (= 4.5.3)
+ - VisionCamera/React (= 4.5.3)
+ - VisionCamera/Core (4.5.3)
+ - VisionCamera/React (4.5.3):
+ - React-Core
- Yoga (0.0.0)
- ZXingObjC/Core (3.6.9)
- ZXingObjC/OneD (3.6.9):
@@ -1524,6 +1567,7 @@ DEPENDENCIES:
- EXBarCodeScanner (from `../node_modules/expo-barcode-scanner/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`)
- EXImageLoader (from `../node_modules/expo-image-loader/ios`)
+ - EXLocation (from `../node_modules/expo-location/ios`)
- Expo (from `../node_modules/expo`)
- ExpoAsset (from `../node_modules/expo-asset/ios`)
- ExpoCamera (from `../node_modules/expo-camera/ios`)
@@ -1542,7 +1586,6 @@ DEPENDENCIES:
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- lottie-ios (from `../node_modules/lottie-ios`)
- lottie-react-native (from `../node_modules/lottie-react-native`)
- - "maplibre-react-native (from `../node_modules/@maplibre/maplibre-react-native`)"
- OneSignalXCFramework (< 6.0, >= 5.0)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
@@ -1573,6 +1616,7 @@ DEPENDENCIES:
- react-native-ble-plx (from `../node_modules/react-native-ble-plx`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- react-native-charts-wrapper (from `../node_modules/react-native-charts-wrapper`)
+ - react-native-compass-heading (from `../node_modules/react-native-compass-heading`)
- react-native-config (from `../node_modules/react-native-config`)
- react-native-config/Extension (from `../node_modules/react-native-config`)
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
@@ -1615,10 +1659,12 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCCheckbox (from `../node_modules/@react-native-community/checkbox`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
+ - "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNICloudStore (from `../node_modules/react-native-icloudstore`)
- RNLocalize (from `../node_modules/react-native-localize`)
+ - "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)"
- RNOS (from `../node_modules/react-native-os`)
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReactNativeSharedGroupPreferences (from `../node_modules/react-native-shared-group-preferences`)
@@ -1628,6 +1674,7 @@ DEPENDENCIES:
- RNSVG (from `../node_modules/react-native-svg`)
- RNTestFlight (from `../node_modules/react-native-test-flight`)
- TcpSockets (from `../node_modules/react-native-tcp`)
+ - VisionCamera (from `../node_modules/react-native-vision-camera`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@@ -1635,12 +1682,16 @@ SPEC REPOS:
- BCrypt
- BEMCheckBox
- Charts
+ - MapboxCommon
+ - MapboxCoreMaps
+ - MapboxMaps
- MultiplatformBleAdapter
- OneSignalXCFramework
- SocketRocket
- SwiftAlgorithms
- SwiftyJSON
- Toast
+ - Turf
- ZXingObjC
EXTERNAL SOURCES:
@@ -1658,6 +1709,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-constants/ios"
EXImageLoader:
:path: "../node_modules/expo-image-loader/ios"
+ EXLocation:
+ :path: "../node_modules/expo-location/ios"
Expo:
:path: "../node_modules/expo"
ExpoAsset:
@@ -1695,8 +1748,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/lottie-ios"
lottie-react-native:
:path: "../node_modules/lottie-react-native"
- maplibre-react-native:
- :path: "../node_modules/@maplibre/maplibre-react-native"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTDeprecation:
@@ -1751,6 +1802,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/blur"
react-native-charts-wrapper:
:path: "../node_modules/react-native-charts-wrapper"
+ react-native-compass-heading:
+ :path: "../node_modules/react-native-compass-heading"
react-native-config:
:path: "../node_modules/react-native-config"
react-native-get-random-values:
@@ -1833,6 +1886,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/checkbox"
RNCClipboard:
:path: "../node_modules/@react-native-community/clipboard"
+ RNCMaskedView:
+ :path: "../node_modules/@react-native-masked-view/masked-view"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNGestureHandler:
@@ -1841,6 +1896,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-icloudstore"
RNLocalize:
:path: "../node_modules/react-native-localize"
+ rnmapbox-maps:
+ :path: "../node_modules/@rnmapbox/maps"
RNOS:
:path: "../node_modules/react-native-os"
RNPermissions:
@@ -1859,6 +1916,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-test-flight"
TcpSockets:
:path: "../node_modules/react-native-tcp"
+ VisionCamera:
+ :path: "../node_modules/react-native-vision-camera"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@@ -1873,6 +1932,7 @@ SPEC CHECKSUMS:
EXBarCodeScanner: e2dd9b42c1b522a2adc9202b1dfbc64cb34456d1
EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59
EXImageLoader: ab589d67d6c5f2c33572afea9917304418566334
+ EXLocation: 43e9b582ca63a23c6f0a18d8cbe2145b3a388b55
Expo: 798848eae1daf13363d69790986146b08d0cf92f
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
ExpoCamera: a5d000b22cd7dfd2c5904ed960e549de42c96da0
@@ -1891,7 +1951,9 @@ SPEC CHECKSUMS:
hermes-engine: 8c1577f3fdb849cbe7729c2e7b5abc4b845e88f8
lottie-ios: e047b1d2e6239b787cc5e9755b988869cf190494
lottie-react-native: f851c0e235f171d99083c803f728f644be1dcf65
- maplibre-react-native: 3a0d9beca427ff9000d75e0974c366ecd3c5375e
+ MapboxCommon: 6acbd8ff41d66abf498e1558b0739f25c562945a
+ MapboxCoreMaps: f306bb1b10ebe995a2247b40e99322ab7f9b8071
+ MapboxMaps: 82044383ae19ec124ff444ec4b5d3ce82cb36ba5
MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
OneSignalXCFramework: f06edd9b146c7ac5935136a117ce2a5fdd6420f6
RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
@@ -1921,6 +1983,7 @@ SPEC CHECKSUMS:
react-native-ble-plx: f10240444452dfb2d2a13a0e4f58d7783e92d76e
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-charts-wrapper: 4268219d67a6fd7e94453d77d31b38ef1cd23860
+ react-native-compass-heading: 1b4403d1c99dfd8311073ca8fc52bfc8e365cfac
react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
react-native-mail: 8fdcd3aef007c33a6877a18eb4cf7447a1d4ce4a
@@ -1962,10 +2025,12 @@ SPEC CHECKSUMS:
RNCAsyncStorage: b90b71f45b8b97be43bc4284e71a6af48ac9f547
RNCCheckbox: a3ca9978cb0846b981d28da4e9914bd437403d77
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
+ RNCMaskedView: da52ec927af4b4c3f3f6b5b5e816a69be62fe642
RNDeviceInfo: aad3c663b25752a52bf8fce93f2354001dd185aa
RNGestureHandler: efed690b8493a00b99654043daeb1335276ac4a2
RNICloudStore: bc6e225811637c09bd1eb055d6cd7448e61cd451
RNLocalize: a64514b46a01375fdfae9349036b4dc7130333b5
+ rnmapbox-maps: 961b998761de9672c448aa17144b987410890992
RNOS: 6f2f9a70895bbbfbdad7196abd952e7b01d45027
RNPermissions: 2af759cf053542b2b4b3c4cf9f43874796106f2c
RNReactNativeSharedGroupPreferences: 29092869fc2e40d5baca5e15d82fa5c24a668977
@@ -1979,9 +2044,11 @@ SPEC CHECKSUMS:
SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7
TcpSockets: 14306fb79f9750ea7d2ddd02d8bed182abb01797
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
+ Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e
+ VisionCamera: cb84d0d8485b3e67c91b62931d3aa88f49747c92
Yoga: 950bbfd7e6f04790fdb51149ed51df41f329fcc8
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
-PODFILE CHECKSUM: d44dfed27ca86fe0b1eb67aab0856b7cc9e24ff7
+PODFILE CHECKSUM: af8e0f0904c0f9cc43a95eef4e1feb504870ee6e
-COCOAPODS: 1.15.2
+COCOAPODS: 1.16.1
diff --git a/package.json b/package.json
index b3ee602cf..14848b8f4 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
"bump-patch": "npx react-native bump-version --skip-semver-for android --skip-code-for all --type patch",
"bump-minor": "npx react-native bump-version --skip-semver-for android --skip-code-for all --type minor",
"bump-major": "npx react-native bump-version --skip-semver-for android --skip-code-for all --type major",
+ "gen-ims-api": "graphql-codegen --config src/store/apis/ims/dashboard/codegen.yml",
+ "gen-ims-payments-api": "graphql-codegen --config src/store/apis/ims/payments/codegen.yml",
"prettier": "prettier --write *.ts*",
"gen-types:all": "yarn gen-types",
"prepare": "husky install"
@@ -29,10 +31,14 @@
"@babel/preset-typescript": "7.21.0",
"@bonfida/spl-name-service": "^1.1.1",
"@coral-xyz/anchor": "^0.28.0",
- "@gorhom/bottom-sheet": "4.6.4",
+ "@gorhom/bottom-sheet": "5.0.4",
"@gorhom/portal": "1.0.14",
- "@helium/account-fetch-cache": "0.9.14",
- "@helium/account-fetch-cache-hooks": "0.9.14",
+ "@graphql-codegen/cli": "^5.0.0",
+ "@graphql-codegen/typescript": "^4.0.1",
+ "@graphql-codegen/typescript-operations": "^4.0.1",
+ "@graphql-codegen/typescript-rtk-query": "^3.1.1",
+ "@helium/account-fetch-cache": "0.9.7",
+ "@helium/account-fetch-cache-hooks": "0.9.7",
"@helium/address": "4.10.2",
"@helium/circuit-breaker-sdk": "^0.9.14",
"@helium/crypto-react-native": "4.8.0",
@@ -66,12 +72,11 @@
"@ledgerhq/react-native-hid": "6.30.0",
"@ledgerhq/react-native-hw-transport-ble": "6.29.5",
"@ledgerhq/types-devices": "^6.22.4",
- "@maplibre/maplibre-react-native": "^9.1.0",
"@metaplex-foundation/js": "^0.19.5",
"@metaplex-foundation/mpl-bubblegum": "0.6.0",
"@metaplex-foundation/mpl-token-metadata": "2.10.0",
"@ngraveio/bc-ur": "^1.1.13",
- "@novalabsxyz/mobile-theme": "2.0.0-y.25",
+ "@novalabsxyz/mobile-theme": "2.0.0-y.26",
"@onsol/tldparser": "^0.5.3",
"@react-native-async-storage/async-storage": "1.18.1",
"@react-native-community/blur": "4.3.0",
@@ -80,12 +85,14 @@
"@react-native-community/hooks": "2.8.1",
"@react-native-community/netinfo": "9.3.7",
"@react-native-community/slider": "^4.5.2",
+ "@react-native-masked-view/masked-view": "^0.3.2",
"@react-navigation/bottom-tabs": "6.4.0",
"@react-navigation/material-top-tabs": "6.5.1",
"@react-navigation/native": "6.0.11",
"@react-navigation/native-stack": "6.7.0",
"@react-navigation/stack": "6.2.2",
"@reduxjs/toolkit": "1.9.1",
+ "@rnmapbox/maps": "^10.1.31",
"@shopify/restyle": "2.4.2",
"@solana/spl-account-compression": "0.1.4",
"@solana/spl-memo": "0.2.3",
@@ -134,9 +141,11 @@
"expo-haptics": "13.0.1",
"expo-linking": "6.3.1",
"expo-local-authentication": "14.0.1",
+ "expo-location": "^17.0.1",
"expo-secure-store": "13.0.2",
"expo-splash-screen": "0.27.5",
"fuse.js": "6.6.2",
+ "geolib": "^3.3.4",
"h3-js": "4.1.0",
"https-browserify": "0.0.1",
"i18next": "21.9.1",
@@ -162,10 +171,13 @@
"react-native-appstate-hook": "1.0.6",
"react-native-ble-plx": "2.0.3",
"react-native-charts-wrapper": "0.5.10",
+ "react-native-compass-heading": "^1.5.0",
+ "react-native-confetti-cannon": "^1.5.2",
"react-native-config": "1.4.6",
"react-native-crypto": "2.2.0",
"react-native-device-info": "8.7.1",
"react-native-flash-message": "0.2.1",
+ "react-native-geocoding": "^0.5.0",
"react-native-gesture-handler": "2.18.1",
"react-native-get-random-values": "1.8.0",
"react-native-icloudstore": "0.9.0",
@@ -190,6 +202,7 @@
"react-native-share": "7.9.0",
"react-native-shared-group-preferences": "1.1.24",
"react-native-simple-toast": "1.1.4",
+ "react-native-skeleton-placeholder": "^5.2.4",
"react-native-snap-carousel": "4.0.0-beta.6",
"react-native-sodium": "^0.4.0",
"react-native-svg": "13.4.0",
@@ -200,6 +213,7 @@
"react-native-udp": "2.7.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-video": "5.2.1",
+ "react-native-vision-camera": "^4.5.3",
"react-native-webview": "13.10.5",
"react-redux": "8.0.4",
"readable-stream": "3.6.0",
diff --git a/patches/@maplibre+maplibre-react-native+9.1.0.patch b/patches/@maplibre+maplibre-react-native+9.1.0.patch
deleted file mode 100644
index 61d3b0349..000000000
--- a/patches/@maplibre+maplibre-react-native+9.1.0.patch
+++ /dev/null
@@ -1,316 +0,0 @@
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/generated/source/buildConfig/debug/com/mapbox/rctmgl/BuildConfig.java b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/generated/source/buildConfig/debug/com/mapbox/rctmgl/BuildConfig.java
-new file mode 100644
-index 0000000..ea64509
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/generated/source/buildConfig/debug/com/mapbox/rctmgl/BuildConfig.java
-@@ -0,0 +1,10 @@
-+/**
-+ * Automatically generated file. DO NOT MODIFY
-+ */
-+package com.mapbox.rctmgl;
-+
-+public final class BuildConfig {
-+ public static final boolean DEBUG = Boolean.parseBoolean("true");
-+ public static final String LIBRARY_PACKAGE_NAME = "com.mapbox.rctmgl";
-+ public static final String BUILD_TYPE = "debug";
-+}
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml
-new file mode 100644
-index 0000000..eecf75d
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml
-@@ -0,0 +1,10 @@
-+
-+
-+
-+
-+
-+
-+
-+
-+
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json
-new file mode 100644
-index 0000000..67b2315
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json
-@@ -0,0 +1,18 @@
-+{
-+ "version": 3,
-+ "artifactType": {
-+ "type": "AAPT_FRIENDLY_MERGED_MANIFESTS",
-+ "kind": "Directory"
-+ },
-+ "applicationId": "com.mapbox.rctmgl",
-+ "variantName": "debug",
-+ "elements": [
-+ {
-+ "type": "SINGLE",
-+ "filters": [],
-+ "attributes": [],
-+ "outputFile": "AndroidManifest.xml"
-+ }
-+ ],
-+ "elementType": "File"
-+}
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aar_metadata/debug/aar-metadata.properties b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aar_metadata/debug/aar-metadata.properties
-new file mode 100644
-index 0000000..1211b1e
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/aar_metadata/debug/aar-metadata.properties
-@@ -0,0 +1,6 @@
-+aarFormatVersion=1.0
-+aarMetadataVersion=1.0
-+minCompileSdk=1
-+minCompileSdkExtension=0
-+minAndroidGradlePluginVersion=1.0.0
-+coreLibraryDesugaringEnabled=false
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/annotation_processor_list/debug/annotationProcessors.json b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/annotation_processor_list/debug/annotationProcessors.json
-new file mode 100644
-index 0000000..9e26dfe
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/annotation_processor_list/debug/annotationProcessors.json
-@@ -0,0 +1 @@
-+{}
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_r_class_jar/debug/R.jar b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_r_class_jar/debug/R.jar
-new file mode 100644
-index 0000000..190e46b
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_r_class_jar/debug/R.jar differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_symbol_list/debug/R.txt b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_symbol_list/debug/R.txt
-new file mode 100644
-index 0000000..e6bb791
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compile_symbol_list/debug/R.txt
-@@ -0,0 +1,8 @@
-+int drawable empty 0x0
-+int drawable empty_drawable 0x0
-+int drawable red_marker 0x0
-+int id annotation_img 0x0
-+int id annotation_layout 0x0
-+int id annotation_view_container 0x0
-+int layout annotation 0x0
-+int string app_name 0x0
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable-xxhdpi-v4_red_marker.png.flat b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable-xxhdpi-v4_red_marker.png.flat
-new file mode 100644
-index 0000000..5b0aa33
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable-xxhdpi-v4_red_marker.png.flat differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty.xml.flat b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty.xml.flat
-new file mode 100644
-index 0000000..8a833ad
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty.xml.flat differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty_drawable.png.flat b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty_drawable.png.flat
-new file mode 100644
-index 0000000..b53aa0c
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/drawable_empty_drawable.png.flat differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/layout_annotation.xml.flat b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/layout_annotation.xml.flat
-new file mode 100644
-index 0000000..942d161
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/compiled_local_resources/debug/out/layout_annotation.xml.flat differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
-new file mode 100644
-index 0000000..62539fb
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
-@@ -0,0 +1,5 @@
-+#Mon Aug 05 14:40:58 PDT 2024
-+com.mapbox.rctmgl.maplibre_maplibre-react-native-main-6\:/drawable-xxhdpi/red_marker.png=/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable-xxhdpi-v4/red_marker.png
-+com.mapbox.rctmgl.maplibre_maplibre-react-native-main-6\:/drawable/empty.xml=/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty.xml
-+com.mapbox.rctmgl.maplibre_maplibre-react-native-main-6\:/layout/annotation.xml=/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/layout/annotation.xml
-+com.mapbox.rctmgl.maplibre_maplibre-react-native-main-6\:/drawable/empty_drawable.png=/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty_drawable.png
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml
-new file mode 100644
-index 0000000..1b0b5d6
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml
-@@ -0,0 +1,4 @@
-+
-+
-+ RCTMGL
-+
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merger.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merger.xml
-new file mode 100644
-index 0000000..5f8b0ab
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/incremental/debug/packageDebugResources/merger.xml
-@@ -0,0 +1,2 @@
-+
-+
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/local_only_symbol_list/debug/R-def.txt b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/local_only_symbol_list/debug/R-def.txt
-new file mode 100644
-index 0000000..826dbbd
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/local_only_symbol_list/debug/R-def.txt
-@@ -0,0 +1,10 @@
-+R_DEF: Internal format may change without notice
-+local
-+drawable empty
-+drawable empty_drawable
-+drawable red_marker
-+id annotation_img
-+id annotation_layout
-+id annotation_view_container
-+layout annotation
-+string app_name
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt
-new file mode 100644
-index 0000000..9065ef8
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt
-@@ -0,0 +1,14 @@
-+1
-+2
-+4
-+5
-+6
-+7
-+7-->/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:2:5-67
-+7-->/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:2:22-64
-+8
-+8-->/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:3:5-78
-+8-->/Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:3:22-76
-+9
-+10
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/merged_manifest/debug/AndroidManifest.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/merged_manifest/debug/AndroidManifest.xml
-new file mode 100644
-index 0000000..eecf75d
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/merged_manifest/debug/AndroidManifest.xml
-@@ -0,0 +1,10 @@
-+
-+
-+
-+
-+
-+
-+
-+
-+
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/navigation_json/debug/navigation.json b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/navigation_json/debug/navigation.json
-new file mode 100644
-index 0000000..0637a08
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/navigation_json/debug/navigation.json
-@@ -0,0 +1 @@
-+[]
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable-xxhdpi-v4/red_marker.png b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable-xxhdpi-v4/red_marker.png
-new file mode 100644
-index 0000000..be782e1
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable-xxhdpi-v4/red_marker.png differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty.xml
-new file mode 100644
-index 0000000..1f83bff
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty.xml
-@@ -0,0 +1,5 @@
-+
-+
-+
-+
-+
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty_drawable.png b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty_drawable.png
-new file mode 100644
-index 0000000..9da19ea
-Binary files /dev/null and b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/drawable/empty_drawable.png differ
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/layout/annotation.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/layout/annotation.xml
-new file mode 100644
-index 0000000..4994bd0
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/layout/annotation.xml
-@@ -0,0 +1,17 @@
-+
-+
-+
-+
-+
-+
-+
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/values/values.xml b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/values/values.xml
-new file mode 100644
-index 0000000..1b0b5d6
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/packaged_res/debug/values/values.xml
-@@ -0,0 +1,4 @@
-+
-+
-+ RCTMGL
-+
-\ No newline at end of file
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
-new file mode 100644
-index 0000000..44307d6
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
-@@ -0,0 +1,9 @@
-+com.mapbox.rctmgl
-+drawable empty
-+drawable empty_drawable
-+drawable red_marker
-+id annotation_img
-+id annotation_layout
-+id annotation_view_container
-+layout annotation
-+string app_name
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/outputs/logs/manifest-merger-debug-report.txt b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/outputs/logs/manifest-merger-debug-report.txt
-new file mode 100644
-index 0000000..3581c51
---- /dev/null
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/build/outputs/logs/manifest-merger-debug-report.txt
-@@ -0,0 +1,25 @@
-+-- Merging decision tree log ---
-+manifest
-+ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:1:1-4:12
-+INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:1:1-4:12
-+ package
-+ ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:1:70-97
-+ INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml
-+ xmlns:android
-+ ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:1:11-69
-+uses-permission#android.permission.INTERNET
-+ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:2:5-67
-+ android:name
-+ ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:2:22-64
-+uses-permission#android.permission.ACCESS_FINE_LOCATION
-+ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:3:5-78
-+ android:name
-+ ADDED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml:3:22-76
-+uses-sdk
-+INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml reason: use-sdk injection requested
-+INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml
-+INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml
-+ android:targetSdkVersion
-+ INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml
-+ android:minSdkVersion
-+ INJECTED from /Users/noahprince/source/wallet-app/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/AndroidManifest.xml
-diff --git a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
-index 3aa0522..9a2248f 100644
---- a/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
-+++ b/node_modules/@maplibre/maplibre-react-native/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
-@@ -3,7 +3,7 @@ package com.mapbox.rctmgl.components.styles;
- import android.util.Log;
-
- import com.facebook.react.bridge.Dynamic;
--import com.facebook.react.bridge.DynamicFromMap;
-+// import com.facebook.react.bridge.DynamicFromMap;
- import com.facebook.react.bridge.NoSuchKeyException;
- import com.facebook.react.bridge.ReadableArray;
- import com.facebook.react.bridge.ReadableMap;
diff --git a/project-structure.md b/project-structure.md
new file mode 100644
index 000000000..ca4df77c2
--- /dev/null
+++ b/project-structure.md
@@ -0,0 +1,71 @@
+# 🗄️ Project Structure
+
+Most of the code lives in the `src` folder and looks something like this:
+
+```sh
+src
+|
++-- app # application layer containing:
+| | # this folder might differ based on the meta framework used
+| +-- services # application services. The super app top level navigation is defined as a set of services
+| +-- RootNavigator.tsx # Main navigator for the app that determines the initial route. Either app onboarding UI or the top level service navigator
+| +-- App.tsx # main application component
++-- assets # assets folder can contain all the static files such as images, fonts, etc.
+|
++-- components # shared components used across the entire application
+|
++-- config # global configurations, exported env variables etc.
+|
++-- features # feature based modules
+|
++-- hooks # shared hooks used across the entire application
+|
++-- lib # reusable libraries preconfigured for the application
+|
++-- stores # global state stores
+|
++-- testing # test utilities and mocks
+|
++-- types # shared types used across the application
+|
++-- utils # shared utility functions
+```
+
+A service could have the following structure:
+
+```sh
+src/services/srcful
+|
++-- pages # pages scoped to a specific service
+|
++-- index.tsx # service entry point
+```
+
+For easy scalability and maintenance, organize most of the code within the features folder. Each feature folder should contain code specific to that feature, keeping things neatly separated. This approach helps prevent mixing feature-related code with shared components, making it simpler to manage and maintain the codebase compared to having many files in a flat folder structure. By adopting this method, you can enhance collaboration, readability, and scalability in the application's architecture.
+
+A feature could have the following structure:
+
+```sh
+src/features/awesome-feature
+|
++-- api # exported API request declarations and api hooks related to a specific feature
+|
++-- assets # assets folder can contain all the static files for a specific feature
+|
++-- components # components scoped to a specific feature
+|
++-- screens # screens scoped to a specific feature
+|
++-- hooks # hooks scoped to a specific feature
+|
++-- stores # state stores for a specific feature
+|
++-- types # typescript types used within the feature
+|
++-- utils # utility functions for a specific feature
+```
+
+NOTE: You don't need all of these folders for every feature. Only include the ones that are necessary for the feature.
+
+By following these practices, you can ensure that your codebase is well-organized, scalable, and maintainable. This will help you and your team to work more efficiently and effectively on the project.
+This approach can also make it easier to apply similar architecture to apps built with Next.js, Remix or React Native.
diff --git a/src/Input.tsx b/src/Input.tsx
deleted file mode 100644
index 0ecb1e4a0..000000000
--- a/src/Input.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/* eslint-disable react/jsx-props-no-spreading */
-import React from 'react'
-import {
- Text,
- TextInput,
- TextInputProps,
- TextProps,
- View,
- ViewStyle,
-} from 'react-native'
-
-type Props = {
- title: string
- textProps?: TextProps
- inputProps?: TextInputProps
- style?: ViewStyle
-}
-const Input = ({ style, title, textProps, inputProps }: Props) => {
- return (
-
- {title}
-
-
- )
-}
-
-export default Input
diff --git a/src/App.tsx b/src/app/App.tsx
similarity index 81%
rename from src/App.tsx
rename to src/app/App.tsx
index 46f815982..5e3bd0983 100644
--- a/src/App.tsx
+++ b/src/app/App.tsx
@@ -2,16 +2,16 @@ import AutoGasBanner from '@components/AutoGasBanner'
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'
import { PortalProvider } from '@gorhom/portal'
import { OnboardingProvider as HotspotOnboardingProvider } from '@helium/react-native-sdk'
-import MapLibreGL from '@maplibre/maplibre-react-native'
import { DarkTheme, NavigationContainer } from '@react-navigation/native'
import { ThemeProvider } from '@shopify/restyle'
-import { ModalProvider } from '@storage/ModalsProvider'
-import TokensProvider from '@storage/TokensProvider'
+import { ModalProvider } from '@config/storage/ModalsProvider'
+import TokensProvider from '@config/storage/TokensProvider'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
-import globalStyles from '@theme/globalStyles'
-import { darkTheme } from '@theme/theme'
+import globalStyles from '@config/theme/globalStyles'
+import { darkTheme } from '@config/theme/theme'
import * as SplashLib from 'expo-splash-screen'
import React, { useMemo } from 'react'
+import Mapbox from '@rnmapbox/maps'
import { LogBox, Platform, StatusBar, UIManager } from 'react-native'
import useAppState from 'react-native-appstate-hook'
import Config from 'react-native-config'
@@ -19,24 +19,24 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { OneSignal } from 'react-native-onesignal'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import 'text-encoding-polyfill'
-import SplashScreen from './components/SplashScreen'
-import WalletConnectProvider from './features/dappLogin/WalletConnectProvider'
-import LockScreen from './features/lock/LockScreen'
-import InsufficientSolConversionModal from './features/modals/InsufficientSolConversionModal'
-import WalletOnboardingProvider from './features/onboarding/OnboardingProvider'
-import SecurityScreen from './features/security/SecurityScreen'
-import useMount from './hooks/useMount'
-import { navigationRef } from './navigation/NavigationHelper'
-import RootNavigator from './navigation/RootNavigator'
-import './polyfill'
-import SolanaProvider from './solana/SolanaProvider'
-import WalletSignProvider from './solana/WalletSignProvider'
-import { useAccountStorage } from './storage/AccountStorageProvider'
-import { GovernanceProvider } from './storage/GovernanceProvider'
-import { useNotificationStorage } from './storage/NotificationStorageProvider'
-import { BalanceProvider } from './utils/Balance'
-import { useDeepLinking } from './utils/linking'
-import KeystoneOnboardingProvider from './features/keystone/KeystoneOnboardingProvider'
+import SolanaProvider from '@features/solana/SolanaProvider'
+import WalletSignProvider from '@features/solana/WalletSignProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { GovernanceProvider } from '@config/storage/GovernanceProvider'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
+import { BalanceProvider } from '@utils/Balance'
+import { useDeepLinking } from '@utils/linking'
+import KeystoneOnboardingProvider from '@features/keystone/KeystoneOnboardingProvider'
+import SplashScreen from '../components/SplashScreen'
+import WalletConnectProvider from '../features/dappLogin/WalletConnectProvider'
+import LockScreen from '../features/lock/LockScreen'
+import InsufficientSolConversionModal from '../features/modals/InsufficientSolConversionModal'
+import WalletOnboardingProvider from '../features/onboarding/OnboardingProvider'
+import SecurityScreen from '../features/security/SecurityScreen'
+import useMount from '../hooks/useMount'
+import { navigationRef } from './NavigationHelper'
+import RootNavigator from './RootNavigator'
+import '../polyfill'
SplashLib.preventAutoHideAsync().catch(() => {
/* reloading the app might trigger some race conditions, ignore them */
@@ -46,7 +46,8 @@ const App = () => {
// Note that the Android SDK is slightly peculiar
// in that it requires setting an access token,
// even though it will be null for most users(only Mapbox authenticates this way)
- MapLibreGL.setAccessToken(null)
+ // MapLibreGL.setAccessToken(null)
+ Mapbox.setAccessToken(Config.MAPBOX_ACCESS_TOKEN)
LogBox.ignoreLogs([
'Module iCloudStorage',
diff --git a/src/navigation/NavigationHelper.ts b/src/app/NavigationHelper.ts
similarity index 84%
rename from src/navigation/NavigationHelper.ts
rename to src/app/NavigationHelper.ts
index 65783beb2..e887d1886 100644
--- a/src/navigation/NavigationHelper.ts
+++ b/src/app/NavigationHelper.ts
@@ -1,5 +1,5 @@
import { createNavigationContainerRef } from '@react-navigation/native'
-import { AccountsServiceStackParamList } from '@services/AccountsService'
+import { AccountsServiceStackParamList } from 'src/app/services/AccountsService'
import { RootStackParamList } from './rootTypes'
export const navigationRef = createNavigationContainerRef()
diff --git a/src/navigation/RootNavigator.tsx b/src/app/RootNavigator.tsx
similarity index 77%
rename from src/navigation/RootNavigator.tsx
rename to src/app/RootNavigator.tsx
index f9cbeecd1..1535cdc85 100644
--- a/src/navigation/RootNavigator.tsx
+++ b/src/app/RootNavigator.tsx
@@ -2,19 +2,19 @@ import {
StackNavigationOptions,
createStackNavigator,
} from '@react-navigation/stack'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import React, { memo, useEffect, useMemo } from 'react'
import changeNavigationBarColor from 'react-native-navigation-bar-color'
import ServiceSheetNavigator from '@services/ServiceSheetNavigator'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import ScanQrCodeScreen from '../features/keystone/ScanQrCodeScreen'
-import SelectKeystoneAccountsScreen from '../features/keystone/SelectKeystoneAccountsScreen'
-import DappLoginScreen from '../features/dappLogin/DappLoginScreen'
-import OnboardingNavigator from '../features/onboarding/OnboardingNavigator'
-import ImportPrivateKey from '../features/onboarding/import/ImportPrivateKey'
-import PaymentScreen from '../features/payment/PaymentScreen'
-import LinkWallet from '../features/txnDelegation/LinkWallet'
-import SignHotspot from '../features/txnDelegation/SignHotspot'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import ScanQrCodeScreen from '@features/keystone/ScanQrCodeScreen'
+import SelectKeystoneAccountsScreen from '@features/keystone/SelectKeystoneAccountsScreen'
+import DappLoginScreen from '@features/dappLogin/DappLoginScreen'
+import OnboardingNavigator from '@features/onboarding/OnboardingNavigator'
+import ImportPrivateKey from '@features/onboarding/import/ImportPrivateKey'
+import PaymentScreen from '@features/payment/PaymentScreen'
+import LinkWallet from '@features/txnDelegation/LinkWallet'
+import SignHotspot from '@features/txnDelegation/SignHotspot'
import { RootStackParamList } from './rootTypes'
const screenOptions = { headerShown: false } as StackNavigationOptions
diff --git a/src/navigation/rootTypes.ts b/src/app/rootTypes.ts
similarity index 93%
rename from src/navigation/rootTypes.ts
rename to src/app/rootTypes.ts
index f74bac82f..95b145444 100644
--- a/src/navigation/rootTypes.ts
+++ b/src/app/rootTypes.ts
@@ -1,7 +1,7 @@
import { LinkWalletRequest, SignHotspotRequest } from '@helium/wallet-link'
import { StackNavigationProp } from '@react-navigation/stack'
import { KeystoneAccountType } from 'src/features/keystone/SelectKeystoneAccountsScreen'
-import { PaymentRouteParam } from '@services/WalletService'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
export type RootStackParamList = {
OnboardingNavigator: undefined
diff --git a/src/services/AccountsService/accountServiceTypes.ts b/src/app/services/AccountsService/accountServiceTypes.ts
similarity index 100%
rename from src/services/AccountsService/accountServiceTypes.ts
rename to src/app/services/AccountsService/accountServiceTypes.ts
diff --git a/src/services/AccountsService/index.tsx b/src/app/services/AccountsService/index.tsx
similarity index 97%
rename from src/services/AccountsService/index.tsx
rename to src/app/services/AccountsService/index.tsx
index 866a6f30a..b2aea7e1d 100644
--- a/src/services/AccountsService/index.tsx
+++ b/src/app/services/AccountsService/index.tsx
@@ -4,7 +4,7 @@ import {
StackNavigationProp,
createStackNavigator,
} from '@react-navigation/stack'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import AddNewAccountNavigator from '@features/home/addNewAccount/AddNewAccountNavigator'
import AccountAssignScreen from '@features/onboarding/AccountAssignScreen'
import { RouteAccount } from '@features/onboarding/create/createAccountNavTypes'
diff --git a/src/services/AccountsService/pages/YourWalletsPage.tsx b/src/app/services/AccountsService/pages/YourWalletsPage.tsx
similarity index 96%
rename from src/services/AccountsService/pages/YourWalletsPage.tsx
rename to src/app/services/AccountsService/pages/YourWalletsPage.tsx
index d2cbf8e3e..395af534b 100644
--- a/src/services/AccountsService/pages/YourWalletsPage.tsx
+++ b/src/app/services/AccountsService/pages/YourWalletsPage.tsx
@@ -5,30 +5,30 @@ import { ReAnimatedBox } from '@components/AnimatedBox'
import { FadeIn } from 'react-native-reanimated'
import Box from '@components/Box'
import { Image, SectionList } from 'react-native'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { NetTypes } from '@helium/address'
-import { CSAccount } from '@storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import TouchableContainer from '@components/TouchableContainer'
import AccountIcon from '@components/AccountIcon'
import { ellipsizeAddress } from '@utils/accountUtils'
-import { useColors, useSpacing } from '@theme/themeHooks'
-import SmallAdd from '@assets/images/smallAdd.svg'
-import BigAdd from '@assets/images/bigAdd.svg'
-import Checkmark from '@assets/images/checkmark.svg'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import SmallAdd from '@assets/svgs/smallAdd.svg'
+import BigAdd from '@assets/svgs/bigAdd.svg'
+import Checkmark from '@assets/svgs/checkmark.svg'
import { useNavigation } from '@react-navigation/native'
import {
HELIUM_DERIVATION,
keypairFromSeed,
solanaDerivation,
} from '@hooks/useDerivationAccounts'
-import { getSecureAccount } from '@storage/secureStorage'
+import { getSecureAccount } from '@config/storage/secureStorage'
import * as bip39 from 'bip39'
import { useOnboarding } from '@features/onboarding/OnboardingProvider'
import Toast from 'react-native-simple-toast'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import useLayoutHeight from '@hooks/useLayoutHeight'
-import { ServiceSheetNavigationProp } from '@services/serviceSheetTypes'
+import { ServiceSheetNavigationProp } from 'src/app/services/serviceSheetTypes'
import CircleLoader from '@components/CircleLoader'
import ScrollBox from '@components/ScrollBox'
import { AccountsServiceNavigationProp } from '../accountServiceTypes'
diff --git a/src/services/BrowserService/index.tsx b/src/app/services/BrowserService/index.tsx
similarity index 100%
rename from src/services/BrowserService/index.tsx
rename to src/app/services/BrowserService/index.tsx
diff --git a/src/services/GovernanceService/index.tsx b/src/app/services/GovernanceService/index.tsx
similarity index 100%
rename from src/services/GovernanceService/index.tsx
rename to src/app/services/GovernanceService/index.tsx
diff --git a/src/app/services/HotspotService/index.tsx b/src/app/services/HotspotService/index.tsx
new file mode 100644
index 000000000..502959672
--- /dev/null
+++ b/src/app/services/HotspotService/index.tsx
@@ -0,0 +1,50 @@
+import React, { useMemo } from 'react'
+import Hotspot from '@assets/svgs/hotspot.svg'
+import Map from '@assets/svgs/map.svg'
+import Add from '@assets/svgs/add.svg'
+import Coin from '@assets/svgs/coin.svg'
+import ServiceSheetPage, {
+ ServiceNavBarOption,
+} from '@components/ServiceSheetPage'
+import { StackNavigationProp } from '@react-navigation/stack'
+import { PortalHost } from '@gorhom/portal'
+import Box from '@components/Box'
+import { HotspotWithPendingRewards } from '../../../types/solana'
+import HotspotPage from './pages/HotspotPage'
+import ExplorerPage from './pages/ExplorerPage'
+import AddHotspotPage from './pages/AddHotspotPage'
+import ClaimTokensPage from './pages/ClaimTokensPage'
+
+export type HotspotServiceStackParamList = {
+ Hotspot: {
+ newHotspot?: HotspotWithPendingRewards
+ }
+ Explorer: undefined
+ AddHotspot: undefined
+ ClaimTokens: undefined
+}
+
+export type HotspotServiceNavigationProp =
+ StackNavigationProp
+
+const HotspotService = () => {
+ const options = useMemo((): Array => {
+ return [
+ { name: 'Hotspot', Icon: Hotspot, component: HotspotPage },
+ { name: 'Explorer', Icon: Map, component: ExplorerPage },
+ { name: 'AddHotspot', Icon: Add, component: AddHotspotPage },
+ { name: 'ClaimTokens', Icon: Coin, component: ClaimTokensPage },
+ ]
+ }, [])
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default HotspotService
diff --git a/src/app/services/HotspotService/pages/AddHotspotPage.tsx b/src/app/services/HotspotService/pages/AddHotspotPage.tsx
new file mode 100644
index 000000000..3a3237a42
--- /dev/null
+++ b/src/app/services/HotspotService/pages/AddHotspotPage.tsx
@@ -0,0 +1,106 @@
+import Box from '@components/Box'
+import ButtonPressable from '@components/ButtonPressable'
+import Text from '@components/Text'
+import React, { useCallback, useMemo, useRef } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Image } from 'react-native'
+import Add from '@assets/svgs/add.svg'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import ScrollBox from '@components/ScrollBox'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import {
+ OnboardingSheetWrapper,
+ OnboardingSheetRef,
+} from '@features/hotspot-onboarding/OnboardingSheet'
+
+const AddHotspotPage = () => {
+ const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+ const colors = useColors()
+ const spacing = useSpacing()
+ const onboardingSheetRef = useRef(null)
+
+ const showOnboardingSheet = useCallback(() => {
+ onboardingSheetRef.current?.show()
+ }, [onboardingSheetRef])
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ padding: spacing['2xl'],
+ }
+ }, [spacing])
+
+ return (
+ <>
+
+
+
+
+
+
+ {t('AddHotspotPage.title')}
+
+
+ {t('AddHotspotPage.subtitle')}
+
+
+ }
+ backgroundColor="primaryText"
+ titleColor="primaryBackground"
+ title={t('AddHotspotPage.addHotspot')}
+ onPress={showOnboardingSheet}
+ marginBottom="3xl"
+ />
+
+
+ {t('AddHotspotPage.locationAndMountingTips')}
+
+
+
+
+
+
+ >
+ )
+}
+
+export default AddHotspotPage
diff --git a/src/app/services/HotspotService/pages/ClaimTokensPage.tsx b/src/app/services/HotspotService/pages/ClaimTokensPage.tsx
new file mode 100644
index 000000000..d8d346402
--- /dev/null
+++ b/src/app/services/HotspotService/pages/ClaimTokensPage.tsx
@@ -0,0 +1,226 @@
+import Box from '@components/Box'
+import ButtonPressable from '@components/ButtonPressable'
+import ScrollBox from '@components/ScrollBox'
+import Text from '@components/Text'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Image, RefreshControl } from 'react-native'
+import MobileIcon from '@assets/svgs/mobileIconNew.svg'
+import IotIcon from '@assets/svgs/iotIconNew.svg'
+import TouchableContainer from '@components/TouchableContainer'
+import BalanceText from '@components/BalanceText'
+import useHotspots from '@hooks/useHotspots'
+import { toNumber } from '@helium/spl-utils'
+import {
+ MOBILE_LAZY_KEY,
+ IOT_LAZY_KEY,
+ MIN_BALANCE_THRESHOLD,
+} from '@utils/constants'
+import useSubmitTxn from '@hooks/useSubmitTxn'
+import { useBN } from '@hooks/useBN'
+import { useSolOwnedAmount } from '@helium/helium-react-hooks'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+import { BN } from 'bn.js'
+import { useModal } from '@config/storage/ModalsProvider'
+import ProgressBar from '@components/ProgressBar'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import { RootState } from '@store/rootReducer'
+import { useSelector } from 'react-redux'
+
+const ClaimTokensPage = () => {
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const { submitClaimAllRewards } = useSubmitTxn()
+ const wallet = useCurrentWallet()
+ const { showModal } = useModal()
+ const solBalance = useBN(useSolOwnedAmount(wallet).amount)
+ const colors = useColors()
+
+ const hasEnoughSol = useMemo(() => {
+ return (solBalance || new BN(0)).gt(new BN(MIN_BALANCE_THRESHOLD))
+ }, [solBalance])
+
+ const {
+ pendingIotRewards,
+ pendingMobileRewards,
+ hotspotsWithMeta,
+ totalHotspots,
+ loading: hotspotsLoading,
+ fetchAll,
+ } = useHotspots()
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ padding: spacing['2xl'],
+ }
+ }, [spacing])
+
+ const totalPendingIot = useMemo(() => {
+ if (!pendingIotRewards) return 0
+ return toNumber(pendingIotRewards, 6)
+ }, [pendingIotRewards])
+
+ const totalPendingMobile = useMemo(() => {
+ if (!pendingMobileRewards) return 0
+ return toNumber(pendingMobileRewards, 6)
+ }, [pendingMobileRewards])
+
+ const solanaPayment = useSelector(
+ (reduxState: RootState) => reduxState.solana.payment,
+ )
+
+ const claiming = useMemo(() => {
+ return solanaPayment?.loading
+ }, [solanaPayment])
+
+ const claimError = useMemo(() => {
+ return solanaPayment?.error
+ }, [solanaPayment])
+
+ const claimingDisabled = useMemo(() => {
+ return (
+ claiming ||
+ !hasEnoughSol ||
+ (totalPendingIot === 0 && totalPendingMobile === 0)
+ )
+ }, [claiming, hasEnoughSol, totalPendingIot, totalPendingMobile])
+
+ const onClaim = useCallback(async () => {
+ try {
+ const claim = async () => {
+ await submitClaimAllRewards(
+ [IOT_LAZY_KEY, MOBILE_LAZY_KEY],
+ hotspotsWithMeta,
+ totalHotspots,
+ )
+ }
+
+ if (!hasEnoughSol) {
+ showModal({
+ type: 'InsufficientSolConversion',
+ onCancel: async () => {},
+ onSuccess: claim,
+ })
+ } else {
+ await claim()
+ }
+ } catch {}
+ }, [
+ hasEnoughSol,
+ submitClaimAllRewards,
+ hotspotsWithMeta,
+ totalHotspots,
+ showModal,
+ ])
+
+ return (
+
+ }
+ >
+
+
+
+
+ {t('ClaimTokensPage.title')}
+
+
+ {t('ClaimTokensPage.subtitle')}
+
+
+
+
+
+
+
+
+ MOBILE
+
+
+
+
+
+
+
+
+
+
+ IOT
+
+
+
+
+
+
+ {claiming && (
+
+
+
+ )}
+ {claimError && (
+
+ {claimError?.message}
+
+ )}
+
+ )
+}
+
+export default ClaimTokensPage
diff --git a/src/app/services/HotspotService/pages/ExplorerPage.tsx b/src/app/services/HotspotService/pages/ExplorerPage.tsx
new file mode 100644
index 000000000..712b544e1
--- /dev/null
+++ b/src/app/services/HotspotService/pages/ExplorerPage.tsx
@@ -0,0 +1,120 @@
+import Box from '@components/Box'
+import ImageBox from '@components/ImageBox'
+import Map from '@components/Map'
+import useHotspots from '@hooks/useHotspots'
+import {
+ Camera,
+ Location,
+ MapState,
+ MarkerView,
+ UserLocation,
+} from '@rnmapbox/maps'
+import React, { useCallback, useState } from 'react'
+import TotalHotspotPuck from '@assets/svgs/totalHotspotPuck.svg'
+import { useSpacing } from '@config/theme/themeHooks'
+import Text from '@components/Text'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+
+const ExplorerPage = () => {
+ const { hotspotsWithMeta } = useHotspots()
+ const spacing = useSpacing()
+ const [userLocation, setUserLocation] = useState()
+ const [showTotalHotspotPuck, setShowTotalHotspotPuck] = useState(false)
+
+ const handleCameraChanged = useCallback((state: MapState) => {
+ if (state.properties.zoom > 12) {
+ setShowTotalHotspotPuck(true)
+ } else {
+ setShowTotalHotspotPuck(false)
+ }
+ }, [])
+
+ const TotalHotspotPuckContainer = useCallback(() => {
+ if (!showTotalHotspotPuck) return null
+
+ return (
+
+
+
+ {hotspotsWithMeta?.length}
+
+
+
+
+ )
+ }, [showTotalHotspotPuck, hotspotsWithMeta, spacing])
+
+ return (
+
+
+
+
+ )
+}
+
+export default ExplorerPage
diff --git a/src/app/services/HotspotService/pages/HotspotPage.tsx b/src/app/services/HotspotService/pages/HotspotPage.tsx
new file mode 100644
index 000000000..89b0ad3fe
--- /dev/null
+++ b/src/app/services/HotspotService/pages/HotspotPage.tsx
@@ -0,0 +1,96 @@
+import {
+ StackNavigationOptions,
+ StackNavigationProp,
+ createStackNavigator,
+} from '@react-navigation/stack'
+import { HotspotBleProvider } from '@helium/react-native-sdk'
+import React, { useMemo } from 'react'
+import { useColors } from '@config/theme/themeHooks'
+import AssertLocationScreen from '@features/hotspots/AssertLocationScreen'
+import TransferCollectableScreen from '@features/collectables/TransferCollectableScreen'
+import ChangeRewardsRecipientScreen from '@features/hotspots/ChangeRewardsRecipientScreen'
+import AntennaSetupScreen from '@features/hotspots/AntennaSetupScreen'
+import Diagnostics from '@features/hotspots/Diagnostics'
+import ModifyWifiScreen from '@features/hotspots/ModifyWifiScreen'
+import HotspotPage from '@features/hotspots/HotspotPage'
+import HotspotDetails from '@features/hotspots/HotspotDetails'
+import HotspotConfig from '@features/hotspots/HotspotConfig'
+import { HotspotWithPendingRewards } from '../../../../types/solana'
+
+export type HotspotStackParamList = {
+ HotspotPage: undefined
+ HotspotDetails: {
+ hotspot: HotspotWithPendingRewards
+ }
+ HotspotConfig: {
+ hotspot: HotspotWithPendingRewards
+ hotspotAddress: string
+ }
+ AssertLocationScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ TransferCollectableScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ ChangeRewardsRecipientScreen: {
+ hotspot: HotspotWithPendingRewards
+ }
+ AntennaSetupScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ DiagnosticsScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ ModifyWifiScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+}
+
+export type HotspotNavigationProp = StackNavigationProp
+
+const HotspotStack = createStackNavigator()
+
+const HotspotPageNavigator = () => {
+ const colors = useColors()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ headerShown: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ } as StackNavigationOptions),
+ [colors],
+ )
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default HotspotPageNavigator
diff --git a/src/services/NotificationsService/index.tsx b/src/app/services/NotificationsService/index.tsx
similarity index 100%
rename from src/services/NotificationsService/index.tsx
rename to src/app/services/NotificationsService/index.tsx
diff --git a/src/services/ServiceSheet.tsx b/src/app/services/ServiceSheet.tsx
similarity index 62%
rename from src/services/ServiceSheet.tsx
rename to src/app/services/ServiceSheet.tsx
index 2e993c38f..6267d42ed 100644
--- a/src/services/ServiceSheet.tsx
+++ b/src/app/services/ServiceSheet.tsx
@@ -1,8 +1,21 @@
import React, { useCallback, useMemo, useRef, useState } from 'react'
import Box from '@components/Box'
import BottomSheet from '@gorhom/bottom-sheet'
-import { useColors, useSpacing } from '@theme/themeHooks'
-import { FadeIn, FadeOut } from 'react-native-reanimated'
+import {
+ useBackgroundStyle,
+ useBorderRadii,
+ useColors,
+ useSpacing,
+} from '@config/theme/themeHooks'
+import {
+ FadeIn,
+ FadeOut,
+ useAnimatedStyle,
+ interpolate,
+ Extrapolation,
+ withSpring,
+ withTiming,
+} from 'react-native-reanimated'
import { ReAnimatedBox, Text } from '@components'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import AccountIcon from '@components/AccountIcon'
@@ -10,26 +23,39 @@ import SideDrawer from '@components/SideDrawer'
import MenuButton from '@components/MenuButton'
import { useNavigation } from '@react-navigation/native'
import { ThemeProvider } from '@shopify/restyle'
-import { lightTheme } from '@theme/theme'
+import { lightTheme } from '@config/theme/theme'
import HeliumBottomSheet from '@components/HeliumBottomSheet'
-import { FadeInSlow } from '@components/FadeInOut'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import changeNavigationBarColor from 'react-native-navigation-bar-color'
+import { Platform, StyleProp, ViewStyle } from 'react-native'
+import { wh } from '@utils/layout'
+import { useSelector } from 'react-redux'
+import { RootState } from '@store/rootReducer'
import { ServiceSheetNavigationProp } from './serviceSheetTypes'
type ServiceSheetProps = {
currentService: string
+ isChild?: boolean
children?: React.ReactNode
}
-const ServiceSheet = ({ children, currentService }: ServiceSheetProps) => {
+const ServiceSheet = ({
+ children,
+ currentService,
+ isChild,
+}: ServiceSheetProps) => {
const [isExpanded, setIsExpanded] = useState(false)
const [bottomSheetOpen, setBottomSheetOpen] = useState(true)
const bottomSheetRef = useRef(null)
const serviceNav = useNavigation()
const { top } = useSafeAreaInsets()
const colors = useColors()
+ const spacing = useSpacing()
+ const bottomSheetStyle = useBackgroundStyle('primaryText')
+ const borderRadii = useBorderRadii()
+
+ const { rootSheetPosition } = useSelector((state: RootState) => state.app)
const onRoute = useCallback(
(value: string) => {
@@ -97,8 +123,62 @@ const ServiceSheet = ({ children, currentService }: ServiceSheetProps) => {
setBottomSheetOpen(index === 0)
}, [])
+ const snapPoints = useMemo(() => {
+ if (Platform.OS === 'ios') {
+ return [
+ wh -
+ top -
+ spacing[20] +
+ interpolate(
+ rootSheetPosition || 0,
+ [0, wh],
+ [0, 14],
+ Extrapolation.CLAMP,
+ ),
+ ]
+ }
+
+ return [wh - top - spacing[20] - spacing[2]]
+ }, [top, spacing, rootSheetPosition])
+
+ const backgroundStyle = useMemo(
+ () =>
+ ({
+ ...bottomSheetStyle,
+ height: '100%',
+ borderRadius: borderRadii['4xl'] + borderRadii['4xl'],
+ backgroundColor: colors['fg.white'],
+ } as StyleProp),
+ [bottomSheetStyle, borderRadii, colors],
+ )
+
+ const sheetStyle = useAnimatedStyle(() => {
+ if (!rootSheetPosition)
+ return {
+ transform: [{ scaleX: withSpring(1) }],
+ opacity: withTiming(1),
+ }
+
+ return {
+ transform: [
+ {
+ scaleX: withSpring(
+ interpolate(
+ rootSheetPosition,
+ [0, wh],
+ [1, 0.9],
+ Extrapolation.CLAMP,
+ ),
+ ),
+ },
+ ],
+ opacity: withTiming(
+ interpolate(rootSheetPosition, [0, wh], [1, 0.15], Extrapolation.CLAMP),
+ ),
+ }
+ }, [isChild, rootSheetPosition])
return (
-
+
{
walletsSelected={bottomSheetOpen && currentService === 'wallets'}
onClose={onCloseSheet}
/>
-
-
-
- {children}
-
-
-
-
+
+
+
+
+ {children}
+
+
+
+
+
)
}
@@ -157,9 +241,10 @@ const Header = ({
return (
{
const colors = useColors()
const borderRadii = useBorderRadii()
const [currentService, setCurrentService] = useState('wallet')
-
+ const dispatch = useAppDispatch()
const navigatorScreenOptions = useMemo(
() =>
({
@@ -33,32 +35,36 @@ const ServiceSheetNavigator = () => {
[borderRadii, colors],
)
- const onFocus = useCallback((target: string | undefined) => {
- switch (target?.split('-')[0]) {
- default:
- case 'WalletService':
- setCurrentService('wallet')
- break
- case 'HotspotService':
- setCurrentService('hotspots')
- break
- case 'AccountsService':
- setCurrentService('wallets')
- break
- case 'GovernanceService':
- setCurrentService('governance')
- break
- case 'BrowserService':
- setCurrentService('browser')
- break
- case 'NotificationsService':
- setCurrentService('notifications')
- break
- case 'SettingsService':
- setCurrentService('settings')
- break
- }
- }, [])
+ const onFocus = useCallback(
+ (target: string | undefined) => {
+ dispatch(appSlice.actions.setRootSheetPosition(undefined))
+ switch (target?.split('-')[0]) {
+ default:
+ case 'WalletService':
+ setCurrentService('wallet')
+ break
+ case 'HotspotService':
+ setCurrentService('hotspots')
+ break
+ case 'AccountsService':
+ setCurrentService('wallets')
+ break
+ case 'GovernanceService':
+ setCurrentService('governance')
+ break
+ case 'BrowserService':
+ setCurrentService('browser')
+ break
+ case 'NotificationsService':
+ setCurrentService('notifications')
+ break
+ case 'SettingsService':
+ setCurrentService('settings')
+ break
+ }
+ },
+ [dispatch],
+ )
return (
diff --git a/src/services/SettingsService/index.tsx b/src/app/services/SettingsService/index.tsx
similarity index 100%
rename from src/services/SettingsService/index.tsx
rename to src/app/services/SettingsService/index.tsx
diff --git a/src/services/WalletService/index.tsx b/src/app/services/WalletService/index.tsx
similarity index 85%
rename from src/services/WalletService/index.tsx
rename to src/app/services/WalletService/index.tsx
index 439aa93df..bb7528592 100644
--- a/src/services/WalletService/index.tsx
+++ b/src/app/services/WalletService/index.tsx
@@ -1,9 +1,9 @@
import React, { useMemo } from 'react'
-import Wallet from '@assets/images/wallet.svg'
-import Receive from '@assets/images/receive.svg'
-import Send from '@assets/images/send.svg'
-import Swap from '@assets/images/swap.svg'
-import Transactions from '@assets/images/transactionsTabIcon.svg'
+import Wallet from '@assets/svgs/wallet.svg'
+import Receive from '@assets/svgs/receive.svg'
+import Send from '@assets/svgs/send.svg'
+import Swap from '@assets/svgs/swap.svg'
+import Transactions from '@assets/svgs/transactionsTabIcon.svg'
import ServiceSheetPage, {
ServiceNavBarOption,
} from '@components/ServiceSheetPage'
diff --git a/src/services/WalletService/pages/ReceivePage/index.tsx b/src/app/services/WalletService/pages/ReceivePage/index.tsx
similarity index 96%
rename from src/services/WalletService/pages/ReceivePage/index.tsx
rename to src/app/services/WalletService/pages/ReceivePage/index.tsx
index 163afa2de..078419993 100644
--- a/src/services/WalletService/pages/ReceivePage/index.tsx
+++ b/src/app/services/WalletService/pages/ReceivePage/index.tsx
@@ -6,8 +6,8 @@ import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { Image } from 'react-native'
import QRCode from 'react-native-qrcode-svg'
-import CarotRight from '@assets/images/carot-right.svg'
-import { useColors } from '@theme/themeHooks'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import { useColors } from '@config/theme/themeHooks'
import useCopyText from '@hooks/useCopyText'
import TouchableContainer from '@components/TouchableContainer'
import { ReAnimatedBox } from '@components/AnimatedBox'
diff --git a/src/services/WalletService/pages/SendPage/SentPageNavigator.tsx b/src/app/services/WalletService/pages/SendPage/index.tsx
similarity index 61%
rename from src/services/WalletService/pages/SendPage/SentPageNavigator.tsx
rename to src/app/services/WalletService/pages/SendPage/index.tsx
index 34eee8c98..4c6ff0387 100644
--- a/src/services/WalletService/pages/SendPage/SentPageNavigator.tsx
+++ b/src/app/services/WalletService/pages/SendPage/index.tsx
@@ -4,10 +4,12 @@ import {
createStackNavigator,
} from '@react-navigation/stack'
import React, { useMemo } from 'react'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import PaymentScreen from '@features/payment/PaymentScreen'
import AddressBookNavigator from '@features/addressBook/AddressBookNavigator'
-import { PaymentRouteParam } from '@services/WalletService'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn } from 'react-native-reanimated'
export type SendStackParamList = {
PaymentScreen: undefined | PaymentRouteParam
@@ -30,10 +32,12 @@ const SendPageNavigator = () => {
)
return (
-
-
-
-
+
+
+
+
+
+
)
}
diff --git a/src/services/WalletService/pages/SwapPage/index.tsx b/src/app/services/WalletService/pages/SwapPage/index.tsx
similarity index 100%
rename from src/services/WalletService/pages/SwapPage/index.tsx
rename to src/app/services/WalletService/pages/SwapPage/index.tsx
diff --git a/src/services/WalletService/pages/TransactionsPage/index.tsx b/src/app/services/WalletService/pages/TransactionsPage/index.tsx
similarity index 100%
rename from src/services/WalletService/pages/TransactionsPage/index.tsx
rename to src/app/services/WalletService/pages/TransactionsPage/index.tsx
diff --git a/src/services/WalletService/pages/WalletPage/WalletPageNavigator.tsx b/src/app/services/WalletService/pages/WalletPage/index.tsx
similarity index 89%
rename from src/services/WalletService/pages/WalletPage/WalletPageNavigator.tsx
rename to src/app/services/WalletService/pages/WalletPage/index.tsx
index 4b1714e9b..5d38b2801 100644
--- a/src/services/WalletService/pages/WalletPage/WalletPageNavigator.tsx
+++ b/src/app/services/WalletService/pages/WalletPage/index.tsx
@@ -4,20 +4,20 @@ import {
createStackNavigator,
} from '@react-navigation/stack'
import React, { useMemo } from 'react'
-import AccountTokenScreen from '@features/account/AccountTokenScreen'
-import { useColors } from '@theme/themeHooks'
-import AirdropScreen from '@features/account/AirdropScreen'
+import AccountTokenScreen from '@features/wallet/AccountTokenScreen'
+import { useColors } from '@config/theme/themeHooks'
+import AirdropScreen from '@features/wallet/AirdropScreen'
import ConfirmPinScreen from '@components/ConfirmPinScreen'
import BurnScreen from '@features/burn/BurnScreen'
-import AccountManageTokenListScreen from '@features/account/AccountManageTokenListScreen'
+import AccountManageTokenListScreen from '@features/wallet/AccountManageTokenListScreen'
import PaymentQrScanner from '@features/payment/PaymentQrScanner'
import NftDetailsScreen from '@features/collectables/NftDetailsScreen'
import CollectionScreen from '@features/collectables/CollectionScreen'
import ManageCollectables from '@features/collectables/ManageCollectables'
import TransferCollectableScreen from '@features/collectables/TransferCollectableScreen'
import TransferCompleteScreen from '@features/collectables/TransferCompleteScreen'
-import { CompressedNFT } from '../../../../types/solana'
-import TokensTabs from './TokensTabs'
+import TokensTabs from '@features/wallet/TokensTabs'
+import { CompressedNFT } from '../../../../../types/solana'
export type BurnRouteParam = {
address: string
diff --git a/src/services/serviceSheetTypes.ts b/src/app/services/serviceSheetTypes.ts
similarity index 100%
rename from src/services/serviceSheetTypes.ts
rename to src/app/services/serviceSheetTypes.ts
diff --git a/src/assets/images/account.svg b/src/assets/images/account.svg
deleted file mode 100644
index d3fdd19c2..000000000
--- a/src/assets/images/account.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/accountIntroIconOne.svg b/src/assets/images/accountIntroIconOne.svg
deleted file mode 100644
index 0bd00bd56..000000000
--- a/src/assets/images/accountIntroIconOne.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/src/assets/images/add.svg b/src/assets/images/add.svg
deleted file mode 100644
index 4598139bf..000000000
--- a/src/assets/images/add.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/addHotspotImage.png b/src/assets/images/addHotspotImage.png
new file mode 100644
index 000000000..ef4650b85
Binary files /dev/null and b/src/assets/images/addHotspotImage.png differ
diff --git a/src/assets/images/addHotspotImage@2x.png b/src/assets/images/addHotspotImage@2x.png
new file mode 100644
index 000000000..f5e94b195
Binary files /dev/null and b/src/assets/images/addHotspotImage@2x.png differ
diff --git a/src/assets/images/addHotspotImage@3x.png b/src/assets/images/addHotspotImage@3x.png
new file mode 100644
index 000000000..7c38ee20a
Binary files /dev/null and b/src/assets/images/addHotspotImage@3x.png differ
diff --git a/src/assets/images/bigClose.svg b/src/assets/images/bigClose.svg
deleted file mode 100644
index 491258957..000000000
--- a/src/assets/images/bigClose.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/assets/images/bluetooth.svg b/src/assets/images/bluetooth.svg
deleted file mode 100644
index 43e690a02..000000000
--- a/src/assets/images/bluetooth.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/boxTriangleTop.svg b/src/assets/images/boxTriangleTop.svg
deleted file mode 100644
index 24c5dadae..000000000
--- a/src/assets/images/boxTriangleTop.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/building.png b/src/assets/images/building.png
new file mode 100644
index 000000000..fdd695e08
Binary files /dev/null and b/src/assets/images/building.png differ
diff --git a/src/assets/images/building@2x.png b/src/assets/images/building@2x.png
new file mode 100644
index 000000000..8cae3ad89
Binary files /dev/null and b/src/assets/images/building@2x.png differ
diff --git a/src/assets/images/building@3x.png b/src/assets/images/building@3x.png
new file mode 100644
index 000000000..5271d56dd
Binary files /dev/null and b/src/assets/images/building@3x.png differ
diff --git a/src/assets/images/buy.svg b/src/assets/images/buy.svg
deleted file mode 100644
index 44803aa95..000000000
--- a/src/assets/images/buy.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/chevronDown.svg b/src/assets/images/chevronDown.svg
deleted file mode 100644
index 5cf6154fd..000000000
--- a/src/assets/images/chevronDown.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/claimTokensIcon.png b/src/assets/images/claimTokensIcon.png
new file mode 100644
index 000000000..25a36fb46
Binary files /dev/null and b/src/assets/images/claimTokensIcon.png differ
diff --git a/src/assets/images/claimTokensIcon@2x.png b/src/assets/images/claimTokensIcon@2x.png
new file mode 100644
index 000000000..b47d61c7d
Binary files /dev/null and b/src/assets/images/claimTokensIcon@2x.png differ
diff --git a/src/assets/images/claimTokensIcon@3x.png b/src/assets/images/claimTokensIcon@3x.png
new file mode 100644
index 000000000..c388d6986
Binary files /dev/null and b/src/assets/images/claimTokensIcon@3x.png differ
diff --git a/src/assets/images/cog.svg b/src/assets/images/cog.svg
deleted file mode 100644
index 831241c60..000000000
--- a/src/assets/images/cog.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/collectableIcon.svg b/src/assets/images/collectableIcon.svg
deleted file mode 100644
index 092e0bfbe..000000000
--- a/src/assets/images/collectableIcon.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/courthouse.svg b/src/assets/images/courthouse.svg
deleted file mode 100644
index 39df878fd..000000000
--- a/src/assets/images/courthouse.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/assets/images/crowdspot-question.svg b/src/assets/images/crowdspot-question.svg
deleted file mode 100644
index a6f7c4c4b..000000000
--- a/src/assets/images/crowdspot-question.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/assets/images/dc.svg b/src/assets/images/dc.svg
deleted file mode 100644
index b34a8badc..000000000
--- a/src/assets/images/dc.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/assets/images/dollar.svg b/src/assets/images/dollar.svg
deleted file mode 100644
index 91cb894f9..000000000
--- a/src/assets/images/dollar.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/assets/images/earth-globe.svg b/src/assets/images/earth-globe.svg
deleted file mode 100644
index 131eb002f..000000000
--- a/src/assets/images/earth-globe.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/expandedViewIcon.svg b/src/assets/images/expandedViewIcon.svg
deleted file mode 100644
index 8a7c148cb..000000000
--- a/src/assets/images/expandedViewIcon.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/src/assets/images/ffiHotspot.png b/src/assets/images/ffiHotspot.png
new file mode 100644
index 000000000..0b2dd5ac2
Binary files /dev/null and b/src/assets/images/ffiHotspot.png differ
diff --git a/src/assets/images/ffiHotspot@2x.png b/src/assets/images/ffiHotspot@2x.png
new file mode 100644
index 000000000..addbcc02d
Binary files /dev/null and b/src/assets/images/ffiHotspot@2x.png differ
diff --git a/src/assets/images/ffiHotspot@3x.png b/src/assets/images/ffiHotspot@3x.png
new file mode 100644
index 000000000..6cda88e44
Binary files /dev/null and b/src/assets/images/ffiHotspot@3x.png differ
diff --git a/src/assets/images/hex.svg b/src/assets/images/hex.svg
deleted file mode 100644
index 71831a536..000000000
--- a/src/assets/images/hex.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/hotspotBeam.png b/src/assets/images/hotspotBeam.png
new file mode 100644
index 000000000..6752129aa
Binary files /dev/null and b/src/assets/images/hotspotBeam.png differ
diff --git a/src/assets/images/hotspotBeam@2x.png b/src/assets/images/hotspotBeam@2x.png
new file mode 100644
index 000000000..5777361ef
Binary files /dev/null and b/src/assets/images/hotspotBeam@2x.png differ
diff --git a/src/assets/images/hotspotBeam@3x.png b/src/assets/images/hotspotBeam@3x.png
new file mode 100644
index 000000000..7eaaf3930
Binary files /dev/null and b/src/assets/images/hotspotBeam@3x.png differ
diff --git a/src/assets/images/hotspotBlackMarker.png b/src/assets/images/hotspotBlackMarker.png
new file mode 100644
index 000000000..9efb61872
Binary files /dev/null and b/src/assets/images/hotspotBlackMarker.png differ
diff --git a/src/assets/images/hotspotBlackMarker@2x.png b/src/assets/images/hotspotBlackMarker@2x.png
new file mode 100644
index 000000000..36b8d9971
Binary files /dev/null and b/src/assets/images/hotspotBlackMarker@2x.png differ
diff --git a/src/assets/images/hotspotBlackMarker@3x.png b/src/assets/images/hotspotBlackMarker@3x.png
new file mode 100644
index 000000000..2f9947c0e
Binary files /dev/null and b/src/assets/images/hotspotBlackMarker@3x.png differ
diff --git a/src/assets/images/hotspotBox.png b/src/assets/images/hotspotBox.png
new file mode 100644
index 000000000..9f4dfa6f1
Binary files /dev/null and b/src/assets/images/hotspotBox.png differ
diff --git a/src/assets/images/hotspotBox@2x.png b/src/assets/images/hotspotBox@2x.png
new file mode 100644
index 000000000..1d5b36f73
Binary files /dev/null and b/src/assets/images/hotspotBox@2x.png differ
diff --git a/src/assets/images/hotspotBox@3x.png b/src/assets/images/hotspotBox@3x.png
new file mode 100644
index 000000000..d925826ca
Binary files /dev/null and b/src/assets/images/hotspotBox@3x.png differ
diff --git a/src/assets/images/hotspotEthernet.png b/src/assets/images/hotspotEthernet.png
new file mode 100644
index 000000000..216ea14a3
Binary files /dev/null and b/src/assets/images/hotspotEthernet.png differ
diff --git a/src/assets/images/hotspotEthernet@2x.png b/src/assets/images/hotspotEthernet@2x.png
new file mode 100644
index 000000000..e6fe77504
Binary files /dev/null and b/src/assets/images/hotspotEthernet@2x.png differ
diff --git a/src/assets/images/hotspotEthernet@3x.png b/src/assets/images/hotspotEthernet@3x.png
new file mode 100644
index 000000000..0a2383bf8
Binary files /dev/null and b/src/assets/images/hotspotEthernet@3x.png differ
diff --git a/src/assets/images/hotspotOutdoorSmall.png b/src/assets/images/hotspotOutdoorSmall.png
new file mode 100644
index 000000000..3fefbef4d
Binary files /dev/null and b/src/assets/images/hotspotOutdoorSmall.png differ
diff --git a/src/assets/images/hotspotOutdoorSmall@2x.png b/src/assets/images/hotspotOutdoorSmall@2x.png
new file mode 100644
index 000000000..69f85ebef
Binary files /dev/null and b/src/assets/images/hotspotOutdoorSmall@2x.png differ
diff --git a/src/assets/images/hotspotOutdoorSmall@3x.png b/src/assets/images/hotspotOutdoorSmall@3x.png
new file mode 100644
index 000000000..e5b440a03
Binary files /dev/null and b/src/assets/images/hotspotOutdoorSmall@3x.png differ
diff --git a/src/assets/images/hotspotQR.png b/src/assets/images/hotspotQR.png
new file mode 100644
index 000000000..777dcca2c
Binary files /dev/null and b/src/assets/images/hotspotQR.png differ
diff --git a/src/assets/images/hotspotQR@2x.png b/src/assets/images/hotspotQR@2x.png
new file mode 100644
index 000000000..26f9c7a85
Binary files /dev/null and b/src/assets/images/hotspotQR@2x.png differ
diff --git a/src/assets/images/hotspotQR@3x.png b/src/assets/images/hotspotQR@3x.png
new file mode 100644
index 000000000..46b41cc12
Binary files /dev/null and b/src/assets/images/hotspotQR@3x.png differ
diff --git a/src/assets/images/indoorHotspot.png b/src/assets/images/indoorHotspot.png
new file mode 100644
index 000000000..3047b4410
Binary files /dev/null and b/src/assets/images/indoorHotspot.png differ
diff --git a/src/assets/images/indoorHotspot@2x.png b/src/assets/images/indoorHotspot@2x.png
new file mode 100644
index 000000000..d76b96d69
Binary files /dev/null and b/src/assets/images/indoorHotspot@2x.png differ
diff --git a/src/assets/images/indoorHotspot@3x.png b/src/assets/images/indoorHotspot@3x.png
new file mode 100644
index 000000000..ee3db6413
Binary files /dev/null and b/src/assets/images/indoorHotspot@3x.png differ
diff --git a/src/assets/images/indoorHotspotBig.png b/src/assets/images/indoorHotspotBig.png
new file mode 100644
index 000000000..e6043fd29
Binary files /dev/null and b/src/assets/images/indoorHotspotBig.png differ
diff --git a/src/assets/images/indoorHotspotBig@2x.png b/src/assets/images/indoorHotspotBig@2x.png
new file mode 100644
index 000000000..a7fff3db3
Binary files /dev/null and b/src/assets/images/indoorHotspotBig@2x.png differ
diff --git a/src/assets/images/indoorHotspotBig@3x.png b/src/assets/images/indoorHotspotBig@3x.png
new file mode 100644
index 000000000..03e3cfe4f
Binary files /dev/null and b/src/assets/images/indoorHotspotBig@3x.png differ
diff --git a/src/assets/images/indoorHotspotBox.png b/src/assets/images/indoorHotspotBox.png
new file mode 100644
index 000000000..c7562b2a5
Binary files /dev/null and b/src/assets/images/indoorHotspotBox.png differ
diff --git a/src/assets/images/indoorHotspotBox@2x.png b/src/assets/images/indoorHotspotBox@2x.png
new file mode 100644
index 000000000..185872879
Binary files /dev/null and b/src/assets/images/indoorHotspotBox@2x.png differ
diff --git a/src/assets/images/indoorHotspotBox@3x.png b/src/assets/images/indoorHotspotBox@3x.png
new file mode 100644
index 000000000..78b13f9fc
Binary files /dev/null and b/src/assets/images/indoorHotspotBox@3x.png differ
diff --git a/src/assets/images/indoorHotspotEthernet.png b/src/assets/images/indoorHotspotEthernet.png
new file mode 100644
index 000000000..114fdccb7
Binary files /dev/null and b/src/assets/images/indoorHotspotEthernet.png differ
diff --git a/src/assets/images/indoorHotspotEthernet@2x.png b/src/assets/images/indoorHotspotEthernet@2x.png
new file mode 100644
index 000000000..433d265aa
Binary files /dev/null and b/src/assets/images/indoorHotspotEthernet@2x.png differ
diff --git a/src/assets/images/indoorHotspotEthernet@3x.png b/src/assets/images/indoorHotspotEthernet@3x.png
new file mode 100644
index 000000000..dfd16fc24
Binary files /dev/null and b/src/assets/images/indoorHotspotEthernet@3x.png differ
diff --git a/src/assets/images/indoorHotspotQR.png b/src/assets/images/indoorHotspotQR.png
new file mode 100644
index 000000000..f04ba29ba
Binary files /dev/null and b/src/assets/images/indoorHotspotQR.png differ
diff --git a/src/assets/images/indoorHotspotQR@2x.png b/src/assets/images/indoorHotspotQR@2x.png
new file mode 100644
index 000000000..ac2e26dfb
Binary files /dev/null and b/src/assets/images/indoorHotspotQR@2x.png differ
diff --git a/src/assets/images/indoorHotspotQR@3x.png b/src/assets/images/indoorHotspotQR@3x.png
new file mode 100644
index 000000000..d21d384cf
Binary files /dev/null and b/src/assets/images/indoorHotspotQR@3x.png differ
diff --git a/src/assets/images/intro.svg b/src/assets/images/intro.svg
deleted file mode 100644
index 0e724a332..000000000
--- a/src/assets/images/intro.svg
+++ /dev/null
@@ -1,33 +0,0 @@
-
diff --git a/src/assets/images/iotCircle.svg b/src/assets/images/iotCircle.svg
deleted file mode 100644
index a1541dffd..000000000
--- a/src/assets/images/iotCircle.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/iotRewardIcon.svg b/src/assets/images/iotRewardIcon.svg
deleted file mode 100644
index a03ec27be..000000000
--- a/src/assets/images/iotRewardIcon.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
diff --git a/src/assets/images/kerlinkHotspot.png b/src/assets/images/kerlinkHotspot.png
new file mode 100644
index 000000000..4e9d9dceb
Binary files /dev/null and b/src/assets/images/kerlinkHotspot.png differ
diff --git a/src/assets/images/kerlinkHotspot@2x.png b/src/assets/images/kerlinkHotspot@2x.png
new file mode 100644
index 000000000..912454ac1
Binary files /dev/null and b/src/assets/images/kerlinkHotspot@2x.png differ
diff --git a/src/assets/images/kerlinkHotspot@3x.png b/src/assets/images/kerlinkHotspot@3x.png
new file mode 100644
index 000000000..b6a231f1a
Binary files /dev/null and b/src/assets/images/kerlinkHotspot@3x.png differ
diff --git a/src/assets/images/listViewIcon.svg b/src/assets/images/listViewIcon.svg
deleted file mode 100644
index 4f8e83c2f..000000000
--- a/src/assets/images/listViewIcon.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/assets/images/mapPin.svg b/src/assets/images/mapPin.svg
deleted file mode 100644
index 35a5c3a49..000000000
--- a/src/assets/images/mapPin.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/merryIotHotspot.png b/src/assets/images/merryIotHotspot.png
new file mode 100644
index 000000000..a3da7c84c
Binary files /dev/null and b/src/assets/images/merryIotHotspot.png differ
diff --git a/src/assets/images/merryIotHotspot@2x.png b/src/assets/images/merryIotHotspot@2x.png
new file mode 100644
index 000000000..d2b7cd184
Binary files /dev/null and b/src/assets/images/merryIotHotspot@2x.png differ
diff --git a/src/assets/images/merryIotHotspot@3x.png b/src/assets/images/merryIotHotspot@3x.png
new file mode 100644
index 000000000..19cc1612b
Binary files /dev/null and b/src/assets/images/merryIotHotspot@3x.png differ
diff --git a/src/assets/images/mini-icon.svg b/src/assets/images/mini-icon.svg
deleted file mode 100644
index 57923cc14..000000000
--- a/src/assets/images/mini-icon.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/assets/images/mntdHotspot.png b/src/assets/images/mntdHotspot.png
new file mode 100644
index 000000000..450ac498e
Binary files /dev/null and b/src/assets/images/mntdHotspot.png differ
diff --git a/src/assets/images/mntdHotspot@2x.png b/src/assets/images/mntdHotspot@2x.png
new file mode 100644
index 000000000..a17694e40
Binary files /dev/null and b/src/assets/images/mntdHotspot@2x.png differ
diff --git a/src/assets/images/mntdHotspot@3x.png b/src/assets/images/mntdHotspot@3x.png
new file mode 100644
index 000000000..840c056af
Binary files /dev/null and b/src/assets/images/mntdHotspot@3x.png differ
diff --git a/src/assets/images/mobileCircle.svg b/src/assets/images/mobileCircle.svg
deleted file mode 100644
index 19d06cc4d..000000000
--- a/src/assets/images/mobileCircle.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/src/assets/images/mobileHotspot.png b/src/assets/images/mobileHotspot.png
new file mode 100644
index 000000000..f39c94659
Binary files /dev/null and b/src/assets/images/mobileHotspot.png differ
diff --git a/src/assets/images/mobileHotspot@2x.png b/src/assets/images/mobileHotspot@2x.png
new file mode 100644
index 000000000..61b80bcec
Binary files /dev/null and b/src/assets/images/mobileHotspot@2x.png differ
diff --git a/src/assets/images/mobileHotspot@3x.png b/src/assets/images/mobileHotspot@3x.png
new file mode 100644
index 000000000..81e30ccf3
Binary files /dev/null and b/src/assets/images/mobileHotspot@3x.png differ
diff --git a/src/assets/images/mobileRewardIcon.svg b/src/assets/images/mobileRewardIcon.svg
deleted file mode 100644
index 87f68cb12..000000000
--- a/src/assets/images/mobileRewardIcon.svg
+++ /dev/null
@@ -1,21 +0,0 @@
-
diff --git a/src/assets/images/multiply.svg b/src/assets/images/multiply.svg
deleted file mode 100644
index 92b40f669..000000000
--- a/src/assets/images/multiply.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/assets/images/nft.svg b/src/assets/images/nft.svg
deleted file mode 100644
index 33ef0c378..000000000
--- a/src/assets/images/nft.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/notificationBell.svg b/src/assets/images/notificationBell.svg
deleted file mode 100644
index 39e2fe56a..000000000
--- a/src/assets/images/notificationBell.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/notifications.svg b/src/assets/images/notifications.svg
deleted file mode 100644
index 456708765..000000000
--- a/src/assets/images/notifications.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/assets/images/ogHotspot.png b/src/assets/images/ogHotspot.png
new file mode 100644
index 000000000..4e6193e78
Binary files /dev/null and b/src/assets/images/ogHotspot.png differ
diff --git a/src/assets/images/ogHotspot@2x.png b/src/assets/images/ogHotspot@2x.png
new file mode 100644
index 000000000..3b5bac409
Binary files /dev/null and b/src/assets/images/ogHotspot@2x.png differ
diff --git a/src/assets/images/ogHotspot@3x.png b/src/assets/images/ogHotspot@3x.png
new file mode 100644
index 000000000..cd2e6a5c7
Binary files /dev/null and b/src/assets/images/ogHotspot@3x.png differ
diff --git a/src/assets/images/outdoorHotspot.png b/src/assets/images/outdoorHotspot.png
new file mode 100644
index 000000000..768ee59fd
Binary files /dev/null and b/src/assets/images/outdoorHotspot.png differ
diff --git a/src/assets/images/outdoorHotspot@2x.png b/src/assets/images/outdoorHotspot@2x.png
new file mode 100644
index 000000000..1c3a92c41
Binary files /dev/null and b/src/assets/images/outdoorHotspot@2x.png differ
diff --git a/src/assets/images/outdoorHotspot@3x.png b/src/assets/images/outdoorHotspot@3x.png
new file mode 100644
index 000000000..879039c13
Binary files /dev/null and b/src/assets/images/outdoorHotspot@3x.png differ
diff --git a/src/assets/images/passwordIcon.png b/src/assets/images/passwordIcon.png
new file mode 100644
index 000000000..2486fc5c5
Binary files /dev/null and b/src/assets/images/passwordIcon.png differ
diff --git a/src/assets/images/passwordIcon@2x.png b/src/assets/images/passwordIcon@2x.png
new file mode 100644
index 000000000..295211c8f
Binary files /dev/null and b/src/assets/images/passwordIcon@2x.png differ
diff --git a/src/assets/images/passwordIcon@3x.png b/src/assets/images/passwordIcon@3x.png
new file mode 100644
index 000000000..1637d2b13
Binary files /dev/null and b/src/assets/images/passwordIcon@3x.png differ
diff --git a/src/assets/images/puck.png b/src/assets/images/puck.png
new file mode 100644
index 000000000..55fb9e412
Binary files /dev/null and b/src/assets/images/puck.png differ
diff --git a/src/assets/images/puck@2x.png b/src/assets/images/puck@2x.png
new file mode 100644
index 000000000..6ecc82b81
Binary files /dev/null and b/src/assets/images/puck@2x.png differ
diff --git a/src/assets/images/puck@3x.png b/src/assets/images/puck@3x.png
new file mode 100644
index 000000000..25b249097
Binary files /dev/null and b/src/assets/images/puck@3x.png differ
diff --git a/src/assets/images/puckNoBearing.png b/src/assets/images/puckNoBearing.png
new file mode 100644
index 000000000..28fa149af
Binary files /dev/null and b/src/assets/images/puckNoBearing.png differ
diff --git a/src/assets/images/puckNoBearing@2x.png b/src/assets/images/puckNoBearing@2x.png
new file mode 100644
index 000000000..92e1cb302
Binary files /dev/null and b/src/assets/images/puckNoBearing@2x.png differ
diff --git a/src/assets/images/puckNoBearing@3x.png b/src/assets/images/puckNoBearing@3x.png
new file mode 100644
index 000000000..322e2bca5
Binary files /dev/null and b/src/assets/images/puckNoBearing@3x.png differ
diff --git a/src/assets/images/rewardBg.svg b/src/assets/images/rewardBg.svg
deleted file mode 100644
index d45130276..000000000
--- a/src/assets/images/rewardBg.svg
+++ /dev/null
@@ -1,20 +0,0 @@
-
diff --git a/src/assets/images/satellite.png b/src/assets/images/satellite.png
new file mode 100644
index 000000000..30207b0a0
Binary files /dev/null and b/src/assets/images/satellite.png differ
diff --git a/src/assets/images/satellite@2x.png b/src/assets/images/satellite@2x.png
new file mode 100644
index 000000000..1fe51a709
Binary files /dev/null and b/src/assets/images/satellite@2x.png differ
diff --git a/src/assets/images/satellite@3x.png b/src/assets/images/satellite@3x.png
new file mode 100644
index 000000000..5586b4a1d
Binary files /dev/null and b/src/assets/images/satellite@3x.png differ
diff --git a/src/assets/images/share.svg b/src/assets/images/share.svg
deleted file mode 100644
index 110d97ace..000000000
--- a/src/assets/images/share.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/solanaCircle.svg b/src/assets/images/solanaCircle.svg
deleted file mode 100644
index 44e2d9fa7..000000000
--- a/src/assets/images/solanaCircle.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/assets/images/store.svg b/src/assets/images/store.svg
deleted file mode 100644
index 6764d2dd2..000000000
--- a/src/assets/images/store.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/tip-up.svg b/src/assets/images/tip-up.svg
deleted file mode 100644
index 1ac8554bb..000000000
--- a/src/assets/images/tip-up.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/images/tokenDC.svg b/src/assets/images/tokenDC.svg
deleted file mode 100644
index 111b82708..000000000
--- a/src/assets/images/tokenDC.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/images/tokenIOT.svg b/src/assets/images/tokenIOT.svg
deleted file mode 100644
index a1541dffd..000000000
--- a/src/assets/images/tokenIOT.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/tokenMOBILE.svg b/src/assets/images/tokenMOBILE.svg
deleted file mode 100644
index 757420796..000000000
--- a/src/assets/images/tokenMOBILE.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/tokenSolana.svg b/src/assets/images/tokenSolana.svg
deleted file mode 100644
index ed6f34d95..000000000
--- a/src/assets/images/tokenSolana.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/src/assets/images/trash.svg b/src/assets/images/trash.svg
deleted file mode 100644
index 1fde57329..000000000
--- a/src/assets/images/trash.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/triangleDown.svg b/src/assets/images/triangleDown.svg
deleted file mode 100644
index b043c4986..000000000
--- a/src/assets/images/triangleDown.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/assets/images/vote.svg b/src/assets/images/vote.svg
deleted file mode 100644
index 41254dcce..000000000
--- a/src/assets/images/vote.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/images/CloseCircle.svg b/src/assets/svgs/CloseCircle.svg
similarity index 100%
rename from src/assets/images/CloseCircle.svg
rename to src/assets/svgs/CloseCircle.svg
diff --git a/src/assets/images/activeCircle.svg b/src/assets/svgs/activeCircle.svg
similarity index 100%
rename from src/assets/images/activeCircle.svg
rename to src/assets/svgs/activeCircle.svg
diff --git a/src/assets/svgs/add.svg b/src/assets/svgs/add.svg
new file mode 100644
index 000000000..41e96f224
--- /dev/null
+++ b/src/assets/svgs/add.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/addDapp.svg b/src/assets/svgs/addDapp.svg
similarity index 100%
rename from src/assets/images/addDapp.svg
rename to src/assets/svgs/addDapp.svg
diff --git a/src/assets/images/addressIcon.svg b/src/assets/svgs/addressIcon.svg
similarity index 100%
rename from src/assets/images/addressIcon.svg
rename to src/assets/svgs/addressIcon.svg
diff --git a/src/assets/images/airdrop.svg b/src/assets/svgs/airdrop.svg
similarity index 100%
rename from src/assets/images/airdrop.svg
rename to src/assets/svgs/airdrop.svg
diff --git a/src/assets/images/alert.svg b/src/assets/svgs/alert.svg
similarity index 100%
rename from src/assets/images/alert.svg
rename to src/assets/svgs/alert.svg
diff --git a/src/assets/images/anchorAccount.svg b/src/assets/svgs/anchorAccount.svg
similarity index 100%
rename from src/assets/images/anchorAccount.svg
rename to src/assets/svgs/anchorAccount.svg
diff --git a/src/assets/svgs/arrowDown.svg b/src/assets/svgs/arrowDown.svg
new file mode 100644
index 000000000..175c220d3
--- /dev/null
+++ b/src/assets/svgs/arrowDown.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/arrowRight.svg b/src/assets/svgs/arrowRight.svg
similarity index 100%
rename from src/assets/images/arrowRight.svg
rename to src/assets/svgs/arrowRight.svg
diff --git a/src/assets/images/arrowUp.svg b/src/assets/svgs/arrowUp.svg
similarity index 100%
rename from src/assets/images/arrowUp.svg
rename to src/assets/svgs/arrowUp.svg
diff --git a/src/assets/images/backArrow.svg b/src/assets/svgs/backArrow.svg
similarity index 100%
rename from src/assets/images/backArrow.svg
rename to src/assets/svgs/backArrow.svg
diff --git a/src/assets/images/backspace.svg b/src/assets/svgs/backspace.svg
similarity index 100%
rename from src/assets/images/backspace.svg
rename to src/assets/svgs/backspace.svg
diff --git a/src/assets/images/bigAdd.svg b/src/assets/svgs/bigAdd.svg
similarity index 100%
rename from src/assets/images/bigAdd.svg
rename to src/assets/svgs/bigAdd.svg
diff --git a/src/assets/images/blueCheck.svg b/src/assets/svgs/blueCheck.svg
similarity index 100%
rename from src/assets/images/blueCheck.svg
rename to src/assets/svgs/blueCheck.svg
diff --git a/src/assets/svgs/bluetooth.svg b/src/assets/svgs/bluetooth.svg
new file mode 100644
index 000000000..8df0cf50b
--- /dev/null
+++ b/src/assets/svgs/bluetooth.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/images/bookmark.svg b/src/assets/svgs/bookmark.svg
similarity index 100%
rename from src/assets/images/bookmark.svg
rename to src/assets/svgs/bookmark.svg
diff --git a/src/assets/images/bookmarkFilled.svg b/src/assets/svgs/bookmarkFilled.svg
similarity index 100%
rename from src/assets/images/bookmarkFilled.svg
rename to src/assets/svgs/bookmarkFilled.svg
diff --git a/src/assets/images/browseVoters.svg b/src/assets/svgs/browseVoters.svg
similarity index 96%
rename from src/assets/images/browseVoters.svg
rename to src/assets/svgs/browseVoters.svg
index a29154e6f..53ff1119d 100644
--- a/src/assets/images/browseVoters.svg
+++ b/src/assets/svgs/browseVoters.svg
@@ -1,6 +1,6 @@
diff --git a/src/assets/svgs/cameraCheck.svg b/src/assets/svgs/cameraCheck.svg
new file mode 100644
index 000000000..1e0d2cae6
--- /dev/null
+++ b/src/assets/svgs/cameraCheck.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/cancelledCircle.svg b/src/assets/svgs/cancelledCircle.svg
similarity index 100%
rename from src/assets/images/cancelledCircle.svg
rename to src/assets/svgs/cancelledCircle.svg
diff --git a/src/assets/images/carot-down.svg b/src/assets/svgs/carot-down.svg
similarity index 100%
rename from src/assets/images/carot-down.svg
rename to src/assets/svgs/carot-down.svg
diff --git a/src/assets/images/carot-right.svg b/src/assets/svgs/carot-right.svg
similarity index 100%
rename from src/assets/images/carot-right.svg
rename to src/assets/svgs/carot-right.svg
diff --git a/src/assets/images/carotDownFull.svg b/src/assets/svgs/carotDownFull.svg
similarity index 100%
rename from src/assets/images/carotDownFull.svg
rename to src/assets/svgs/carotDownFull.svg
diff --git a/src/assets/images/checkIco.svg b/src/assets/svgs/checkIco.svg
similarity index 100%
rename from src/assets/images/checkIco.svg
rename to src/assets/svgs/checkIco.svg
diff --git a/src/assets/images/checkmark.svg b/src/assets/svgs/checkmark.svg
similarity index 100%
rename from src/assets/images/checkmark.svg
rename to src/assets/svgs/checkmark.svg
diff --git a/src/assets/svgs/checkmarkCircle.svg b/src/assets/svgs/checkmarkCircle.svg
new file mode 100644
index 000000000..a0f40733a
--- /dev/null
+++ b/src/assets/svgs/checkmarkCircle.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/checkmarkFill.svg b/src/assets/svgs/checkmarkFill.svg
similarity index 100%
rename from src/assets/images/checkmarkFill.svg
rename to src/assets/svgs/checkmarkFill.svg
diff --git a/src/assets/svgs/chevronDown.svg b/src/assets/svgs/chevronDown.svg
new file mode 100644
index 000000000..08f7de437
--- /dev/null
+++ b/src/assets/svgs/chevronDown.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/circleLoader.svg b/src/assets/svgs/circleLoader.svg
similarity index 100%
rename from src/assets/images/circleLoader.svg
rename to src/assets/svgs/circleLoader.svg
diff --git a/src/assets/svgs/clock.svg b/src/assets/svgs/clock.svg
new file mode 100644
index 000000000..6ae655919
--- /dev/null
+++ b/src/assets/svgs/clock.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/close.svg b/src/assets/svgs/close.svg
similarity index 100%
rename from src/assets/images/close.svg
rename to src/assets/svgs/close.svg
diff --git a/src/assets/images/closeCircleFilled.svg b/src/assets/svgs/closeCircleFilled.svg
similarity index 100%
rename from src/assets/images/closeCircleFilled.svg
rename to src/assets/svgs/closeCircleFilled.svg
diff --git a/src/assets/images/closeModal.svg b/src/assets/svgs/closeModal.svg
similarity index 100%
rename from src/assets/images/closeModal.svg
rename to src/assets/svgs/closeModal.svg
diff --git a/src/assets/svgs/coin.svg b/src/assets/svgs/coin.svg
new file mode 100644
index 000000000..194e302cb
--- /dev/null
+++ b/src/assets/svgs/coin.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/collectables.svg b/src/assets/svgs/collectables.svg
similarity index 100%
rename from src/assets/images/collectables.svg
rename to src/assets/svgs/collectables.svg
diff --git a/src/assets/images/config.svg b/src/assets/svgs/config.svg
similarity index 100%
rename from src/assets/images/config.svg
rename to src/assets/svgs/config.svg
diff --git a/src/assets/images/copyAddress.svg b/src/assets/svgs/copyAddress.svg
similarity index 100%
rename from src/assets/images/copyAddress.svg
rename to src/assets/svgs/copyAddress.svg
diff --git a/src/assets/images/createAccount.svg b/src/assets/svgs/createAccount.svg
similarity index 100%
rename from src/assets/images/createAccount.svg
rename to src/assets/svgs/createAccount.svg
diff --git a/src/assets/images/crowdspot.svg b/src/assets/svgs/crowdspot.svg
similarity index 100%
rename from src/assets/images/crowdspot.svg
rename to src/assets/svgs/crowdspot.svg
diff --git a/src/assets/svgs/crown.svg b/src/assets/svgs/crown.svg
new file mode 100644
index 000000000..3dd55b9f1
--- /dev/null
+++ b/src/assets/svgs/crown.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/customWarning.svg b/src/assets/svgs/customWarning.svg
similarity index 100%
rename from src/assets/images/customWarning.svg
rename to src/assets/svgs/customWarning.svg
diff --git a/src/assets/images/dapp-ellipsis.svg b/src/assets/svgs/dapp-ellipsis.svg
similarity index 100%
rename from src/assets/images/dapp-ellipsis.svg
rename to src/assets/svgs/dapp-ellipsis.svg
diff --git a/src/assets/images/detailArrow.svg b/src/assets/svgs/detailArrow.svg
similarity index 100%
rename from src/assets/images/detailArrow.svg
rename to src/assets/svgs/detailArrow.svg
diff --git a/src/assets/images/dots.svg b/src/assets/svgs/dots.svg
similarity index 100%
rename from src/assets/images/dots.svg
rename to src/assets/svgs/dots.svg
diff --git a/src/assets/images/downArrow.svg b/src/assets/svgs/downArrow.svg
similarity index 100%
rename from src/assets/images/downArrow.svg
rename to src/assets/svgs/downArrow.svg
diff --git a/src/assets/images/dripLogo.svg b/src/assets/svgs/dripLogo.svg
similarity index 100%
rename from src/assets/images/dripLogo.svg
rename to src/assets/svgs/dripLogo.svg
diff --git a/src/assets/svgs/electricity.svg b/src/assets/svgs/electricity.svg
new file mode 100644
index 000000000..0a761a71a
--- /dev/null
+++ b/src/assets/svgs/electricity.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/error.svg b/src/assets/svgs/error.svg
similarity index 100%
rename from src/assets/images/error.svg
rename to src/assets/svgs/error.svg
diff --git a/src/assets/svgs/expand.svg b/src/assets/svgs/expand.svg
new file mode 100644
index 000000000..61f5e5bbc
--- /dev/null
+++ b/src/assets/svgs/expand.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/externalLink.svg b/src/assets/svgs/externalLink.svg
similarity index 100%
rename from src/assets/images/externalLink.svg
rename to src/assets/svgs/externalLink.svg
diff --git a/src/assets/svgs/eyeIcon.svg b/src/assets/svgs/eyeIcon.svg
new file mode 100644
index 000000000..bf0394bd2
--- /dev/null
+++ b/src/assets/svgs/eyeIcon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/face.svg b/src/assets/svgs/face.svg
similarity index 100%
rename from src/assets/images/face.svg
rename to src/assets/svgs/face.svg
diff --git a/src/assets/images/fail.svg b/src/assets/svgs/fail.svg
similarity index 100%
rename from src/assets/images/fail.svg
rename to src/assets/svgs/fail.svg
diff --git a/src/assets/images/filter.svg b/src/assets/svgs/filter.svg
similarity index 100%
rename from src/assets/images/filter.svg
rename to src/assets/svgs/filter.svg
diff --git a/src/assets/images/flag.svg b/src/assets/svgs/flag.svg
similarity index 100%
rename from src/assets/images/flag.svg
rename to src/assets/svgs/flag.svg
diff --git a/src/assets/images/globe.svg b/src/assets/svgs/globe.svg
similarity index 100%
rename from src/assets/images/globe.svg
rename to src/assets/svgs/globe.svg
diff --git a/src/assets/images/helium.svg b/src/assets/svgs/helium.svg
similarity index 100%
rename from src/assets/images/helium.svg
rename to src/assets/svgs/helium.svg
diff --git a/src/assets/images/heliumUpdateIcon.svg b/src/assets/svgs/heliumUpdateIcon.svg
similarity index 100%
rename from src/assets/images/heliumUpdateIcon.svg
rename to src/assets/svgs/heliumUpdateIcon.svg
diff --git a/src/assets/svgs/hex.svg b/src/assets/svgs/hex.svg
new file mode 100644
index 000000000..40644d5eb
--- /dev/null
+++ b/src/assets/svgs/hex.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/hnt.svg b/src/assets/svgs/hnt.svg
similarity index 100%
rename from src/assets/images/hnt.svg
rename to src/assets/svgs/hnt.svg
diff --git a/src/assets/images/hotspot.svg b/src/assets/svgs/hotspot.svg
similarity index 100%
rename from src/assets/images/hotspot.svg
rename to src/assets/svgs/hotspot.svg
diff --git a/src/assets/svgs/hotspotMarker.svg b/src/assets/svgs/hotspotMarker.svg
new file mode 100644
index 000000000..8b4bafde7
--- /dev/null
+++ b/src/assets/svgs/hotspotMarker.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/importIcon.svg b/src/assets/svgs/importIcon.svg
similarity index 100%
rename from src/assets/images/importIcon.svg
rename to src/assets/svgs/importIcon.svg
diff --git a/src/assets/images/indentArrow.svg b/src/assets/svgs/indentArrow.svg
similarity index 100%
rename from src/assets/images/indentArrow.svg
rename to src/assets/svgs/indentArrow.svg
diff --git a/src/assets/images/info.svg b/src/assets/svgs/info.svg
similarity index 100%
rename from src/assets/images/info.svg
rename to src/assets/svgs/info.svg
diff --git a/src/assets/images/infoError.svg b/src/assets/svgs/infoError.svg
similarity index 100%
rename from src/assets/images/infoError.svg
rename to src/assets/svgs/infoError.svg
diff --git a/src/assets/svgs/infoIcon.svg b/src/assets/svgs/infoIcon.svg
new file mode 100644
index 000000000..913596728
--- /dev/null
+++ b/src/assets/svgs/infoIcon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/iot.svg b/src/assets/svgs/iot.svg
similarity index 100%
rename from src/assets/images/iot.svg
rename to src/assets/svgs/iot.svg
diff --git a/src/assets/svgs/iotIconNew.svg b/src/assets/svgs/iotIconNew.svg
new file mode 100644
index 000000000..e7e5ed5de
--- /dev/null
+++ b/src/assets/svgs/iotIconNew.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/iotSymbol.svg b/src/assets/svgs/iotSymbol.svg
similarity index 100%
rename from src/assets/images/iotSymbol.svg
rename to src/assets/svgs/iotSymbol.svg
diff --git a/src/assets/images/kabob.svg b/src/assets/svgs/kabob.svg
similarity index 100%
rename from src/assets/images/kabob.svg
rename to src/assets/svgs/kabob.svg
diff --git a/src/assets/images/keystoneLogo.svg b/src/assets/svgs/keystoneLogo.svg
similarity index 100%
rename from src/assets/images/keystoneLogo.svg
rename to src/assets/svgs/keystoneLogo.svg
diff --git a/src/assets/images/ledger-circle.svg b/src/assets/svgs/ledger-circle.svg
similarity index 100%
rename from src/assets/images/ledger-circle.svg
rename to src/assets/svgs/ledger-circle.svg
diff --git a/src/assets/images/ledger.svg b/src/assets/svgs/ledger.svg
similarity index 100%
rename from src/assets/images/ledger.svg
rename to src/assets/svgs/ledger.svg
diff --git a/src/assets/images/lightningBolt.svg b/src/assets/svgs/lightningBolt.svg
similarity index 100%
rename from src/assets/images/lightningBolt.svg
rename to src/assets/svgs/lightningBolt.svg
diff --git a/src/assets/images/link.svg b/src/assets/svgs/link.svg
similarity index 100%
rename from src/assets/images/link.svg
rename to src/assets/svgs/link.svg
diff --git a/src/assets/images/listItemRight.svg b/src/assets/svgs/listItemRight.svg
similarity index 100%
rename from src/assets/images/listItemRight.svg
rename to src/assets/svgs/listItemRight.svg
diff --git a/src/assets/svgs/locationCheckmark.svg b/src/assets/svgs/locationCheckmark.svg
new file mode 100644
index 000000000..dd2a6212c
--- /dev/null
+++ b/src/assets/svgs/locationCheckmark.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/lock.svg b/src/assets/svgs/lock.svg
similarity index 100%
rename from src/assets/images/lock.svg
rename to src/assets/svgs/lock.svg
diff --git a/src/assets/images/lockClosed.svg b/src/assets/svgs/lockClosed.svg
similarity index 100%
rename from src/assets/images/lockClosed.svg
rename to src/assets/svgs/lockClosed.svg
diff --git a/src/assets/images/majorityCircle.svg b/src/assets/svgs/majorityCircle.svg
similarity index 100%
rename from src/assets/images/majorityCircle.svg
rename to src/assets/svgs/majorityCircle.svg
diff --git a/src/assets/svgs/map.svg b/src/assets/svgs/map.svg
new file mode 100644
index 000000000..c3f03cc9d
--- /dev/null
+++ b/src/assets/svgs/map.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/svgs/mapPin.svg b/src/assets/svgs/mapPin.svg
new file mode 100644
index 000000000..a3d1bd761
--- /dev/null
+++ b/src/assets/svgs/mapPin.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/mapUserLocation.svg b/src/assets/svgs/mapUserLocation.svg
similarity index 100%
rename from src/assets/images/mapUserLocation.svg
rename to src/assets/svgs/mapUserLocation.svg
diff --git a/src/assets/images/menu.svg b/src/assets/svgs/menu.svg
similarity index 100%
rename from src/assets/images/menu.svg
rename to src/assets/svgs/menu.svg
diff --git a/src/assets/images/minorityCircle.svg b/src/assets/svgs/minorityCircle.svg
similarity index 100%
rename from src/assets/images/minorityCircle.svg
rename to src/assets/svgs/minorityCircle.svg
diff --git a/src/assets/images/mobile.svg b/src/assets/svgs/mobile.svg
similarity index 100%
rename from src/assets/images/mobile.svg
rename to src/assets/svgs/mobile.svg
diff --git a/src/assets/images/mobileIcon.svg b/src/assets/svgs/mobileIcon.svg
similarity index 100%
rename from src/assets/images/mobileIcon.svg
rename to src/assets/svgs/mobileIcon.svg
diff --git a/src/assets/svgs/mobileIconNew.svg b/src/assets/svgs/mobileIconNew.svg
new file mode 100644
index 000000000..c1b543b3f
--- /dev/null
+++ b/src/assets/svgs/mobileIconNew.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/mobileSymbol.svg b/src/assets/svgs/mobileSymbol.svg
similarity index 100%
rename from src/assets/images/mobileSymbol.svg
rename to src/assets/svgs/mobileSymbol.svg
diff --git a/src/assets/svgs/mobileTextLogo.svg b/src/assets/svgs/mobileTextLogo.svg
new file mode 100644
index 000000000..483d499f1
--- /dev/null
+++ b/src/assets/svgs/mobileTextLogo.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/svgs/modalBackButton.svg b/src/assets/svgs/modalBackButton.svg
new file mode 100644
index 000000000..f7e10d41a
--- /dev/null
+++ b/src/assets/svgs/modalBackButton.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/svgs/modalCheckButton.svg b/src/assets/svgs/modalCheckButton.svg
new file mode 100644
index 000000000..622e26553
--- /dev/null
+++ b/src/assets/svgs/modalCheckButton.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/svgs/modalCheckOnDarkButton.svg b/src/assets/svgs/modalCheckOnDarkButton.svg
new file mode 100644
index 000000000..92b30dad2
--- /dev/null
+++ b/src/assets/svgs/modalCheckOnDarkButton.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/svgs/modalForwardButton.svg b/src/assets/svgs/modalForwardButton.svg
new file mode 100644
index 000000000..51f510009
--- /dev/null
+++ b/src/assets/svgs/modalForwardButton.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/svgs/noCamera.svg b/src/assets/svgs/noCamera.svg
new file mode 100644
index 000000000..f511b9b3a
--- /dev/null
+++ b/src/assets/svgs/noCamera.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/payment.svg b/src/assets/svgs/payment.svg
similarity index 100%
rename from src/assets/images/payment.svg
rename to src/assets/svgs/payment.svg
diff --git a/src/assets/images/paymentArrow.svg b/src/assets/svgs/paymentArrow.svg
similarity index 100%
rename from src/assets/images/paymentArrow.svg
rename to src/assets/svgs/paymentArrow.svg
diff --git a/src/assets/images/paymentFailure.svg b/src/assets/svgs/paymentFailure.svg
similarity index 100%
rename from src/assets/images/paymentFailure.svg
rename to src/assets/svgs/paymentFailure.svg
diff --git a/src/assets/images/paymentSuccess.svg b/src/assets/svgs/paymentSuccess.svg
similarity index 100%
rename from src/assets/images/paymentSuccess.svg
rename to src/assets/svgs/paymentSuccess.svg
diff --git a/src/assets/images/pending.svg b/src/assets/svgs/pending.svg
similarity index 100%
rename from src/assets/images/pending.svg
rename to src/assets/svgs/pending.svg
diff --git a/src/assets/svgs/person.svg b/src/assets/svgs/person.svg
new file mode 100644
index 000000000..1b989ec5e
--- /dev/null
+++ b/src/assets/svgs/person.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/plus.svg b/src/assets/svgs/plus.svg
similarity index 100%
rename from src/assets/images/plus.svg
rename to src/assets/svgs/plus.svg
diff --git a/src/assets/images/qr.svg b/src/assets/svgs/qr.svg
similarity index 100%
rename from src/assets/images/qr.svg
rename to src/assets/svgs/qr.svg
diff --git a/src/assets/images/questionMark.svg b/src/assets/svgs/questionMark.svg
similarity index 100%
rename from src/assets/images/questionMark.svg
rename to src/assets/svgs/questionMark.svg
diff --git a/src/assets/images/receive.svg b/src/assets/svgs/receive.svg
similarity index 100%
rename from src/assets/images/receive.svg
rename to src/assets/svgs/receive.svg
diff --git a/src/assets/images/refresh.svg b/src/assets/svgs/refresh.svg
similarity index 100%
rename from src/assets/images/refresh.svg
rename to src/assets/svgs/refresh.svg
diff --git a/src/assets/images/remixArrowRight.svg b/src/assets/svgs/remixArrowRight.svg
similarity index 100%
rename from src/assets/images/remixArrowRight.svg
rename to src/assets/svgs/remixArrowRight.svg
diff --git a/src/assets/images/remixCancel.svg b/src/assets/svgs/remixCancel.svg
similarity index 100%
rename from src/assets/images/remixCancel.svg
rename to src/assets/svgs/remixCancel.svg
diff --git a/src/assets/images/remixChevronDown.svg b/src/assets/svgs/remixChevronDown.svg
similarity index 100%
rename from src/assets/images/remixChevronDown.svg
rename to src/assets/svgs/remixChevronDown.svg
diff --git a/src/assets/images/remixChevronUp.svg b/src/assets/svgs/remixChevronUp.svg
similarity index 100%
rename from src/assets/images/remixChevronUp.svg
rename to src/assets/svgs/remixChevronUp.svg
diff --git a/src/assets/images/remove.svg b/src/assets/svgs/remove.svg
similarity index 100%
rename from src/assets/images/remove.svg
rename to src/assets/svgs/remove.svg
diff --git a/src/assets/svgs/rightArrow.svg b/src/assets/svgs/rightArrow.svg
new file mode 100644
index 000000000..ab580e6a7
--- /dev/null
+++ b/src/assets/svgs/rightArrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/svgs/rotateIcon.svg b/src/assets/svgs/rotateIcon.svg
new file mode 100644
index 000000000..c06901b72
--- /dev/null
+++ b/src/assets/svgs/rotateIcon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/search.svg b/src/assets/svgs/search.svg
similarity index 100%
rename from src/assets/images/search.svg
rename to src/assets/svgs/search.svg
diff --git a/src/assets/svgs/searchIcon.svg b/src/assets/svgs/searchIcon.svg
new file mode 100644
index 000000000..567d7b23b
--- /dev/null
+++ b/src/assets/svgs/searchIcon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/send.svg b/src/assets/svgs/send.svg
similarity index 100%
rename from src/assets/images/send.svg
rename to src/assets/svgs/send.svg
diff --git a/src/assets/svgs/settings.svg b/src/assets/svgs/settings.svg
new file mode 100644
index 000000000..2fac8a39b
--- /dev/null
+++ b/src/assets/svgs/settings.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/shareAddress.svg b/src/assets/svgs/shareAddress.svg
similarity index 100%
rename from src/assets/images/shareAddress.svg
rename to src/assets/svgs/shareAddress.svg
diff --git a/src/assets/images/smallAdd.svg b/src/assets/svgs/smallAdd.svg
similarity index 100%
rename from src/assets/images/smallAdd.svg
rename to src/assets/svgs/smallAdd.svg
diff --git a/src/assets/images/stake.svg b/src/assets/svgs/stake.svg
similarity index 100%
rename from src/assets/images/stake.svg
rename to src/assets/svgs/stake.svg
diff --git a/src/assets/images/swap.svg b/src/assets/svgs/swap.svg
similarity index 100%
rename from src/assets/images/swap.svg
rename to src/assets/svgs/swap.svg
diff --git a/src/assets/images/swaps.svg b/src/assets/svgs/swaps.svg
similarity index 100%
rename from src/assets/images/swaps.svg
rename to src/assets/svgs/swaps.svg
diff --git a/src/assets/images/swipeIcon.svg b/src/assets/svgs/swipeIcon.svg
similarity index 100%
rename from src/assets/images/swipeIcon.svg
rename to src/assets/svgs/swipeIcon.svg
diff --git a/src/assets/images/terminal.svg b/src/assets/svgs/terminal.svg
similarity index 100%
rename from src/assets/images/terminal.svg
rename to src/assets/svgs/terminal.svg
diff --git a/src/assets/images/tokenHNT.svg b/src/assets/svgs/tokenHNT.svg
similarity index 100%
rename from src/assets/images/tokenHNT.svg
rename to src/assets/svgs/tokenHNT.svg
diff --git a/src/assets/images/tokenSOL.svg b/src/assets/svgs/tokenSOL.svg
similarity index 100%
rename from src/assets/images/tokenSOL.svg
rename to src/assets/svgs/tokenSOL.svg
diff --git a/src/assets/images/tokens.svg b/src/assets/svgs/tokens.svg
similarity index 100%
rename from src/assets/images/tokens.svg
rename to src/assets/svgs/tokens.svg
diff --git a/src/assets/svgs/totalHotspotPuck.svg b/src/assets/svgs/totalHotspotPuck.svg
new file mode 100644
index 000000000..175db764f
--- /dev/null
+++ b/src/assets/svgs/totalHotspotPuck.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/images/transactions.svg b/src/assets/svgs/transactions.svg
similarity index 100%
rename from src/assets/images/transactions.svg
rename to src/assets/svgs/transactions.svg
diff --git a/src/assets/images/transactionsTabIcon.svg b/src/assets/svgs/transactionsTabIcon.svg
similarity index 100%
rename from src/assets/images/transactionsTabIcon.svg
rename to src/assets/svgs/transactionsTabIcon.svg
diff --git a/src/assets/images/txnReceive.svg b/src/assets/svgs/txnReceive.svg
similarity index 100%
rename from src/assets/images/txnReceive.svg
rename to src/assets/svgs/txnReceive.svg
diff --git a/src/assets/images/txnSend.svg b/src/assets/svgs/txnSend.svg
similarity index 100%
rename from src/assets/images/txnSend.svg
rename to src/assets/svgs/txnSend.svg
diff --git a/src/assets/images/unknownAccount.svg b/src/assets/svgs/unknownAccount.svg
similarity index 100%
rename from src/assets/images/unknownAccount.svg
rename to src/assets/svgs/unknownAccount.svg
diff --git a/src/assets/images/userShare.svg b/src/assets/svgs/userShare.svg
similarity index 100%
rename from src/assets/images/userShare.svg
rename to src/assets/svgs/userShare.svg
diff --git a/src/assets/images/userStar.svg b/src/assets/svgs/userStar.svg
similarity index 100%
rename from src/assets/images/userStar.svg
rename to src/assets/svgs/userStar.svg
diff --git a/src/assets/images/userX.svg b/src/assets/svgs/userX.svg
similarity index 100%
rename from src/assets/images/userX.svg
rename to src/assets/svgs/userX.svg
diff --git a/src/assets/svgs/visibility.svg b/src/assets/svgs/visibility.svg
new file mode 100644
index 000000000..24dd516e8
--- /dev/null
+++ b/src/assets/svgs/visibility.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/images/visibilityOff.svg b/src/assets/svgs/visibilityOff.svg
similarity index 100%
rename from src/assets/images/visibilityOff.svg
rename to src/assets/svgs/visibilityOff.svg
diff --git a/src/assets/images/voteChevron.svg b/src/assets/svgs/voteChevron.svg
similarity index 100%
rename from src/assets/images/voteChevron.svg
rename to src/assets/svgs/voteChevron.svg
diff --git a/src/assets/images/wallet.svg b/src/assets/svgs/wallet.svg
similarity index 100%
rename from src/assets/images/wallet.svg
rename to src/assets/svgs/wallet.svg
diff --git a/src/assets/images/walletUpdateIcon.svg b/src/assets/svgs/walletUpdateIcon.svg
similarity index 100%
rename from src/assets/images/walletUpdateIcon.svg
rename to src/assets/svgs/walletUpdateIcon.svg
diff --git a/src/assets/images/warning.svg b/src/assets/svgs/warning.svg
similarity index 100%
rename from src/assets/images/warning.svg
rename to src/assets/svgs/warning.svg
diff --git a/src/assets/images/warning2.svg b/src/assets/svgs/warning2.svg
similarity index 100%
rename from src/assets/images/warning2.svg
rename to src/assets/svgs/warning2.svg
diff --git a/src/assets/images/warningKeystone.svg b/src/assets/svgs/warningKeystone.svg
similarity index 100%
rename from src/assets/images/warningKeystone.svg
rename to src/assets/svgs/warningKeystone.svg
diff --git a/src/components/AccountButton.tsx b/src/components/AccountButton.tsx
index 15ff99e3a..2ae04d9a5 100644
--- a/src/components/AccountButton.tsx
+++ b/src/components/AccountButton.tsx
@@ -1,10 +1,10 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { memo, useCallback, useMemo } from 'react'
-import ChevronDown from '@assets/images/chevronDown.svg'
+import ChevronDown from '@assets/svgs/chevronDown.svg'
import { Keyboard, StyleSheet } from 'react-native'
import { BoxProps } from '@shopify/restyle'
-import { useColors, useHitSlop } from '@theme/themeHooks'
-import { Color, Theme } from '@theme/theme'
+import { useColors, useHitSlop } from '@config/theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
import useHaptic from '@hooks/useHaptic'
import AccountIcon from './AccountIcon'
import Box from './Box'
diff --git a/src/components/AccountIcon.tsx b/src/components/AccountIcon.tsx
index 976ef7292..72dc47872 100644
--- a/src/components/AccountIcon.tsx
+++ b/src/components/AccountIcon.tsx
@@ -1,6 +1,6 @@
import React, { memo, useMemo } from 'react'
import Jazzicon, { IJazziconProps } from 'react-native-jazzicon'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { useAsync } from 'react-async-hook'
import { getJazzSeed } from '../utils/accountUtils'
import { ImageBox } from '.'
diff --git a/src/components/AccountListItem.tsx b/src/components/AccountListItem.tsx
index d32565a9f..cc7584e05 100644
--- a/src/components/AccountListItem.tsx
+++ b/src/components/AccountListItem.tsx
@@ -1,13 +1,13 @@
import React, { memo, useCallback, useMemo } from 'react'
-import Checkmark from '@assets/images/checkIco.svg'
-import { useColors } from '@theme/themeHooks'
+import Checkmark from '@assets/svgs/checkIco.svg'
+import { useColors } from '@config/theme/themeHooks'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
+import { CSAccount } from '@config/storage/cloudStorage'
import Text from './Text'
import Box from './Box'
import AccountIcon from './AccountIcon'
import { ellipsizeAddress, formatAccountAlias } from '../utils/accountUtils'
-import { CSAccount } from '../storage/cloudStorage'
import TouchableContainer from './TouchableContainer'
type Props = {
diff --git a/src/components/AccountSelector.tsx b/src/components/AccountSelector.tsx
index 0bb69cec7..9ae2b3d16 100644
--- a/src/components/AccountSelector.tsx
+++ b/src/components/AccountSelector.tsx
@@ -16,12 +16,12 @@ import {
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet'
import { GestureResponderEvent } from 'react-native'
-import { useColors, useOpacity, useSpacing } from '@theme/themeHooks'
+import { useColors, useOpacity, useSpacing } from '@config/theme/themeHooks'
import useBackHandler from '@hooks/useBackHandler'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
import { AccountNetTypeOpt } from '../utils/accountUtils'
import AccountListItem from './AccountListItem'
-import { CSAccount } from '../storage/cloudStorage'
export type AccountSelectorRef = {
show: (_type?: AccountNetTypeOpt | GestureResponderEvent) => void
diff --git a/src/components/ActivityIndicator.tsx b/src/components/ActivityIndicator.tsx
index 52c3f6dc5..308ed26f9 100644
--- a/src/components/ActivityIndicator.tsx
+++ b/src/components/ActivityIndicator.tsx
@@ -3,8 +3,8 @@ import {
ActivityIndicatorProps,
ActivityIndicator as RNActivityIndicator,
} from 'react-native'
-import { Color } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
type Props = { color?: Color } & ActivityIndicatorProps
const ActivityIndicator = ({ color, ...props }: Props) => {
diff --git a/src/components/AddressBookSelector.tsx b/src/components/AddressBookSelector.tsx
index 218e2e566..5013d4ede 100644
--- a/src/components/AddressBookSelector.tsx
+++ b/src/components/AddressBookSelector.tsx
@@ -14,12 +14,12 @@ import BottomSheet, {
} from '@gorhom/bottom-sheet'
import { useNavigation } from '@react-navigation/native'
import { BoxProps, ThemeProvider } from '@shopify/restyle'
-import { lightTheme, Theme } from '@theme/theme'
+import { lightTheme, Theme } from '@config/theme/theme'
import ContactsList from '@features/addressBook/ContactsList'
-import { CSAccount } from '@storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { Portal } from '@gorhom/portal'
import { useTranslation } from 'react-i18next'
-import { SendNavigationProp } from '@services/WalletService/pages/SendPage/SentPageNavigator'
+import { SendNavigationProp } from 'src/app/services/WalletService/pages/SendPage'
import { AddressBookNavigationProp } from '@features/addressBook/addressBookTypes'
import HeliumBottomSheet from './HeliumBottomSheet'
import { SafeAreaBox, Text } from '.'
diff --git a/src/components/AutoGasBanner.tsx b/src/components/AutoGasBanner.tsx
index 7285a7822..4da2fd99d 100644
--- a/src/components/AutoGasBanner.tsx
+++ b/src/components/AutoGasBanner.tsx
@@ -1,5 +1,5 @@
-import CloseCircle from '@assets/images/closeCircleFilled.svg'
-import Warning from '@assets/images/warning.svg'
+import CloseCircle from '@assets/svgs/closeCircleFilled.svg'
+import Warning from '@assets/svgs/warning.svg'
import {
useMint,
useOwnedAmount,
@@ -13,8 +13,8 @@ import {
VersionedTransaction,
sendAndConfirmRawTransaction,
} from '@solana/web3.js'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import { Theme } from '@theme/theme'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { Theme } from '@config/theme/theme'
import { MIN_BALANCE_THRESHOLD } from '@utils/constants'
import axios from 'axios'
import BN from 'bn.js'
@@ -29,9 +29,9 @@ import {
useSafeAreaInsets,
} from 'react-native-safe-area-context'
import { useDispatch } from 'react-redux'
-import { useSolana } from '../solana/SolanaProvider'
-import { useWalletSign } from '../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../solana/walletSignBottomSheetTypes'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import { appSlice } from '../store/slices/appSlice'
import { ReAnimatedBox } from './AnimatedBox'
import Box from './Box'
diff --git a/src/components/BackButton.tsx b/src/components/BackButton.tsx
index e419bcbc9..5ea1808f1 100644
--- a/src/components/BackButton.tsx
+++ b/src/components/BackButton.tsx
@@ -2,9 +2,9 @@
import React from 'react'
import { BoxProps } from '@shopify/restyle'
import { Insets } from 'react-native'
-import BackArrow from '@assets/images/backArrow.svg'
-import { Color, Spacing, Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import BackArrow from '@assets/svgs/backArrow.svg'
+import { Color, Spacing, Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import Box from './Box'
import IconPressedContainer from './IconPressedContainer'
diff --git a/src/components/BackScreen.tsx b/src/components/BackScreen.tsx
index d2396a58b..e9a0a2715 100644
--- a/src/components/BackScreen.tsx
+++ b/src/components/BackScreen.tsx
@@ -5,8 +5,8 @@ import React, { memo, useCallback, useMemo } from 'react'
import { LayoutChangeEvent, Platform } from 'react-native'
import { Edge } from 'react-native-safe-area-context'
import { SvgProps } from 'react-native-svg'
-import { Color, Spacing, Theme } from '@theme/theme'
-import { useColors, useHitSlop } from '@theme/themeHooks'
+import { Color, Spacing, Theme } from '@config/theme/theme'
+import { useColors, useHitSlop } from '@config/theme/themeHooks'
import BackButton from './BackButton'
import Box from './Box'
import CloseButton from './CloseButton'
diff --git a/src/components/BackgroundFill.tsx b/src/components/BackgroundFill.tsx
index 889f7ddb6..a5e47b8a4 100644
--- a/src/components/BackgroundFill.tsx
+++ b/src/components/BackgroundFill.tsx
@@ -1,7 +1,7 @@
import { BoxProps } from '@shopify/restyle'
import React, { memo } from 'react'
import { StyleSheet } from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
type Props = BoxProps
diff --git a/src/components/BalanceText.tsx b/src/components/BalanceText.tsx
new file mode 100644
index 000000000..018ad72c0
--- /dev/null
+++ b/src/components/BalanceText.tsx
@@ -0,0 +1,47 @@
+import React, { memo, useMemo } from 'react'
+import { TextVariant } from '@config/theme/theme'
+import Box from './Box'
+import Text from './Text'
+
+const BalanceText = ({
+ amount,
+ variant = 'textLgSemibold',
+}: {
+ amount: number
+ variant?: TextVariant
+}) => {
+ const integral = useMemo(() => Math.floor(amount || 0), [amount])
+
+ const firstFractional = useMemo(() => {
+ if (amount === undefined) return 0
+ const decimal = amount - integral
+ const fraction = decimal.toString().split('.')[1]
+ // Fraction with max length of decimals
+ const fractionWithMaxDecimals = fraction?.slice(0, 1)
+ return fraction ? Number(fractionWithMaxDecimals) : 0
+ }, [amount, integral])
+
+ const secondFractional = useMemo(() => {
+ if (amount === undefined) return 0
+ const decimal = amount - integral
+ const fraction = decimal.toString().split('.')[1]
+ // Fraction with max length of decimals
+ const fractionWithMaxDecimals = fraction?.slice(1, 2)
+ return fraction ? Number(fractionWithMaxDecimals) : 0
+ }, [amount, integral])
+
+ return (
+
+
+
+ {`${integral.toLocaleString()}`}
+
+
+ {`.${firstFractional}${secondFractional}`}
+
+
+
+ )
+}
+
+export default memo(BalanceText)
diff --git a/src/components/BlurActionSheet.tsx b/src/components/BlurActionSheet.tsx
index 18b0819c7..5997bf82e 100644
--- a/src/components/BlurActionSheet.tsx
+++ b/src/components/BlurActionSheet.tsx
@@ -1,17 +1,16 @@
-import React, { memo, useCallback, useMemo, useRef } from 'react'
-import BottomSheet, {
- BottomSheetBackdrop,
- BottomSheetScrollView,
-} from '@gorhom/bottom-sheet'
-import { Edge } from 'react-native-safe-area-context'
+import React, { memo, useCallback, useRef } from 'react'
+import BottomSheet, { BottomSheetBackdrop } from '@gorhom/bottom-sheet'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useAsync } from 'react-async-hook'
import { Portal } from '@gorhom/portal'
import { ThemeProvider } from '@shopify/restyle'
-import { lightTheme } from '@theme/theme'
+import { lightTheme } from '@config/theme/theme'
import { useTranslation } from 'react-i18next'
-import SafeAreaBox from './SafeAreaBox'
+import { useSpacing } from '@config/theme/themeHooks'
import HeliumBottomSheet from './HeliumBottomSheet'
import Text from './Text'
+import Box from './Box'
+import ScrollBox from './ScrollBox'
type Props = {
title: string
@@ -23,6 +22,8 @@ type Props = {
const BlurActionSheet = ({ title, open, children, onClose }: Props) => {
const bottomSheetModalRef = useRef(null)
const { t } = useTranslation()
+ const { top, bottom } = useSafeAreaInsets()
+ const spacing = useSpacing()
const handleOnClose = useCallback(() => {
if (onClose) {
@@ -48,7 +49,7 @@ const BlurActionSheet = ({ title, open, children, onClose }: Props) => {
opacity={1}
{...props}
>
-
+
{
>
{t('blurActionSheet.selectAnOption')}
-
+
),
- [handleOnClose, title, t],
+ [handleOnClose, title, top, t],
)
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
-
return (
{
onClose={handleOnClose}
>
-
-
+
+
{children}
-
-
+
+
diff --git a/src/components/BlurBox.tsx b/src/components/BlurBox.tsx
index 5b2f9c8f7..57feae9b3 100644
--- a/src/components/BlurBox.tsx
+++ b/src/components/BlurBox.tsx
@@ -2,7 +2,7 @@ import React from 'react'
import { createBox } from '@shopify/restyle'
import { BlurView, BlurViewProps } from '@react-native-community/blur'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
const BlurBox = createBox<
Theme,
diff --git a/src/components/Box.tsx b/src/components/Box.tsx
index 0d175fbfe..4a667b3df 100644
--- a/src/components/Box.tsx
+++ b/src/components/Box.tsx
@@ -1,5 +1,5 @@
import { createBox } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
const Box = createBox()
diff --git a/src/components/ButtonPressAnimation.tsx b/src/components/ButtonPressAnimation.tsx
index f37f35279..13e962e36 100644
--- a/src/components/ButtonPressAnimation.tsx
+++ b/src/components/ButtonPressAnimation.tsx
@@ -1,6 +1,6 @@
import useHaptic from '@hooks/useHaptic'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import React from 'react'
import {
GestureResponderEvent,
diff --git a/src/components/ButtonPressable.tsx b/src/components/ButtonPressable.tsx
index 6d7c422bb..92a579f13 100644
--- a/src/components/ButtonPressable.tsx
+++ b/src/components/ButtonPressable.tsx
@@ -4,8 +4,8 @@ import React, { FC, memo, useState, useMemo } from 'react'
import { GestureResponderEvent, ViewStyle } from 'react-native'
import { SvgProps } from 'react-native-svg'
import { useDebouncedCallback } from 'use-debounce'
-import { Color, FontWeight, Theme } from '@theme/theme'
-import { useCreateOpacity } from '@theme/themeHooks'
+import { Color, FontWeight, Theme } from '@config/theme/theme'
+import { useCreateOpacity } from '@config/theme/themeHooks'
import Box from './Box'
import ButtonPressAnimation from './ButtonPressAnimation'
import Text from './Text'
@@ -181,7 +181,7 @@ const ButtonPressable = ({
{title && (
diff --git a/src/components/CopyAddress.tsx b/src/components/CopyAddress.tsx
index 2ec6860c5..f56f46c0b 100644
--- a/src/components/CopyAddress.tsx
+++ b/src/components/CopyAddress.tsx
@@ -4,10 +4,10 @@ import { BoxProps } from '@shopify/restyle'
import { useTranslation } from 'react-i18next'
import Clipboard from '@react-native-community/clipboard'
import Toast from 'react-native-simple-toast'
-import CopyAddressIcon from '@assets/images/copyAddress.svg'
-import { Theme } from '@theme/theme'
+import CopyAddressIcon from '@assets/svgs/copyAddress.svg'
+import { Theme } from '@config/theme/theme'
import useHaptic from '@hooks/useHaptic'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import TouchableOpacityBox from './TouchableOpacityBox'
import Text from './Text'
import { ellipsizeAddress } from '../utils/accountUtils'
diff --git a/src/components/CopyAddressPill.tsx b/src/components/CopyAddressPill.tsx
index 2563c8f3a..e44964de3 100644
--- a/src/components/CopyAddressPill.tsx
+++ b/src/components/CopyAddressPill.tsx
@@ -1,13 +1,13 @@
import React, { memo, useCallback, useMemo } from 'react'
import useCopyText from '@hooks/useCopyText'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import useHaptic from '@hooks/useHaptic'
import { ellipsizeAddress } from '@utils/accountUtils'
import { ViewStyle } from 'react-native'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
-import CopyAddress from '@assets/images/copyAddress.svg'
+import { Theme } from '@config/theme/theme'
+import CopyAddress from '@assets/svgs/copyAddress.svg'
import ButtonPressAnimation from './ButtonPressAnimation'
import Text from './Text'
import Box from './Box'
diff --git a/src/components/CountdownTimer.tsx b/src/components/CountdownTimer.tsx
index 9704c2e84..d3112ba10 100644
--- a/src/components/CountdownTimer.tsx
+++ b/src/components/CountdownTimer.tsx
@@ -9,13 +9,13 @@ import React, {
useRef,
useState,
} from 'react'
-import Lock from '@assets/images/lockClosed.svg'
+import Lock from '@assets/svgs/lockClosed.svg'
import { LayoutChangeEvent } from 'react-native'
import { BoxProps } from '@shopify/restyle'
import { format } from 'date-fns'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import useDisappear from '@hooks/useDisappear'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Text from './Text'
import Box from './Box'
diff --git a/src/components/DynamicQrScanner.tsx b/src/components/DynamicQrScanner.tsx
index e3d8a3571..644180cfa 100644
--- a/src/components/DynamicQrScanner.tsx
+++ b/src/components/DynamicQrScanner.tsx
@@ -6,7 +6,7 @@ import { useNavigation } from '@react-navigation/native'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import useAlert from '@hooks/useAlert'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { CameraScannerLayout } from './CameraScannerLayout'
import Box from './Box'
import BackScreen from './BackScreen'
diff --git a/src/components/FabButton.tsx b/src/components/FabButton.tsx
index c8b8a2be9..f58f31f14 100644
--- a/src/components/FabButton.tsx
+++ b/src/components/FabButton.tsx
@@ -8,24 +8,26 @@ import {
StyleSheet,
ViewStyle,
} from 'react-native'
-import ArrowDown from '@assets/images/downArrow.svg'
-import FatArrowUp from '@assets/images/arrowUp.svg'
-import Payment from '@assets/images/payment.svg'
-import Stake from '@assets/images/stake.svg'
-import Lock from '@assets/images/lock.svg'
-import Plus from '@assets/images/plus.svg'
-import Close from '@assets/images/close.svg'
-import Dots from '@assets/images/dots.svg'
-import Filter from '@assets/images/filter.svg'
-import { Color, FontWeight, Theme } from '@theme/theme'
-import { useColors, useCreateOpacity } from '@theme/themeHooks'
-import Swaps from '@assets/images/swaps.svg'
-import Airdrop from '@assets/images/airdrop.svg'
-import MapUserLocation from '@assets/images/mapUserLocation.svg'
-import Search from '@assets/images/search.svg'
-import Info from '@assets/images/info.svg'
-import QuestionMark from '@assets/images/questionMark.svg'
-import BrowseVoters from '@assets/images/browseVoters.svg'
+import ArrowDown from '@assets/svgs/arrowDown.svg'
+import Settings from '@assets/svgs/settings.svg'
+import FatArrowUp from '@assets/svgs/arrowUp.svg'
+import Payment from '@assets/svgs/payment.svg'
+import Stake from '@assets/svgs/stake.svg'
+import Lock from '@assets/svgs/lock.svg'
+import Plus from '@assets/svgs/plus.svg'
+import Close from '@assets/svgs/close.svg'
+import Dots from '@assets/svgs/dots.svg'
+import Filter from '@assets/svgs/filter.svg'
+import { Color, FontWeight, Theme } from '@config/theme/theme'
+import { useColors, useCreateOpacity } from '@config/theme/themeHooks'
+import Swaps from '@assets/svgs/swaps.svg'
+import Airdrop from '@assets/svgs/airdrop.svg'
+import MapUserLocation from '@assets/svgs/mapUserLocation.svg'
+import Search from '@assets/svgs/search.svg'
+import Info from '@assets/svgs/info.svg'
+import QuestionMark from '@assets/svgs/questionMark.svg'
+import BrowseVoters from '@assets/svgs/browseVoters.svg'
+import Expand from '@assets/svgs/expand.svg'
import Box from './Box'
import Text from './Text'
import ButtonPressAnimation from './ButtonPressAnimation'
@@ -49,7 +51,9 @@ type IconName =
| 'info'
| 'questionMark'
| 'browseVoters'
-
+ | 'expand'
+ | 'settings'
+ | 'arrowLeft'
type Props = BoxProps & {
backgroundColorOpacity?: number
backgroundColorPressed?: Color
@@ -247,6 +251,13 @@ const FabIcon = ({ icon, pressed, color, colorPressed }: IconProps) => {
style={{ transform: [{ rotate: '270deg' }] }}
/>
)
+ case 'arrowLeft':
+ return (
+
+ )
case 'arrowDown':
return
case 'fatArrowUp':
@@ -287,6 +298,10 @@ const FabIcon = ({ icon, pressed, color, colorPressed }: IconProps) => {
return
case 'browseVoters':
return
+ case 'expand':
+ return
+ case 'settings':
+ return
}
}
diff --git a/src/components/FinePrint.tsx b/src/components/FinePrint.tsx
index 683311123..f1a9e548b 100644
--- a/src/components/FinePrint.tsx
+++ b/src/components/FinePrint.tsx
@@ -3,9 +3,9 @@ import React, { memo, useCallback } from 'react'
import { Linking, TouchableOpacity } from 'react-native'
import { useTranslation } from 'react-i18next'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Text from './Text'
-import { PRIVACY_POLICY, TERMS_OF_SERVICE } from '../constants/urls'
+import { PRIVACY_POLICY, TERMS_OF_SERVICE } from '../utils/constants/urls'
import Box from './Box'
type Props = BoxProps
diff --git a/src/components/GlobalError.tsx b/src/components/GlobalError.tsx
index cfac64bd8..319b99c50 100644
--- a/src/components/GlobalError.tsx
+++ b/src/components/GlobalError.tsx
@@ -1,4 +1,4 @@
-import CopyAddress from '@assets/images/copyAddress.svg'
+import CopyAddress from '@assets/svgs/copyAddress.svg'
import useCopyText from '@hooks/useCopyText'
import useHaptic from '@hooks/useHaptic'
import React, { useCallback } from 'react'
diff --git a/src/components/HNTKeyboard.tsx b/src/components/HNTKeyboard.tsx
index b597917c5..387ca993e 100644
--- a/src/components/HNTKeyboard.tsx
+++ b/src/components/HNTKeyboard.tsx
@@ -1,4 +1,4 @@
-import PaymentArrow from '@assets/images/paymentArrow.svg'
+import PaymentArrow from '@assets/svgs/paymentArrow.svg'
import BottomSheet, {
BottomSheetBackdrop,
BottomSheetModalProvider,
@@ -14,8 +14,8 @@ import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps, ThemeProvider } from '@shopify/restyle'
import { NATIVE_MINT } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
-import { Theme, lightTheme } from '@theme/theme'
-import { useSafeTopPaddingStyle } from '@theme/themeHooks'
+import { Theme, lightTheme } from '@config/theme/theme'
+import { useSafeTopPaddingStyle } from '@config/theme/themeHooks'
import BN from 'bn.js'
import React, {
ReactNode,
@@ -31,8 +31,8 @@ import React, {
import { useTranslation } from 'react-i18next'
import { LayoutChangeEvent } from 'react-native'
import { Edge } from 'react-native-safe-area-context'
-import { Payment } from '../features/payment/PaymentItem'
-import { CSAccount } from '../storage/cloudStorage'
+import { Payment } from '@features/payment/PaymentItem'
+import { CSAccount } from '@config/storage/cloudStorage'
import { decimalSeparator, groupSeparator } from '../utils/i18n'
import { humanReadable } from '../utils/solanaUtils'
import AccountIcon from './AccountIcon'
@@ -177,7 +177,10 @@ const HNTKeyboardSelector = forwardRef(
: undefined
setValue(val || '0')
- bottomSheetModalRef.current?.expand()
+ // wait 1 render cycle to expand
+ setTimeout(() => {
+ bottomSheetModalRef.current?.expand()
+ }, 100)
},
[handleVisible, decimals],
)
diff --git a/src/components/HandleBasic.tsx b/src/components/HandleBasic.tsx
index f097bc6d3..394e72a51 100644
--- a/src/components/HandleBasic.tsx
+++ b/src/components/HandleBasic.tsx
@@ -1,7 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import { BoxProps } from '@shopify/restyle'
import React from 'react'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
type Props = BoxProps
diff --git a/src/components/HeliumActionSheet.tsx b/src/components/HeliumActionSheet.tsx
index ee5442d51..948bd2e24 100644
--- a/src/components/HeliumActionSheet.tsx
+++ b/src/components/HeliumActionSheet.tsx
@@ -10,13 +10,13 @@ import React, {
useState,
} from 'react'
import { BoxProps } from '@shopify/restyle'
-import CarotDown from '@assets/images/carot-down.svg'
-import Kabob from '@assets/images/kabob.svg'
+import CarotDown from '@assets/svgs/carot-down.svg'
+import Kabob from '@assets/svgs/kabob.svg'
import { useTranslation } from 'react-i18next'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { FlatList } from 'react-native-gesture-handler'
-import { Color, Theme } from '@theme/theme'
-import { useColors, useHitSlop } from '@theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
+import { useColors, useHitSlop } from '@config/theme/themeHooks'
import HeliumActionSheetItem, {
HeliumActionSheetItemHeight,
HeliumActionSheetItemType,
diff --git a/src/components/HeliumActionSheetItem.tsx b/src/components/HeliumActionSheetItem.tsx
index 45860b4d4..0db5945f7 100644
--- a/src/components/HeliumActionSheetItem.tsx
+++ b/src/components/HeliumActionSheetItem.tsx
@@ -1,7 +1,7 @@
import React, { memo, useMemo } from 'react'
import { SvgProps } from 'react-native-svg'
-import { Color } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import Text from './Text'
import TouchableOpacityBox from './TouchableOpacityBox'
diff --git a/src/components/HeliumBottomActionSheet.tsx b/src/components/HeliumBottomActionSheet.tsx
index 91a3caecc..bc455c7ae 100644
--- a/src/components/HeliumBottomActionSheet.tsx
+++ b/src/components/HeliumBottomActionSheet.tsx
@@ -1,14 +1,14 @@
import React, { memo, useCallback, useEffect } from 'react'
import { BoxProps } from '@shopify/restyle'
-import Close from '@assets/images/close.svg'
+import Close from '@assets/svgs/close.svg'
import { Modal } from 'react-native'
import {
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated'
-import { Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import useDisappear from '@hooks/useDisappear'
import Text from './Text'
import Box from './Box'
diff --git a/src/components/HeliumBottomSheet.tsx b/src/components/HeliumBottomSheet.tsx
index 8bb36145b..7c12781c3 100644
--- a/src/components/HeliumBottomSheet.tsx
+++ b/src/components/HeliumBottomSheet.tsx
@@ -5,7 +5,7 @@ import {
useBorderRadii,
useColors,
useSpacing,
-} from '@theme/themeHooks'
+} from '@config/theme/themeHooks'
import { wh } from '@utils/layout'
import { Platform, StyleProp, ViewStyle } from 'react-native'
import { useSharedValue } from 'react-native-reanimated'
@@ -33,7 +33,7 @@ const HeliumBottomSheet = forwardRef(
return {
width: 90,
height: 4,
- backgroundColor: colors.secondaryText,
+ backgroundColor: colors['base.black'],
}
}, [colors])
@@ -44,7 +44,7 @@ const HeliumBottomSheet = forwardRef(
top: 0,
left: 0,
right: 0,
- backgroundColor: 'transparent',
+ opacity: 0.1,
} as StyleProp),
[],
)
@@ -64,6 +64,7 @@ const HeliumBottomSheet = forwardRef(
(Image)
diff --git a/src/components/IndeterminateProgressBar.tsx b/src/components/IndeterminateProgressBar.tsx
index 0e3d579a0..8d170952d 100644
--- a/src/components/IndeterminateProgressBar.tsx
+++ b/src/components/IndeterminateProgressBar.tsx
@@ -9,7 +9,7 @@ import {
withRepeat,
withTiming,
} from 'react-native-reanimated'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { ReAnimatedBox } from './AnimatedBox'
import Box from './Box'
diff --git a/src/components/Keypad.tsx b/src/components/Keypad.tsx
index 3339d3891..46e86af24 100644
--- a/src/components/Keypad.tsx
+++ b/src/components/Keypad.tsx
@@ -1,7 +1,7 @@
import React, { memo, useCallback } from 'react'
import { BoxProps } from '@shopify/restyle'
import useHaptic from '@hooks/useHaptic'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
import KeypadButton, { KeypadCustomInput, KeypadInput } from './KeypadButton'
diff --git a/src/components/KeypadButton.tsx b/src/components/KeypadButton.tsx
index 8f081c0d8..24dba2ce0 100644
--- a/src/components/KeypadButton.tsx
+++ b/src/components/KeypadButton.tsx
@@ -1,9 +1,9 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useCallback } from 'react'
import { Pressable } from 'react-native'
-import Backspace from '@assets/images/backspace.svg'
+import Backspace from '@assets/svgs/backspace.svg'
import { useTranslation } from 'react-i18next'
-import { useColors, useHitSlop, useOpacity } from '@theme/themeHooks'
+import { useColors, useHitSlop, useOpacity } from '@config/theme/themeHooks'
import Box from './Box'
import Text from './Text'
import { decimalSeparator } from '../utils/i18n'
diff --git a/src/components/ListItem.tsx b/src/components/ListItem.tsx
index a03410b62..ab3cbfd72 100644
--- a/src/components/ListItem.tsx
+++ b/src/components/ListItem.tsx
@@ -1,7 +1,7 @@
import React from 'react'
-import CheckMarkFill from '@assets/images/checkmarkFill.svg'
-import { useColors } from '@theme/themeHooks'
-import { Color, Theme } from '@theme/theme'
+import CheckMarkFill from '@assets/svgs/checkmarkFill.svg'
+import { useColors } from '@config/theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
import { Insets } from 'react-native'
import { BoxProps } from '@shopify/restyle'
import Box from './Box'
diff --git a/src/components/ListSeperator.tsx b/src/components/ListSeperator.tsx
new file mode 100644
index 000000000..b93c707b3
--- /dev/null
+++ b/src/components/ListSeperator.tsx
@@ -0,0 +1,10 @@
+import { BoxProps } from '@shopify/restyle'
+import React from 'react'
+import { Theme } from '@config/theme/theme'
+import Box from './Box'
+
+const ListSeparator = (props: BoxProps) => (
+
+)
+
+export default ListSeparator
diff --git a/src/components/MakerHotspotImage.tsx b/src/components/MakerHotspotImage.tsx
new file mode 100644
index 000000000..bb3fe993c
--- /dev/null
+++ b/src/components/MakerHotspotImage.tsx
@@ -0,0 +1,570 @@
+import React, { useCallback } from 'react'
+import { BoxProps } from '@shopify/restyle'
+import { Theme } from '@config/theme/theme'
+import ImageBox from './ImageBox'
+
+const MakerHotspotImage = ({
+ maker,
+ deviceType,
+ subDao,
+ ...rest
+}: {
+ maker: string
+ deviceType: string
+ subDao: 'iot' | 'mobile'
+} & BoxProps) => {
+ const Image = useCallback(
+ ({
+ deviceType: dType,
+ subDao: dao,
+ ...boxProps
+ }: { deviceType: string; subDao: 'iot' | 'mobile' } & BoxProps) => {
+ switch (maker) {
+ default:
+ case 'Nova Labs':
+ if (dType === 'cbrs') {
+ return (
+
+ )
+ }
+ if (dao === 'iot') {
+ return (
+
+ )
+ }
+ return (
+
+ )
+ case 'Nebra Ltd':
+ return (
+
+ )
+ case 'Maker Integration Tests':
+ return (
+
+ )
+ case 'Smart Harvest':
+ return (
+
+ )
+ case 'Osprey':
+ return (
+
+ )
+ case 'COTX Networks':
+ return (
+
+ )
+ case 'OPTION':
+ return (
+
+ )
+ case 'Heltec Automation':
+ return (
+
+ )
+ case 'Bobcat':
+ return (
+
+ )
+ case 'Helium Inc':
+ return (
+
+ )
+ case 'Dusun':
+ return (
+
+ )
+ case 'RAKwireless':
+ return (
+
+ )
+ case 'SONoC':
+ return (
+
+ )
+ case 'Mimiq':
+ return (
+
+ )
+ case 'DeWi Foundation':
+ return (
+
+ )
+ case 'CalChip Connect':
+ return (
+
+ )
+ case 'Polyhex':
+ return (
+
+ )
+ case 'SenseCAP':
+ return (
+
+ )
+ case 'Atom':
+ return (
+
+ )
+ case 'embit':
+ return (
+
+ )
+ case 'KS Technologies':
+ return (
+
+ )
+ case 'FreedomFi':
+ return (
+
+ )
+ case 'RisingHF':
+ return (
+
+ )
+ case 'MNTD':
+ return (
+
+ )
+ case 'Dragino':
+ return (
+
+ )
+ case 'hummingbird':
+ return (
+
+ )
+ case 'Migrated Helium Hotspot':
+ return (
+
+ )
+ case 'Milesight':
+ return (
+
+ )
+ case 'Pisces Miner':
+ return (
+
+ )
+ case 'PantherX':
+ return (
+
+ )
+ case 'Nebra 5G':
+ return (
+
+ )
+ case 'ClodPi':
+ return (
+
+ )
+ case 'Deeper':
+ return (
+
+ )
+ case 'LongAP':
+ return (
+
+ )
+ case 'Aitek Inc':
+ return (
+
+ )
+ case 'Kerlink':
+ return (
+
+ )
+ case 'ResIOT.io':
+ return (
+
+ )
+ case 'SyncroB.it':
+ return (
+
+ )
+ case 'Bobcat 5G':
+ return (
+
+ )
+ case 'Linxdot':
+ return (
+
+ )
+ case 'Controllino':
+ return (
+
+ )
+ case 'EDA-IoT':
+ return (
+
+ )
+ case 'TMG':
+ return (
+
+ )
+ case 'Midas':
+ return (
+
+ )
+ case 'uG Miner':
+ return (
+
+ )
+ case 'Pycom':
+ return (
+
+ )
+ case 'Browan/MerryIoT':
+ return (
+
+ )
+ }
+ },
+ [maker],
+ )
+
+ return
+}
+
+export default MakerHotspotImage
diff --git a/src/components/Map.tsx b/src/components/Map.tsx
new file mode 100644
index 000000000..804c48310
--- /dev/null
+++ b/src/components/Map.tsx
@@ -0,0 +1,26 @@
+import Mapbox from '@rnmapbox/maps'
+import { HELIUM_WORLD_NO_LABELS } from '@utils/constants'
+import React, { forwardRef } from 'react'
+
+const Map = forwardRef<
+ Mapbox.MapView,
+ React.ComponentProps & { children?: React.ReactNode }
+>(({ children, ...rest }, ref) => {
+ return (
+
+ {children}
+
+ )
+})
+
+export default Map
diff --git a/src/components/Markdown.tsx b/src/components/Markdown.tsx
index 9fd69f2b7..e9e2fbe6f 100644
--- a/src/components/Markdown.tsx
+++ b/src/components/Markdown.tsx
@@ -1,5 +1,5 @@
import { useTheme } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import React from 'react'
import MarkdownDisplay from 'react-native-markdown-display'
diff --git a/src/components/MemoInput.tsx b/src/components/MemoInput.tsx
index b6b584c29..bf367c615 100644
--- a/src/components/MemoInput.tsx
+++ b/src/components/MemoInput.tsx
@@ -1,7 +1,7 @@
import { BoxProps } from '@shopify/restyle'
import React, { memo, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
import Text from './Text'
import TextInput from './TextInput'
diff --git a/src/components/MiniMap.tsx b/src/components/MiniMap.tsx
new file mode 100644
index 000000000..b7be0ed25
--- /dev/null
+++ b/src/components/MiniMap.tsx
@@ -0,0 +1,107 @@
+import Mapbox, {
+ Location,
+ Camera,
+ Images,
+ MarkerView,
+ UserLocation,
+} from '@rnmapbox/maps'
+import { Box, FabButton, ImageBox } from '@components/index'
+import React, { useCallback, useRef, useState } from 'react'
+import { useSpacing } from '@config/theme/themeHooks'
+import { useNavigation } from '@react-navigation/native'
+import Map from '@components/Map'
+import HotspotMarker from '@assets/svgs/hotspotMarker.svg'
+import { HotspotServiceNavigationProp } from '../app/services/HotspotService'
+
+type MiniMapProps = {
+ hasExpandButton?: boolean
+ height?: number
+ lat?: number
+ long?: number
+ children?: React.ReactNode
+ onUserLocationUpdate?: (location: Location) => void
+}
+
+const MiniMap = ({
+ hasExpandButton = true,
+ height = 253,
+ lat,
+ long,
+ onUserLocationUpdate,
+ children,
+}: MiniMapProps) => {
+ const mapRef = useRef(null)
+ const spacing = useSpacing()
+ const navigation = useNavigation()
+ const [userLocation, setUserLocation] = useState()
+
+ const onExpand = useCallback(() => {
+ navigation.navigate('Explorer')
+ }, [navigation])
+
+ const handleUserLocationUpdate = useCallback(
+ (location: Location) => {
+ setUserLocation(location)
+ onUserLocationUpdate?.(location)
+ },
+ [onUserLocationUpdate],
+ )
+
+ return (
+
+
+ {hasExpandButton && (
+
+ )}
+
+ )
+}
+
+export default MiniMap
diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx
index 5ac2e949b..d9ad44cd3 100644
--- a/src/components/NavBar.tsx
+++ b/src/components/NavBar.tsx
@@ -13,7 +13,7 @@ import Animated, {
withSpring,
} from 'react-native-reanimated'
import { SvgProps } from 'react-native-svg'
-import { useColors, useVerticalHitSlop } from '@theme/themeHooks'
+import { useColors, useVerticalHitSlop } from '@config/theme/themeHooks'
import Box from './Box'
import TouchableOpacityBox, {
TouchableOpacityBoxProps,
diff --git a/src/components/Pill.tsx b/src/components/Pill.tsx
index cb1c2bd60..ac0efcdd3 100644
--- a/src/components/Pill.tsx
+++ b/src/components/Pill.tsx
@@ -1,6 +1,6 @@
import Box from '@components/Box'
import { TextProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import React, { memo } from 'react'
import { SvgProps } from 'react-native-svg'
import Text from './Text'
diff --git a/src/components/PinDisplay.tsx b/src/components/PinDisplay.tsx
index 3ddde1d3f..6f8e64b09 100644
--- a/src/components/PinDisplay.tsx
+++ b/src/components/PinDisplay.tsx
@@ -1,7 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import { BoxProps } from '@shopify/restyle'
import React, { memo } from 'react'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
import Dot from './Dot'
diff --git a/src/components/ProgressBar.tsx b/src/components/ProgressBar.tsx
index c1b84c1c8..a695f24af 100644
--- a/src/components/ProgressBar.tsx
+++ b/src/components/ProgressBar.tsx
@@ -1,19 +1,21 @@
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { LayoutChangeEvent, LayoutRectangle } from 'react-native'
import {
useAnimatedStyle,
useSharedValue,
- withSpring,
+ withTiming,
} from 'react-native-reanimated'
import { ReAnimatedBox } from './AnimatedBox'
import Box from './Box'
+import Text from './Text'
const ProgressBar = ({
progress: progressIn,
+ withLabel = false,
...rest
-}: BoxProps & { progress: number }) => {
+}: BoxProps & { progress: number; withLabel?: boolean }) => {
const HEIGHT = 15
const [progressRect, setProgressRect] = useState()
@@ -33,7 +35,7 @@ const ProgressBar = ({
useEffect(() => {
// withRepeat to repeat the animation
- width.value = withSpring((progressIn / 100) * PROGRESS_WIDTH)
+ width.value = withTiming((progressIn / 100) * PROGRESS_WIDTH)
}, [PROGRESS_WIDTH, width, progressIn])
const progress = useAnimatedStyle(() => {
@@ -48,19 +50,28 @@ const ProgressBar = ({
{...rest}
borderRadius="full"
width="100%"
- height={HEIGHT}
- backgroundColor="transparent10"
- overflow="hidden"
- flexDirection="row"
+ flexDirection="column"
justifyContent="flex-start"
+ gap="2"
>
-
-
-
+
+
+
+
+
+ {withLabel && (
+
+ {`Progress: ${progressIn}%`}
+
+ )}
)
}
diff --git a/src/components/RadioButton.tsx b/src/components/RadioButton.tsx
index fa9b9a4f1..bcf6e3cc8 100644
--- a/src/components/RadioButton.tsx
+++ b/src/components/RadioButton.tsx
@@ -27,7 +27,7 @@ const RadioButton: React.FC = ({
width={20}
borderRadius="full"
borderWidth={2}
- borderColor="blue.light-500"
+ borderColor="text.quaternary-500"
alignItems="center"
justifyContent="center"
onPress={() => onClick()}
@@ -36,7 +36,7 @@ const RadioButton: React.FC = ({
width={10}
height={10}
borderRadius="full"
- backgroundColor={selected ? 'blue.light-500' : 'transparent'}
+ backgroundColor={selected ? 'base.black' : 'transparent'}
/>
>(
SafeAreaView,
diff --git a/src/components/ScrollBox.tsx b/src/components/ScrollBox.tsx
index 8ae28b0aa..1e4d64abf 100644
--- a/src/components/ScrollBox.tsx
+++ b/src/components/ScrollBox.tsx
@@ -1,6 +1,6 @@
import { createBox } from '@shopify/restyle'
import { ReactNode } from 'react'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { ScrollViewProps } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
diff --git a/src/components/Search.tsx b/src/components/Search.tsx
new file mode 100644
index 000000000..8d203fb6d
--- /dev/null
+++ b/src/components/Search.tsx
@@ -0,0 +1,50 @@
+import React from 'react'
+import SearchIcon from '@assets/svgs/searchIcon.svg'
+import { BoxProps } from '@shopify/restyle'
+import { Theme } from '@config/theme/theme'
+import { useColors, useTextVariants } from '@config/theme/themeHooks'
+import { TextInput } from 'react-native'
+import Box from './Box'
+
+type SearchProps = BoxProps & {
+ placeholder: string
+ onChangeText: (text: string) => void
+ onEnter?: () => void
+}
+
+export const Search = ({
+ placeholder,
+ onChangeText,
+ onEnter,
+ ...rest
+}: SearchProps) => {
+ const textVariants = useTextVariants()
+ const colors = useColors()
+ return (
+
+
+
+
+ )
+}
diff --git a/src/components/SearchInput.tsx b/src/components/SearchInput.tsx
index 0fe871714..24ad2a66a 100644
--- a/src/components/SearchInput.tsx
+++ b/src/components/SearchInput.tsx
@@ -1,8 +1,8 @@
/* eslint-disable react/jsx-props-no-spreading */
-import Search from '@assets/images/search.svg'
+import Search from '@assets/svgs/search.svg'
import { BoxProps } from '@shopify/restyle'
-import { BorderRadii, Spacing, Theme } from '@theme/theme'
-import { useColors, useInputVariants } from '@theme/themeHooks'
+import { BorderRadii, Spacing, Theme } from '@config/theme/theme'
+import { useColors, useInputVariants } from '@config/theme/themeHooks'
import React, { useCallback } from 'react'
import { TextInputProps } from 'react-native'
import Box from './Box'
diff --git a/src/components/SecretKeyWarningScreen.tsx b/src/components/SecretKeyWarningScreen.tsx
index b1ab78c48..b860f840e 100644
--- a/src/components/SecretKeyWarningScreen.tsx
+++ b/src/components/SecretKeyWarningScreen.tsx
@@ -1,6 +1,6 @@
import React, { memo, ReactNode, useCallback, useEffect, useState } from 'react'
import { View } from 'react-native'
-import InfoWarning from '@assets/images/customWarning.svg'
+import InfoWarning from '@assets/svgs/customWarning.svg'
import { useTranslation } from 'react-i18next'
import Animated, {
runOnJS,
@@ -8,8 +8,8 @@ import Animated, {
useSharedValue,
withTiming,
} from 'react-native-reanimated'
-import globalStyles from '@theme/globalStyles'
-import { useColors } from '@theme/themeHooks'
+import globalStyles from '@config/theme/globalStyles'
+import { useColors } from '@config/theme/themeHooks'
import Text from './Text'
import Box from './Box'
import ButtonPressable from './ButtonPressable'
diff --git a/src/components/SegmentedControl.tsx b/src/components/SegmentedControl.tsx
index 162752535..4fdd8bb04 100644
--- a/src/components/SegmentedControl.tsx
+++ b/src/components/SegmentedControl.tsx
@@ -11,9 +11,9 @@ import React, {
import { BoxProps } from '@shopify/restyle'
import { GestureResponderEvent, LayoutChangeEvent } from 'react-native'
import { SvgProps } from 'react-native-svg'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { useAnimatedStyle, withTiming } from 'react-native-reanimated'
-import { Theme } from '../theme/theme'
+import { Theme } from '../config/theme/theme'
import { Box, ReAnimatedBox, Text } from '.'
import TouchableOpacityBox from './TouchableOpacityBox'
@@ -30,12 +30,14 @@ const SegmentedItem = ({
onSelected,
onSetWidth,
fullWidth,
+ size,
}: {
option: Option
selected: boolean
onSelected: ((event: GestureResponderEvent) => void) | undefined
onSetWidth: (width: number) => void
fullWidth?: boolean
+ size?: 'sm' | 'md'
}) => {
const { primaryBackground, ...colors } = useColors()
const [hasTouched, setHasTouched] = useState(false)
@@ -71,8 +73,8 @@ const SegmentedItem = ({
return (
void
fullWidth?: boolean
+ size?: 'sm' | 'md'
} & BoxProps
const SegmentedControl = forwardRef(
(
- { options, onItemSelected, fullWidth, ...boxProps }: Props,
+ { options, onItemSelected, fullWidth, size = 'sm', ...boxProps }: Props,
ref: Ref,
) => {
const [selectedIndex, setSelectedIndex] = useState(0)
@@ -180,6 +183,7 @@ const SegmentedControl = forwardRef(
selected={index === selectedIndex}
onSelected={handleItemSelected(index)}
onSetWidth={onSetWidth(index)}
+ size={size}
/>
))}
diff --git a/src/components/Select.tsx b/src/components/Select.tsx
index 7103b395e..5c3a93062 100644
--- a/src/components/Select.tsx
+++ b/src/components/Select.tsx
@@ -1,38 +1,103 @@
-import { useColors } from '@theme/themeHooks'
-import ChevronDown from '@assets/images/chevronDown.svg'
+import { useColors } from '@config/theme/themeHooks'
+import ChevronDown from '@assets/svgs/chevronDown.svg'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
-import React, { useState } from 'react'
+import { Theme } from '@config/theme/theme'
+import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
+import { FlatList } from 'react-native'
import BlurActionSheet from './BlurActionSheet'
import Box from './Box'
import ListItem from './ListItem'
import Text from './Text'
import TouchableContainer from './TouchableContainer'
+import { Search } from './Search'
export type SelectProps = {
- value: string
- onValueChange: (value: string) => void
+ placeholder: string
+ initialValue: string | number | undefined
+ onValueChange: (value: string | number) => void
+ hasSearch?: boolean
options: {
label: string
- value: string
+ value: string | number
+ subLabel?: string
icon?: React.ReactNode
}[]
} & BoxProps
export const Select: React.FC = ({
- value,
+ initialValue,
onValueChange,
options,
+ placeholder,
+ hasSearch,
...rest
}) => {
+ const [value, setValue] = useState(initialValue)
const [filtersOpen, setFiltersOpen] = useState(false)
const { t } = useTranslation()
const colors = useColors()
+ const selectedOption = useMemo(
+ () => options.find((o) => o.value === value),
+ [options, value],
+ )
+
+ const [filteredOptions, setFilteredOptions] = useState(options)
+
+ const onFilterChange = useCallback(
+ (text: string) => {
+ if (text === '') {
+ setFilteredOptions(options)
+ } else {
+ setFilteredOptions(options.filter((o) => o.label.includes(text)))
+ }
+ },
+ [options],
+ )
+
+ const renderItem = useCallback(
+ ({ item, index }: { item: (typeof options)[0]; index: number }) => {
+ const borderTopStartRadius = index === 0 ? 'xl' : 'none'
+ const borderTopEndRadius = index === 0 ? 'xl' : 'none'
+ const borderBottomStartRadius =
+ index === filteredOptions.length - 1 ? 'xl' : 'none'
+ const borderBottomEndRadius =
+ index === filteredOptions.length - 1 ? 'xl' : 'none'
+
+ return (
+ {
+ setValue(item.value)
+ onValueChange(item.value)
+ setFiltersOpen(false)
+ }}
+ selected={value === item.value}
+ borderTopStartRadius={borderTopStartRadius}
+ borderTopEndRadius={borderTopEndRadius}
+ borderBottomStartRadius={borderBottomStartRadius}
+ borderBottomEndRadius={borderBottomEndRadius}
+ />
+ )
+ },
+ [onValueChange, filteredOptions, value],
+ )
+
+ const renderHeader = useCallback(() => {
+ return hasSearch ? (
+
+ ) : null
+ }, [hasSearch, placeholder, onFilterChange])
+
return (
<>
= ({
onPress={() => setFiltersOpen(true)}
{...rest}
>
-
- {options.find((o) => o.value === value)?.icon}
-
- {options.find((o) => o.value === value)?.label}
-
+
+
+ {selectedOption?.icon}
+ {selectedOption ? (
+
+ {selectedOption?.label}
+
+ ) : (
+
+ {placeholder}
+
+ )}
+
+ {selectedOption?.subLabel && (
+
+ {selectedOption?.subLabel}
+
+ )}
@@ -55,32 +133,12 @@ export const Select: React.FC = ({
open={filtersOpen}
onClose={() => setFiltersOpen(false)}
>
-
- {options.map((option, index) => {
- const borderTopStartRadius = index === 0 ? 'xl' : 'none'
- const borderTopEndRadius = index === 0 ? 'xl' : 'none'
- const borderBottomStartRadius =
- index === options.length - 1 ? 'xl' : 'none'
- const borderBottomEndRadius =
- index === options.length - 1 ? 'xl' : 'none'
-
- return (
- {
- onValueChange(option.value)
- setFiltersOpen(false)
- }}
- selected={value === option.value}
- borderTopStartRadius={borderTopStartRadius}
- borderTopEndRadius={borderTopEndRadius}
- borderBottomStartRadius={borderBottomStartRadius}
- borderBottomEndRadius={borderBottomEndRadius}
- />
- )
- })}
-
+ `${item.value}`}
+ ListHeaderComponent={renderHeader}
+ />
>
)
diff --git a/src/components/ServiceNavBar.tsx b/src/components/ServiceNavBar.tsx
index 0f2d4abd8..ffe8abbed 100644
--- a/src/components/ServiceNavBar.tsx
+++ b/src/components/ServiceNavBar.tsx
@@ -13,7 +13,7 @@ import Animated, {
withSpring,
} from 'react-native-reanimated'
import { SvgProps } from 'react-native-svg'
-import { useColors, useVerticalHitSlop } from '@theme/themeHooks'
+import { useColors, useVerticalHitSlop } from '@config/theme/themeHooks'
import Box from './Box'
import TouchableOpacityBox, {
TouchableOpacityBoxProps,
@@ -176,7 +176,7 @@ const NavServiceNavBar = ({
{...containerProps}
paddingHorizontal="2xl"
flexDirection="row"
- justifyContent="center"
+ flex={1}
shadowColor="base.black"
shadowOpacity={0.3}
shadowOffset={{ width: 0, height: 6 }}
@@ -188,6 +188,7 @@ const NavServiceNavBar = ({
backgroundColor="primaryText"
borderRadius="full"
padding="md"
+ flex={1}
gap="2"
>
{items}
diff --git a/src/components/ServiceSheetPage.tsx b/src/components/ServiceSheetPage.tsx
index 261a9471d..1462a5844 100644
--- a/src/components/ServiceSheetPage.tsx
+++ b/src/components/ServiceSheetPage.tsx
@@ -5,11 +5,11 @@ import {
createBottomTabNavigator,
} from '@react-navigation/bottom-tabs'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { Color } from '@theme/theme'
+import { Color } from '@config/theme/theme'
import Box from '@components/Box'
import useEnrichedTransactions from '@hooks/useEnrichedTransactions'
import useHaptic from '@hooks/useHaptic'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import ServiceNavBar from './ServiceNavBar'
const Tab = createBottomTabNavigator()
diff --git a/src/components/SplashScreen.tsx b/src/components/SplashScreen.tsx
index f4258ab29..2afebb050 100644
--- a/src/components/SplashScreen.tsx
+++ b/src/components/SplashScreen.tsx
@@ -6,10 +6,10 @@ import Animated, {
useSharedValue,
withTiming,
} from 'react-native-reanimated'
-import globalStyles from '@theme/globalStyles'
-import { useColors } from '@theme/themeHooks'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
-import { useAppStorage } from '../storage/AppStorageProvider'
+import globalStyles from '@config/theme/globalStyles'
+import { useColors } from '@config/theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { ReAnimatedBox } from './AnimatedBox'
const SplashScreen = ({ children }: { children: ReactNode }) => {
diff --git a/src/components/SubmitButton.tsx b/src/components/SubmitButton.tsx
index b0d8caa7c..ae780f14f 100644
--- a/src/components/SubmitButton.tsx
+++ b/src/components/SubmitButton.tsx
@@ -1,9 +1,10 @@
import { BoxProps } from '@shopify/restyle'
import React, { memo, useMemo } from 'react'
import SwipeButton from 'rn-swipe-button'
-import SwipeIcon from '@assets/images/swipeIcon.svg'
-import { Font, Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import SwipeIcon from '@assets/svgs/swipeIcon.svg'
+import { Font, Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
+import { StyleProp, TextStyle } from 'react-native'
import Box from './Box'
type Props = {
@@ -37,6 +38,7 @@ const SubmitButton = ({
color: disabled ? secondaryText : colorActual,
fontSize: 19,
paddingLeft: 30,
+ fontWeight: 600,
},
railStyles: {
backgroundColor: rest['bg.tertiary'],
@@ -58,7 +60,7 @@ const SubmitButton = ({
railBackgroundColor={backgroundActual}
railStyles={styles.railStyles}
railBorderColor={backgroundActual}
- titleStyles={styles.titleStyles}
+ titleStyles={styles.titleStyles as StyleProp}
titleMaxFontScale={1}
thumbIconBackgroundColor={backgroundActual}
thumbIconBorderColor={colorActual}
diff --git a/src/components/Surface.tsx b/src/components/Surface.tsx
index a27d6523d..dd29b0783 100644
--- a/src/components/Surface.tsx
+++ b/src/components/Surface.tsx
@@ -2,8 +2,8 @@
import { BoxProps } from '@shopify/restyle'
import React, { memo, useMemo } from 'react'
import { StyleProp, ViewStyle } from 'react-native'
-import { Color, Theme } from '@theme/theme'
-import { useColorScheme, useCreateOpacity } from '@theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
+import { useColorScheme, useCreateOpacity } from '@config/theme/themeHooks'
import Box from './Box'
type Props = BoxProps & {
diff --git a/src/components/TabBar.tsx b/src/components/TabBar.tsx
index f9238677d..5d5f8022a 100644
--- a/src/components/TabBar.tsx
+++ b/src/components/TabBar.tsx
@@ -14,8 +14,8 @@ import Animated, {
} from 'react-native-reanimated'
import { SvgProps } from 'react-native-svg'
import useHaptic from '@hooks/useHaptic'
-import { Color } from '@theme/theme'
-import { useColors, useVerticalHitSlop } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors, useVerticalHitSlop } from '@config/theme/themeHooks'
import Box from './Box'
import Text from './Text'
import TouchableOpacityBox, {
diff --git a/src/components/Text.tsx b/src/components/Text.tsx
index 63309d83c..39a3bb59c 100644
--- a/src/components/Text.tsx
+++ b/src/components/Text.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import createText from './createText'
const Text = createText()
diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx
index 77b2bd075..305823b6e 100644
--- a/src/components/TextInput.tsx
+++ b/src/components/TextInput.tsx
@@ -8,8 +8,12 @@ import {
import { TextInput, TextStyle } from 'react-native'
import tinycolor from 'tinycolor2'
import { SvgProps } from 'react-native-svg'
-import { Color, darkTheme, Theme } from '@theme/theme'
-import { useColors, useInputVariants, useTextVariants } from '@theme/themeHooks'
+import { Color, darkTheme, Theme } from '@config/theme/theme'
+import {
+ useColors,
+ useInputVariants,
+ useTextVariants,
+} from '@config/theme/themeHooks'
import Box from './Box'
import Text from './Text'
import TouchableOpacityBox, {
diff --git a/src/components/TextInputNew.tsx b/src/components/TextInputNew.tsx
new file mode 100644
index 000000000..85d3b1ed9
--- /dev/null
+++ b/src/components/TextInputNew.tsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import { BoxProps } from '@shopify/restyle'
+import { Theme } from '@config/theme/theme'
+import { useColors, useTextVariants } from '@config/theme/themeHooks'
+import { TextInput, TextInputProps } from 'react-native'
+import Box from './Box'
+import Text from './Text'
+
+type SearchProps = BoxProps & {
+ label: string
+ textInputProps?: TextInputProps
+}
+
+const TextInputNew = ({ label, textInputProps, ...rest }: SearchProps) => {
+ const textVariants = useTextVariants()
+ const colors = useColors()
+ return (
+
+ {label}
+
+
+ )
+}
+
+export default TextInputNew
diff --git a/src/components/TextTransform.tsx b/src/components/TextTransform.tsx
index 61f7b02c3..dcdb625cb 100644
--- a/src/components/TextTransform.tsx
+++ b/src/components/TextTransform.tsx
@@ -4,7 +4,7 @@
import React, { useMemo } from 'react'
import { Trans } from 'react-i18next'
import { ResponsiveValue, TextProps } from '@shopify/restyle'
-import { TextVariant, Theme } from '@theme/theme'
+import { TextVariant, Theme } from '@config/theme/theme'
import Text from './Text'
const getComponents = (variant?: ResponsiveValue) => ({
@@ -18,6 +18,7 @@ const getComponents = (variant?: ResponsiveValue) => ({
'green.light-500': ,
'blue.light-500': ,
'green.400': ,
+ quaternary: ,
codeHighlight: (
- camera?: React.RefObject
- onUserLocationUpdate?: (userLocation: MapLibreGL.Location) => void
- centerCoordinate?: Position
- mapProps?: Omit, 'children'>
- cameraProps?: React.ComponentProps
- }>
-> = ({
- children,
- map,
- camera,
- onUserLocationUpdate,
- centerCoordinate,
- mapProps = {},
- cameraProps = {},
-}) => {
- const mapStyle: string = useMemo(
- () =>
- JSON.stringify({
- version: 8,
- sources: {
- protomaps: {
- type: 'vector',
- tiles: [`${Config.PMTILES_URL}/{z}/{x}/{y}.mvt`],
- },
- },
- glyphs: 'https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf',
- layers: mapLayers,
- }),
- [],
- )
-
- return (
-
-
-
- {children}
-
- )
-}
-
-export default Map
diff --git a/src/components/map/mapLayers.ts b/src/components/map/mapLayers.ts
deleted file mode 100644
index 6b35c1002..000000000
--- a/src/components/map/mapLayers.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-export const mapLayers: { [key: string]: unknown }[] = [
- {
- id: 'land',
- type: 'background',
- layout: {},
- paint: {
- 'background-color': '#2A2A2A',
- },
- },
- {
- id: 'natural_features',
- type: 'fill',
- source: 'protomaps',
- 'source-layer': 'natural',
- filter: [
- 'any',
- ['==', 'natural', 'wood'],
- ['==', 'leisure', 'nature_reserve'],
- ['==', 'landuse', 'forest'],
- ['==', 'natural', 'glacier'],
- ['==', 'natural', 'sand'],
- ],
- paint: {
- 'fill-color': '#2A2A2A',
- },
- },
- {
- id: 'transit_runway',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'transit',
- filter: ['has', 'aeroway'],
- paint: {
- 'line-color': '#2A2A2A',
- 'line-width': 6,
- },
- },
- {
- id: 'landuse_runway',
- type: 'fill',
- source: 'protomaps',
- 'source-layer': 'landuse',
- filter: [
- 'any',
- ['==', 'aeroway', 'runway'],
- ['==', 'area:aeroway', 'runway'],
- ['==', 'area:aeroway', 'taxiway'],
- ],
- paint: {
- 'fill-color': '#2A2A2A',
- },
- },
- {
- id: 'water',
- type: 'fill',
- source: 'protomaps',
- 'source-layer': 'water',
- paint: {
- 'fill-color': '#202020',
- },
- },
- {
- id: 'roads_other',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'roads',
- filter: ['==', 'pmap:kind', 'other'],
- paint: {
- 'line-color': '#3D3D3D',
- 'line-dasharray': [2, 1],
- 'line-width': [
- 'interpolate',
- ['exponential', 1.6],
- ['zoom'],
- 14,
- 0,
- 14.5,
- 0.5,
- 20,
- 12,
- ],
- },
- },
- {
- id: 'roads_minor',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'roads',
- filter: ['==', 'pmap:kind', 'minor_road'],
- paint: {
- 'line-color': '#3D3D3D',
- 'line-width': [
- 'interpolate',
- ['exponential', 1.6],
- ['zoom'],
- 12,
- 0,
- 12.5,
- 0.5,
- 20,
- 32,
- ],
- },
- },
- {
- id: 'roads_medium',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'roads',
- filter: ['==', 'pmap:kind', 'medium_road'],
- paint: {
- 'line-color': '#3D3D3D',
- 'line-width': [
- 'interpolate',
- ['exponential', 1.6],
- ['zoom'],
- 7,
- 0,
- 7.5,
- 0.5,
- 20,
- 32,
- ],
- },
- },
- {
- id: 'roads_major',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'roads',
- filter: ['==', 'pmap:kind', 'major_road'],
- paint: {
- 'line-color': '#3D3D3D',
- 'line-width': [
- 'interpolate',
- ['exponential', 1.6],
- ['zoom'],
- 7,
- 0,
- 7.5,
- 0.5,
- 19,
- 32,
- ],
- },
- },
- {
- id: 'roads_highway',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'roads',
- filter: ['==', 'pmap:kind', 'highway'],
- paint: {
- 'line-color': '#3D3D3D',
- 'line-width': [
- 'interpolate',
- ['exponential', 1.6],
- ['zoom'],
- 3,
- 0,
- 3.5,
- 0.5,
- 18,
- 32,
- ],
- },
- },
- {
- id: 'boundaries_country',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'boundaries',
- filter: ['<=', 'pmap:min_admin_level', 2],
- paint: {
- 'line-color': '#696969',
- 'line-width': 1.5,
- },
- },
- {
- id: 'boundaries',
- type: 'line',
- source: 'protomaps',
- 'source-layer': 'boundaries',
- filter: ['>', 'pmap:min_admin_level', 2],
- paint: {
- 'line-color': '#696969',
- 'line-width': 1,
- 'line-dasharray': [1, 2],
- },
- },
- {
- id: 'roads_labels',
- type: 'symbol',
- source: 'protomaps',
- 'source-layer': 'roads',
- layout: {
- 'symbol-placement': 'line',
- 'text-font': ['NotoSans-Regular'],
- 'text-field': ['coalesce', ['get', 'name_en'], ['get', 'name']],
- 'text-letter-spacing': 0.01,
- 'text-size': 12,
- },
- paint: {
- 'text-color': '#6D6D6D',
- },
- },
- {
- id: 'places_city',
- type: 'symbol',
- source: 'protomaps',
- 'source-layer': 'places',
- filter: ['==', 'pmap:kind', 'city'],
- layout: {
- 'text-field': '{name:en}',
- 'text-font': ['NotoSans-Regular'],
- 'text-size': ['step', ['get', 'pmap:rank'], 0, 1, 12, 2, 10],
- 'text-variable-anchor': ['bottom-left'],
- 'text-radial-offset': 0.2,
- },
- paint: {
- 'text-color': '#6D6D6D',
- 'text-halo-color': '#151515',
- 'text-halo-width': 1,
- },
- },
- {
- id: 'places_state',
- type: 'symbol',
- source: 'protomaps',
- 'source-layer': 'places',
- filter: ['==', 'pmap:kind', 'state'],
- layout: {
- 'text-field': '{name:en}',
- 'text-font': ['NotoSans-Regular'],
- 'text-size': 14,
- 'text-radial-offset': 0.2,
- 'text-anchor': 'center',
- 'text-transform': 'uppercase',
- 'text-letter-spacing': 0.1,
- },
- paint: {
- 'text-color': '#6D6D6D',
- 'text-halo-color': '#151515',
- 'text-halo-width': 1,
- },
- },
- {
- id: 'places_country',
- type: 'symbol',
- source: 'protomaps',
- 'source-layer': 'places',
- filter: ['==', 'place', 'country'],
- layout: {
- 'text-field': '{name:en}',
- 'text-font': ['NotoSans-Regular'],
- 'text-size': 10,
- },
- paint: {
- 'text-color': '#6D6D6D',
- 'text-halo-color': '#151515',
- 'text-halo-width': 1,
- },
- },
-]
diff --git a/src/locales/en.ts b/src/config/locales/en.ts
similarity index 92%
rename from src/locales/en.ts
rename to src/config/locales/en.ts
index 628e8229c..3ecc2b7d8 100644
--- a/src/locales/en.ts
+++ b/src/config/locales/en.ts
@@ -25,8 +25,9 @@ export default {
},
hotspotOnboarding: {
scan: {
- title: 'Scan for Hotspots',
- start: 'Start Scan',
+ title: 'Choose your Hotspot',
+ hotspotsFound: '{{count}} Hotspots were found',
+ start: 'Scan Again',
stop: 'Stop Scan',
notEnabled: 'Bluetooth is not enabled',
scanning: 'Scanning for Hotspots',
@@ -42,13 +43,25 @@ export default {
noneFound: 'No diagnostics found',
},
wifiSettings: {
- title: 'Wifi Settings',
+ title: 'Share Wi-Fi',
+ subtitle:
+ 'Choose the Wi-Fi network you’d like your Hotspot to connect to.',
remove: 'Would you like to remove {{network}}?',
available: 'Available Networks',
configured: 'Configured Networks',
setup: 'Setup Wifi',
},
+ wifiSetup: {
+ title: 'Enter Password',
+ subtitle: 'Provide password for {{ network }}',
+ enterPassword: 'Enter Password',
+ setWifi: 'Set Wi-Fi',
+ },
onboarding: {
+ hotspotConnected: 'Hotspot Connected',
+ hotspotConnectedBody:
+ 'Awesome! Your Hotspot now has an internet connection.',
+ confirmLocation: 'Confirm Location',
title: 'Onboarding',
subtitle:
'Onboard your Hotspot to the {{network}} network. After onboarding this Hotspot, you will be able to set the location and antenna details.',
@@ -1529,4 +1542,119 @@ export default {
manageCollectables: {
title: 'Manage collectable list',
},
+ HotspotPage: {
+ metersAway: '{{meters}}m away',
+ amountOfHotspots: '{{amount}} Hotspots',
+ byDistance: 'By Distance',
+ byEarnings: 'By Earnings',
+ noHotspotsTitle: 'No Hotspots. Yet',
+ noHotspotsSubtitle:
+ 'Hotspots create wireless coverage for millions of devices.',
+ learnMore: 'Learn More',
+ add: 'Add',
+ filter: 'Filter Hotspots',
+ new: 'NEW',
+ nearby: 'Nearby',
+ distanceNotAvailable: 'Distance not available',
+ },
+ AddHotspotPage: {
+ title: 'Let’s get your Hotspot connected!',
+ subtitle: 'Got a good spot for your Hotspot?',
+ locationAndMountingTips: 'Location & Mounting Tips',
+ addHotspot: 'Add Hotspot',
+ },
+ SelectNetworkScreen: {
+ title: 'What Network?',
+ subtitle: 'What network does your Hotspot create coverage for?',
+ helpText: 'I’m not sure what I have',
+ },
+ SelectDeviceScreen: {
+ title: 'What Device?',
+ subtitle: 'Which device to do wish to deploy?',
+ indoor: 'Indoor Hotspot',
+ outdoor: 'Outdoor Hotspot',
+ },
+ KeepYourBoxScreen: {
+ title: 'Keep Your Box',
+ subtitle: 'You will need the QR Code on the box to deploy your Hotspot.',
+ },
+ ConnectEthernetScreen: {
+ title: 'Connect Ethernet',
+ titleIndoor: 'Connect Ethernet\n& Power',
+ subtitle: 'Connect the powered ethernet cable to the rear of the Hotspot.',
+ subtitleIndoor:
+ 'Connect the powered ethernet cable to the rear of the Hotspot.',
+ helpText: 'The status light should turn blue.',
+ help: 'Help',
+ },
+ ConnectToHotspotScreen: {
+ title: 'Connect to Hotspot',
+ subtitle: 'We’ll use your camera to scan the QR code on the Hotspot box.',
+ requestCameraPermissions: 'Request Camera Permissions',
+ perissionsGranted: 'Camera Permissions Granted',
+ perissionsDenied: 'Camera Permissions Denied',
+ manualEntry: 'Manual Entry',
+ },
+ ScanQRCodeScreen: {
+ title: 'Scan QR Code',
+ subtitle: 'Scan the QR code on the box of the Helium Mobile Hotspot.',
+ manualEntry: 'Manual Entry',
+ validatingQRCode: 'Validating QR Code...',
+ tryAgain: 'There was an error, please check your network and try again.',
+ },
+ AcquireLocationScreen: {
+ title: 'Acquiring Location',
+ subtitle:
+ 'Your Hotspot is waiting for a GPS signal to determine its location.',
+ gpsHelp: 'GPS Help',
+ isThisCorrect: 'Is this correct?',
+ locationDetermined:
+ 'We’ve determined the following location via GPS. Does it look correct? Rescan, if not.',
+ },
+ SelectFloorScreen: {
+ title: 'What Floor?',
+ subtitle: 'What floor is your Hotspot on?',
+ selectPlaceholder: 'Select Floor',
+ approx: 'Approx. {{meters}}m',
+ floor: 'Floor {{floor}}',
+ },
+ SetDirectionScreen: {
+ title: 'Rotate dial to\nset direction',
+ subtitle:
+ 'Your Hotspot should face the same direction. Point towards where you expect traffic.',
+ },
+ AddToWalletScreen: {
+ title: 'WELCOME',
+ addressDetails: 'Floor {{floor}} | Pointing {{direction}}',
+ addressDetailsIndoor: 'Floor {{floor}}',
+ errorOnboarding:
+ 'There was an error onboarding your device. Please make sure your device is connected to the internet and try again.',
+ },
+ ManualEntryScreen: {
+ title: 'Manual Entry',
+ subtitle: 'Enter the network name and password from the Hotspot’s box.',
+ scanQRCode: 'Scan QR Code',
+ tryAgain:
+ 'There was an error, please check your network name and password and try again.',
+ },
+ OnboardingSheet: {
+ addToWallet: 'Add to wallet',
+ },
+ ClaimTokensPage: {
+ title: 'Unclaimed Tokens',
+ subtitle:
+ 'Your Hotspots have earned the following tokens, that you need to claim.',
+ claimTokens: 'Claim Tokens',
+ },
+ HotspotDetails: {
+ heliumMobileHotspot: 'Helium Mobile Hotspot Mines MOBILE.',
+ heliumIoTHotspot: 'Helium IoT Hotspot Mines HNT.',
+ deployed: 'Deployed {{date}}',
+ },
+ ConnectViaBluetoothScreen: {
+ title: 'Connect via Bluetooth',
+ subtitle: 'All supported Hotspots use Bluetooth for initial setup.',
+ body: 'Follow the manufacturer’s instructions to power up your device and enter Bluetooth pairing mode.',
+ scanForHotspots: 'Scan for Hotspots',
+ },
}
diff --git a/src/storage/AccountStorageProvider.tsx b/src/config/storage/AccountStorageProvider.tsx
similarity index 98%
rename from src/storage/AccountStorageProvider.tsx
rename to src/config/storage/AccountStorageProvider.tsx
index 7ab50afa9..415caf048 100644
--- a/src/storage/AccountStorageProvider.tsx
+++ b/src/config/storage/AccountStorageProvider.tsx
@@ -15,16 +15,16 @@ import React, {
import { useAsync } from 'react-async-hook'
import Config from 'react-native-config'
import { cloneDeep } from 'lodash'
-import { authSlice } from '../store/slices/authSlice'
-import { useAppDispatch } from '../store/store'
+import { authSlice } from '@store/slices/authSlice'
+import { useAppDispatch } from '@store/store'
import {
accountNetType,
AccountNetTypeOpt,
heliumAddressToSolAddress,
solAddressToHelium,
-} from '../utils/accountUtils'
-import makeApiToken from '../utils/makeApiToken'
-import { getSessionKey } from '../utils/walletApiV2'
+} from '@utils/accountUtils'
+import makeApiToken from '@utils/makeApiToken'
+import { getSessionKey } from '@utils/walletApiV2'
import { useAppStorage } from './AppStorageProvider'
import {
CSAccount,
diff --git a/src/storage/AppStorageProvider.tsx b/src/config/storage/AppStorageProvider.tsx
similarity index 99%
rename from src/storage/AppStorageProvider.tsx
rename to src/config/storage/AppStorageProvider.tsx
index 46c76eeff..01eec2160 100644
--- a/src/storage/AppStorageProvider.tsx
+++ b/src/config/storage/AppStorageProvider.tsx
@@ -8,7 +8,7 @@ import React, {
import { useAsync } from 'react-async-hook'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { Cluster, PublicKey } from '@solana/web3.js'
-import { Intervals } from '../features/settings/useAuthIntervals'
+import { Intervals } from '@features/settings/useAuthIntervals'
import {
getSecureItem,
SecureStorageKeys,
diff --git a/src/storage/GovernanceProvider.tsx b/src/config/storage/GovernanceProvider.tsx
similarity index 98%
rename from src/storage/GovernanceProvider.tsx
rename to src/config/storage/GovernanceProvider.tsx
index a3cc5a81c..b878131a4 100644
--- a/src/storage/GovernanceProvider.tsx
+++ b/src/config/storage/GovernanceProvider.tsx
@@ -17,8 +17,8 @@ import React, { FC, ReactNode, createContext, useContext, useMemo } from 'react'
import { useAsync } from 'react-async-hook'
import Config from 'react-native-config'
import { useSelector } from 'react-redux'
-import { useSolana } from '../solana/SolanaProvider'
-import { RootState } from '../store/rootReducer'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { RootState } from '@store/rootReducer'
import { useAccountStorage } from './AccountStorageProvider'
type GovNetwork = 'hnt' | 'mobile' | 'iot'
diff --git a/src/storage/JupiterProvider.tsx b/src/config/storage/JupiterProvider.tsx
similarity index 98%
rename from src/storage/JupiterProvider.tsx
rename to src/config/storage/JupiterProvider.tsx
index d51c85198..6f8730f14 100644
--- a/src/storage/JupiterProvider.tsx
+++ b/src/config/storage/JupiterProvider.tsx
@@ -17,7 +17,7 @@ import React, {
} from 'react'
import { useTranslation } from 'react-i18next'
import Config from 'react-native-config'
-import * as Logger from '../utils/logger'
+import * as Logger from '@utils/logger'
interface IJupiterContextState {
loading: boolean
diff --git a/src/storage/LanguageProvider.tsx b/src/config/storage/LanguageProvider.tsx
similarity index 92%
rename from src/storage/LanguageProvider.tsx
rename to src/config/storage/LanguageProvider.tsx
index 4e8bca3ba..408802335 100644
--- a/src/storage/LanguageProvider.tsx
+++ b/src/config/storage/LanguageProvider.tsx
@@ -1,5 +1,5 @@
import React, { createContext, ReactNode, useContext } from 'react'
-import { useLanguage } from '../utils/i18n'
+import { useLanguage } from '@utils/i18n'
const initialState = { language: 'en', changeLanguage: async () => undefined }
diff --git a/src/storage/ModalsProvider.tsx b/src/config/storage/ModalsProvider.tsx
similarity index 100%
rename from src/storage/ModalsProvider.tsx
rename to src/config/storage/ModalsProvider.tsx
diff --git a/src/storage/NotificationStorageProvider.tsx b/src/config/storage/NotificationStorageProvider.tsx
similarity index 93%
rename from src/storage/NotificationStorageProvider.tsx
rename to src/config/storage/NotificationStorageProvider.tsx
index 7a56672df..df8592d67 100644
--- a/src/storage/NotificationStorageProvider.tsx
+++ b/src/config/storage/NotificationStorageProvider.tsx
@@ -14,13 +14,13 @@ import { orderBy, without } from 'lodash'
import {
HELIUM_UPDATES_ITEM,
WALLET_UPDATES_ITEM,
-} from '../features/notifications/notificationTypes'
-import { useAppDispatch } from '../store/store'
-import { getNotifications } from '../store/slices/notificationsSlice'
-import usePrevious from '../hooks/usePrevious'
-import { RootState } from '../store/rootReducer'
+} from '@features/notifications/notificationTypes'
+import { useAppDispatch } from '@store/store'
+import { getNotifications } from '@store/slices/notificationsSlice'
+import usePrevious from '@hooks/usePrevious'
+import { RootState } from '@store/rootReducer'
+import { Notification } from '@utils/walletApiV2'
import { useAccountStorage } from './AccountStorageProvider'
-import { Notification } from '../utils/walletApiV2'
const useNotificationStorageHook = () => {
const [selectedList, setSelectedList] = useState()
diff --git a/src/storage/TokensProvider.tsx b/src/config/storage/TokensProvider.tsx
similarity index 98%
rename from src/storage/TokensProvider.tsx
rename to src/config/storage/TokensProvider.tsx
index cf751e3a4..d140b1afe 100644
--- a/src/storage/TokensProvider.tsx
+++ b/src/config/storage/TokensProvider.tsx
@@ -9,7 +9,7 @@ import React, {
useState,
} from 'react'
import { useAsync } from 'react-async-hook'
-import * as Logger from '../utils/logger'
+import * as Logger from '@utils/logger'
import { useAccountStorage } from './AccountStorageProvider'
import {
CSToken,
diff --git a/src/storage/cloudStorage.ts b/src/config/storage/cloudStorage.ts
similarity index 100%
rename from src/storage/cloudStorage.ts
rename to src/config/storage/cloudStorage.ts
diff --git a/src/storage/oneSignalStorage.ts b/src/config/storage/oneSignalStorage.ts
similarity index 100%
rename from src/storage/oneSignalStorage.ts
rename to src/config/storage/oneSignalStorage.ts
diff --git a/src/storage/secureStorage.ts b/src/config/storage/secureStorage.ts
similarity index 97%
rename from src/storage/secureStorage.ts
rename to src/config/storage/secureStorage.ts
index 8753ffe70..f2158923c 100644
--- a/src/storage/secureStorage.ts
+++ b/src/config/storage/secureStorage.ts
@@ -10,9 +10,9 @@ import * as bip39 from 'bip39'
import * as SecureStore from 'expo-secure-store'
import { Alert } from 'react-native'
import Config from 'react-native-config'
-import { navToImportAccount } from '../navigation/NavigationHelper'
-import { ellipsizeAddress } from '../utils/accountUtils'
-import i18n from '../utils/i18n'
+import { ellipsizeAddress } from '@utils/accountUtils'
+import i18n from '@utils/i18n'
+import { navToImportAccount } from '../../app/NavigationHelper'
import { CSAccount } from './cloudStorage'
export enum SecureStorageKeys {
diff --git a/src/theme/globalStyles.ts b/src/config/theme/globalStyles.ts
similarity index 100%
rename from src/theme/globalStyles.ts
rename to src/config/theme/globalStyles.ts
diff --git a/src/theme/theme.ts b/src/config/theme/theme.ts
similarity index 98%
rename from src/theme/theme.ts
rename to src/config/theme/theme.ts
index a0b503cd6..93396c863 100644
--- a/src/theme/theme.ts
+++ b/src/config/theme/theme.ts
@@ -25,7 +25,7 @@ export const breakpoints = {
}
export const baseTheme = {
- borderRadii: lightThemeTokens.borderRadii,
+ borderRadii: { ...lightThemeTokens.borderRadii, '6xl': 40 },
breakpoints,
Font: NovaFont,
inputVariants: {
diff --git a/src/theme/themeHooks.ts b/src/config/theme/themeHooks.ts
similarity index 98%
rename from src/theme/themeHooks.ts
rename to src/config/theme/themeHooks.ts
index ad41624bc..fa9b25cff 100644
--- a/src/theme/themeHooks.ts
+++ b/src/config/theme/themeHooks.ts
@@ -3,7 +3,7 @@ import tinycolor from 'tinycolor2'
import { Platform, ViewStyle } from 'react-native'
import { useCallback, useMemo } from 'react'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { Color, Spacing, Theme } from '@theme/theme'
+import { Color, Spacing, Theme } from 'src/config/theme/theme'
import { ww } from '@utils/layout'
const colorScheme = 'dark' as 'dark' | 'light'
diff --git a/src/features/StatusPage/StatusBanner.tsx b/src/features/StatusPage/StatusBanner.tsx
index 0fc83bb87..2bdbdc27d 100644
--- a/src/features/StatusPage/StatusBanner.tsx
+++ b/src/features/StatusPage/StatusBanner.tsx
@@ -7,9 +7,9 @@ import FlashMessage, {
import { Linking } from 'react-native'
import { formatDistanceToNow, parseISO } from 'date-fns'
import { useTranslation } from 'react-i18next'
-import Close from '@assets/images/closeModal.svg'
+import Close from '@assets/svgs/closeModal.svg'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors, useHitSlop } from '@theme/themeHooks'
+import { useColors, useHitSlop } from '@config/theme/themeHooks'
import useStatusPage from './useStatusPage'
import { HELIUM_STATUS_URL } from './statusPageTypes'
import shortLocale from '../../utils/formatDistance'
diff --git a/src/features/activity/ActivityDetailsScreen.tsx b/src/features/activity/ActivityDetailsScreen.tsx
index 56983c6c4..007ee08b5 100644
--- a/src/features/activity/ActivityDetailsScreen.tsx
+++ b/src/features/activity/ActivityDetailsScreen.tsx
@@ -1,6 +1,6 @@
-import Error from '@assets/images/error.svg'
-import Receive from '@assets/images/receive.svg'
-import Send from '@assets/images/send.svg'
+import Error from '@assets/svgs/error.svg'
+import Receive from '@assets/svgs/receive.svg'
+import Send from '@assets/svgs/send.svg'
import BackScreen from '@components/BackScreen'
import BlurActionSheet from '@components/BlurActionSheet'
import Box from '@components/Box'
@@ -14,14 +14,14 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import useHaptic from '@hooks/useHaptic'
import { RouteProp, useRoute } from '@react-navigation/native'
import { ConfirmedSignatureInfo } from '@solana/web3.js'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Linking } from 'react-native'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import ScrollBox from '@components/ScrollBox'
-import { useCreateExplorerUrl } from '../../constants/urls'
+import { useCreateExplorerUrl } from '../../utils/constants/urls'
import { EnrichedTransaction } from '../../types/solana'
import { ellipsizeAddress, solAddressIsValid } from '../../utils/accountUtils'
import AddressActivityItem from './AddressActivityItem'
diff --git a/src/features/activity/ActivityListItem.tsx b/src/features/activity/ActivityListItem.tsx
index 6521e347d..28e849343 100644
--- a/src/features/activity/ActivityListItem.tsx
+++ b/src/features/activity/ActivityListItem.tsx
@@ -1,13 +1,13 @@
-import Send from '@assets/images/send.svg'
-import Receive from '@assets/images/receive.svg'
-import Error from '@assets/images/error.svg'
+import Send from '@assets/svgs/send.svg'
+import Receive from '@assets/svgs/receive.svg'
+import Error from '@assets/svgs/error.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableContainer from '@components/TouchableContainer'
import { TouchableOpacityBoxProps } from '@components/TouchableOpacityBox'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { ConfirmedSignatureInfo } from '@solana/web3.js'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { ellipsizeAddress, solAddressIsValid } from '@utils/accountUtils'
import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
diff --git a/src/features/activity/ActivityScreen.tsx b/src/features/activity/ActivityScreen.tsx
index 7846006a3..fabd8a027 100644
--- a/src/features/activity/ActivityScreen.tsx
+++ b/src/features/activity/ActivityScreen.tsx
@@ -11,7 +11,7 @@ import useEnrichedTransactions from '@hooks/useEnrichedTransactions'
import CircleLoader from '@components/CircleLoader'
import FadeInOut from '@components/FadeInOut'
import useHaptic from '@hooks/useHaptic'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { NavBarHeight } from '@components/ServiceNavBar'
import ScrollBox from '@components/ScrollBox'
import { ActivityNavigationProp } from './activityTypes'
diff --git a/src/features/activity/AddressActivityItem.tsx b/src/features/activity/AddressActivityItem.tsx
index c1bff8bf8..bf8c18635 100644
--- a/src/features/activity/AddressActivityItem.tsx
+++ b/src/features/activity/AddressActivityItem.tsx
@@ -2,14 +2,14 @@ import React from 'react'
import { StyleSheet } from 'react-native'
import { useTranslation } from 'react-i18next'
import { BoxProps } from '@shopify/restyle'
-import Menu from '@assets/images/menu.svg'
+import Menu from '@assets/svgs/menu.svg'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import AccountIcon from '@components/AccountIcon'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { ellipsizeAddress } from '../../utils/accountUtils'
export const LIST_ITEM_HEIGHT = 70
diff --git a/src/features/addressBook/AddressBook.tsx b/src/features/addressBook/AddressBook.tsx
index 72288d816..57403a3b2 100644
--- a/src/features/addressBook/AddressBook.tsx
+++ b/src/features/addressBook/AddressBook.tsx
@@ -2,7 +2,7 @@ import React, { memo, useCallback } from 'react'
import { useNavigation } from '@react-navigation/native'
import { useTranslation } from 'react-i18next'
import Box from '@components/Box'
-import { CSAccount } from '@storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import BackScreen from '@components/BackScreen'
import ScrollBox from '@components/ScrollBox'
import ContactsList from './ContactsList'
diff --git a/src/features/addressBook/AddressBookNavigator.tsx b/src/features/addressBook/AddressBookNavigator.tsx
index 428d809ee..875500689 100644
--- a/src/features/addressBook/AddressBookNavigator.tsx
+++ b/src/features/addressBook/AddressBookNavigator.tsx
@@ -1,5 +1,5 @@
import React, { memo, useMemo } from 'react'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import {
createStackNavigator,
StackNavigationOptions,
diff --git a/src/features/addressBook/AddressExtra.tsx b/src/features/addressBook/AddressExtra.tsx
index a999a8d6d..e654d3e10 100644
--- a/src/features/addressBook/AddressExtra.tsx
+++ b/src/features/addressBook/AddressExtra.tsx
@@ -1,8 +1,8 @@
import React, { memo } from 'react'
import { ActivityIndicator } from 'react-native'
-import QR from '@assets/images/qr.svg'
-import Checkmark from '@assets/images/checkmark.svg'
-import { useColors, useHitSlop } from '@theme/themeHooks'
+import QR from '@assets/svgs/qr.svg'
+import Checkmark from '@assets/svgs/checkmark.svg'
+import { useColors, useHitSlop } from '@config/theme/themeHooks'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
type AddressExtraProps = {
diff --git a/src/features/addressBook/AddressQrScanner.tsx b/src/features/addressBook/AddressQrScanner.tsx
index f87dda2ee..4d899940c 100644
--- a/src/features/addressBook/AddressQrScanner.tsx
+++ b/src/features/addressBook/AddressQrScanner.tsx
@@ -4,8 +4,8 @@ import { useNavigation } from '@react-navigation/native'
import useHaptic from '@hooks/useHaptic'
import useAlert from '@hooks/useAlert'
import QrScanner from '@components/QrScanner'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { parsePaymentLink } from '../../utils/linking'
import { solAddressIsValid } from '../../utils/accountUtils'
diff --git a/src/features/addressBook/ContactDetails.tsx b/src/features/addressBook/ContactDetails.tsx
index febe41a69..f1ab9981d 100644
--- a/src/features/addressBook/ContactDetails.tsx
+++ b/src/features/addressBook/ContactDetails.tsx
@@ -15,10 +15,10 @@ import {
TextInput as RNTextInput,
Platform,
} from 'react-native'
-import Checkmark from '@assets/images/checkmark.svg'
+import Checkmark from '@assets/svgs/checkmark.svg'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import TextInput from '@components/TextInput'
import ButtonPressable from '@components/ButtonPressable'
import AccountIcon from '@components/AccountIcon'
@@ -31,15 +31,15 @@ import BackScreen from '@components/BackScreen'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import ScrollBox from '@components/ScrollBox'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { useSolana } from '@features/solana/SolanaProvider'
+import AddressExtra from './AddressExtra'
import {
AddressBookNavigationProp,
AddressBookStackParamList,
} from './addressBookTypes'
-import { useAppStorage } from '../../storage/AppStorageProvider'
-import AddressExtra from './AddressExtra'
-import { CSAccount } from '../../storage/cloudStorage'
-import { useSolana } from '../../solana/SolanaProvider'
import { solAddressToHelium } from '../../utils/accountUtils'
const BUTTON_HEIGHT = 55
diff --git a/src/features/addressBook/ContactsList.tsx b/src/features/addressBook/ContactsList.tsx
index 726534d2a..3b24231a3 100644
--- a/src/features/addressBook/ContactsList.tsx
+++ b/src/features/addressBook/ContactsList.tsx
@@ -8,14 +8,14 @@ import { sortBy, unionBy } from 'lodash'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import FabButton from '@components/FabButton'
import SearchInput from '@components/SearchInput'
import AccountListItem from '@components/AccountListItem'
-import { useSpacing } from '@theme/themeHooks'
+import { useSpacing } from '@config/theme/themeHooks'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
type Props = {
onAddNew: () => void
diff --git a/src/features/addressBook/addressBookTypes.ts b/src/features/addressBook/addressBookTypes.ts
index 99537317a..c3dbc33ba 100644
--- a/src/features/addressBook/addressBookTypes.ts
+++ b/src/features/addressBook/addressBookTypes.ts
@@ -1,5 +1,5 @@
import { StackNavigationProp } from '@react-navigation/stack'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
export type AddressBookStackParamList = {
AddressBook: undefined
diff --git a/src/features/browser/BrowserNavigator.tsx b/src/features/browser/BrowserNavigator.tsx
index 83044c109..425c30b2d 100644
--- a/src/features/browser/BrowserNavigator.tsx
+++ b/src/features/browser/BrowserNavigator.tsx
@@ -3,11 +3,11 @@ import {
createNativeStackNavigator,
NativeStackNavigationOptions,
} from '@react-navigation/native-stack'
-import { useAppStorage } from '@storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import BrowserScreen from './BrowserScreen'
import { BrowserWrapper } from './BrowserWebViewScreen'
import DAppTutorial from './DAppTutorial'
-import { useSolana } from '../../solana/SolanaProvider'
const BrowserStack = createNativeStackNavigator()
diff --git a/src/features/browser/BrowserScreen.tsx b/src/features/browser/BrowserScreen.tsx
index 1b25f3bb7..b98f0ef58 100644
--- a/src/features/browser/BrowserScreen.tsx
+++ b/src/features/browser/BrowserScreen.tsx
@@ -6,22 +6,22 @@ import {
TextInput as RNTextInput,
TextInputSubmitEditingEventData,
} from 'react-native'
-import CloseCircle from '@assets/images/CloseCircle.svg'
+import CloseCircle from '@assets/svgs/CloseCircle.svg'
import { useNavigation } from '@react-navigation/native'
import { useTranslation } from 'react-i18next'
import FadeInOut from '@components/FadeInOut'
import TextInput from '@components/TextInput'
import Box from '@components/Box'
import { ReAnimatedBox } from '@components/AnimatedBox'
-import { useColors, useOpacity, useSpacing } from '@theme/themeHooks'
+import { useColors, useOpacity, useSpacing } from '@config/theme/themeHooks'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import Text from '@components/Text'
import useBrowser from '@hooks/useBrowser'
import { prependHttp } from '@utils/url'
import { useAsync } from 'react-async-hook'
+import { useSolana } from '@features/solana/SolanaProvider'
import { BrowserNavigationProp } from './browserTypes'
import BrowserListItem from './BrowserListItem'
-import { useSolana } from '../../solana/SolanaProvider'
import { getRecommendedDapps } from '../../utils/walletApiV2'
const BrowserScreen = () => {
diff --git a/src/features/browser/BrowserWebViewScreen.tsx b/src/features/browser/BrowserWebViewScreen.tsx
index 697911189..fa47f69ee 100644
--- a/src/features/browser/BrowserWebViewScreen.tsx
+++ b/src/features/browser/BrowserWebViewScreen.tsx
@@ -1,15 +1,15 @@
-import BackArrow from '@assets/images/backArrow.svg'
-import Bookmark from '@assets/images/bookmark.svg'
-import BookmarkFilled from '@assets/images/bookmarkFilled.svg'
-import Close from '@assets/images/close.svg'
-import Refresh from '@assets/images/refresh.svg'
+import BackArrow from '@assets/svgs/backArrow.svg'
+import Bookmark from '@assets/svgs/bookmark.svg'
+import BookmarkFilled from '@assets/svgs/bookmarkFilled.svg'
+import Close from '@assets/svgs/close.svg'
+import Refresh from '@assets/svgs/refresh.svg'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import {
SolanaSignAndSendTransactionInput,
SolanaSignMessageInput,
} from '@solana/wallet-standard-features'
import { Transaction, VersionedTransaction } from '@solana/web3.js'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import bs58 from 'bs58'
import React, { useCallback, useMemo, useRef, useState } from 'react'
import { Platform, StyleSheet } from 'react-native'
@@ -19,18 +19,18 @@ import {
WebViewMessageEvent,
WebViewNavigation,
} from 'react-native-webview'
+import SolanaProvider, { useSolana } from '@features/solana/SolanaProvider'
+import WalletSignBottomSheet from '@features/solana/WalletSignBottomSheet'
+import {
+ WalletSignBottomSheetRef,
+ WalletStandardMessageTypes,
+} from '@features/solana/walletSignBottomSheetTypes'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import Box from '../../components/Box'
import SafeAreaBox from '../../components/SafeAreaBox'
import Text from '../../components/Text'
import TouchableOpacityBox from '../../components/TouchableOpacityBox'
import useBrowser from '../../hooks/useBrowser'
-import SolanaProvider, { useSolana } from '../../solana/SolanaProvider'
-import WalletSignBottomSheet from '../../solana/WalletSignBottomSheet'
-import {
- WalletSignBottomSheetRef,
- WalletStandardMessageTypes,
-} from '../../solana/walletSignBottomSheetTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
import * as Logger from '../../utils/logger'
import { BrowserNavigationProp, BrowserStackParamList } from './browserTypes'
import injectWalletStandard from './walletStandard'
diff --git a/src/features/browser/DAppTutorial.tsx b/src/features/browser/DAppTutorial.tsx
index 6baf02cd7..f5aa845ce 100644
--- a/src/features/browser/DAppTutorial.tsx
+++ b/src/features/browser/DAppTutorial.tsx
@@ -8,16 +8,16 @@ import ImageBox from '@components/ImageBox'
import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import TextTransform from '@components/TextTransform'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import { Spacing } from '@theme/theme'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { Spacing } from '@config/theme/theme'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { wp } from '@utils/layout'
import ButtonPressable from '@components/ButtonPressable'
import { ReAnimatedBox } from '@components/AnimatedBox'
import { DelayedFadeIn } from '@components/FadeInOut'
import { NativeViewGestureHandler } from 'react-native-gesture-handler'
+import { useSolana } from '@features/solana/SolanaProvider'
import { BrowserNavigationProp } from './browserTypes'
-import { useSolana } from '../../solana/SolanaProvider'
type CarouselItem = {
titleKey: string
diff --git a/src/features/burn/BurnScreen.tsx b/src/features/burn/BurnScreen.tsx
index 3b11c1fcc..c168e761a 100644
--- a/src/features/burn/BurnScreen.tsx
+++ b/src/features/burn/BurnScreen.tsx
@@ -1,11 +1,6 @@
-import Close from '@assets/images/close.svg'
-import QR from '@assets/images/qr.svg'
-import AccountButton from '@components/AccountButton'
-import AccountSelector, {
- AccountSelectorRef,
-} from '@components/AccountSelector'
+import Close from '@assets/svgs/close.svg'
+import QR from '@assets/svgs/qr.svg'
import Box from '@components/Box'
-import SafeAreaBox from '@components/SafeAreaBox'
import SubmitButton from '@components/SubmitButton'
import Text from '@components/Text'
import TokenButton from '@components/TokenButton'
@@ -28,7 +23,7 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useColors, useHitSlop } from '@theme/themeHooks'
+import { useColors, useHitSlop, useSpacing } from '@config/theme/themeHooks'
import { BN } from 'bn.js'
import React, {
memo as reactMemo,
@@ -39,30 +34,27 @@ import React, {
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
-import { Platform } from 'react-native'
+import { Keyboard, Platform } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
-import { Edge, useSafeAreaInsets } from 'react-native-safe-area-context'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import {
WalletNavigationProp,
WalletStackParamList,
-} from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+} from '@services/WalletService/pages/WalletPage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import ScrollBox from '@components/ScrollBox'
import AddressBookSelector, {
AddressBookRef,
} from '../../components/AddressBookSelector'
import HNTKeyboard, { HNTKeyboardRef } from '../../components/HNTKeyboard'
import IconPressedContainer from '../../components/IconPressedContainer'
import useSubmitTxn from '../../hooks/useSubmitTxn'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { CSAccount } from '../../storage/cloudStorage'
import { RootState } from '../../store/rootReducer'
import { useBalance } from '../../utils/Balance'
-import {
- accountNetType,
- ellipsizeAddress,
- formatAccountAlias,
- solAddressIsValid,
-} from '../../utils/accountUtils'
+import { accountNetType, solAddressIsValid } from '../../utils/accountUtils'
import { TXN_FEE_IN_SOL } from '../../utils/solanaUtils'
import PaymentItem from '../payment/PaymentItem'
import PaymentSubmit from '../payment/PaymentSubmit'
@@ -80,12 +72,12 @@ const BurnScreen = () => {
setCurrentAccount,
defaultAccountAddress,
} = useAccountStorage()
- const { top } = useSafeAreaInsets()
+ const spacing = useSpacing()
+ const { top, bottom } = useSafeAreaInsets()
const navigation = useNavigation()
const { t } = useTranslation()
const { primaryText } = useColors()
const hitSlop = useHitSlop('6')
- const accountSelectorRef = useRef(null)
const { submitDelegateDataCredits } = useSubmitTxn()
const addressBookRef = useRef(null)
const { networkTokensToDc } = useBalance()
@@ -111,8 +103,12 @@ const BurnScreen = () => {
const { isDelegate } = useMemo(() => route.params, [route.params])
const containerStyle = useMemo(
- () => ({ marginTop: Platform.OS === 'android' ? top : undefined }),
- [top],
+ () => ({
+ marginTop: Platform.OS === 'android' ? top : undefined,
+ paddingBottom: NavBarHeight + spacing['2xl'] + bottom,
+ flex: 1,
+ }),
+ [top, spacing, bottom],
)
const networkType = useMemo(
@@ -120,11 +116,6 @@ const BurnScreen = () => {
[route.params.address],
)
- const handleShowAccounts = useCallback(() => {
- if (!accountSelectorRef?.current) return
- accountSelectorRef.current.showAccountTypes(networkType)()
- }, [networkType])
-
const amountBalance = useMemo(() => {
const amount = new BN(route.params.amount || 0)
@@ -139,11 +130,15 @@ const BurnScreen = () => {
}, [amountBalance, networkTokensToDc])
const onTokenItemPressed = useCallback(() => {
+ Keyboard.dismiss()
hntKeyboardRef.current?.show({
payer: currentAccount,
+ payee: delegateAddress,
+ index: 0,
balance: amountBalance,
+ payments: [],
})
- }, [amountBalance, currentAccount])
+ }, [amountBalance, currentAccount, delegateAddress])
useEffect(() => {
if (currentAccount?.netType === networkType || isDelegate) return
@@ -302,210 +297,178 @@ const BurnScreen = () => {
return (
<>
-
-
+
-
-
-
-
-
-
-
+
- {t(isDelegate ? 'delegate.title' : 'burn.title')}
-
-
-
-
+
+
-
-
- 1}
- address={currentAccount?.address}
- onPress={handleShowAccounts}
- showBubbleArrow
- marginHorizontal="6"
- marginBottom="xs"
- />
-
-
-
- {isDelegate ? (
-
- {
- setMemo(m)
- }}
- onEditAddress={({ address }) => {
- setDelegateAddress(address)
- handleAddressError({
- address,
- })
- }}
- handleAddressError={handleAddressError}
- mint={DC_MINT}
- address={delegateAddress}
- amount={amountBalance}
- memo={memo}
- hasError={hasError}
- />
-
- ) : (
- <>
-
-
-
- {t('burn.amount')}
-
-
- {amountBalance.toString()}
-
-
- {t('payment.fee', {
- value: humanReadable(FEE, 9),
- })}
-
-
-
-
-
- {t('burn.equivalent')}
-
-
- {amountInDc?.toString()}
-
-
-
-
- >
- )}
-
- {submitError && (
-
-
- {submitError}
-
-
- )}
-
+
-
-
-
+
+
+
+
+
+
+ {isDelegate ? (
+
+ {
+ setMemo(m)
+ }}
+ onEditAddress={({ address }) => {
+ setDelegateAddress(address)
+ handleAddressError({
+ address,
+ })
+ }}
+ handleAddressError={handleAddressError}
+ mint={DC_MINT}
+ address={delegateAddress}
+ account={currentAccount || undefined}
+ amount={amountBalance}
+ memo={memo}
+ hasError={hasError}
/>
+ ) : (
+ <>
+
+
+ {t('burn.amount')}
+
+
+ {amountBalance.toString()}
+
+
+ {t('payment.fee', {
+ value: humanReadable(FEE, 9),
+ })}
+
+
+
+
+
+ {t('burn.equivalent')}
+
+
+ {amountInDc?.toString()}
+
+
+
+
+ >
+ )}
+
+ {submitError && (
+
+
+ {submitError}
+
-
+ )}
+
+
+
+
+
+
{
onSuccess={navigation.popToTop}
actionTitle={t('generic.ok')}
/>
-
+
{
- const colors = useColors()
- const screenOptions: StackNavigationOptions = useMemo(
- () => ({
- headerShown: false,
- cardStyle: { backgroundColor: colors.primaryBackground },
- }),
- [colors],
- )
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default memo(CollectablesStackScreen)
diff --git a/src/features/collectables/CollectionItem.tsx b/src/features/collectables/CollectionItem.tsx
index ea338bd87..58a446fa2 100644
--- a/src/features/collectables/CollectionItem.tsx
+++ b/src/features/collectables/CollectionItem.tsx
@@ -1,12 +1,12 @@
import Box from '@components/Box'
import Text from '@components/Text'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { Theme } from '@config/theme/theme'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import React, { useCallback, useState } from 'react'
import { Image, Switch } from 'react-native'
import { useDispatch } from 'react-redux'
-import VisibilityOff from '@assets/images/visibilityOff.svg'
+import VisibilityOff from '@assets/svgs/visibilityOff.svg'
import { collectables as collectablesSli } from '@store/slices/collectablesSlice'
export type Collection = {
diff --git a/src/features/collectables/CollectionScreen.tsx b/src/features/collectables/CollectionScreen.tsx
index 224588836..9b3a1ef3c 100644
--- a/src/features/collectables/CollectionScreen.tsx
+++ b/src/features/collectables/CollectionScreen.tsx
@@ -8,8 +8,8 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { DelayedFadeIn } from '@components/FadeInOut'
import { ReAnimatedBox } from '@components/AnimatedBox'
import useHaptic from '@hooks/useHaptic'
-import globalStyles from '@theme/globalStyles'
-import { useBorderRadii } from '@theme/themeHooks'
+import globalStyles from '@config/theme/globalStyles'
+import { useBorderRadii } from '@config/theme/themeHooks'
import ScrollBox from '@components/ScrollBox'
import {
CollectableNavigationProp,
diff --git a/src/features/collectables/HotspotCompressedListItem.tsx b/src/features/collectables/HotspotCompressedListItem.tsx
deleted file mode 100644
index 8b74f0880..000000000
--- a/src/features/collectables/HotspotCompressedListItem.tsx
+++ /dev/null
@@ -1,251 +0,0 @@
-import IotSymbol from '@assets/images/iotSymbol.svg'
-import MobileSymbol from '@assets/images/mobileSymbol.svg'
-import { ReAnimatedBox } from '@components/AnimatedBox'
-import Box from '@components/Box'
-import ImageBox from '@components/ImageBox'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useMint } from '@helium/helium-react-hooks'
-import { IOT_MINT, MOBILE_MINT, toNumber } from '@helium/spl-utils'
-import { useHotspotAddress } from '@hooks/useHotspotAddress'
-import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
-import { ellipsizeAddress, formatLargeNumber } from '@utils/accountUtils'
-import BigNumber from 'bignumber.js'
-import BN from 'bn.js'
-import React, { useMemo } from 'react'
-import { FadeIn, FadeOut } from 'react-native-reanimated'
-import { useColors, useOpacity } from '@theme/themeHooks'
-import { PublicKey } from '@solana/web3.js'
-import { useCurrentWallet } from '@hooks/useCurrentWallet'
-import { useTranslation } from 'react-i18next'
-import { HotspotWithPendingRewards } from '../../types/solana'
-import { Mints } from '../../utils/constants'
-import { removeDashAndCapitalize } from '../../utils/hotspotNftsUtils'
-
-export type HotspotListItemProps = {
- hotspot: HotspotWithPendingRewards
- onPress: (hotspot: HotspotWithPendingRewards) => void
-} & BoxProps
-
-const HotspotListItem = ({
- hotspot,
- onPress,
- ...rest
-}: HotspotListItemProps) => {
- const {
- content: { metadata },
- } = hotspot
- const { t } = useTranslation()
- const colors = useColors()
- const wallet = useCurrentWallet()
- const { backgroundStyle: flamecoOpaque } = useOpacity('orange.500', 0.1)
- const streetAddress = useHotspotAddress(hotspot)
-
- const { info: iotMint } = useMint(IOT_MINT)
- const { info: mobileMint } = useMint(MOBILE_MINT)
-
- const pendingIotRewards = useMemo(
- () => hotspot.pendingRewards && new BN(hotspot.pendingRewards[Mints.IOT]),
- [hotspot],
- )
-
- const pendingIotRewardsString = useMemo(() => {
- if (!hotspot.pendingRewards) return
- const num = toNumber(
- new BN(hotspot.pendingRewards[Mints.IOT]),
- iotMint?.decimals || 6,
- )
- return formatLargeNumber(new BigNumber(num))
- }, [hotspot, iotMint])
-
- const pendingMobileRewards = useMemo(
- () =>
- hotspot.pendingRewards && new BN(hotspot.pendingRewards[Mints.MOBILE]),
- [hotspot.pendingRewards],
- )
-
- const pendingMobileRewardsString = useMemo(() => {
- if (!hotspot.pendingRewards) return
- const num = toNumber(
- new BN(hotspot.pendingRewards[Mints.MOBILE]),
- mobileMint?.decimals || 6,
- )
- return formatLargeNumber(new BigNumber(num))
- }, [hotspot, mobileMint])
-
- const eccCompact = useMemo(() => {
- if (!metadata || !metadata?.attributes?.length) {
- return undefined
- }
-
- return metadata.attributes.find(
- (attr: any) => attr?.trait_type === 'ecc_compact',
- )?.value
- }, [metadata])
-
- const hasIotRewards = useMemo(
- () => pendingIotRewards && pendingIotRewards.gt(new BN(0)),
- [pendingIotRewards],
- )
- const hasMobileRewards = useMemo(
- () => pendingMobileRewards && pendingMobileRewards.gt(new BN(0)),
- [pendingMobileRewards],
- )
-
- const mobileRecipient = useMemo(
- () => hotspot?.rewardRecipients?.[Mints.MOBILE],
- [hotspot],
- )
-
- const iotRecipient = useMemo(
- () => hotspot?.rewardRecipients?.[Mints.IOT],
- [hotspot],
- )
-
- const hasIotRecipient = useMemo(
- () =>
- iotRecipient?.destination &&
- wallet &&
- !new PublicKey(iotRecipient.destination).equals(wallet) &&
- !new PublicKey(iotRecipient.destination).equals(PublicKey.default),
- [iotRecipient, wallet],
- )
-
- const hasMobileRecipient = useMemo(
- () =>
- mobileRecipient?.destination &&
- wallet &&
- !new PublicKey(mobileRecipient.destination).equals(wallet) &&
- !new PublicKey(mobileRecipient.destination).equals(PublicKey.default),
- [mobileRecipient, wallet],
- )
-
- const hasRecipientSet = useMemo(
- () => hasIotRecipient || hasMobileRecipient,
- [hasIotRecipient, hasMobileRecipient],
- )
-
- return (
-
- onPress(hotspot)}
- >
- {hasRecipientSet && (
-
-
-
- {t('changeRewardsRecipientScreen.set')}
-
-
-
- )}
-
-
-
- {metadata?.name && (
-
- {removeDashAndCapitalize(metadata.name)}
-
- )}
-
- {streetAddress && (
-
- {streetAddress}
-
- )}
-
- {eccCompact ? ellipsizeAddress(eccCompact) : ''}
-
-
-
- {!!hasMobileRewards && (
-
-
-
- {pendingMobileRewardsString}
-
-
- )}
- {!!hasIotRewards && (
-
-
-
- {pendingIotRewardsString}
-
-
- )}
-
-
-
-
- )
-}
-
-export default HotspotListItem
diff --git a/src/features/collectables/HotspotList.tsx b/src/features/collectables/HotspotList.tsx
deleted file mode 100644
index ea79fa37d..000000000
--- a/src/features/collectables/HotspotList.tsx
+++ /dev/null
@@ -1,322 +0,0 @@
-import Plus from '@assets/images/plus.svg'
-import Globe from '@assets/images/globe.svg'
-import Box from '@components/Box'
-import ButtonPressable from '@components/ButtonPressable'
-import CircleLoader from '@components/CircleLoader'
-import Text from '@components/Text'
-import TokenIcon from '@components/TokenIcon'
-import { useMint } from '@helium/helium-react-hooks'
-import { IOT_MINT, MOBILE_MINT, toNumber } from '@helium/spl-utils'
-import useHaptic from '@hooks/useHaptic'
-import useHotspots from '@hooks/useHotspots'
-import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
-import { useIsFocused, useNavigation } from '@react-navigation/native'
-import { PublicKey } from '@solana/web3.js'
-import { useColors, useSpacing } from '@theme/themeHooks'
-import BigNumber from 'bignumber.js'
-import BN from 'bn.js'
-import { times } from 'lodash'
-import React, { useCallback, useEffect } from 'react'
-import { useTranslation } from 'react-i18next'
-import { RefreshControl } from 'react-native'
-import { FlatList } from 'react-native-gesture-handler'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import ScrollBox from '@components/ScrollBox'
-import { CompressedNFT, HotspotWithPendingRewards } from '../../types/solana'
-import { formatLargeNumber } from '../../utils/accountUtils'
-import HotspotCompressedListItem from './HotspotCompressedListItem'
-import { NFTSkeleton } from './NftListItem'
-import { CollectableNavigationProp } from './collectablesTypes'
-
-export const DEFAULT_PAGE_AMOUNT = 20
-
-function RewardItem({
- mint,
- amount,
- hasMore,
-}: {
- mint: PublicKey
- amount: BN | undefined
- hasMore: boolean
-}) {
- const decimals = useMint(mint)?.info?.decimals
- const { json, symbol } = useMetaplexMetadata(mint)
- let realAmount = ''
- if (amount) {
- const num = toNumber(amount, decimals || 6)
- realAmount = formatLargeNumber(new BigNumber(num))
- }
-
- return (
-
-
-
- {realAmount}
- {hasMore ? '+' : ''}
-
-
- {symbol}
-
-
- )
-}
-
-const HotspotList = () => {
- const navigation = useNavigation()
- const { t } = useTranslation()
- const isFocused = useIsFocused()
- const { primaryText } = useColors()
- const { triggerImpact } = useHaptic()
- const spacing = useSpacing()
- const { bottom } = useSafeAreaInsets()
-
- const {
- hotspots,
- hotspotsWithMeta,
- loading: loadingHotspots,
- refresh,
- fetchMore,
- fetchingMore,
- pendingIotRewards,
- pendingMobileRewards,
- onEndReached,
- totalHotspots,
- } = useHotspots()
-
- const pageAmount = 20
- const handleOnEndReached = useCallback(() => {
- if (!fetchingMore && isFocused && !onEndReached) {
- fetchMore(pageAmount)
- }
- }, [fetchingMore, isFocused, fetchMore, pageAmount, onEndReached])
-
- const handleNavigateToHotspot = useCallback(
- (hotspot: HotspotWithPendingRewards) => {
- if (hotspot.content.metadata) {
- triggerImpact('light')
- const { iot, mobile } = hotspot.content.metadata.hotspot_infos || {}
- navigation.navigate('HotspotMapScreen', {
- hotspot,
- network: iot?.location
- ? 'IOT'
- : mobile?.location
- ? 'MOBILE'
- : undefined,
- })
- }
- },
- [navigation, triggerImpact],
- )
-
- const handleNavigateToClaimRewards = useCallback(() => {
- navigation.navigate('ClaimAllRewardsScreen')
- }, [navigation])
-
- const handleNavigateToMap = useCallback(() => {
- navigation.navigate('HotspotMapScreen')
- }, [navigation])
-
- const handleNavigateToHotspotOnboard = useCallback(() => {
- navigation.navigate('OnboardingNavigator')
- }, [navigation])
-
- const renderHeader = useCallback(() => {
- return (
-
-
-
- }
- title={t('collectablesScreen.hotspots.openMap')}
- titleColor="base.white"
- fontSize={14}
- onPress={handleNavigateToMap}
- />
-
- }
- title={t('collectablesScreen.hotspots.connect')}
- titleColor="base.black"
- fontSize={14}
- onPress={handleNavigateToHotspotOnboard}
- />
-
-
-
-
-
- You own
-
-
- {totalHotspots} hotspots
-
-
-
-
-
-
- )
- }, [t, handleNavigateToMap, handleNavigateToHotspotOnboard, totalHotspots])
-
- const renderCollectable = useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item }: { item: HotspotWithPendingRewards }) => {
- return (
-
- )
- },
- [handleNavigateToHotspot],
- )
-
- const renderEmptyComponent = useCallback(() => {
- if (!loadingHotspots) return null
-
- if (loadingHotspots && hotspots) {
- return (
-
- {times(hotspots.length).map((i) => (
-
- ))}
-
- )
- }
-
- return null
- }, [hotspots, loadingHotspots])
-
- const keyExtractor = useCallback((item: CompressedNFT) => {
- return item.id
- }, [])
-
- const Footer = useCallback(
- () => (
-
- {fetchingMore ? : }
-
- ),
- [fetchingMore],
- )
-
- const handleRefresh = useCallback(() => {
- refresh(pageAmount)
- }, [pageAmount, refresh])
-
- useEffect(() => {
- return navigation.addListener('focus', () => {
- refresh()
- })
- }, [navigation, refresh])
-
- return (
- <>
-
- }
- >
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default HotspotList
diff --git a/src/features/collectables/HotspotListItem.tsx b/src/features/collectables/HotspotListItem.tsx
deleted file mode 100644
index 2ff84989c..000000000
--- a/src/features/collectables/HotspotListItem.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import React, { useMemo } from 'react'
-import { FadeIn, FadeOut } from 'react-native-reanimated'
-import { BoxProps } from '@shopify/restyle'
-import IotSymbol from '@assets/images/iotSymbol.svg'
-import MobileSymbol from '@assets/images/mobileSymbol.svg'
-import BN from 'bn.js'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import Box from '@components/Box'
-import { ReAnimatedBox } from '@components/AnimatedBox'
-import ImageBox from '@components/ImageBox'
-import { Theme } from '@theme/theme'
-import { IOT_MINT, MOBILE_MINT, toNumber } from '@helium/spl-utils'
-import { useMint } from '@helium/helium-react-hooks'
-import BigNumber from 'bignumber.js'
-import { useColors } from '@theme/themeHooks'
-import { removeDashAndCapitalize } from '../../utils/hotspotNftsUtils'
-import { ww } from '../../utils/layout'
-import { formatLargeNumber } from '../../utils/accountUtils'
-import { Mints } from '../../utils/constants'
-import { HotspotWithPendingRewards } from '../../types/solana'
-
-export type HotspotListItemProps = {
- hotspot: HotspotWithPendingRewards
- onPress: (hotspot: HotspotWithPendingRewards) => void
-} & BoxProps
-
-const HotspotListItem = ({
- hotspot,
- onPress,
- ...rest
-}: HotspotListItemProps) => {
- const colors = useColors()
- const COLLECTABLE_HEIGHT = ww / 2
- const {
- content: { metadata },
- } = hotspot
-
- const { info: iotMint } = useMint(IOT_MINT)
- const { info: mobileMint } = useMint(MOBILE_MINT)
-
- const pendingIotRewards = useMemo(
- () => hotspot.pendingRewards && new BN(hotspot.pendingRewards[Mints.IOT]),
- [hotspot.pendingRewards],
- )
- const pendingIotRewardsString = useMemo(() => {
- if (!hotspot.pendingRewards) return
- const num = toNumber(
- new BN(hotspot.pendingRewards[Mints.IOT]),
- iotMint?.decimals || 6,
- )
- return formatLargeNumber(new BigNumber(num))
- }, [iotMint, hotspot])
-
- const pendingMobileRewards = useMemo(
- () =>
- hotspot.pendingRewards && new BN(hotspot.pendingRewards[Mints.MOBILE]),
- [hotspot.pendingRewards],
- )
-
- const pendingMobileRewardsString = useMemo(() => {
- if (!hotspot.pendingRewards) return
- const num = toNumber(
- new BN(hotspot.pendingRewards[Mints.MOBILE]),
- mobileMint?.decimals || 6,
- )
- return formatLargeNumber(new BigNumber(num))
- }, [hotspot, mobileMint])
-
- const hasIotRewards = useMemo(
- () => pendingIotRewards && pendingIotRewards.gt(new BN(0)),
- [pendingIotRewards],
- )
- const hasMobileRewards = useMemo(
- () => pendingMobileRewards && pendingMobileRewards.gt(new BN(0)),
- [pendingMobileRewards],
- )
-
- return (
-
- onPress(hotspot)}
- >
-
- {!!hasMobileRewards && (
-
-
- {pendingMobileRewardsString}
-
-
-
- )}
- {!!hasIotRewards && (
-
-
- {pendingIotRewardsString}
-
-
-
- )}
-
- {metadata?.name && (
-
- {removeDashAndCapitalize(metadata.name)}
-
- )}
-
- )
-}
-
-export default HotspotListItem
diff --git a/src/features/collectables/ManageCollectables.tsx b/src/features/collectables/ManageCollectables.tsx
index ecc61adf1..798a5d550 100644
--- a/src/features/collectables/ManageCollectables.tsx
+++ b/src/features/collectables/ManageCollectables.tsx
@@ -3,7 +3,7 @@ import ScrollBox from '@components/ScrollBox'
import { NavBarHeight } from '@components/ServiceNavBar'
import useCollectables from '@hooks/useCollectables'
import { RootState } from '@store/rootReducer'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { heliumNFTs } from '@utils/solanaUtils'
import React, { useCallback } from 'react'
import { useAsync } from 'react-async-hook'
diff --git a/src/features/collectables/NftDetailsScreen.tsx b/src/features/collectables/NftDetailsScreen.tsx
index 186914bdb..ba24b1028 100644
--- a/src/features/collectables/NftDetailsScreen.tsx
+++ b/src/features/collectables/NftDetailsScreen.tsx
@@ -3,24 +3,24 @@ import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import 'text-encoding-polyfill'
import { useTranslation } from 'react-i18next'
-import Face from '@assets/images/face.svg'
-import ArrowRight from '@assets/images/arrowRight.svg'
+import Face from '@assets/svgs/face.svg'
+import ArrowRight from '@assets/svgs/arrowRight.svg'
import { DelayedFadeIn } from '@components/FadeInOut'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
import Box from '@components/Box'
import ImageBox from '@components/ImageBox'
import Text from '@components/Text'
import BackScreen from '@components/BackScreen'
-import { useSpacing } from '@theme/themeHooks'
+import { useSpacing } from '@config/theme/themeHooks'
import { ReAnimatedBox } from '@components/AnimatedBox'
import ScrollBox from '@components/ScrollBox'
import {
WalletNavigationProp,
WalletStackParamList,
-} from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+} from '@services/WalletService/pages/WalletPage'
import { NavBarHeight } from '@components/ServiceNavBar'
import ButtonPressable from '@components/ButtonPressable'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import NftMetadata from './NftMetadata'
import { ww } from '../../utils/layout'
import { CompressedNFT } from '../../types/solana'
diff --git a/src/features/collectables/NftList.tsx b/src/features/collectables/NftList.tsx
index 65d1e8b17..e4ed8c853 100644
--- a/src/features/collectables/NftList.tsx
+++ b/src/features/collectables/NftList.tsx
@@ -4,14 +4,14 @@ import { FlatList } from 'react-native-gesture-handler'
import { RefreshControl } from 'react-native'
import Box from '@components/Box'
import useCollectables from '@hooks/useCollectables'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { useNavigation } from '@react-navigation/native'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import Config from '@assets/images/config.svg'
+import Config from '@assets/svgs/config.svg'
import Text from '@components/Text'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
import ScrollBox from '@components/ScrollBox'
import { useSelector } from 'react-redux'
import { RootState } from '@store/rootReducer'
diff --git a/src/features/collectables/NftListItem.tsx b/src/features/collectables/NftListItem.tsx
index e31c9f1b7..a22b1af6c 100644
--- a/src/features/collectables/NftListItem.tsx
+++ b/src/features/collectables/NftListItem.tsx
@@ -8,7 +8,7 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import CircleLoader from '@components/CircleLoader'
import { ReAnimatedBox } from '@components/AnimatedBox'
import useHaptic from '@hooks/useHaptic'
-import { useBorderRadii } from '@theme/themeHooks'
+import { useBorderRadii } from '@config/theme/themeHooks'
import useLayoutWidth from '@hooks/useLayoutWidth'
import { ww } from '../../utils/layout'
import { Collectable } from '../../types/solana'
diff --git a/src/features/collectables/NftMetadata.tsx b/src/features/collectables/NftMetadata.tsx
index cad7c6a08..96353d5af 100644
--- a/src/features/collectables/NftMetadata.tsx
+++ b/src/features/collectables/NftMetadata.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import Box from '@components/Box'
import Text from '@components/Text'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
function stringify(
s: boolean | string | string[] | undefined,
diff --git a/src/features/collectables/TransferCollectableScreen.tsx b/src/features/collectables/TransferCollectableScreen.tsx
index 89441df32..30953b08a 100644
--- a/src/features/collectables/TransferCollectableScreen.tsx
+++ b/src/features/collectables/TransferCollectableScreen.tsx
@@ -1,4 +1,4 @@
-import ArrowRight from '@assets/images/arrowRight.svg'
+import ArrowRight from '@assets/svgs/arrowRight.svg'
import AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
@@ -12,7 +12,7 @@ import ImageBox from '@components/ImageBox'
import Text from '@components/Text'
import TextInput from '@components/TextInput'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import React, { memo, useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import {
@@ -27,10 +27,10 @@ import ScrollBox from '@components/ScrollBox'
import { Asset } from '@helium/spl-utils'
import { NavBarHeight } from '@components/ServiceNavBar'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import AddressIcon from '@assets/images/addressIcon.svg'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+import AddressIcon from '@assets/svgs/addressIcon.svg'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { CSAccount } from '@config/storage/cloudStorage'
import useSubmitTxn from '../../hooks/useSubmitTxn'
-import { CSAccount } from '../../storage/cloudStorage'
import { solAddressIsValid } from '../../utils/accountUtils'
import { ww } from '../../utils/layout'
import * as Logger from '../../utils/logger'
@@ -87,10 +87,6 @@ const TransferCollectableScreen = () => {
[],
)
- const backgroundImageUri = useMemo(() => {
- return metadata.image
- }, [metadata])
-
const handleEditAddress = useCallback((text?: string) => {
setRecipient(text || '')
setRecipientName('')
@@ -130,7 +126,6 @@ const TransferCollectableScreen = () => {
diff --git a/src/features/collectables/TransferCompleteScreen.tsx b/src/features/collectables/TransferCompleteScreen.tsx
index 80cd82703..c77da09f3 100644
--- a/src/features/collectables/TransferCompleteScreen.tsx
+++ b/src/features/collectables/TransferCompleteScreen.tsx
@@ -1,4 +1,4 @@
-import BackArrow from '@assets/images/backArrow.svg'
+import BackArrow from '@assets/svgs/backArrow.svg'
import { ReAnimatedBox } from '@components/AnimatedBox'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
@@ -11,7 +11,7 @@ import { useSolOwnedAmount } from '@helium/helium-react-hooks'
import { useBN } from '@hooks/useBN'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { parseTransactionError } from '@utils/solanaUtils'
import React, { memo, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
@@ -22,7 +22,7 @@ import 'text-encoding-polyfill'
import ScrollBox from '@components/ScrollBox'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
import { RootState } from '../../store/rootReducer'
import { CompressedNFT } from '../../types/solana'
import { ww } from '../../utils/layout'
diff --git a/src/features/dappLogin/DappAccount.tsx b/src/features/dappLogin/DappAccount.tsx
index 42f2434fb..f36ca8d16 100644
--- a/src/features/dappLogin/DappAccount.tsx
+++ b/src/features/dappLogin/DappAccount.tsx
@@ -1,8 +1,8 @@
import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
-import Crowdspot from '@assets/images/crowdspot.svg'
-import AddDapp from '@assets/images/addDapp.svg'
-import DappEllipsis from '@assets/images/dapp-ellipsis.svg'
+import Crowdspot from '@assets/svgs/crowdspot.svg'
+import AddDapp from '@assets/svgs/addDapp.svg'
+import DappEllipsis from '@assets/svgs/dapp-ellipsis.svg'
import { NetTypes as NetType, NetTypes } from '@helium/address'
import { ActivityIndicator } from 'react-native'
import AccountButton from '@components/AccountButton'
@@ -12,9 +12,9 @@ import AccountSelector, {
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import AccountIcon from '@components/AccountIcon'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
type Props = {
onLogin: () => void
diff --git a/src/features/dappLogin/DappConnect.tsx b/src/features/dappLogin/DappConnect.tsx
index 2d5267ad2..f512072e6 100644
--- a/src/features/dappLogin/DappConnect.tsx
+++ b/src/features/dappLogin/DappConnect.tsx
@@ -1,11 +1,11 @@
import React, { memo, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import Crowdspot from '@assets/images/crowdspot.svg'
-import AddDapp from '@assets/images/addDapp.svg'
+import Crowdspot from '@assets/svgs/crowdspot.svg'
+import AddDapp from '@assets/svgs/addDapp.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
type Props = { appName: string; onApprove: () => void; onDeny: () => void }
const DappConnect = ({ appName, onApprove, onDeny }: Props) => {
diff --git a/src/features/dappLogin/DappLoginScreen.tsx b/src/features/dappLogin/DappLoginScreen.tsx
index 0624cfea9..fa6a37fb0 100644
--- a/src/features/dappLogin/DappLoginScreen.tsx
+++ b/src/features/dappLogin/DappLoginScreen.tsx
@@ -1,23 +1,20 @@
-import Close from '@assets/images/close.svg'
+import Close from '@assets/svgs/close.svg'
import SafeAreaBox from '@components/SafeAreaBox'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import Address from '@helium/address'
import { TokenBurnV1 } from '@helium/transactions'
import useAlert from '@hooks/useAlert'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { ActivityIndicator, Linking } from 'react-native'
import { useDebouncedCallback } from 'use-debounce'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import {
- RootNavigationProp,
- RootStackParamList,
-} from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { getKeypair } from '../../storage/secureStorage'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { getKeypair } from '@config/storage/secureStorage'
+import { RootNavigationProp, RootStackParamList } from '../../app/rootTypes'
import DappAccount from './DappAccount'
import DappConnect from './DappConnect'
import { useWalletConnect } from './WalletConnectProvider'
diff --git a/src/features/governance/AssignProxyScreen.tsx b/src/features/governance/AssignProxyScreen.tsx
index d7d02ed07..208458404 100644
--- a/src/features/governance/AssignProxyScreen.tsx
+++ b/src/features/governance/AssignProxyScreen.tsx
@@ -22,7 +22,7 @@ import { usePublicKey } from '@hooks/usePublicKey'
import Slider from '@react-native-community/slider'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { MAX_TRANSACTIONS_PER_SIGNATURE_BATCH } from '@utils/constants'
import sleep from '@utils/sleep'
import { getBasePriorityFee } from '@utils/walletApiV2'
@@ -31,9 +31,9 @@ import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList } from 'react-native'
import { Edge } from 'react-native-safe-area-context'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useWalletSign } from '../../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../../solana/walletSignBottomSheetTypes'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import { PositionPreview } from './PositionPreview'
import { ProxySearch } from './ProxySearch'
import {
@@ -253,8 +253,10 @@ export const AssignProxyScreen = () => {
{t('gov.assignProxy.selectNetwork')}
navigation.setParams({ mint: m })}
+ placeholder="Select Network"
+ initialValue={mint.toBase58()}
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ onValueChange={(m: any) => navigation.setParams({ mint: m })}
options={networks}
/>
diff --git a/src/features/governance/TransferTokensModal.tsx b/src/features/governance/TransferTokensModal.tsx
index 0a85fec2d..7be76d9a4 100644
--- a/src/features/governance/TransferTokensModal.tsx
+++ b/src/features/governance/TransferTokensModal.tsx
@@ -12,7 +12,7 @@ import { useMint, useSolanaUnixNow } from '@helium/helium-react-hooks'
import { getMintMinAmountAsDecimal, precision } from '@utils/formatting'
import { Keyboard } from 'react-native'
import HNTKeyboard, { HNTKeyboardRef } from '@components/HNTKeyboard'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import BN from 'bn.js'
import { humanReadable, toBN, toNumber } from '@helium/spl-utils'
import CircleLoader from '@components/CircleLoader'
diff --git a/src/features/governance/VoteHistory.tsx b/src/features/governance/VoteHistory.tsx
index 595240ef6..824fb7857 100644
--- a/src/features/governance/VoteHistory.tsx
+++ b/src/features/governance/VoteHistory.tsx
@@ -1,5 +1,5 @@
-import ActiveCircle from '@assets/images/activeCircle.svg'
-import CancelledCircle from '@assets/images/cancelledCircle.svg'
+import ActiveCircle from '@assets/svgs/activeCircle.svg'
+import CancelledCircle from '@assets/svgs/cancelledCircle.svg'
import Box from '@components/Box'
import { CardSkeleton } from '@components/CardSkeleton'
import { Pill } from '@components/Pill'
@@ -10,9 +10,9 @@ import { ProposalWithVotes } from '@helium/voter-stake-registry-sdk'
import { useProposalStatus } from '@hooks/useProposalStatus'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { useInfiniteQuery } from '@tanstack/react-query'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { getTimeFromNowFmt } from '@utils/dateTools'
import BN from 'bn.js'
import { times } from 'lodash'
diff --git a/src/features/governance/VoteOption.tsx b/src/features/governance/VoteOption.tsx
index 91780ceef..4e8d8e69a 100644
--- a/src/features/governance/VoteOption.tsx
+++ b/src/features/governance/VoteOption.tsx
@@ -5,8 +5,8 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useKnownProxy } from '@helium/voter-stake-registry-hooks'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Color, Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import { shortenAddress } from '@utils/formatting'
import BN from 'bn.js'
import React from 'react'
diff --git a/src/features/governance/VoterCardStat.tsx b/src/features/governance/VoterCardStat.tsx
index 775273012..075801fe4 100644
--- a/src/features/governance/VoterCardStat.tsx
+++ b/src/features/governance/VoterCardStat.tsx
@@ -2,7 +2,7 @@ import Box from '@components/Box'
import Text from '@components/Text'
import React from 'react'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
export const VoterCardStat: React.FC<
{
diff --git a/src/features/governance/VoterScreen.tsx b/src/features/governance/VoterScreen.tsx
index 8a5c81fae..58fad36cc 100644
--- a/src/features/governance/VoterScreen.tsx
+++ b/src/features/governance/VoterScreen.tsx
@@ -1,5 +1,5 @@
-import UserShare from '@assets/images/userShare.svg'
-import UserX from '@assets/images/userX.svg'
+import UserShare from '@assets/svgs/userShare.svg'
+import UserX from '@assets/svgs/userX.svg'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
@@ -11,7 +11,7 @@ import { proxyQuery, useProxiedTo } from '@helium/voter-stake-registry-hooks'
import { PartialEnhancedProxy } from '@helium/voter-stake-registry-sdk'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { useQuery } from '@tanstack/react-query'
import { humanReadable, shortenAddress } from '@utils/formatting'
import BN from 'bn.js'
diff --git a/src/features/governance/VotersScreen.tsx b/src/features/governance/VotersScreen.tsx
index 1b09068f0..1eccfa3a4 100644
--- a/src/features/governance/VotersScreen.tsx
+++ b/src/features/governance/VotersScreen.tsx
@@ -1,7 +1,7 @@
-import BlueCheck from '@assets/images/blueCheck.svg'
-import MajorityCircle from '@assets/images/majorityCircle.svg'
-import MinorityCircle from '@assets/images/minorityCircle.svg'
-import Warning from '@assets/images/warning2.svg'
+import BlueCheck from '@assets/svgs/blueCheck.svg'
+import MajorityCircle from '@assets/svgs/majorityCircle.svg'
+import MinorityCircle from '@assets/svgs/minorityCircle.svg'
+import Warning from '@assets/svgs/warning2.svg'
import Box from '@components/Box'
import { CardSkeleton } from '@components/CardSkeleton'
import { Pill } from '@components/Pill'
@@ -11,9 +11,9 @@ import TouchableContainer from '@components/TouchableContainer'
import { proxiesQuery } from '@helium/voter-stake-registry-hooks'
import { EnhancedProxy } from '@helium/voter-stake-registry-sdk'
import { useNavigation } from '@react-navigation/native'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { useInfiniteQuery } from '@tanstack/react-query'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { humanReadable, shortenAddress } from '@utils/formatting'
import BN from 'bn.js'
import { times } from 'lodash'
diff --git a/src/features/governance/VotingPowerCard.tsx b/src/features/governance/VotingPowerCard.tsx
index 3e7d87b2d..bc5ee3875 100644
--- a/src/features/governance/VotingPowerCard.tsx
+++ b/src/features/governance/VotingPowerCard.tsx
@@ -1,4 +1,4 @@
-import LightningBolt from '@assets/images/transactions.svg'
+import LightningBolt from '@assets/svgs/transactions.svg'
import { ReAnimatedBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import FadeInOut from '@components/FadeInOut'
@@ -9,9 +9,9 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
-import { Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { useGovernance } from '@config/storage/GovernanceProvider'
+import { Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import { humanReadable } from '@utils/formatting'
import BN from 'bn.js'
import React, { useCallback } from 'react'
diff --git a/src/features/governance/governanceTypes.ts b/src/features/governance/governanceTypes.ts
index df917353b..6bfc6ff27 100644
--- a/src/features/governance/governanceTypes.ts
+++ b/src/features/governance/governanceTypes.ts
@@ -1,7 +1,7 @@
import { IdlAccounts } from '@coral-xyz/anchor'
import { Proposal } from '@helium/modular-governance-idls/lib/types/proposal'
import { StackNavigationProp } from '@react-navigation/stack'
-import { Color } from '@theme/theme'
+import { Color } from 'src/config/theme/theme'
export type ProposalV0 = IdlAccounts['proposalV0']
export type VoteChoice = IdlAccounts['proposalV0']['choices'][0]
diff --git a/src/features/governance/useSetTab.tsx b/src/features/governance/useSetTab.tsx
index 2e03a6303..9560ef60f 100644
--- a/src/features/governance/useSetTab.tsx
+++ b/src/features/governance/useSetTab.tsx
@@ -1,5 +1,5 @@
import { useNavigation } from '@react-navigation/native'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { useCallback } from 'react'
import { GovernanceNavigationProp } from './governanceTypes'
@@ -8,7 +8,8 @@ export function useSetTab() {
const navigation = useNavigation()
return useCallback(
- (tab: string) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (tab: any) => {
switch (tab) {
case 'proposals':
navigation.navigate('ProposalsScreen', {
diff --git a/src/features/home/addNewAccount/AddNewAccountNavigator.tsx b/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
index 54cbc80cb..9e0b7e5d3 100644
--- a/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
+++ b/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
@@ -3,7 +3,7 @@ import {
createStackNavigator,
StackNavigationOptions,
} from '@react-navigation/stack'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import KeystoneNavigator from '../../keystone/KeystoneNavigator'
import AddNewAccountScreen from './AddNewAccountScreen'
import LedgerNavigator from '../../ledger/LedgerNavigator'
diff --git a/src/features/home/addNewAccount/AddNewAccountScreen.tsx b/src/features/home/addNewAccount/AddNewAccountScreen.tsx
index 79878693e..e9175e6a3 100644
--- a/src/features/home/addNewAccount/AddNewAccountScreen.tsx
+++ b/src/features/home/addNewAccount/AddNewAccountScreen.tsx
@@ -5,7 +5,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
import Box from '@components/Box'
import FadeInOut from '@components/FadeInOut'
import TabBar from '@components/TabBar'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
import ScrollBox from '@components/ScrollBox'
import BackScreen from '@components/BackScreen'
import ConnectKeystoneStart from '../../keystone/ConnectKeystoneStartScreen'
diff --git a/src/features/hotspot-onboarding/OnboardingNav.tsx b/src/features/hotspot-onboarding/OnboardingNav.tsx
deleted file mode 100644
index 2329b1839..000000000
--- a/src/features/hotspot-onboarding/OnboardingNav.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import {
- createNativeStackNavigator,
- NativeStackNavigationOptions,
-} from '@react-navigation/native-stack'
-import * as React from 'react'
-import { useColors } from '@theme/themeHooks'
-import HotspotBLENav from './iot-ble/HotspotBLENav'
-import SelectDevice from './SelectDevice'
-
-const Stack = createNativeStackNavigator()
-
-export default React.memo(function OnboardingNav() {
- const colors = useColors()
-
- const screenOptions = React.useMemo(
- () =>
- ({
- headerShown: false,
- contentStyle: {
- backgroundColor: colors.primaryBackground,
- },
- } as NativeStackNavigationOptions),
- [colors],
- )
-
- return (
-
-
-
-
- )
-})
diff --git a/src/features/hotspot-onboarding/OnboardingSheet.tsx b/src/features/hotspot-onboarding/OnboardingSheet.tsx
new file mode 100644
index 000000000..1d37f79ab
--- /dev/null
+++ b/src/features/hotspot-onboarding/OnboardingSheet.tsx
@@ -0,0 +1,457 @@
+import HeliumBottomSheet from '@components/HeliumBottomSheet'
+import React, {
+ createContext,
+ forwardRef,
+ Ref,
+ RefObject,
+ useCallback,
+ useContext,
+ useEffect,
+ useImperativeHandle,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
+import BottomSheet from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheet/BottomSheet'
+import { useSpacing } from '@config/theme/themeHooks'
+import { Platform } from 'react-native'
+import { wh, wp } from '@utils/layout'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { Carousel } from 'react-native-snap-carousel'
+import BackButton from '@assets/svgs/modalBackButton.svg'
+import Box from '@components/Box'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { appSlice } from '@store/slices/appSlice'
+import { useAppDispatch } from '@store/store'
+import Config from 'react-native-config'
+import { useAsyncCallback } from 'react-async-hook'
+import { Portal } from '@gorhom/portal'
+import { ThemeProvider } from '@shopify/restyle'
+import { lightTheme } from '@config/theme/theme'
+import { HotspotBleProvider } from '@helium/react-native-sdk'
+import SelectNetworkScreen from './screens/SelectNetworkScreen'
+import SelectDeviceScreen from './screens/mobile/SelectDeviceScreen'
+import KeepYourBoxScreen from './screens/mobile/KeepYourBoxScreen'
+import ConnectEthernetScreen from './screens/mobile/ConnectEthernetScreen'
+import ConnectToHotspotScreen from './screens/mobile/ConnectToHotspotScreen'
+import ScanQRCodeScreen from './screens/mobile/ScanQRCodeScreen'
+import AcquireLocationScreen from './screens/mobile/AcquireLocationScreen'
+import SelectFloorScreen from './screens/SelectFloorScreen'
+import SetDirectionScreen from './screens/mobile/SetDirectionScreen'
+import AddToWalletScreenMobile from './screens/mobile/AddToWalletScreen'
+import AddToWalletScreenIot from './screens/iot/AddToWalletScreen'
+import ManualEntryScreen from './screens/mobile/ManualEntryScreen'
+import {
+ OnboardingV3Client,
+ DeviceInfo,
+ HmhOnboardParams,
+ VendorSlugs,
+} from './OnboardingV3Client'
+import ScanHotspots from './screens/iot/ScanHotspots'
+import WifiSettings from './screens/iot/WifiSettings'
+import WifiSetup from './screens/iot/WifiSetup'
+import HotspotConnected from './screens/iot/HotspotConnected'
+import SelectLocationScreen from './screens/SelectLocationScreen'
+import ConnectViaBluetoothScreen from './screens/iot/ConnectViaBluetoothScreen'
+
+export type OnboardingSheetRef = {
+ show: () => void
+ hide: () => void
+}
+
+type CarouselItem = {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ Screen: (ScreenProps) => React.JSX.Element
+}
+
+type Network = 'mobile' | 'iot'
+
+export type DeviceType = 'WifiIndoor' | 'WifiOutdoor'
+
+export type OnboardDetails = {
+ network: Network
+ deviceInfo: DeviceInfo
+ iotDetails: OnboardIotDetails
+ latitude: number
+ longitude: number
+ height: number
+ qrCode: string
+ azimuth: number
+}
+
+export type OnboardIotDetails = {
+ network: string
+ onboardingAddress: string
+ animalName: string
+}
+
+type HotspotOnboarding = {
+ onboardDetails: OnboardDetails
+ manualEntry: boolean
+ carouselRef: RefObject> | null
+ setOnboardDetails: React.Dispatch>
+ setManualEntry: (manualEntry: boolean) => void
+ getDeviceInfo: (qrCode: string) => Promise
+ getDeviceInfoLoading: boolean
+ getDeviceInfoError: Error | undefined
+ onboardDevice: ({
+ walletAddress,
+ device,
+ }: {
+ walletAddress: string
+ device: HmhOnboardParams
+ }) => Promise
+ onboardDeviceLoading: boolean
+ onboardDeviceError: Error | undefined
+}
+
+const useHotspotOnboardingHook = (): HotspotOnboarding => {
+ const [onboardDetails, setOnboardDetails] = useState({
+ network: 'mobile',
+ latitude: 0,
+ longitude: 0,
+ height: 0,
+ qrCode: '',
+ azimuth: 0,
+ iotDetails: {
+ network: '',
+ onboardingAddress: '',
+ animalName: '',
+ },
+ deviceInfo: {
+ serialNumber: '',
+ heliumPubKey: '',
+ maker: VendorSlugs.HELIUM_MOBILE,
+ deviceType: 'WifiIndoor',
+ sku: '',
+ animalName: '',
+ },
+ })
+ const [manualEntry, setManualEntry] = useState(false)
+
+ const clientRef = useRef()
+
+ const lazyGetClient = useCallback(async () => {
+ if (clientRef.current) {
+ return clientRef.current
+ }
+
+ const nextClient = new OnboardingV3Client(
+ Config.ONBOARDING_V3_URL || '',
+ Config.ONBOARDING_V3_API_KEY || '',
+ )
+
+ clientRef.current = nextClient
+ return nextClient
+ }, [])
+
+ const {
+ execute: getDeviceInfo,
+ loading: getDeviceInfoLoading,
+ error: getDeviceInfoError,
+ } = useAsyncCallback(async (qrCode: string) => {
+ const client = await lazyGetClient()
+ const deviceInfo = await client.getDeviceInfo(qrCode)
+
+ setOnboardDetails((o) => ({
+ ...o,
+ qrCode,
+ deviceInfo,
+ }))
+
+ return deviceInfo
+ })
+
+ const {
+ execute: onboardDevice,
+ loading: onboardDeviceLoading,
+ error: onboardDeviceError,
+ } = useAsyncCallback(
+ async ({
+ walletAddress,
+ device,
+ }: {
+ walletAddress: string
+ device: HmhOnboardParams
+ }) => {
+ const client = await lazyGetClient()
+
+ const response = await client.onboardDevice(walletAddress, device)
+
+ return response
+ },
+ )
+
+ return {
+ onboardDetails,
+ manualEntry,
+ setOnboardDetails,
+ setManualEntry,
+ carouselRef: null,
+ getDeviceInfo,
+ onboardDevice,
+ onboardDeviceLoading,
+ onboardDeviceError,
+ getDeviceInfoLoading,
+ getDeviceInfoError,
+ }
+}
+
+export type HotspotOnboardingManager = ReturnType<
+ typeof useHotspotOnboardingHook
+>
+
+const HotspotOnboardingContext = createContext(
+ null,
+)
+
+const { Provider } = HotspotOnboardingContext
+
+const HotspotOnboardingProvider = forwardRef(
+ (_, ref: Ref) => {
+ useImperativeHandle(ref, () => ({ show, hide }))
+ const [visible, setVisible] = useState(false)
+
+ const hookValues = useHotspotOnboardingHook()
+ const { manualEntry, onboardDetails } = hookValues
+ const bottomSheetRef = useRef(null)
+ const carouselRef = useRef>(null)
+ const { top } = useSafeAreaInsets()
+ const spacing = useSpacing()
+ const dispatch = useAppDispatch()
+ const [currentIndex, setCurrentIndex] = useState(0)
+
+ const iotSelected = useMemo(() => {
+ return onboardDetails.network === 'iot'
+ }, [onboardDetails])
+
+ const show = useCallback(() => {
+ setVisible(true)
+ }, [])
+
+ const hide = useCallback(() => {
+ bottomSheetRef.current?.close()
+ }, [bottomSheetRef])
+
+ useEffect(() => {
+ return () => {
+ dispatch(appSlice.actions.setRootSheetPosition(undefined))
+ }
+ }, [dispatch])
+
+ const snapPoints = useMemo(() => {
+ if (Platform.OS === 'ios') {
+ return [wh - top - spacing[20]]
+ }
+
+ return [wh - top - spacing[20] - spacing[2]]
+ }, [top, spacing])
+
+ const onBack = useCallback(() => {
+ if (carouselRef.current?.currentIndex === 0) {
+ bottomSheetRef.current?.close()
+ return
+ }
+
+ carouselRef.current?.snapToPrev()
+ }, [carouselRef, bottomSheetRef])
+
+ const slides = useMemo(() => {
+ const pages = [
+ {
+ Screen: SelectNetworkScreen,
+ },
+ ]
+
+ if (iotSelected) {
+ pages.push(
+ ...[
+ {
+ Screen: ConnectViaBluetoothScreen,
+ },
+ {
+ Screen: ScanHotspots,
+ },
+ {
+ Screen: WifiSettings,
+ },
+ {
+ Screen: WifiSetup,
+ },
+ {
+ Screen: HotspotConnected,
+ },
+ {
+ Screen: SelectLocationScreen,
+ },
+ {
+ Screen: SelectFloorScreen,
+ },
+ ],
+ )
+ }
+
+ if (!iotSelected) {
+ pages.push(
+ ...[
+ {
+ Screen: SelectDeviceScreen,
+ },
+ {
+ Screen: KeepYourBoxScreen,
+ },
+ {
+ Screen: ConnectEthernetScreen,
+ },
+ {
+ Screen: ConnectToHotspotScreen,
+ },
+ ],
+ )
+ }
+
+ if (!iotSelected) {
+ if (manualEntry) {
+ pages.push({
+ Screen: ManualEntryScreen,
+ })
+ } else {
+ pages.push({
+ Screen: ScanQRCodeScreen,
+ })
+ }
+ }
+
+ if (!iotSelected) {
+ pages.push(
+ ...[
+ {
+ Screen: AcquireLocationScreen,
+ },
+ {
+ Screen: SelectFloorScreen,
+ },
+ ],
+ )
+ }
+
+ if (onboardDetails.deviceInfo.deviceType === 'WifiOutdoor') {
+ pages.push({
+ Screen: SetDirectionScreen,
+ })
+ }
+
+ pages.push({
+ Screen: iotSelected ? AddToWalletScreenIot : AddToWalletScreenMobile,
+ })
+
+ return pages
+ }, [manualEntry, onboardDetails, iotSelected])
+
+ const renderCarouselItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item: { Screen }, index }: { item: CarouselItem; index: number }) => {
+ // Only render the screen if the index is the current one or one before or after
+ if (
+ currentIndex === index ||
+ currentIndex === index - 1 ||
+ currentIndex === index + 1
+ ) {
+ return
+ }
+ },
+ [currentIndex],
+ )
+
+ const onChange = useCallback((index) => {
+ setVisible(index === 0)
+ if (index === -1) {
+ setCurrentIndex(0)
+ }
+ }, [])
+
+ const onAnimate = useCallback(
+ (index) => {
+ dispatch(appSlice.actions.setRootSheetPosition(index === 0 ? 0 : wh))
+ },
+ [dispatch],
+ )
+
+ return (
+
+
+ {visible && (
+
+ setCurrentIndex(index)}
+ />
+
+
+
+
+
+
+ )}
+
+
+ )
+ },
+)
+
+const useHotspotOnboarding = (): HotspotOnboardingManager => {
+ const context = useContext(HotspotOnboardingContext)
+ if (!context) {
+ throw new Error(
+ 'useHotspotOnboarding has to be used within ',
+ )
+ }
+ return context
+}
+
+const OnboardingSheetWrapper = forwardRef((_, ref: Ref) => {
+ return (
+
+
+
+
+
+ )
+})
+
+export {
+ useHotspotOnboarding,
+ HotspotOnboardingProvider,
+ OnboardingSheetWrapper,
+}
diff --git a/src/features/hotspot-onboarding/OnboardingV3Client.ts b/src/features/hotspot-onboarding/OnboardingV3Client.ts
new file mode 100644
index 000000000..7334edb81
--- /dev/null
+++ b/src/features/hotspot-onboarding/OnboardingV3Client.ts
@@ -0,0 +1,177 @@
+import axios, { AxiosInstance } from 'axios'
+import Config from 'react-native-config'
+import { camelCase, mapKeys } from 'lodash'
+import { handleAxiosError } from '@utils/axios'
+
+export type SupportedMaker = (typeof SUPPORTED_MAKERS)[number]
+
+export enum VendorSlugs {
+ RAKWIRELESS = 'rakwireless',
+ HELIUM_MOBILE = 'helium mobile',
+}
+export const SUPPORTED_MAKERS = [
+ VendorSlugs.RAKWIRELESS,
+ VendorSlugs.HELIUM_MOBILE,
+] as const
+
+const DEFAULT_ANTENNA = 18 // 18 is the model of the outdoor antenna
+
+export type HotspotOnboardingDevice = {
+ qr_code: string
+ wallet: string
+ location: Location
+ settings: Settings
+}
+
+type Location = {
+ latitude: number
+ longitude: number
+ antenna_id?: number
+ height?: number
+ height_type?: 'agl' | 'msl'
+ azimuth?: number
+ mechanical_downtilt?: number
+ electrical_downtilt?: number
+}
+
+type Settings = {
+ public_wifi?: boolean
+ public_wifi_throttling?: number
+ continuous_connectivity?: boolean
+ continuous_connectivity_throttling?: number
+}
+
+type DeviceInfoRaw = {
+ serial_number: string
+ helium_pub_key: string
+ manufacturer: string
+ device_type: string
+ sku: string
+ animal_name: string
+}
+
+export type DeviceInfo = {
+ serialNumber: string
+ heliumPubKey: string
+ maker: SupportedMaker
+ deviceType: 'WifiIndoor' | 'WifiOutdoor'
+ sku: string
+ animalName: string
+}
+
+export type HmhOnboardParams = {
+ serial: string
+ qrCode: string
+ deviceType: 'WifiIndoor' | 'WifiOutdoor'
+ location: {
+ lat: number
+ lng: number
+ height?: number
+ azimuth?: number
+ }
+ settings: {
+ publicWifi?: boolean
+ publicWifiThrottling?: number
+ continuousConnectivity?: boolean
+ continuousConnectivityThrottling?: number
+ }
+}
+
+const shouldMock = Config.MOCK_HMH === 'true'
+
+export class OnboardingV3Client {
+ private axios!: AxiosInstance
+
+ constructor(baseURL: string, authKey: string) {
+ this.axios = axios.create({
+ baseURL: baseURL.endsWith('/') ? baseURL : `${baseURL}/`,
+ })
+ this.axios.defaults.headers['x-api-key'] = authKey
+ }
+
+ async onboardDevice(wallet: string, device: HmhOnboardParams) {
+ let success = false
+ try {
+ const postBody: HotspotOnboardingDevice = {
+ qr_code: device.qrCode,
+ wallet,
+ location: {
+ latitude: device.location.lat,
+ longitude: device.location.lng,
+ },
+ settings: {
+ continuous_connectivity: device.settings.continuousConnectivity,
+ continuous_connectivity_throttling:
+ device.settings.continuousConnectivityThrottling,
+ public_wifi: device.settings.publicWifi,
+ public_wifi_throttling: device.settings.publicWifiThrottling,
+ },
+ }
+ if (device.deviceType === 'WifiOutdoor') {
+ postBody.location.antenna_id = DEFAULT_ANTENNA
+ postBody.location.height = device.location.height
+ postBody.location.height_type = 'agl'
+ postBody.location.azimuth = device.location.azimuth
+ postBody.location.mechanical_downtilt = 0
+ postBody.location.electrical_downtilt = 0
+ }
+
+ if (shouldMock) {
+ await new Promise((resolve) => setTimeout(resolve, 3000))
+ return true
+ }
+
+ const response = await this.axios.post<{ status: string }>(
+ `onboarding/device/${device.serial}/`,
+ postBody,
+ )
+
+ success = response.status >= 200 && response.status < 300
+
+ if (!success) {
+ throw new Error(
+ `Failed with status: ${response.status} ${response.data}`,
+ )
+ }
+ } catch (e) {
+ const error = handleAxiosError(e)
+ throw new Error(error)
+ }
+
+ return success
+ }
+
+ async getDeviceInfo(qrCodeB64: string): Promise {
+ if (shouldMock) {
+ // wait 3 seconds
+ await new Promise((resolve) => setTimeout(resolve, 3000))
+ return {
+ serialNumber: 'HMH-1234-12345678',
+ heliumPubKey:
+ '1trSuseizDjp9cPghN3TZdxpqZq3ks4jvLruhCE7DxbP87QsLrhTVeRHFN8cwKgtzxEsRy3rVLw8zF8zuy8FZE9JQni5Mu48sbnW8wb8ncNF9968inqNS81eNUCCR6r4zsUwjkRZ6rqgHY2F2RymwgUGNoGGrk9n4j5uRwECD1rvygvTgi6U7BkbaJX3V43HYZRuCiQjsh8ebFeHERXYiRz5oGxczVsPgb17BZnKHgoCH5GxWvu35nRpdSGnDMMiXQLm1ziVvhUPob2C5HqWGEQtNXxdzykTg68LzMcCwrasZECeXgUU7w73Fgg6z7Pw5gQtgD3N8z26ogM2JsRS9PT6qx4dN7wVkuKkWCiWEG31uJ',
+ maker: VendorSlugs.HELIUM_MOBILE,
+ deviceType: 'WifiIndoor',
+ sku: 'HMH-1234',
+ animalName: 'angry purple tiger',
+ }
+ }
+
+ try {
+ const response = await this.axios.get(
+ `onboarding/device/?qr_code_b64=${qrCodeB64}`,
+ )
+
+ // map snake case to camel
+ const data = mapKeys(response.data, (_v, k) => camelCase(k))
+
+ return {
+ ...data,
+ maker: data.manufacturer?.toLowerCase().includes('helium')
+ ? VendorSlugs.HELIUM_MOBILE
+ : VendorSlugs.RAKWIRELESS,
+ } as DeviceInfo
+ } catch (e) {
+ throw new Error(handleAxiosError(e, false))
+ }
+ }
+}
diff --git a/src/features/hotspot-onboarding/SelectDevice.tsx b/src/features/hotspot-onboarding/SelectDevice.tsx
deleted file mode 100644
index 04efd2a3a..000000000
--- a/src/features/hotspot-onboarding/SelectDevice.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import BackScreen from '@components/BackScreen'
-import Bluetooth from '@assets/images/bluetooth.svg'
-import ImageBox from '@components/ImageBox'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useNavigation } from '@react-navigation/native'
-import React from 'react'
-import { useTranslation } from 'react-i18next'
-import { FlatList } from 'react-native'
-import { OnboardableDevice, OnboardingNavProp } from './navTypes'
-
-const data: OnboardableDevice[] = [
- {
- name: 'Bluetooth Enabled Hotspot',
- type: 'IotBle',
- icon: ,
- options: {
- bleInstructions:
- 'Power on your Hotspot. Follow manufacturer instructions for enabling bluetooth discovery on the Hotspot.',
- },
- },
-]
-
-const SelectOnboardableDevice = () => {
- const { t } = useTranslation()
- const navigation = useNavigation()
- const renderItem = React.useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item, index }: { item: OnboardableDevice; index: number }) => {
- return (
- {
- navigation.push(item.type, item.options)
- }}
- alignItems="center"
- padding="2"
- flexDirection="row"
- borderTopWidth={index === 0 ? 0 : 1}
- borderColor="gray.900"
- borderBottomWidth={1}
- >
- {item.image && (
-
- )}
- {item.icon && item.icon}
-
- {item.name}
-
-
- )
- },
- [navigation],
- )
-
- const keyExtractor = React.useCallback(
- ({ name }: OnboardableDevice) => name,
- [],
- )
-
- return (
-
-
- {t('hotspotOnboarding.selectOnboardingMethod.subtitle')}
-
-
-
- )
-}
-
-export default SelectOnboardableDevice
diff --git a/src/features/hotspot-onboarding/components/CheckButton.tsx b/src/features/hotspot-onboarding/components/CheckButton.tsx
new file mode 100644
index 000000000..6c615817b
--- /dev/null
+++ b/src/features/hotspot-onboarding/components/CheckButton.tsx
@@ -0,0 +1,69 @@
+import React, { useCallback } from 'react'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import TouchableContainer from '@components/TouchableContainer'
+import ModalCheckButton from '@assets/svgs/modalCheckButton.svg'
+import ModalOnDarkCheckButton from '@assets/svgs/modalCheckOnDarkButton.svg'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+
+export type CheckButtonProps = {
+ onPress: () => void
+ isDark?: boolean
+}
+
+const CheckButton = ({ onPress, isDark }: CheckButtonProps) => {
+ const handlePress = useCallback(() => {
+ onPress()
+ }, [onPress])
+
+ if (isDark) {
+ return (
+
+
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default CheckButton
diff --git a/src/features/hotspot-onboarding/components/ForwardButton.tsx b/src/features/hotspot-onboarding/components/ForwardButton.tsx
new file mode 100644
index 000000000..89242b99b
--- /dev/null
+++ b/src/features/hotspot-onboarding/components/ForwardButton.tsx
@@ -0,0 +1,37 @@
+import React, { useCallback } from 'react'
+import ModalForwardButton from '@assets/svgs/modalForwardButton.svg'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import TouchableContainer from '@components/TouchableContainer'
+
+const ForwardButton = ({ onPress }: { onPress: () => void }) => {
+ const handlePress = useCallback(() => {
+ onPress()
+ }, [onPress])
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default ForwardButton
diff --git a/src/features/hotspot-onboarding/components/Loading.tsx b/src/features/hotspot-onboarding/components/Loading.tsx
new file mode 100644
index 000000000..e3c43409a
--- /dev/null
+++ b/src/features/hotspot-onboarding/components/Loading.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import Box from '@components/Box'
+import CircleLoader from '@components/CircleLoader'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+
+const Loading = () => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default Loading
diff --git a/src/features/hotspot-onboarding/components/WalletButton.tsx b/src/features/hotspot-onboarding/components/WalletButton.tsx
new file mode 100644
index 000000000..9cbfd54dd
--- /dev/null
+++ b/src/features/hotspot-onboarding/components/WalletButton.tsx
@@ -0,0 +1,110 @@
+import React, { useCallback } from 'react'
+import Box from '@components/Box'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import AccountIcon from '@components/AccountIcon'
+import { useColors } from '@config/theme/themeHooks'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import { useTranslation } from 'react-i18next'
+import { useBottomSheet } from '@gorhom/bottom-sheet'
+import { useNavigation } from '@react-navigation/native'
+import { HotspotServiceNavigationProp } from 'src/app/services/HotspotService'
+import Loading from './Loading'
+import { useHotspotOnboarding } from '../OnboardingSheet'
+import { HmhOnboardParams } from '../OnboardingV3Client'
+
+const WalletButton = () => {
+ const colors = useColors()
+ const wallet = useCurrentWallet()
+ const { close } = useBottomSheet()
+ const { t } = useTranslation()
+ const { onboardDevice, onboardDetails, onboardDeviceLoading } =
+ useHotspotOnboarding()
+ const navigation = useNavigation()
+
+ const addToWallet = useCallback(async () => {
+ if (!wallet) {
+ return
+ }
+
+ const device: HmhOnboardParams = {
+ serial: onboardDetails.deviceInfo.serialNumber,
+ qrCode: onboardDetails.qrCode,
+ deviceType: onboardDetails.deviceInfo.deviceType,
+ location: {
+ lat: onboardDetails.latitude,
+ lng: onboardDetails.longitude,
+ },
+ settings: {
+ // TODO: Do we need a new screen to allow the user to choose?
+ publicWifi: true,
+ // TODO: Do we need a new screen to allow the user to choose?
+ publicWifiThrottling: 1000,
+ // TODO: Do we need a new screen to allow the user to choose?
+ continuousConnectivity: true,
+ // TODO: Do we need a new screen to allow the user to choose?
+ continuousConnectivityThrottling: 0,
+ },
+ }
+
+ const result = await onboardDevice({
+ walletAddress: wallet?.toBase58(),
+ device,
+ })
+
+ if (result) {
+ close()
+ navigation.navigate('Hotspot', {
+ newHotspot: undefined,
+ })
+ }
+ }, [onboardDetails, onboardDevice, wallet, close, navigation])
+
+ return (
+
+ {onboardDeviceLoading ? (
+
+ ) : (
+
+
+ {t('OnboardingSheet.addToWallet')}
+
+
+
+
+
+
+ )}
+
+ )
+}
+
+export default WalletButton
diff --git a/src/features/hotspot-onboarding/iot-ble/HotspotBLENav.tsx b/src/features/hotspot-onboarding/iot-ble/HotspotBLENav.tsx
deleted file mode 100644
index 6894676ba..000000000
--- a/src/features/hotspot-onboarding/iot-ble/HotspotBLENav.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import { HotspotBleProvider } from '@helium/react-native-sdk'
-import { RouteProp, useRoute } from '@react-navigation/native'
-import {
- createNativeStackNavigator,
- NativeStackNavigationOptions,
-} from '@react-navigation/native-stack'
-import * as React from 'react'
-import { useColors } from '@theme/themeHooks'
-import { OnboardingtackParamList } from '../navTypes'
-import AddGatewayBle from './AddGatewayBle'
-import ScanHotspots from './ScanHotspots'
-import Settings from './Settings'
-import WifiSettings from './WifiSettings'
-import Diagnostics from './Diagnostics'
-import WifiSetup from './WifiSetup'
-import { IotBleOptionsProvider } from './optionsContext'
-
-const Stack = createNativeStackNavigator()
-
-type Route = RouteProp
-export default React.memo(function HotspotBLENav() {
- const colors = useColors()
- const route = useRoute()
- const iotParams = route.params
-
- const screenOptions = React.useMemo(
- () =>
- ({
- headerShown: false,
- contentStyle: {
- backgroundColor: colors.primaryBackground,
- },
- } as NativeStackNavigationOptions),
- [colors],
- )
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- )
-})
diff --git a/src/features/hotspot-onboarding/iot-ble/ScanHotspots.tsx b/src/features/hotspot-onboarding/iot-ble/ScanHotspots.tsx
deleted file mode 100644
index c432f23ff..000000000
--- a/src/features/hotspot-onboarding/iot-ble/ScanHotspots.tsx
+++ /dev/null
@@ -1,254 +0,0 @@
-import BackScreen from '@components/BackScreen'
-import ButtonPressable from '@components/ButtonPressable'
-import CircleLoader from '@components/CircleLoader'
-import FabButton from '@components/FabButton'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { Device, useHotspotBle } from '@helium/react-native-sdk'
-import { useNavigation } from '@react-navigation/native'
-import React, { useCallback, useEffect, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import { FlatList, Platform, PermissionsAndroid } from 'react-native'
-import {
- PERMISSIONS,
- PermissionStatus,
- RESULTS,
- check,
- request,
-} from 'react-native-permissions'
-import * as Logger from '../../../utils/logger'
-import type { HotspotBleNavProp } from './navTypes'
-import { useIotBleOptions } from './optionsContext'
-
-const ScanHotspots = () => {
- const { startScan, stopScan, connect, scannedDevices } = useHotspotBle()
- const [scanning, setScanning] = useState(false)
- const { bleInstructions } = useIotBleOptions()
- const [canScan, setCanScan] = useState(undefined)
- const navigation = useNavigation()
- const { t } = useTranslation()
- const [error, setError] = useState(undefined)
-
- const showError = (e: any) => {
- Logger.error(e)
- setError(e.toString())
- }
-
- const updateCanScan = useCallback((result: PermissionStatus) => {
- switch (result) {
- case RESULTS.UNAVAILABLE:
- case RESULTS.BLOCKED:
- case RESULTS.DENIED:
- case RESULTS.LIMITED:
- setCanScan(false)
- break
- case RESULTS.GRANTED:
- setCanScan(true)
- break
- }
- }, [])
-
- useEffect(() => {
- if (Platform.OS === 'ios') {
- setCanScan(true)
- return
- }
-
- check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
- .then(updateCanScan)
- .catch(showError)
- }, [updateCanScan])
-
- useEffect(() => {
- if (canScan !== false) return
-
- request(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
- .then(updateCanScan)
- .catch(showError)
- }, [canScan, updateCanScan])
-
- const checkPermission = async () => {
- if (Platform.OS === 'ios') {
- return true
- }
-
- const perms = [
- PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
- PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
- ]
-
- const results = await Promise.all(
- perms.map((p) => PermissionsAndroid.check(p)),
- )
-
- if (results.findIndex((r) => r === false) === -1) {
- return true
- }
-
- const granted = await PermissionsAndroid.requestMultiple([
- PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
- PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
- ])
-
- perms.forEach((p) => {
- if (!granted[p]) {
- return false
- }
- })
-
- return true
- }
-
- const handleScanPress = useCallback(async () => {
- const shouldScan = !scanning
- setScanning(shouldScan)
- await checkPermission()
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let timeout: any | undefined
- if (shouldScan) {
- setError(undefined)
- timeout = setTimeout(() => {
- stopScan()
- setScanning(false)
- if (scannedDevices.length === 0) {
- setError(
- 'No hotspots found. Please ensure bluetooth pairing is enabled',
- )
- }
- }, 30 * 1000)
- }
-
- if (shouldScan) {
- startScan((e) => {
- if (e) {
- showError(e)
- }
- })
- } else {
- stopScan()
- }
- return () => {
- if (timeout) {
- clearTimeout(timeout)
- stopScan()
- }
- }
- }, [scannedDevices.length, scanning, startScan, stopScan])
-
- const navNext = useCallback(() => navigation.push('Settings'), [navigation])
-
- const [connecting, setConnecting] = useState(false)
- const connectDevice = useCallback(
- (d: Device) => async () => {
- try {
- setConnecting(true)
- await connect(d)
- if (scanning) {
- stopScan()
- setScanning(false)
- }
- setConnecting(false)
- navNext()
- } catch (e) {
- showError(e)
- } finally {
- setConnecting(false)
- }
- },
- [connect, navNext, scanning, stopScan],
- )
-
- const renderItem = React.useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item }: { item: Device }) => {
- return (
-
-
-
- {item.name}
-
-
- )
- },
- [connectDevice, connecting],
- )
-
- const keyExtractor = React.useCallback(({ id }: Device) => id, [])
-
- return (
-
-
- {bleInstructions || t('hotspotOnboarding.scan.subtitle')}
-
- {scannedDevices.length === 0 && scanning && }
- {scannedDevices.length === 0 && scanning && (
-
- {t('hotspotOnboarding.scan.scanning')}
-
- )}
-
-
- {error && (
-
- {error}
-
- )}
-
-
- )
-}
-
-export default ScanHotspots
diff --git a/src/features/hotspot-onboarding/iot-ble/Settings.tsx b/src/features/hotspot-onboarding/iot-ble/Settings.tsx
deleted file mode 100644
index c942bab6b..000000000
--- a/src/features/hotspot-onboarding/iot-ble/Settings.tsx
+++ /dev/null
@@ -1,214 +0,0 @@
-import BackScreen from '@components/BackScreen'
-import ButtonPressable from '@components/ButtonPressable'
-import FabButton from '@components/FabButton'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { keyToAssetKey } from '@helium/helium-entity-manager-sdk'
-import { useHotspotBle } from '@helium/react-native-sdk'
-import { useCurrentWallet } from '@hooks/useCurrentWallet'
-import { useIotInfo } from '@hooks/useIotInfo'
-import { useKeyToAsset } from '@hooks/useKeyToAsset'
-import { useNavigation } from '@react-navigation/native'
-import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { DAO_KEY } from '@utils/constants'
-import { getHotspotWithRewards } from '@utils/solanaUtils'
-import React, { useCallback, useEffect, useState } from 'react'
-import { useAsync } from 'react-async-hook'
-import { useTranslation } from 'react-i18next'
-import { FlatList } from 'react-native'
-import { useSolana } from '../../../solana/SolanaProvider'
-import { CollectableNavigationProp } from '../../collectables/collectablesTypes'
-import type { HotspotBLEStackParamList, HotspotBleNavProp } from './navTypes'
-
-type Option = {
- name: string
- route: keyof HotspotBLEStackParamList
-}
-
-const data: Option[] = [
- {
- name: 'Wifi Settings',
- route: 'WifiSettings',
- },
- {
- name: 'Diagnostics',
- route: 'Diagnostics',
- },
-]
-
-// For testing "fresh" hotspots
-// export const TEST_HOTSPOT_WORDS = [
-
-// ]
-// let TEST_HOTSPOT: Keypair = null
-// async function setTestHotspot() {
-// TEST_HOTSPOT = await Keypair.fromMnemonic(new Mnemonic(TEST_HOTSPOT_WORDS))
-// }
-// setTestHotspot()
-// export function getTestHotspot() {
-// return TEST_HOTSPOT!
-// }
-
-const Settings = () => {
- const navigation = useNavigation()
- const collectNav = useNavigation()
- const { t } = useTranslation()
- const {
- isConnected,
- getOnboardingAddress,
- createGatewayTxn: getCreateGatewayTxn,
- } = useHotspotBle()
- const [connected, setConnected] = useState(false)
- const { anchorProvider } = useSolana()
- const wallet = useCurrentWallet()
- const { currentAccount } = useAccountStorage()
-
- useEffect(() => {
- isConnected().then(setConnected)
- }, [isConnected])
- const {
- result: { address, keyToAssetK, createGatewayTx } = {} as {
- address?: string
- keyToAssetK?: PublicKey
- createGatewayTx?: string
- },
- loading: loadingAddress,
- error,
- } = useAsync(
- async (
- c: boolean,
- accountAddress?: string,
- ): Promise<{
- address?: string
- keyToAssetK?: PublicKey
- createGatewayTx?: string
- }> => {
- if (c && accountAddress) {
- const addr = await getOnboardingAddress()
- const tx = await getCreateGatewayTxn({
- ownerAddress: accountAddress,
- payerAddress: accountAddress,
- })
- // For testing
- // const addr = TEST_HOTSPOT.address.b58
- return {
- address: addr,
- keyToAssetK: keyToAssetKey(DAO_KEY, addr, 'b58')[0],
- createGatewayTx: tx,
- }
- }
- return {}
- },
- [connected, currentAccount?.address],
- )
- const { info: iotInfo, loading: loadingInfo } = useIotInfo(address)
- const { info: keyToAsset, loading: loadingKta } = useKeyToAsset(
- keyToAssetK?.toBase58(),
- )
- const loading = loadingInfo || loadingAddress || loadingKta
-
- const navNext = useCallback(async () => {
- if (iotInfo && keyToAsset && anchorProvider && wallet) {
- const collectable = await getHotspotWithRewards(
- keyToAsset.asset,
- anchorProvider,
- )
-
- if (collectable.ownership.owner.toString() !== wallet.toBase58()) {
- collectNav.push('HotspotList')
- }
-
- collectNav.push('HotspotMapScreen', {
- hotspot: collectable,
- network: 'IOT',
- })
- } else {
- navigation.push('AddGatewayBle', {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- onboardingAddress: address!,
- createGatewayTx,
- network: 'IOT',
- })
- }
- }, [
- createGatewayTx,
- address,
- anchorProvider,
- navigation,
- iotInfo,
- keyToAsset,
- collectNav,
- wallet,
- ])
-
- const renderItem = React.useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item, index }: { item: Option; index: number }) => {
- return (
- {
- navigation.push(item.route, {})
- }}
- alignItems="center"
- padding="6"
- flexDirection="row"
- borderTopWidth={index === 0 ? 0 : 1}
- borderColor="gray.900"
- borderBottomWidth={1}
- >
-
-
- {item.name}
-
-
- )
- },
- [navigation],
- )
-
- const keyExtractor = useCallback((option: Option) => option.name, [])
- let errorMessage = error?.message
- ? error?.message.toString()
- : error?.toString()
- if (errorMessage === 'wait') {
- errorMessage = t('hotspotOnboarding.settings.notReady')
- }
-
- return (
-
-
- {error && (
-
- {t('hotspotOnboarding.settings.hotspotError')}
- {errorMessage}
-
- )}
- {!loadingInfo && !loadingKta && (
-
- )}
-
- )
-}
-
-export default Settings
diff --git a/src/features/hotspot-onboarding/iot-ble/WifiSettings.tsx b/src/features/hotspot-onboarding/iot-ble/WifiSettings.tsx
deleted file mode 100644
index a615b60eb..000000000
--- a/src/features/hotspot-onboarding/iot-ble/WifiSettings.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-import BackScreen from '@components/BackScreen'
-import ButtonPressable from '@components/ButtonPressable'
-import FabButton from '@components/FabButton'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useHotspotBle } from '@helium/react-native-sdk'
-import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import React, { useCallback, useEffect, useMemo, useState } from 'react'
-import { useAsyncCallback } from 'react-async-hook'
-import { useTranslation } from 'react-i18next'
-import { Alert, SectionList } from 'react-native'
-import type { HotspotBLEStackParamList, HotspotBleNavProp } from './navTypes'
-
-type Section = {
- title: string
- data: string[]
- type: 'configured' | 'available'
-}
-
-type Route = RouteProp
-
-const WifiSettings = () => {
- const {
- params: { network: networkIn },
- } = useRoute()
- const navigation = useNavigation()
- const { t } = useTranslation()
- const navNext = useCallback(() => navigation.goBack(), [navigation])
- const [networks, setNetworks] = useState()
- const [configuredNetworks, setConfiguredNetworks] = useState()
- const [connected, setConnected] = useState(false)
-
- const { isConnected, readWifiNetworks, removeConfiguredWifi } =
- useHotspotBle()
-
- useEffect(() => {
- isConnected().then(setConnected)
- }, [isConnected])
-
- const {
- execute: handleRefresh,
- loading: refreshing,
- error,
- } = useAsyncCallback(async () => {
- if (!connected) return
-
- const configured = await readWifiNetworks(true)
- setConfiguredNetworks(configured)
- const available = await readWifiNetworks(false)
- setNetworks(available)
- })
-
- // Refresh on network change or on load
- useEffect(() => {
- handleRefresh()
- }, [handleRefresh, networkIn, connected])
-
- const handleNetworkSelected = useCallback(
- ({
- network,
- type,
- }: {
- network: string
- type: 'configured' | 'available'
- }) =>
- async () => {
- if (type === 'available') {
- navigation.push('WifiSetup', { network })
- } else {
- Alert.alert(
- t('hotspotOnboarding.wifiSettings.title'),
- t('hotspotOnboarding.wifiSettings.remove', { network }),
- [
- {
- text: t('generic.cancel'),
- style: 'default',
- },
- {
- text: t('generic.remove'),
- style: 'destructive',
- onPress: async () => {
- setConfiguredNetworks(
- configuredNetworks?.filter((n) => n !== network),
- )
- await removeConfiguredWifi(network)
- readWifiNetworks(true).then(setConfiguredNetworks)
- readWifiNetworks(false).then(setNetworks)
- },
- },
- ],
- )
- }
- },
- [configuredNetworks, navigation, readWifiNetworks, removeConfiguredWifi, t],
- )
-
- const renderItem = useCallback(
- ({
- item: network,
- section: { type },
- }: {
- // eslint-disable-next-line react/no-unused-prop-types
- item: string
- // eslint-disable-next-line react/no-unused-prop-types
- section: Section
- }) => {
- return (
-
-
-
- {network}
-
-
- )
- },
- [handleNetworkSelected],
- )
-
- const keyExtractor = useCallback((name: string) => name, [])
-
- const renderSectionHeader = ({
- section: { title },
- }: {
- section: Section
- }) => (
-
- {title}
-
- )
-
- const sections = useMemo(
- (): Section[] => [
- {
- data: configuredNetworks || [],
- title: t('hotspotOnboarding.wifiSettings.configured'),
- type: 'configured',
- },
- {
- data: networks || [],
- title: t('hotspotOnboarding.wifiSettings.available'),
- type: 'available',
- },
- ],
- [configuredNetworks, networks, t],
- )
-
- return (
-
- {error && (
-
- {error.message ? error.message.toString() : error.toString()}
-
- )}
-
-
-
- )
-}
-
-export default WifiSettings
diff --git a/src/features/hotspot-onboarding/iot-ble/WifiSetup.tsx b/src/features/hotspot-onboarding/iot-ble/WifiSetup.tsx
deleted file mode 100644
index 79db51c7b..000000000
--- a/src/features/hotspot-onboarding/iot-ble/WifiSetup.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import BackScreen from '@components/BackScreen'
-import Box from '@components/Box'
-import ButtonPressable from '@components/ButtonPressable'
-import Text from '@components/Text'
-import TextInput from '@components/TextInput'
-import { BleError, useHotspotBle } from '@helium/react-native-sdk'
-import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import React, { useCallback, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import type { HotspotBLEStackParamList, HotspotBleNavProp } from './navTypes'
-
-type Route = RouteProp
-const WifiSetup = () => {
- const {
- params: { network },
- } = useRoute()
- const [secureTextEntry, setSecureTextEntry] = useState(true)
- const [loading, setLoading] = useState(false)
- const [status, setStatus] = useState('')
- const [password, setPassword] = useState('')
- const { setWifi } = useHotspotBle()
- const { t } = useTranslation()
- const navigation = useNavigation()
- const onBack = useCallback(() => {
- navigation.navigate('WifiSettings', {
- network,
- })
- }, [network, navigation])
-
- const toggleSecureEntry = useCallback(() => {
- setSecureTextEntry(!secureTextEntry)
- }, [secureTextEntry])
-
- const handleSetWifi = useCallback(async () => {
- setLoading(true)
- try {
- const nextStatus = await setWifi(network, password)
- setStatus(nextStatus)
- onBack()
- } catch (e) {
- if (typeof e === 'string') {
- setStatus(e)
- } else {
- setStatus((e as BleError).toString())
- }
- }
- setLoading(false)
- }, [onBack, network, password, setWifi])
-
- return (
-
-
-
-
-
-
-
- {loading ? 'loading...' : status}
-
- )
-}
-
-export default WifiSetup
diff --git a/src/features/hotspot-onboarding/navTypes.tsx b/src/features/hotspot-onboarding/navTypes.tsx
deleted file mode 100644
index 8c01db29a..000000000
--- a/src/features/hotspot-onboarding/navTypes.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { NativeStackNavigationProp } from '@react-navigation/native-stack'
-
-export type IotBleOptions = {
- bleInstructions?: string
-}
-
-export type OnboardableDevice = {
- name: string
- type: 'IotBle'
- image?: string
- icon?: React.ReactElement
- options: IotBleOptions
-}
-
-export type OnboardingtackParamList = {
- IotBle: IotBleOptions
- SelectDevice: undefined
-}
-
-export type OnboardingNavProp =
- NativeStackNavigationProp
diff --git a/src/features/hotspot-onboarding/screens/SelectFloorScreen.tsx b/src/features/hotspot-onboarding/screens/SelectFloorScreen.tsx
new file mode 100644
index 000000000..7e62bd93e
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/SelectFloorScreen.tsx
@@ -0,0 +1,71 @@
+import Box from '@components/Box'
+import React, { useCallback, useMemo } from 'react'
+import Text from '@components/Text'
+import ImageBox from '@components/ImageBox'
+import { useTranslation } from 'react-i18next'
+import { Select } from '@components/Select'
+import CheckButton from '../components/CheckButton'
+import { useHotspotOnboarding } from '../OnboardingSheet'
+
+export const SelectFloorScreen = () => {
+ const { t } = useTranslation()
+ const {
+ setOnboardDetails,
+ carouselRef,
+ onboardDetails: { height },
+ } = useHotspotOnboarding()
+
+ const floors = useMemo(() => {
+ return Array.from({ length: 200 }, (_, i) => ({
+ label: t('SelectFloorScreen.floor', { floor: i + 1 }),
+ value: (i + 1) * 5,
+ subLabel: t('SelectFloorScreen.approx', { meters: (i + 1) * 5 }),
+ }))
+ }, [t])
+
+ const onValueChange = useCallback(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (value: any) => {
+ setOnboardDetails((o) => ({
+ ...o,
+ height: value,
+ }))
+ carouselRef?.current?.snapToNext()
+ },
+ [setOnboardDetails, carouselRef],
+ )
+
+ const onNext = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ return (
+
+
+
+ {t('SelectFloorScreen.title')}
+
+
+ {t('SelectFloorScreen.subtitle')}
+
+
+ {height ? : null}
+
+ )
+}
+
+export default SelectFloorScreen
diff --git a/src/features/hotspot-onboarding/screens/SelectLocationScreen.tsx b/src/features/hotspot-onboarding/screens/SelectLocationScreen.tsx
new file mode 100644
index 000000000..9a9c0cf85
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/SelectLocationScreen.tsx
@@ -0,0 +1,287 @@
+import MapPin from '@assets/svgs/mapPin.svg'
+import { Box, DelayedFadeIn, FadeInOut, ReAnimatedBox, Text } from '@components'
+import useAlert from '@hooks/useAlert'
+import { useForwardGeo } from '@hooks/useForwardGeo'
+import { useReverseGeo } from '@hooks/useReverseGeo'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { KeyboardAvoidingView } from 'react-native'
+import 'text-encoding-polyfill'
+import { useDebounce } from 'use-debounce'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import Map from '@components/Map'
+import {
+ Camera,
+ Location,
+ MapState,
+ MapView,
+ UserLocation,
+} from '@rnmapbox/maps'
+import { INITIAL_MAP_VIEW_STATE, MAX_MAP_ZOOM } from '@utils/mapUtils'
+import { Search } from '@components/Search'
+import CheckButton from '../components/CheckButton'
+import { useHotspotOnboarding } from '../OnboardingSheet'
+
+const SelectLocationScreen = () => {
+ const { t } = useTranslation()
+ const mapRef = useRef(null)
+ const cameraRef = useRef(null)
+ const { showOKAlert } = useAlert()
+ const colors = useColors()
+ const spacing = useSpacing()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+ const [mapCenter, setMapCenter] = useState()
+ const [searchValue, setSearchValue] = useState()
+ const reverseGeo = useReverseGeo(mapCenter)
+ const forwardGeo = useForwardGeo()
+ const [darkCheckMode, setDarkCheckMode] = useState(true)
+
+ const [initialUserLocation, setInitialUserLocation] = useState()
+ const [initialCenterSet, setInitalCenter] = useState(false)
+
+ const [userLocation, setUserLocation] = useState()
+ const onUserLocationUpdate = useCallback(
+ (loc: Location) => {
+ setUserLocation(loc)
+ },
+ [setUserLocation],
+ )
+
+ const handleCameraChanged = useCallback((state: MapState) => {
+ setDarkCheckMode(state.properties.zoom < 3)
+ }, [])
+
+ useEffect(() => {
+ const coords = userLocation?.coords
+ if (!initialUserLocation && coords) {
+ setInitialUserLocation([coords.longitude, coords.latitude])
+ }
+ }, [initialUserLocation, setInitialUserLocation, userLocation?.coords])
+
+ const initialCenter = useMemo(() => {
+ return initialUserLocation || INITIAL_MAP_VIEW_STATE.centerCoordinate
+ }, [initialUserLocation])
+
+ useEffect(() => {
+ if (
+ initialCenter &&
+ JSON.stringify(initialCenter) !==
+ JSON.stringify(INITIAL_MAP_VIEW_STATE.centerCoordinate) &&
+ !initialCenterSet
+ ) {
+ setInitalCenter(true)
+ cameraRef.current?.setCamera({
+ centerCoordinate: initialCenter,
+ animationDuration: 0,
+ })
+ }
+ }, [initialCenter, cameraRef, initialCenterSet, setInitalCenter])
+
+ const handleOnSearch = useCallback(async () => {
+ if (searchValue) {
+ try {
+ const coords = await forwardGeo.execute(searchValue)
+
+ if (cameraRef?.current && coords) {
+ cameraRef.current.setCamera({
+ animationDuration: 500,
+ centerCoordinate: coords,
+ zoomLevel: MAX_MAP_ZOOM / 1.2,
+ })
+ }
+ } catch (error) {
+ const { message = '' } = error as Error
+ if (message === t('noData')) {
+ await showOKAlert({
+ title: t('generic.error'),
+ message: t('assertLocationScreen.locationNotFound'),
+ })
+ }
+ }
+ }
+ }, [cameraRef, t, searchValue, forwardGeo, showOKAlert])
+
+ const handleRegionChanged = useCallback(async () => {
+ if (mapRef?.current) {
+ const center = await mapRef?.current.getCenter()
+ if (JSON.stringify(center) !== JSON.stringify(mapCenter)) {
+ setMapCenter(center)
+ }
+ }
+ }, [mapRef, mapCenter, setMapCenter])
+
+ const onConfirmLocation = useCallback(() => {
+ const long = mapCenter?.[0]
+ const lat = mapCenter?.[1]
+
+ setOnboardDetails((o) => ({
+ ...o,
+ latitude: lat || 0,
+ longitude: long || 0,
+ }))
+ carouselRef?.current?.snapToNext()
+ }, [mapCenter, carouselRef, setOnboardDetails])
+
+ const [reverseGeoLoading] = useDebounce(reverseGeo.loading, 300)
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!reverseGeoLoading && reverseGeo.result && (
+
+
+
+ {reverseGeo.result}
+
+
+
+ )}
+
+
+
+
+ )
+}
+
+export default SelectLocationScreen
diff --git a/src/features/hotspot-onboarding/screens/SelectNetworkScreen.tsx b/src/features/hotspot-onboarding/screens/SelectNetworkScreen.tsx
new file mode 100644
index 000000000..15bea522c
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/SelectNetworkScreen.tsx
@@ -0,0 +1,111 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import MobileIcon from '@assets/svgs/mobileIconNew.svg'
+import IotIcon from '@assets/svgs/iotIconNew.svg'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import { useColors } from '@config/theme/themeHooks'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { HOTSPOT_HELP } from '@utils/constants/urls'
+import { Linking } from 'react-native'
+import { useHotspotOnboarding, OnboardDetails } from '../OnboardingSheet'
+
+const SelectNetworkScreen = () => {
+ const { t } = useTranslation()
+ const colors = useColors()
+ const { setOnboardDetails, carouselRef } = useHotspotOnboarding()
+
+ const onMobileSelected = useCallback(() => {
+ setOnboardDetails((o: OnboardDetails) => ({ ...o, network: 'mobile' }))
+ carouselRef?.current?.snapToNext()
+ }, [setOnboardDetails, carouselRef])
+
+ const onIotSelected = useCallback(() => {
+ setOnboardDetails((o: OnboardDetails) => ({ ...o, network: 'iot' }))
+ carouselRef?.current?.snapToNext()
+ }, [setOnboardDetails, carouselRef])
+
+ const onOpenHelp = useCallback(() => {
+ Linking.openURL(HOTSPOT_HELP)
+ }, [])
+
+ return (
+
+
+ {t('SelectNetworkScreen.title')}
+
+
+ {t('SelectNetworkScreen.subtitle')}
+
+
+
+
+ MOBILE
+
+
+
+
+
+
+ IOT
+
+
+
+
+
+ {t('SelectNetworkScreen.helpText')}
+
+
+
+
+ )
+}
+
+export default SelectNetworkScreen
diff --git a/src/features/hotspot-onboarding/iot-ble/AddGatewayBle.tsx b/src/features/hotspot-onboarding/screens/iot/AddToWalletScreen.tsx
similarity index 58%
rename from src/features/hotspot-onboarding/iot-ble/AddGatewayBle.tsx
rename to src/features/hotspot-onboarding/screens/iot/AddToWalletScreen.tsx
index 6e874be77..46505ffb7 100644
--- a/src/features/hotspot-onboarding/iot-ble/AddGatewayBle.tsx
+++ b/src/features/hotspot-onboarding/screens/iot/AddToWalletScreen.tsx
@@ -1,21 +1,15 @@
-import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
-import CircleLoader from '@components/CircleLoader'
import RadioButton from '@components/RadioButton'
import Text from '@components/Text'
import {
init,
iotInfoKey,
keyToAssetKey,
- mobileInfoKey,
} from '@helium/helium-entity-manager-sdk'
-import { daoKey } from '@helium/helium-sub-daos-sdk'
-import { useOnboarding } from '@helium/react-native-sdk'
+import { useHotspotBle, useOnboarding } from '@helium/react-native-sdk'
import {
- HNT_MINT,
IOT_MINT,
- MOBILE_MINT,
bufferToTransaction,
getAsset,
sendAndConfirmWithRetry,
@@ -25,10 +19,9 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useImplicitBurn } from '@hooks/useImplicitBurn'
import { useKeyToAsset } from '@hooks/useKeyToAsset'
import { useOnboardingBalnces } from '@hooks/useOnboardingBalances'
-import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { LAMPORTS_PER_SOL, Transaction } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { IOT_CONFIG_KEY, MOBILE_CONFIG_KEY } from '@utils/constants'
+import { LAMPORTS_PER_SOL, PublicKey, Transaction } from '@solana/web3.js'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { IOT_CONFIG_KEY, DAO_KEY } from '@utils/constants'
import sleep from '@utils/sleep'
import { getHotspotWithRewards, isInsufficientBal } from '@utils/solanaUtils'
import BN from 'bn.js'
@@ -36,23 +29,91 @@ import { Buffer } from 'buffer'
import React, { useMemo, useState } from 'react'
import { useAsync, useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
-import { Alert, Linking, ScrollView } from 'react-native'
-import { useSolana } from '../../../solana/SolanaProvider'
-import { CollectableNavigationProp } from '../../collectables/collectablesTypes'
-import { HotspotBLEStackParamList } from './navTypes'
-
-type Route = RouteProp
+import { Alert, Linking } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import Map from '@components/Map'
+import { Camera } from '@rnmapbox/maps'
+import ImageBox from '@components/ImageBox'
+import { getAddressFromLatLng } from '@utils/location'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import TouchableContainer from '@components/TouchableContainer'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import AccountIcon from '@components/AccountIcon'
+import { useBottomSheet } from '@gorhom/bottom-sheet'
+import { useNavigation } from '@react-navigation/native'
+import { HotspotServiceNavigationProp } from 'src/app/services/HotspotService'
+import { useSolana } from '@features/solana/SolanaProvider'
+import Loading from '../../components/Loading'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
const REQUIRED_SOL = new BN((0.00089088 + 0.00001) * LAMPORTS_PER_SOL)
-const AddGatewayBle = () => {
- const route = useRoute()
- const { createGatewayTx, onboardingAddress, network } = route.params
+const AddToWalletScreen = () => {
const { onboardingClient, getOnboardTransactions } = useOnboarding()
const { currentAccount } = useAccountStorage()
const { anchorProvider } = useSolana()
const { t } = useTranslation()
- const collectNav = useNavigation()
const wallet = useCurrentWallet()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const { close } = useBottomSheet()
+ const navigation = useNavigation()
+
+ const {
+ onboardDetails: {
+ iotDetails: { animalName },
+ latitude,
+ longitude,
+ height,
+ },
+ } = useHotspotOnboarding()
+
+ const {
+ isConnected,
+ getOnboardingAddress,
+ createGatewayTxn: getCreateGatewayTxn,
+ } = useHotspotBle()
+
+ const { result: connected } = useAsync(isConnected, [])
+
+ const {
+ result: {
+ address: onboardingAddress,
+ keyToAssetK,
+ createGatewayTx,
+ } = {} as {
+ address?: string
+ keyToAssetK?: PublicKey
+ createGatewayTx?: string
+ },
+ } = useAsync(
+ async (
+ c: boolean | undefined,
+ accountAddress?: string,
+ ): Promise<{
+ address?: string
+ keyToAssetK?: PublicKey
+ createGatewayTx?: string
+ }> => {
+ if (c && accountAddress) {
+ const addr = await getOnboardingAddress()
+ const tx = await getCreateGatewayTxn({
+ ownerAddress: accountAddress,
+ payerAddress: accountAddress,
+ })
+ // For testing
+ // const addr = TEST_HOTSPOT.address.b58
+ return {
+ address: addr,
+ keyToAssetK: keyToAssetKey(DAO_KEY, addr, 'b58')[0],
+ createGatewayTx: tx,
+ }
+ }
+ return {}
+ },
+ [connected, currentAccount?.address],
+ )
const {
error: onboardBalError,
@@ -70,10 +131,8 @@ const AddGatewayBle = () => {
locationAssertDcRequirements,
loadingOnboardingDcRequirements,
} = useOnboardingBalnces(onboardingAddress)
- const keyToAssetK = useMemo(() => {
- return keyToAssetKey(daoKey(HNT_MINT)[0], onboardingAddress)[0].toBase58()
- }, [onboardingAddress])
- const { info: keyToAsset } = useKeyToAsset(keyToAssetK)
+
+ const { info: keyToAsset } = useKeyToAsset(keyToAssetK?.toBase58())
const { result: asset } = useAsync(async () => {
if (anchorProvider && keyToAsset) {
return getAsset(anchorProvider.connection.rpcEndpoint, keyToAsset.asset)
@@ -81,7 +140,7 @@ const AddGatewayBle = () => {
return undefined
}, [anchorProvider, keyToAsset])
const wrongOwner = asset && wallet && !asset.ownership.owner.equals(wallet)
- const mint = network === 'IOT' ? IOT_MINT : MOBILE_MINT
+ const mint = IOT_MINT
const requiredDc = onboardingDcRequirements[mint.toBase58()] || new BN(0)
const assertRequiredDc =
locationAssertDcRequirements[mint.toBase58()] || new BN(0)
@@ -203,15 +262,10 @@ const AddGatewayBle = () => {
wrapProgramError(e)
}
- const configKey = network === 'IOT' ? IOT_CONFIG_KEY : MOBILE_CONFIG_KEY
- const fetcher =
- network === 'IOT'
- ? hemProgram.account.iotHotspotInfoV0
- : hemProgram.account.mobileHotspotInfoV0
- const networkInfoK =
- network === 'IOT'
- ? iotInfoKey(configKey, onboardingAddress)[0]
- : mobileInfoKey(configKey, onboardingAddress)[0]
+ const configKey = IOT_CONFIG_KEY
+ const fetcher = hemProgram.account.iotHotspotInfoV0
+ const networkInfoK = iotInfoKey(configKey, onboardingAddress || '')[0]
+
const networkInfo = await fetcher.fetchNullable(networkInfoK)
if (!networkInfo && onboardingAddress) {
// Implicit burn to DC if needed
@@ -223,7 +277,14 @@ const AddGatewayBle = () => {
const { solanaTransactions } = await getOnboardTransactions({
hotspotAddress: onboardingAddress,
payer,
- networkDetails: [{ hotspotType: network }],
+ networkDetails: [
+ {
+ hotspotType: 'IOT',
+ lat: latitude,
+ lng: longitude,
+ elevation: height,
+ },
+ ],
})
let solanaSignedTransactions: Transaction[] | undefined
@@ -267,7 +328,9 @@ const AddGatewayBle = () => {
totalTime += 2000
// eslint-disable-next-line no-await-in-loop
keyToAssetPostOnboard =
- await hemProgram.account.keyToAssetV0.fetchNullable(keyToAssetK)
+ await hemProgram.account.keyToAssetV0.fetchNullable(
+ keyToAssetK?.toBase58() || '',
+ )
}
if (!keyToAssetPostOnboard) {
throw new Error(t('hotspotOnboarding.onboarding.failedToFind'))
@@ -278,11 +341,10 @@ const AddGatewayBle = () => {
anchorProvider,
)
- if (networkInfo) {
- collectNav.navigate('HotspotMapScreen', { hotspot: collectable, network })
- } else {
- collectNav.navigate('AssertLocationScreen', { collectable })
- }
+ close()
+ navigation.navigate('Hotspot', {
+ newHotspot: collectable,
+ })
})
const error =
onboardBalError ||
@@ -310,32 +372,117 @@ const AddGatewayBle = () => {
const usd = requiredDc.toNumber() / 100000
const assertUsd = assertRequiredDc.toNumber() / 100000
+ const { result: location } = useAsync(async () => {
+ const address = await getAddressFromLatLng(latitude, longitude)
+
+ return `~${address?.street ? `${address?.street}, ` : ''}${address.city}, ${
+ address.state
+ }`
+ }, [latitude, longitude])
+
+ const floor = useMemo(() => height / 5, [height])
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ flexGrow: 1,
+ padding: spacing['2xl'],
+ paddingBottom: spacing['10xl'],
+ }),
+ [spacing],
+ )
+
return (
-
-
+ <>
+
+
+
+
+
+
+
+
+
+
+ {t('AddToWalletScreen.title')}
+
- {t('hotspotOnboarding.onboarding.subtitle', {
- network,
- })}
+ {animalName}
+
+
+ {location}
+
+
+ {t('AddToWalletScreen.addressDetailsIndoor', {
+ floor,
+ })}
+
+
{error && (
-
+
{error.message ? error.message.toString() : error.toString()}
)}
{!wrongOwner && balError && (
<>
-
+
{t('hotspotOnboarding.onboarding.responsible')}
-
+
{t('hotspotOnboarding.onboarding.manufacturerMissing', {
name: maker?.name,
tokens: `${[
@@ -346,7 +493,12 @@ const AddGatewayBle = () => {
.join(' and ')}`,
})}
-
+
{t('hotspotOnboarding.onboarding.twoSolutions')}
{
{
const url = `https://docs.helium.com/hotspot-makers/#${maker?.name.toLowerCase()}`
@@ -393,12 +545,24 @@ const AddGatewayBle = () => {
{selectedOption === 'pay' && (
<>
{!callbackLoading && insufficientMySolBal && (
-
+
{t('hotspotOnboarding.onboarding.notEnoughSol')}
)}
{!callbackLoading && insufficientMyDcBal && (
-
+
{t('hotspotOnboarding.onboarding.notEnoughDc')}
)}
@@ -410,51 +574,65 @@ const AddGatewayBle = () => {
mt="2"
variant="textMdMedium"
color="error.500"
+ marginHorizontal="2xl"
+ textAlign="center"
>
{t('hotspotOnboarding.onboarding.pay', {
usd,
assertUsd,
})}
- : undefined}
- />
>
)}
>
)}
>
)}
- {!wrongOwner && !balError ? (
-
+
+ {loading ? (
+
+ ) : (
+ : undefined}
- />
- ) : null}
-
-
+ pressableStyles={{ flex: undefined }}
+ >
+
+ {t('OnboardingSheet.addToWallet')}
+
+
+
+
+
+
+ )}
+
+ >
)
}
-export default AddGatewayBle
+export default AddToWalletScreen
diff --git a/src/features/hotspot-onboarding/screens/iot/ConnectViaBluetoothScreen.tsx b/src/features/hotspot-onboarding/screens/iot/ConnectViaBluetoothScreen.tsx
new file mode 100644
index 000000000..93d57a848
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/iot/ConnectViaBluetoothScreen.tsx
@@ -0,0 +1,105 @@
+import Box from '@components/Box'
+import ScrollBox from '@components/ScrollBox'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import { useHotspotOnboarding } from '@features/hotspot-onboarding/OnboardingSheet'
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import BluetoothIcon from '@assets/svgs/bluetooth.svg'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { ViewStyle, StyleProp } from 'react-native'
+
+const ConnectViaBluetoothScreen = () => {
+ const { t } = useTranslation()
+ const colors = useColors()
+ const spacing = useSpacing()
+ const { carouselRef } = useHotspotOnboarding()
+
+ const onScanForHotspots = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ padding: spacing['2xl'],
+ paddingBottom: spacing['4xl'],
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ gap: spacing['2.5'],
+ }
+ }, [spacing])
+
+ return (
+ <>
+ }
+ >
+
+
+ {t('ConnectViaBluetoothScreen.title')}
+
+
+ {t('ConnectViaBluetoothScreen.subtitle')}
+
+
+ {t('ConnectViaBluetoothScreen.body')}
+
+
+
+
+
+ {t('ConnectViaBluetoothScreen.scanForHotspots')}
+
+
+
+
+
+
+ >
+ )
+}
+
+export default ConnectViaBluetoothScreen
diff --git a/src/features/hotspot-onboarding/screens/iot/HotspotConnected.tsx b/src/features/hotspot-onboarding/screens/iot/HotspotConnected.tsx
new file mode 100644
index 000000000..6afb0851c
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/iot/HotspotConnected.tsx
@@ -0,0 +1,86 @@
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import ScrollBox from '@components/ScrollBox'
+import CheckmarkCircle from '@assets/svgs/checkmarkCircle.svg'
+import Text from '@components/Text'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn, FadeOut } from 'react-native-reanimated'
+import TouchableContainer from '@components/TouchableContainer'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import Box from '@components/Box'
+import { useSpacing } from '@config/theme/themeHooks'
+import { StyleProp, ViewStyle } from 'react-native'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+export default function HotspotConnected() {
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const { carouselRef } = useHotspotOnboarding()
+
+ const onConfirmLocation = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }
+ }, [spacing])
+
+ return (
+ }
+ >
+
+
+
+ {t('hotspotOnboarding.onboarding.hotspotConnected')}
+
+
+ {t('hotspotOnboarding.onboarding.hotspotConnectedBody')}
+
+
+
+
+
+ {t('hotspotOnboarding.onboarding.confirmLocation')}
+
+
+
+
+
+ )
+}
diff --git a/src/features/hotspot-onboarding/screens/iot/ScanHotspots.tsx b/src/features/hotspot-onboarding/screens/iot/ScanHotspots.tsx
new file mode 100644
index 000000000..ab862e7a7
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/iot/ScanHotspots.tsx
@@ -0,0 +1,336 @@
+import Text from '@components/Text'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { Device, useHotspotBle } from '@helium/react-native-sdk'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import {
+ FlatList,
+ Platform,
+ PermissionsAndroid,
+ RefreshControl,
+ StyleProp,
+ ViewStyle,
+} from 'react-native'
+import {
+ PERMISSIONS,
+ PermissionStatus,
+ RESULTS,
+ check,
+ request,
+} from 'react-native-permissions'
+import ScrollBox from '@components/ScrollBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import Box from '@components/Box'
+import TouchableContainer from '@components/TouchableContainer'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import Config from 'react-native-config'
+import * as Logger from '@utils/logger'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+const MOCK = Config.MOCK_IOT === 'true'
+const MOCK_DEVICES = [
+ { id: '1', name: 'RAK-78908' },
+ { id: '2', name: 'Helium-Hotspot-775' },
+] as Device[]
+
+const ScanHotspots = () => {
+ const { startScan, stopScan, connect, scannedDevices } = useHotspotBle()
+ const [scanning, setScanning] = useState(false)
+ const colors = useColors()
+ const { carouselRef } = useHotspotOnboarding()
+ const [canScan, setCanScan] = useState(undefined)
+ const spacing = useSpacing()
+ const { t } = useTranslation()
+ const [error, setError] = useState(undefined)
+
+ const bluetoothDevices = useMemo(() => {
+ if (MOCK) {
+ return MOCK_DEVICES
+ }
+ return scannedDevices
+ }, [scannedDevices])
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const showError = (e: any) => {
+ Logger.error(e)
+ setError(e.toString())
+ }
+
+ const updateCanScan = useCallback((result: PermissionStatus) => {
+ switch (result) {
+ case RESULTS.UNAVAILABLE:
+ case RESULTS.BLOCKED:
+ case RESULTS.DENIED:
+ case RESULTS.LIMITED:
+ setCanScan(false)
+ break
+ case RESULTS.GRANTED:
+ setCanScan(true)
+ break
+ }
+ }, [])
+
+ useEffect(() => {
+ if (Platform.OS === 'ios') {
+ setCanScan(true)
+ return
+ }
+
+ check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
+ .then(updateCanScan)
+ .catch(showError)
+ }, [updateCanScan])
+
+ useEffect(() => {
+ if (canScan !== false) return
+
+ request(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
+ .then(updateCanScan)
+ .catch(showError)
+ }, [canScan, updateCanScan])
+
+ const checkPermission = async () => {
+ if (Platform.OS === 'ios') {
+ return true
+ }
+
+ const perms = [
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
+ ]
+
+ const results = await Promise.all(
+ perms.map((p) => PermissionsAndroid.check(p)),
+ )
+
+ if (results.findIndex((r) => r === false) === -1) {
+ return true
+ }
+
+ const granted = await PermissionsAndroid.requestMultiple([
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
+ ])
+
+ perms.forEach((p) => {
+ if (!granted[p]) {
+ return false
+ }
+ })
+
+ return true
+ }
+
+ const handleScanPress = useCallback(async () => {
+ setError(undefined)
+ const shouldScan = !scanning
+ setScanning(shouldScan)
+ await checkPermission()
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ let timeout: any | undefined
+ if (shouldScan) {
+ setError(undefined)
+ timeout = setTimeout(() => {
+ stopScan()
+ setScanning(false)
+ if (scannedDevices.length === 0) {
+ setError(
+ 'No hotspots found. Please ensure bluetooth pairing is enabled',
+ )
+ }
+ }, 30 * 1000)
+ }
+
+ if (shouldScan) {
+ startScan((e) => {
+ if (e) {
+ showError(e)
+ }
+ })
+ } else {
+ stopScan()
+ }
+ return () => {
+ if (timeout) {
+ clearTimeout(timeout)
+ stopScan()
+ }
+ }
+ }, [scannedDevices.length, scanning, startScan, stopScan])
+
+ useEffect(() => {
+ // eslint-disable-next-line no-underscore-dangle
+ if (carouselRef?.current?._activeItem === 1) {
+ handleScanPress()
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps, no-underscore-dangle
+ }, [carouselRef?.current?._activeItem])
+
+ const navNext = useCallback(
+ () => carouselRef?.current?.snapToNext(),
+ [carouselRef],
+ )
+
+ const [connecting, setConnecting] = useState(false)
+ const connectDevice = useCallback(
+ (d: Device) => async () => {
+ if (MOCK) {
+ navNext()
+ return
+ }
+
+ try {
+ setConnecting(true)
+ await connect(d)
+ if (scanning) {
+ stopScan()
+ setScanning(false)
+ }
+ setConnecting(false)
+ navNext()
+ } catch (e) {
+ showError(e)
+ } finally {
+ setConnecting(false)
+ }
+ },
+ [connect, navNext, scanning, stopScan],
+ )
+
+ const renderItem = React.useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item }: { item: Device }) => {
+ const first = item.id === bluetoothDevices[0].id
+ const last = item.id === bluetoothDevices[bluetoothDevices.length - 1].id
+ const borderTopStartRadius = first ? '2xl' : 'none'
+ const borderTopEndRadius = first ? '2xl' : 'none'
+ const borderBottomStartRadius = last ? '2xl' : 'none'
+ const borderBottomEndRadius = last ? '2xl' : 'none'
+ return (
+
+
+ {item.name}
+
+
+
+ )
+ },
+ [connectDevice, connecting, bluetoothDevices, colors],
+ )
+
+ const renderHeader = useCallback(() => {
+ return (
+
+
+ {t('hotspotOnboarding.scan.title')}
+
+ {bluetoothDevices.length > 0 && (
+
+ {t('hotspotOnboarding.scan.hotspotsFound', {
+ count: bluetoothDevices.length,
+ })}
+
+ )}
+ {error && (
+
+ {error}
+
+ )}
+
+ )
+ }, [t, bluetoothDevices, error])
+
+ const renderFooter = useCallback(() => {
+ return (
+
+
+ {canScan
+ ? scanning
+ ? t('hotspotOnboarding.scan.stop')
+ : t('hotspotOnboarding.scan.start')
+ : t('hotspotOnboarding.scan.notEnabled')}
+
+
+
+ )
+ }, [canScan, handleScanPress, scanning, t, colors])
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ const keyExtractor = React.useCallback(({ id }: Device) => id, [])
+
+ return (
+
+ }
+ contentContainerStyle={{
+ flex: 1,
+ }}
+ >
+ }
+ ListHeaderComponent={renderHeader}
+ data={bluetoothDevices}
+ renderItem={renderItem}
+ keyExtractor={keyExtractor}
+ ListFooterComponent={renderFooter}
+ />
+
+ )
+}
+
+export default ScanHotspots
diff --git a/src/features/hotspot-onboarding/screens/iot/WifiSettings.tsx b/src/features/hotspot-onboarding/screens/iot/WifiSettings.tsx
new file mode 100644
index 000000000..fb2fb0e08
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/iot/WifiSettings.tsx
@@ -0,0 +1,253 @@
+import Text from '@components/Text'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { useHotspotBle } from '@helium/react-native-sdk'
+import { Keypair } from '@solana/web3.js'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useAsyncCallback } from 'react-async-hook'
+import { useTranslation } from 'react-i18next'
+import { FlatList, RefreshControl, StyleProp, ViewStyle } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import Box from '@components/Box'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import Checkmark from '@assets/svgs/checkmark.svg'
+import TouchableContainer from '@components/TouchableContainer'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import Config from 'react-native-config'
+import animalName from 'angry-purple-tiger'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+const MOCK = Config.MOCK_IOT === 'true'
+
+const WifiSettings = () => {
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const [networks, setNetworks] = useState()
+ const [configuredNetworks, setConfiguredNetworks] = useState()
+ const [connected, setConnected] = useState(false)
+
+ const { isConnected, readWifiNetworks, getOnboardingAddress } =
+ useHotspotBle()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+
+ useEffect(() => {
+ isConnected().then(setConnected)
+ }, [isConnected])
+
+ const {
+ execute: handleRefresh,
+ loading: refreshing,
+ error,
+ } = useAsyncCallback(async () => {
+ if (MOCK) {
+ setConfiguredNetworks(['Solana-House-5678'])
+ setNetworks(['Helium-House-1234'])
+ return
+ }
+
+ if (!connected) return
+
+ const configured = await readWifiNetworks(true)
+ setConfiguredNetworks(configured)
+ const available = await readWifiNetworks(false)
+ setNetworks(available)
+ })
+
+ // Refresh on network change or on load
+ useEffect(() => {
+ handleRefresh()
+ }, [handleRefresh, connected])
+
+ const handleNetworkSelected = useCallback(
+ ({
+ network,
+ type,
+ }: {
+ network: string
+ type: 'configured' | 'available'
+ }) =>
+ async () => {
+ if (type === 'available') {
+ setOnboardDetails((o) => ({
+ ...o,
+ iotDetails: {
+ ...o.iotDetails,
+ network,
+ },
+ }))
+ carouselRef?.current?.snapToNext()
+ } else {
+ // DO something
+ const onboardingAddress = MOCK
+ ? Keypair.generate().publicKey.toBase58()
+ : await getOnboardingAddress()
+ setOnboardDetails((o) => ({
+ ...o,
+ iotDetails: {
+ ...o.iotDetails,
+ onboardingAddress,
+ network,
+ animalName: animalName(onboardingAddress),
+ },
+ }))
+ carouselRef?.current?.snapToItem(5)
+ }
+ },
+ [carouselRef, setOnboardDetails, getOnboardingAddress],
+ )
+
+ const data = useMemo(
+ () => [...(configuredNetworks || []), ...(networks || [])],
+ [configuredNetworks, networks],
+ )
+
+ const renderItem = useCallback(
+ ({
+ item: network,
+ }: {
+ // eslint-disable-next-line react/no-unused-prop-types
+ item: string
+ // eslint-disable-next-line react/no-unused-prop-types
+ }) => {
+ const first = data[0] === network
+ const last = data[data.length - 1] === network
+ const borderTopStartRadius = first ? '2xl' : 'none'
+ const borderBottomStartRadius = last ? '2xl' : 'none'
+ const borderBottomEndRadius = last ? '2xl' : 'none'
+ const borderTopEndRadius = first ? '2xl' : 'none'
+
+ const isConfigured = configuredNetworks?.includes(network)
+
+ return (
+
+
+ {network}
+
+ {!isConfigured && (
+
+ )}
+ {isConfigured && }
+
+ )
+ },
+ [handleNetworkSelected, data, colors, configuredNetworks],
+ )
+
+ const keyExtractor = useCallback((name: string) => name, [])
+
+ const renderHeader = useCallback(
+ () => (
+
+
+ {t('hotspotOnboarding.wifiSettings.title')}
+
+
+ {t('hotspotOnboarding.wifiSettings.subtitle')}
+
+ {error && (
+
+ {error.message ? error.message.toString() : error.toString()}
+
+ )}
+
+ ),
+ [error, t],
+ )
+
+ const renderFooter = useCallback(
+ () => (
+
+
+ {refreshing
+ ? t('hotspotOnboarding.scan.stop')
+ : t('hotspotOnboarding.scan.start')}
+
+
+
+ ),
+ [colors, handleRefresh, refreshing, t],
+ )
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ }),
+ [spacing],
+ )
+
+ const flatListContentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ return (
+
+ }
+ >
+
+ }
+ />
+
+ )
+}
+
+export default WifiSettings
diff --git a/src/features/hotspot-onboarding/screens/iot/WifiSetup.tsx b/src/features/hotspot-onboarding/screens/iot/WifiSetup.tsx
new file mode 100644
index 000000000..a67a1e7a5
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/iot/WifiSetup.tsx
@@ -0,0 +1,168 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import TextInput from '@components/TextInput'
+import { BleError, useHotspotBle } from '@helium/react-native-sdk'
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import ScrollBox from '@components/ScrollBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import { ViewStyle, StyleProp, KeyboardAvoidingView } from 'react-native'
+import Visibility from '@assets/svgs/visibility.svg'
+import VisibilityOff from '@assets/svgs/visibilityOff.svg'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import ImageBox from '@components/ImageBox'
+import { Keypair } from '@solana/web3.js'
+import animalName from 'angry-purple-tiger'
+import Config from 'react-native-config'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import CheckButton from '../../components/CheckButton'
+import Loading from '../../components/Loading'
+
+const MOCK = Config.MOCK_IOT === 'true'
+
+const WifiSetup = () => {
+ const [secureTextEntry, setSecureTextEntry] = useState(true)
+ const [error, setError] = useState('')
+ const [loading, setLoading] = useState(false)
+ const [password, setPassword] = useState('')
+ const { setWifi, getOnboardingAddress } = useHotspotBle()
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+
+ const {
+ onboardDetails: {
+ iotDetails: { network },
+ },
+ } = useHotspotOnboarding()
+
+ const toggleSecureEntry = useCallback(() => {
+ setSecureTextEntry(!secureTextEntry)
+ }, [secureTextEntry])
+
+ const handleSetWifi = useCallback(async () => {
+ if (MOCK) {
+ setLoading(true)
+
+ // wait 2 seconds
+ setTimeout(() => {
+ setLoading(false)
+ }, 2000)
+
+ const onboardingAddress = Keypair.generate().publicKey.toBase58()
+ setOnboardDetails((o) => ({
+ ...o,
+ iotDetails: { ...o.iotDetails, onboardingAddress },
+ }))
+ carouselRef?.current?.snapToNext()
+ return
+ }
+
+ setLoading(true)
+ try {
+ await setWifi(network, password)
+ const onboardingAddress = await getOnboardingAddress()
+ setOnboardDetails((o) => ({
+ ...o,
+ iotDetails: {
+ ...o.iotDetails,
+ onboardingAddress,
+ animalName: animalName(onboardingAddress),
+ },
+ }))
+ carouselRef?.current?.snapToNext()
+ } catch (e) {
+ if (typeof e === 'string') {
+ setError(e)
+ } else {
+ setError((e as BleError).toString())
+ }
+ }
+ setLoading(false)
+ }, [
+ password,
+ setWifi,
+ network,
+ carouselRef,
+ getOnboardingAddress,
+ setOnboardDetails,
+ ])
+
+ const contentContainer = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ return (
+ }>
+
+
+
+
+ {t('hotspotOnboarding.wifiSetup.title')}
+
+
+ {t('hotspotOnboarding.wifiSetup.subtitle', { network })}
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+ {secureTextEntry ? (
+
+ ) : (
+
+ )}
+
+
+
+ {!loading && }
+ {loading && }
+
+ )
+}
+
+export default WifiSetup
diff --git a/src/features/hotspot-onboarding/iot-ble/navTypes.tsx b/src/features/hotspot-onboarding/screens/iot/navTypes.tsx
similarity index 88%
rename from src/features/hotspot-onboarding/iot-ble/navTypes.tsx
rename to src/features/hotspot-onboarding/screens/iot/navTypes.tsx
index d702ccf8b..c8eaf1354 100644
--- a/src/features/hotspot-onboarding/iot-ble/navTypes.tsx
+++ b/src/features/hotspot-onboarding/screens/iot/navTypes.tsx
@@ -1,5 +1,8 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
-import { IotBleOptions } from '../navTypes'
+
+export type IotBleOptions = {
+ bleInstructions?: string
+}
export type HotspotBLEStackParamList = {
ScanHotspots: IotBleOptions
diff --git a/src/features/hotspot-onboarding/iot-ble/optionsContext.tsx b/src/features/hotspot-onboarding/screens/iot/optionsContext.tsx
similarity index 90%
rename from src/features/hotspot-onboarding/iot-ble/optionsContext.tsx
rename to src/features/hotspot-onboarding/screens/iot/optionsContext.tsx
index 8f56b8832..7b7f88944 100644
--- a/src/features/hotspot-onboarding/iot-ble/optionsContext.tsx
+++ b/src/features/hotspot-onboarding/screens/iot/optionsContext.tsx
@@ -1,5 +1,5 @@
import React, { useContext } from 'react'
-import { IotBleOptions } from '../navTypes'
+import { IotBleOptions } from './navTypes'
const IotBleOptionsContext = React.createContext({})
diff --git a/src/features/hotspot-onboarding/screens/mobile/AcquireLocationScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/AcquireLocationScreen.tsx
new file mode 100644
index 000000000..77127a03c
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/AcquireLocationScreen.tsx
@@ -0,0 +1,149 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import InfoIcon from '@assets/svgs/infoIcon.svg'
+import ImageBox from '@components/ImageBox'
+import MiniMap from '@components/MiniMap'
+import { getAddressFromLatLng } from '@utils/location'
+import { useAsync } from 'react-async-hook'
+import * as Location from 'expo-location'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import CheckButton from '../../components/CheckButton'
+
+export const AcquireLocationScreen = () => {
+ const [lat, setLat] = useState(null)
+ const [lng, setLng] = useState(null)
+ const { t } = useTranslation()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+
+ const onNext = useCallback(() => {
+ if (!lat || !lng) {
+ // TODO: show error. Show retry button
+ return
+ }
+
+ carouselRef?.current?.snapToNext()
+ setOnboardDetails((o) => ({
+ ...o,
+ latitude: lat,
+ longitude: lng,
+ }))
+ }, [carouselRef, setOnboardDetails, lat, lng])
+
+ const DeterminingLocation = useCallback(() => {
+ return (
+ <>
+
+
+ {t('AcquireLocationScreen.title')}
+
+
+ {t('AcquireLocationScreen.subtitle')}
+
+
+
+
+ {t('AcquireLocationScreen.gpsHelp')}
+
+
+ >
+ )
+ }, [t])
+
+ const { result: location, loading: loadingLocation } = useAsync(async () => {
+ const loc = await Location.getCurrentPositionAsync({
+ accuracy: Location.LocationAccuracy.Highest,
+ })
+
+ const newLat = loc?.coords.latitude
+ const newLng = loc?.coords.longitude
+ setLat(newLat)
+ setLng(newLng)
+
+ if (!newLat || !newLng) {
+ return null
+ }
+
+ const address = await getAddressFromLatLng(newLat, newLng)
+
+ return `~${address.street}, ${address.city}, ${address.state}`
+ }, [])
+
+ const DeterminedLocation = useCallback(() => {
+ return (
+
+
+
+
+
+ {location}
+
+
+
+
+ {t('AcquireLocationScreen.isThisCorrect')}
+
+
+ {t('AcquireLocationScreen.locationDetermined')}
+
+
+ )
+ }, [t, location])
+
+ return (
+
+ {!loadingLocation && location ? (
+
+ ) : (
+
+ )}
+ {location && }
+
+ )
+}
+
+export default AcquireLocationScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/AddToWalletScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/AddToWalletScreen.tsx
new file mode 100644
index 000000000..11536fe8c
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/AddToWalletScreen.tsx
@@ -0,0 +1,132 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import React, { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import ImageBox from '@components/ImageBox'
+import Map from '@components/Map'
+import { Camera } from '@rnmapbox/maps'
+import { getAddressFromLatLng } from '@utils/location'
+import { useAsync } from 'react-async-hook'
+import AddToWalletButton from '../../components/WalletButton'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+export const AddToWalletScreen = () => {
+ const { t } = useTranslation()
+
+ const {
+ onboardDetails: {
+ deviceInfo: { deviceType, animalName },
+ latitude,
+ longitude,
+ height,
+ azimuth,
+ },
+ onboardDeviceError,
+ } = useHotspotOnboarding()
+
+ const { result: location } = useAsync(async () => {
+ const address = await getAddressFromLatLng(latitude, longitude)
+
+ return `~${address?.street ? `${address?.street}, ` : ''}${address.city}, ${
+ address.state
+ }`
+ }, [latitude, longitude])
+
+ const floor = useMemo(() => height / 5, [height])
+
+ return (
+
+
+
+
+
+
+ {deviceType === 'WifiOutdoor' && (
+
+
+
+ )}
+
+ {deviceType === 'WifiIndoor' && (
+
+
+
+ )}
+
+
+ {t('AddToWalletScreen.title')}
+
+
+ {animalName}
+
+
+
+ {location}
+
+
+ {deviceType === 'WifiIndoor'
+ ? t('AddToWalletScreen.addressDetailsIndoor', {
+ floor,
+ })
+ : t('AddToWalletScreen.addressDetails', {
+ floor,
+ direction: `${azimuth}°`,
+ })}
+
+
+ {onboardDeviceError && (
+
+ {t('AddToWalletScreen.errorOnboarding')}
+
+ )}
+
+
+ )
+}
+
+export default AddToWalletScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/ConnectEthernetScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/ConnectEthernetScreen.tsx
new file mode 100644
index 000000000..f4ed05a41
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/ConnectEthernetScreen.tsx
@@ -0,0 +1,94 @@
+import Box from '@components/Box'
+import React, { useCallback } from 'react'
+import Text from '@components/Text'
+import { useTranslation } from 'react-i18next'
+import ImageBox from '@components/ImageBox'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import InfoIcon from '@assets/svgs/infoIcon.svg'
+import { Linking } from 'react-native'
+import { HOTSPOT_HELP } from '@utils/constants/urls'
+import CheckButton from '../../components/CheckButton'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+export const ConnectEthernetScreen = () => {
+ const { t } = useTranslation()
+
+ const {
+ carouselRef,
+ onboardDetails: {
+ deviceInfo: { deviceType },
+ },
+ } = useHotspotOnboarding()
+
+ const onNext = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ const onOpenHelp = useCallback(() => {
+ Linking.openURL(HOTSPOT_HELP)
+ }, [])
+
+ return (
+
+ {deviceType === 'WifiOutdoor' && (
+
+ )}
+ {deviceType === 'WifiIndoor' && (
+
+ )}
+
+ {t(
+ deviceType === 'WifiOutdoor'
+ ? 'ConnectEthernetScreen.title'
+ : 'ConnectEthernetScreen.titleIndoor',
+ )}
+
+
+ {deviceType === 'WifiOutdoor'
+ ? t('ConnectEthernetScreen.subtitle')
+ : t('ConnectEthernetScreen.subtitleIndoor')}
+
+
+ {t('ConnectEthernetScreen.helpText')}
+
+
+
+
+ {t('ConnectEthernetScreen.help')}
+
+
+
+
+ )
+}
+
+export default ConnectEthernetScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/ConnectToHotspotScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/ConnectToHotspotScreen.tsx
new file mode 100644
index 000000000..560e03049
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/ConnectToHotspotScreen.tsx
@@ -0,0 +1,140 @@
+import Box from '@components/Box'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import ImageBox from '@components/ImageBox'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import CameraCheck from '@assets/svgs/cameraCheck.svg'
+import NoCamera from '@assets/svgs/noCamera.svg'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import { useColors } from '@config/theme/themeHooks'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { requestCameraPermission } from '@utils/camera'
+import { PermissionStatus } from 'react-native-permissions'
+import { Color } from '@config/theme/theme'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import CheckButton from '../../components/CheckButton'
+
+export const ConnectToHotspotScreen = () => {
+ const {
+ manualEntry,
+ setManualEntry,
+ carouselRef,
+ onboardDetails: {
+ deviceInfo: { deviceType },
+ },
+ } = useHotspotOnboarding()
+ const { t } = useTranslation()
+ const colors = useColors()
+ const [cameraPermission, setCameraPermission] = useState()
+
+ const onRequest = useCallback(async () => {
+ const status = __DEV__ ? 'granted' : await requestCameraPermission()
+
+ setCameraPermission(status)
+
+ if (status === 'granted') {
+ setManualEntry(false)
+ }
+ }, [setManualEntry])
+
+ useEffect(() => {
+ if (manualEntry) {
+ setCameraPermission(undefined)
+ }
+ }, [cameraPermission, manualEntry])
+
+ const onNext = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ const onManualEntry = useCallback(() => {
+ setManualEntry(true)
+ setCameraPermission(undefined)
+ carouselRef?.current?.snapToNext()
+ }, [setManualEntry, carouselRef])
+
+ const CameraCheckButton = useCallback(() => {
+ let backgroundColor: Color = 'primaryText'
+ let backgroundColorPressed: Color = 'base.black'
+
+ if (cameraPermission === 'granted') {
+ backgroundColor = 'success.500'
+ backgroundColorPressed = 'success.600'
+ }
+
+ if (cameraPermission === 'denied') {
+ backgroundColor = 'error.500'
+ backgroundColorPressed = 'error.600'
+ }
+
+ return (
+
+ {cameraPermission === 'denied' && }
+ {cameraPermission === 'granted' && }
+
+ {t('ConnectToHotspotScreen.requestCameraPermissions')}
+
+
+ )
+ }, [t, onRequest, cameraPermission])
+
+ return (
+
+ {deviceType === 'WifiOutdoor' && (
+
+ )}
+ {deviceType === 'WifiIndoor' && (
+
+ )}
+
+ {t('ConnectToHotspotScreen.title')}
+
+
+ {t('ConnectToHotspotScreen.subtitle')}
+
+
+
+
+ {t('ConnectToHotspotScreen.manualEntry')}
+
+
+
+ {cameraPermission === 'granted' && }
+
+ )
+}
+
+export default ConnectToHotspotScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/KeepYourBoxScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/KeepYourBoxScreen.tsx
new file mode 100644
index 000000000..2b1cd6874
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/KeepYourBoxScreen.tsx
@@ -0,0 +1,46 @@
+import Box from '@components/Box'
+import React, { useCallback } from 'react'
+import Text from '@components/Text'
+import { useTranslation } from 'react-i18next'
+import ImageBox from '@components/ImageBox'
+
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import ForwardButton from '../../components/ForwardButton'
+
+export const KeepYourBoxScreen = () => {
+ const { t } = useTranslation()
+ const {
+ onboardDetails: {
+ deviceInfo: { deviceType },
+ },
+ carouselRef,
+ } = useHotspotOnboarding()
+
+ const onNext = useCallback(() => {
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef])
+
+ return (
+
+ {deviceType === 'WifiOutdoor' && (
+
+ )}
+ {deviceType === 'WifiIndoor' && (
+
+ )}
+
+ {t('KeepYourBoxScreen.title')}
+
+
+ {t('KeepYourBoxScreen.subtitle')}
+
+
+
+ )
+}
+
+export default KeepYourBoxScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/ManualEntryScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/ManualEntryScreen.tsx
new file mode 100644
index 000000000..fffd305f6
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/ManualEntryScreen.tsx
@@ -0,0 +1,107 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import Text from '@components/Text'
+import Box from '@components/Box'
+import { useTranslation } from 'react-i18next'
+import TextInputNew from '@components/TextInputNew'
+import CheckButton from '../../components/CheckButton'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import Loading from '../../components/Loading'
+
+const ManualEntryScreen = () => {
+ const { t } = useTranslation()
+ const [validNetworkName, setValidNetworkName] = useState(false)
+ const [validNetworkPassword, setValidNetworkPassword] = useState(false)
+ const [ssid, setSsid] = useState('')
+ const [password, setPassword] = useState('')
+
+ const {
+ carouselRef,
+ getDeviceInfo,
+ getDeviceInfoError,
+ getDeviceInfoLoading,
+ } = useHotspotOnboarding()
+
+ const onChangeNetworkName = useCallback((text: string) => {
+ // Regex to validate network name looks like Helium-XXXX
+ setValidNetworkName(text.length > 8 && text.includes('Helium-'))
+ setSsid(text)
+ }, [])
+
+ const onChangeNetworkPassword = useCallback((text: string) => {
+ setValidNetworkPassword(text.length > 7)
+ setPassword(text)
+ }, [])
+
+ const wifiDataB64 = useMemo(() => {
+ if (!validNetworkName || !validNetworkPassword) return
+
+ const wifiData = `WIFI:S:${ssid};T:WPA;P:${password};H:false;`
+ return Buffer.from(wifiData).toString('base64')
+ }, [password, ssid, validNetworkName, validNetworkPassword])
+
+ const onNext = useCallback(async () => {
+ if (!wifiDataB64) {
+ // TODO: Show generic error
+ return
+ }
+ const deviceInfo = await getDeviceInfo(wifiDataB64)
+
+ if (deviceInfo) {
+ carouselRef?.current?.snapToNext()
+ }
+ }, [carouselRef, getDeviceInfo, wifiDataB64])
+
+ return (
+
+
+ {t('ManualEntryScreen.title')}
+
+
+ {t('ManualEntryScreen.subtitle')}
+
+
+
+
+
+
+
+ {getDeviceInfoError && (
+
+ {t('ManualEntryScreen.tryAgain')}
+
+ )}
+ {validNetworkName && validNetworkPassword && !getDeviceInfoLoading && (
+
+ )}
+ {getDeviceInfoLoading && }
+
+ )
+}
+
+export default ManualEntryScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/ScanQRCodeScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/ScanQRCodeScreen.tsx
new file mode 100644
index 000000000..8c5885664
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/ScanQRCodeScreen.tsx
@@ -0,0 +1,157 @@
+import Box from '@components/Box'
+import React, { useCallback, useState } from 'react'
+import { StyleSheet } from 'react-native'
+import Text from '@components/Text'
+import { useTranslation } from 'react-i18next'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { useColors } from '@config/theme/themeHooks'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import {
+ Camera,
+ useCameraDevice,
+ useCodeScanner,
+} from 'react-native-vision-camera'
+import useAppear from '@hooks/useAppear'
+import useDisappear from '@hooks/useDisappear'
+import useHaptic from '@hooks/useHaptic'
+import { useAsync } from 'react-async-hook'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+import CheckButton from '../../components/CheckButton'
+import Loading from '../../components/Loading'
+
+const ScanQRCodeScreen = () => {
+ const { t } = useTranslation()
+ const colors = useColors()
+ const [isActive, setIsActive] = useState(false)
+ const { triggerImpact } = useHaptic()
+ const [qrCode, setQrCode] = useState(null)
+
+ const {
+ carouselRef,
+ setManualEntry,
+ getDeviceInfo,
+ getDeviceInfoLoading,
+ getDeviceInfoError,
+ onboardDetails,
+ } = useHotspotOnboarding()
+
+ const onManualEntry = useCallback(() => {
+ setManualEntry(true)
+ }, [setManualEntry])
+
+ const device = useCameraDevice('back', {
+ physicalDevices: ['ultra-wide-angle-camera'],
+ })
+
+ useAppear(() => {
+ setIsActive(true)
+ })
+
+ useDisappear(() => {
+ setIsActive(false)
+ })
+ const onNext = useCallback(async () => {
+ if (__DEV__) {
+ // Make sure MOCK_HMH is set to true in .env
+ await getDeviceInfo('MOCK_QR')
+ carouselRef?.current?.snapToNext()
+ return
+ }
+
+ if (!qrCode) return
+
+ const deviceInfo = await getDeviceInfo(qrCode)
+
+ if (deviceInfo) {
+ carouselRef?.current?.snapToNext()
+ }
+ }, [carouselRef, getDeviceInfo, qrCode])
+
+ const codeScanner = useCodeScanner({
+ codeTypes: ['qr'],
+ onCodeScanned: (codes) => {
+ if (!codes.length || !codes[0].value || onboardDetails.qrCode) return
+
+ setQrCode(codes[0].value)
+ },
+ })
+
+ useAsync(async () => {
+ if (!qrCode) return
+ triggerImpact('heavy')
+ onNext()
+ }, [qrCode, getDeviceInfo, onNext])
+
+ return (
+
+
+
+ {device ? (
+
+ ) : (
+
+ )}
+
+
+
+ {t('ScanQRCodeScreen.title')}
+
+
+ {t('ScanQRCodeScreen.subtitle')}
+
+
+
+ {t('ScanQRCodeScreen.manualEntry')}
+
+
+
+ {getDeviceInfoError && (
+
+ {t('ScanQRCodeScreen.tryAgain')}
+
+ )}
+ {__DEV__ && !getDeviceInfoLoading && }
+ {getDeviceInfoLoading && }
+
+ )
+}
+
+export default ScanQRCodeScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/SelectDeviceScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/SelectDeviceScreen.tsx
new file mode 100644
index 000000000..2d669e7bc
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/SelectDeviceScreen.tsx
@@ -0,0 +1,102 @@
+import Box from '@components/Box'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import MobileTextLogo from '@assets/svgs/mobileTextLogo.svg'
+import ImageBox from '@components/ImageBox'
+import TextTransform from '@components/TextTransform'
+import { DeviceType, useHotspotOnboarding } from '../../OnboardingSheet'
+
+const SelectDeviceScreen = () => {
+ const { t } = useTranslation()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+
+ const onSelectHotspot = useCallback(
+ (deviceType: DeviceType) => () => {
+ setOnboardDetails((o) => ({
+ ...o,
+ deviceInfo: {
+ ...o.deviceInfo,
+ deviceType,
+ },
+ }))
+ carouselRef?.current?.snapToNext()
+ },
+ [carouselRef, setOnboardDetails],
+ )
+
+ return (
+
+
+ {t('SelectDeviceScreen.title')}
+
+
+ {t('SelectDeviceScreen.subtitle')}
+
+
+
+
+
+
+
+
+ {t('SelectDeviceScreen.indoor')}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default SelectDeviceScreen
diff --git a/src/features/hotspot-onboarding/screens/mobile/SetDirectionScreen.tsx b/src/features/hotspot-onboarding/screens/mobile/SetDirectionScreen.tsx
new file mode 100644
index 000000000..efbb7f484
--- /dev/null
+++ b/src/features/hotspot-onboarding/screens/mobile/SetDirectionScreen.tsx
@@ -0,0 +1,96 @@
+import Box from '@components/Box'
+import React, { useCallback } from 'react'
+import Text from '@components/Text'
+import { useTranslation } from 'react-i18next'
+import RotateIcon from '@assets/svgs/rotateIcon.svg'
+import Map from '@components/Map'
+import { Camera } from '@rnmapbox/maps'
+import ImageBox from '@components/ImageBox'
+import useHeading from '@hooks/useHeading'
+import { degToCompass } from '@utils/degree'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { useAnimatedStyle, withSpring } from 'react-native-reanimated'
+import { HELIUM_WORLD_POI } from '@utils/constants'
+import CheckButton from '../../components/CheckButton'
+import { useHotspotOnboarding } from '../../OnboardingSheet'
+
+const SetDirectionScreen = () => {
+ const { t } = useTranslation()
+ const { heading } = useHeading()
+ const { carouselRef, setOnboardDetails } = useHotspotOnboarding()
+
+ const onNext = useCallback(() => {
+ setOnboardDetails((o) => ({
+ ...o,
+ azimuth: heading,
+ }))
+ carouselRef?.current?.snapToNext()
+ }, [carouselRef, setOnboardDetails, heading])
+
+ const rotationStyle = useAnimatedStyle(() => {
+ return {
+ transform: [{ rotate: withSpring(`-${heading}deg`) }],
+ }
+ })
+
+ return (
+
+
+
+
+ {t('SetDirectionScreen.title')}
+
+
+ {t('SetDirectionScreen.subtitle')}
+
+
+ {`${heading}° | ${degToCompass(heading)}`}
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default SetDirectionScreen
diff --git a/src/features/collectables/AntennaSetupScreen.tsx b/src/features/hotspots/AntennaSetupScreen.tsx
similarity index 99%
rename from src/features/collectables/AntennaSetupScreen.tsx
rename to src/features/hotspots/AntennaSetupScreen.tsx
index 24d33278f..9a65758f0 100644
--- a/src/features/collectables/AntennaSetupScreen.tsx
+++ b/src/features/hotspots/AntennaSetupScreen.tsx
@@ -22,7 +22,7 @@ import { DelayedFadeIn } from '@components/FadeInOut'
import {
CollectableNavigationProp,
CollectableStackParamList,
-} from './collectablesTypes'
+} from './hotspotTypes'
import { parseH3BNLocation } from '../../utils/h3'
import * as Logger from '../../utils/logger'
diff --git a/src/features/collectables/AssertLocationScreen.tsx b/src/features/hotspots/AssertLocationScreen.tsx
similarity index 80%
rename from src/features/collectables/AssertLocationScreen.tsx
rename to src/features/hotspots/AssertLocationScreen.tsx
index 3970d37dd..9097c8082 100644
--- a/src/features/collectables/AssertLocationScreen.tsx
+++ b/src/features/hotspots/AssertLocationScreen.tsx
@@ -1,6 +1,5 @@
-import BackArrow from '@assets/images/backArrow.svg'
-import Hex from '@assets/images/hex.svg'
-import MapPin from '@assets/images/mapPin.svg'
+import Hex from '@assets/svgs/hex.svg'
+import MapPin from '@assets/svgs/mapPin.svg'
import {
Box,
ButtonPressable,
@@ -12,12 +11,9 @@ import {
ImageBox,
ReAnimatedBlurBox,
ReAnimatedBox,
- SearchInput,
Text,
TextInput,
} from '@components'
-import Map from '@components/map/Map'
-import { INITIAL_MAP_VIEW_STATE, MAX_MAP_ZOOM } from '@components/map/utils'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { NetworkType } from '@helium/onboarding'
import { IOT_MINT, MOBILE_MINT } from '@helium/spl-utils'
@@ -31,7 +27,6 @@ import { useMobileInfo } from '@hooks/useMobileInfo'
import { useOnboardingBalnces } from '@hooks/useOnboardingBalances'
import { useReverseGeo } from '@hooks/useReverseGeo'
import useSubmitTxn from '@hooks/useSubmitTxn'
-import MapLibreGL from '@maplibre/maplibre-react-native'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { parseH3BNLocation } from '@utils/h3'
import { removeDashAndCapitalize } from '@utils/hotspotNftsUtils'
@@ -54,28 +49,41 @@ import {
} from 'react-native'
import 'text-encoding-polyfill'
import { useDebounce } from 'use-debounce'
-import { useColors, useCreateOpacity, useSpacing } from '@theme/themeHooks'
+import { useColors, useCreateOpacity } from '@config/theme/themeHooks'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import CloseButton from '@components/CloseButton'
+import Map from '@components/Map'
+import {
+ Camera,
+ Location,
+ MapView,
+ MarkerView,
+ UserLocation,
+} from '@rnmapbox/maps'
+import {
+ MIN_MAP_ZOOM,
+ INITIAL_MAP_VIEW_STATE,
+ MAX_MAP_ZOOM,
+} from '@utils/mapUtils'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { Search } from '@components/Search'
import {
CollectableNavigationProp,
CollectableStackParamList,
-} from './collectablesTypes'
+} from './hotspotTypes'
type Route = RouteProp
const AssertLocationScreen = () => {
const { t } = useTranslation()
const { bottom } = useSafeAreaInsets()
- const spacing = useSpacing()
const route = useRoute()
const { backgroundStyle } = useCreateOpacity()
const { collectable } = route.params
const entityKey = useEntityKey(collectable)
const { info: iotInfoAcc } = useIotInfo(entityKey)
const { info: mobileInfoAcc } = useMobileInfo(entityKey)
- const mapRef = useRef(null)
- const cameraRef = useRef(null)
+ const mapRef = useRef(null)
+ const cameraRef = useRef(null)
const { showOKAlert } = useAlert()
const colors = useColors()
const [mapCenter, setMapCenter] = useState()
@@ -90,6 +98,7 @@ const AssertLocationScreen = () => {
const forwardGeo = useForwardGeo()
const { submitUpdateEntityInfo } = useSubmitTxn()
const navigation = useNavigation()
+
const {
maker,
makerDc,
@@ -131,9 +140,9 @@ const AssertLocationScreen = () => {
const [initialUserLocation, setInitialUserLocation] = useState()
const [initialCenterSet, setInitalCenter] = useState(false)
- const [userLocation, setUserLocation] = useState()
+ const [userLocation, setUserLocation] = useState()
const onUserLocationUpdate = useCallback(
- (loc: MapLibreGL.Location) => {
+ (loc: Location) => {
setUserLocation(loc)
},
[setUserLocation],
@@ -252,7 +261,10 @@ const AssertLocationScreen = () => {
cameraRef.current.setCamera({
animationDuration: 500,
zoomLevel: MAX_MAP_ZOOM,
- centerCoordinate: userLocation?.coords,
+ centerCoordinate: [
+ userLocation?.coords.longitude,
+ userLocation?.coords.latitude,
+ ],
})
}
}, [cameraRef, userLocation?.coords])
@@ -407,6 +419,10 @@ const AssertLocationScreen = () => {
[loadingMyDc, loadingMakerDc, loadingLocationAssertDcRequirements],
)
+ const onBack = useCallback(() => {
+ navigation.goBack()
+ }, [navigation])
+
const [debouncedDisabled] = useDebounce(disabled, 300)
const [reverseGeoLoading] = useDebounce(reverseGeo.loading, 300)
@@ -417,7 +433,7 @@ const AssertLocationScreen = () => {
flexGrow={1}
justifyContent="center"
alignItems="center"
- backgroundColor="bg.tertiary"
+ backgroundColor="primaryBackground"
overflow="hidden"
position="relative"
>
@@ -435,73 +451,86 @@ const AssertLocationScreen = () => {
{
paddingLeft="5"
top={0}
>
- navigation.goBack()}
- >
-
-
- Back
-
-
+
{
{
{
{
) : (
-
+
+
+
)}
{!searchVisible && (
-
+
{
justifyContent="center"
onPress={handleAssertLocationPress}
style={{
- marginBottom: bottom + spacing['0.5'],
+ marginBottom: bottom + NavBarHeight,
}}
>
{debouncedDisabled || asserting ? (
@@ -742,17 +764,19 @@ const AssertLocationScreen = () => {
bottom={0}
height="100%"
width="100%"
+ paddingHorizontal="xl"
>
Keyboard.dismiss()}>
-
-
-
+ setElevGainVisible(false)}
/>
+
{
@@ -798,9 +822,9 @@ const AssertLocationScreen = () => {
}}
/>
{
-
+
{
const { t } = useTranslation()
diff --git a/src/features/collectables/ClaimRewardsScreen.tsx b/src/features/hotspots/ClaimRewardsScreen.tsx
similarity index 99%
rename from src/features/collectables/ClaimRewardsScreen.tsx
rename to src/features/hotspots/ClaimRewardsScreen.tsx
index 5b9e729f5..046ac8403 100644
--- a/src/features/collectables/ClaimRewardsScreen.tsx
+++ b/src/features/hotspots/ClaimRewardsScreen.tsx
@@ -19,7 +19,7 @@ import { Mints } from '../../utils/constants'
import {
CollectableNavigationProp,
CollectableStackParamList,
-} from './collectablesTypes'
+} from './hotspotTypes'
type Route = RouteProp
diff --git a/src/features/collectables/ClaimingRewardsScreen.tsx b/src/features/hotspots/ClaimingRewardsScreen.tsx
similarity index 96%
rename from src/features/collectables/ClaimingRewardsScreen.tsx
rename to src/features/hotspots/ClaimingRewardsScreen.tsx
index 94f7759d5..5bbaae094 100644
--- a/src/features/collectables/ClaimingRewardsScreen.tsx
+++ b/src/features/hotspots/ClaimingRewardsScreen.tsx
@@ -1,4 +1,4 @@
-import BackArrow from '@assets/images/backArrow.svg'
+import BackArrow from '@assets/svgs/backArrow.svg'
import AccountIcon from '@components/AccountIcon'
import { ReAnimatedBox } from '@components/AnimatedBox'
import Box from '@components/Box'
@@ -13,7 +13,7 @@ import { useBN } from '@hooks/useBN'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
import useHotspots from '@hooks/useHotspots'
import { useNavigation } from '@react-navigation/native'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
import { parseTransactionError } from '@utils/solanaUtils'
import LottieView from 'lottie-react-native'
import React, { memo, useCallback, useEffect, useRef, useState } from 'react'
@@ -22,9 +22,9 @@ import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import 'text-encoding-polyfill'
-import { useColors } from '@theme/themeHooks'
-import { HotspotServiceNavigationProp } from '@services/HotspotService'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useColors } from '@config/theme/themeHooks'
+import { HotspotServiceNavigationProp } from 'src/app/services/HotspotService'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { RootState } from '../../store/rootReducer'
import iotMobileTokens from './animations/iot-mobile-tokens.json'
import iotTokens from './animations/iot-tokens.json'
diff --git a/src/features/hotspot-onboarding/iot-ble/Diagnostics.tsx b/src/features/hotspots/Diagnostics.tsx
similarity index 96%
rename from src/features/hotspot-onboarding/iot-ble/Diagnostics.tsx
rename to src/features/hotspots/Diagnostics.tsx
index a4b50c5a5..1a7ebacac 100644
--- a/src/features/hotspot-onboarding/iot-ble/Diagnostics.tsx
+++ b/src/features/hotspots/Diagnostics.tsx
@@ -9,10 +9,9 @@ import React, { useCallback, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native'
-import type { HotspotBleNavProp } from './navTypes'
const Diagnostics = () => {
- const navigation = useNavigation()
+ const navigation = useNavigation()
const navNext = useCallback(() => navigation.goBack(), [navigation])
const { getDiagnosticInfo } = useHotspotBle()
diff --git a/src/features/hotspots/EmptyState.tsx b/src/features/hotspots/EmptyState.tsx
new file mode 100644
index 000000000..9544f3ceb
--- /dev/null
+++ b/src/features/hotspots/EmptyState.tsx
@@ -0,0 +1,92 @@
+import Box from '@components/Box'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import Text from '@components/Text'
+import ButtonPressable from '@components/ButtonPressable'
+import AddIcon from '@assets/svgs/add.svg'
+import { Image, Linking } from 'react-native'
+import { useNavigation } from '@react-navigation/native'
+import { HotspotServiceNavigationProp } from 'src/app/services/HotspotService'
+
+const EmptyState = () => {
+ const spacing = useSpacing()
+ const colors = useColors()
+ const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+ const navigation = useNavigation()
+
+ const onLearnMore = useCallback(() => {
+ Linking.openURL('https://hellohelium.com/hotspot')
+ }, [])
+
+ const onAddHotspot = useCallback(() => {
+ navigation.navigate('AddHotspot')
+ }, [navigation])
+
+ return (
+
+
+
+
+ {t('HotspotPage.noHotspotsTitle')}
+
+
+ {t('HotspotPage.noHotspotsSubtitle')}
+
+
+
+
+ }
+ />
+
+
+
+ )
+}
+
+export default EmptyState
diff --git a/src/features/hotspots/HotspotConfig.tsx b/src/features/hotspots/HotspotConfig.tsx
new file mode 100644
index 000000000..7aa75e43d
--- /dev/null
+++ b/src/features/hotspots/HotspotConfig.tsx
@@ -0,0 +1,206 @@
+import Box from '@components/Box'
+import FabButton from '@components/FabButton'
+import Text from '@components/Text'
+import { useNavigation, useRoute } from '@react-navigation/native'
+import React, { useCallback, useMemo } from 'react'
+import ScrollBox from '@components/ScrollBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import { FlatList } from 'react-native'
+import TouchableContainer from '@components/TouchableContainer'
+import useCopyText from '@hooks/useCopyText'
+import useHaptic from '@hooks/useHaptic'
+import { ellipsizeAddress } from '@utils/accountUtils'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import { HotspotNavigationProp } from '@services/HotspotService/pages/HotspotPage'
+import { HotspotWithPendingRewards } from '../../types/solana'
+
+type HotspotConfigItem = {
+ title: string
+ subtitle?: string
+ onPress: () => void
+}
+
+export const HotspotConfig = () => {
+ const { hotspot, hotspotAddress } = useRoute().params as {
+ hotspot: HotspotWithPendingRewards
+ hotspotAddress: string
+ }
+
+ const isIotHotspot = useMemo(() => {
+ return (
+ hotspot?.content?.metadata?.hotspot_infos?.iot?.device_type ||
+ !hotspot?.content?.metadata?.hotspot_infos?.mobile?.device_type
+ )
+ }, [hotspot])
+
+ const spacing = useSpacing()
+ const colors = useColors()
+ const navigation = useNavigation()
+ const copyText = useCopyText()
+ const { triggerImpact } = useHaptic()
+
+ const data = useMemo(() => {
+ return [
+ {
+ title: 'Update Location',
+ subtitle: hotspotAddress,
+ Icon: undefined,
+ onPress: () => {
+ navigation.navigate('AssertLocationScreen', {
+ collectable: hotspot,
+ })
+ },
+ },
+ {
+ title: 'Update Rewards Recipient',
+ subtitle: undefined,
+ Icon: undefined,
+ onPress: () => {
+ navigation.navigate('ChangeRewardsRecipientScreen', {
+ hotspot,
+ })
+ },
+ },
+ {
+ title: 'Antenna Setup',
+ subtitle: undefined,
+ Icon: undefined,
+ onPress: () => {
+ navigation.navigate('AntennaSetupScreen', {
+ collectable: hotspot,
+ })
+ },
+ },
+ {
+ title: 'Transfer ownership',
+ subtitle: undefined,
+ onPress: () => {
+ navigation.navigate('TransferCollectableScreen', {
+ collectable: hotspot,
+ })
+ },
+ },
+ {
+ title: 'Copy address',
+ subtitle: undefined,
+ onPress: () => {
+ triggerImpact('light')
+ copyText({
+ message: ellipsizeAddress(hotspot?.id),
+ copyText: hotspot?.id,
+ })
+ },
+ },
+ !isIotHotspot && {
+ title: 'Reboot',
+ subtitle: undefined,
+ Icon: undefined,
+ onPress: () => {},
+ },
+ isIotHotspot && {
+ title: 'Diagnostics',
+ subtitle: undefined,
+ onPress: () => {
+ navigation.navigate('DiagnosticsScreen', {
+ collectable: hotspot,
+ })
+ },
+ },
+ isIotHotspot && {
+ title: 'Setup Wifi',
+ subtitle: undefined,
+ onPress: () => {
+ navigation.navigate('ModifyWifiScreen', {
+ collectable: hotspot,
+ })
+ },
+ },
+ ].filter(Boolean) as HotspotConfigItem[]
+ }, [
+ copyText,
+ hotspot,
+ triggerImpact,
+ navigation,
+ hotspotAddress,
+ isIotHotspot,
+ ])
+
+ const onBack = useCallback(() => {
+ navigation.goBack()
+ }, [navigation])
+
+ const keyExtractor = useCallback((item: HotspotConfigItem) => item.title, [])
+
+ const renderItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item }: { item: HotspotConfigItem }) => {
+ const isFirst = item.title === data[0].title
+ const isLast = item.title === data[data.length - 1].title
+ const borderTopStartRadius = isFirst ? '3xl' : undefined
+ const borderTopEndRadius = isFirst ? '3xl' : undefined
+ const borderBottomStartRadius = isLast ? '3xl' : undefined
+ const borderBottomEndRadius = isLast ? '3xl' : undefined
+
+ return (
+
+
+
+ {item.title}
+ {item.subtitle && (
+
+ {item.subtitle}
+
+ )}
+
+
+
+
+
+
+
+ )
+ },
+ [data, colors],
+ )
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ // paddingBottom: spacing['2xl'],
+ }
+ }, [])
+
+ const renderHeader = useCallback(() => {
+ return (
+
+
+
+ )
+ }, [onBack])
+
+ return (
+
+
+
+ )
+}
+
+export default HotspotConfig
diff --git a/src/features/hotspots/HotspotDetails.tsx b/src/features/hotspots/HotspotDetails.tsx
new file mode 100644
index 000000000..a5413519f
--- /dev/null
+++ b/src/features/hotspots/HotspotDetails.tsx
@@ -0,0 +1,258 @@
+import Box from '@components/Box'
+import ScrollBox from '@components/ScrollBox'
+import React, { useCallback, useMemo } from 'react'
+import { useBorderRadii, useColors, useSpacing } from '@config/theme/themeHooks'
+import Crown from '@assets/svgs/crown.svg'
+import Text from '@components/Text'
+import MapPin from '@assets/svgs/mapPin.svg'
+import Hex from '@assets/svgs/hex.svg'
+import Clock from '@assets/svgs/clock.svg'
+import Person from '@assets/svgs/person.svg'
+import Electricity from '@assets/svgs/electricity.svg'
+import FabButton from '@components/FabButton'
+import { useNavigation, useRoute } from '@react-navigation/native'
+import { PublicKey } from '@solana/web3.js'
+import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
+import { useMaker } from '@hooks/useMaker'
+import MakerHotspotImage from '@components/MakerHotspotImage'
+import { getAddressFromLatLng } from '@utils/location'
+import { useAsync } from 'react-async-hook'
+import SkeletonPlaceholder from 'react-native-skeleton-placeholder'
+import { useTranslation } from 'react-i18next'
+import { formatDistanceToNow } from 'date-fns'
+import MiniMap from '@components/MiniMap'
+import { HotspotNavigationProp } from '@services/HotspotService/pages/HotspotPage'
+import { HotspotWithPendingRewards } from '../../types/solana'
+
+const MINI_MAP_HEIGHT = 310
+
+const HotspotDetails = () => {
+ const { t } = useTranslation()
+ const { hotspot } = useRoute().params as {
+ hotspot: HotspotWithPendingRewards
+ }
+ const spacing = useSpacing()
+ const navigation = useNavigation()
+
+ const colors = useColors()
+ const borderRadii = useBorderRadii()
+
+ const onBack = useCallback(() => {
+ navigation.goBack()
+ }, [navigation])
+
+ const collectionKey = useMemo(() => {
+ return new PublicKey(
+ hotspot.grouping.find((g) => g.group_key === 'collection')?.group_value,
+ )
+ }, [hotspot])
+
+ const subDao = useMemo(() => {
+ if (hotspot?.content?.metadata?.hotspot_infos?.iot?.device_type) {
+ return 'iot'
+ }
+
+ if (hotspot?.content?.metadata?.hotspot_infos?.mobile?.device_type) {
+ return 'mobile'
+ }
+
+ return 'iot'
+ }, [hotspot])
+
+ const { result: hotspotAddress } = useAsync(async () => {
+ const subDaoInfo = hotspot?.content?.metadata?.hotspot_infos[subDao]
+
+ const lat = subDaoInfo?.lat
+ const long = subDaoInfo?.long
+
+ const address = await getAddressFromLatLng(lat, long)
+
+ return `${address.street}, ${address.city}, ${address.state}`
+ }, [hotspot, subDao])
+
+ const onConfig = useCallback(() => {
+ if (!hotspotAddress) return
+ navigation.push('HotspotConfig', { hotspot, hotspotAddress })
+ }, [navigation, hotspot, hotspotAddress])
+
+ const deviceType = useMemo(() => {
+ return hotspot?.content?.metadata?.hotspot_infos?.iot?.device_type
+ }, [hotspot])
+
+ const { metadata: mplxMetadata } = useMetaplexMetadata(collectionKey)
+
+ const { info: makerAcc } = useMaker(mplxMetadata?.updateAuthority.toBase58())
+
+ const HeaderButtons = useCallback(() => {
+ return (
+
+
+
+
+ )
+ }, [onBack, spacing, onConfig])
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const LevelBadge = useCallback(() => {
+ return (
+
+
+
+ Level 15
+
+
+ )
+ }, [])
+
+ const deployedDate = useMemo(() => {
+ const subDaoInfo = hotspot?.content?.metadata?.hotspot_infos[subDao]
+
+ const date = new Date(subDaoInfo?.created_at)
+
+ return t('HotspotDetails.deployed', {
+ date: formatDistanceToNow(date, { addSuffix: true }),
+ })
+ }, [hotspot, subDao, t])
+
+ const coordinates = useMemo(() => {
+ const subDaoInfo = hotspot?.content?.metadata?.hotspot_infos[subDao]
+
+ return [subDaoInfo?.lat, subDaoInfo?.long]
+ }, [hotspot, subDao])
+
+ const HotspotMetaLineItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ type, label }: { type: string; label: string | undefined }) => {
+ let Icon = MapPin
+ switch (type) {
+ default:
+ case 'mapPin':
+ Icon = MapPin
+ break
+ case 'hex':
+ Icon = Hex
+ break
+ case 'clock':
+ Icon = Clock
+ break
+ case 'person':
+ Icon = Person
+ break
+ case 'electricity':
+ Icon = Electricity
+ break
+ }
+
+ const iconColor = colors['blue.dark-500']
+
+ return (
+
+
+ {label ? (
+
+ {label}
+
+ ) : (
+
+
+
+ )}
+
+ )
+ },
+ [colors, borderRadii],
+ )
+
+ return (
+
+
+
+
+
+
+
+ {/*
+ TODO: Add level badge
+ */}
+
+
+ {hotspot?.content?.metadata?.name}
+
+
+
+
+
+
+ {/*
+ */}
+
+
+ )
+}
+
+export default HotspotDetails
diff --git a/src/features/collectables/HotspotMapHotspotDetails.tsx b/src/features/hotspots/HotspotMapHotspotDetails.tsx
similarity index 98%
rename from src/features/collectables/HotspotMapHotspotDetails.tsx
rename to src/features/hotspots/HotspotMapHotspotDetails.tsx
index e3521c8f2..a72270599 100644
--- a/src/features/collectables/HotspotMapHotspotDetails.tsx
+++ b/src/features/hotspots/HotspotMapHotspotDetails.tsx
@@ -1,7 +1,7 @@
-import CopyAddress from '@assets/images/copyAddress.svg'
-import Hex from '@assets/images/hex.svg'
-import IotSymbol from '@assets/images/iotSymbol.svg'
-import MobileSymbol from '@assets/images/mobileSymbol.svg'
+import CopyAddress from '@assets/svgs/copyAddress.svg'
+import Hex from '@assets/svgs/hex.svg'
+import IotSymbol from '@assets/svgs/iotSymbol.svg'
+import MobileSymbol from '@assets/svgs/mobileSymbol.svg'
import { ReAnimatedBlurBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import CircleLoader from '@components/CircleLoader'
@@ -29,7 +29,7 @@ import { MobileHotspotInfoV0, useMobileInfo } from '@hooks/useMobileInfo'
import { usePublicKey } from '@hooks/usePublicKey'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useColors, useOpacity } from '@theme/themeHooks'
+import { useColors, useOpacity } from '@config/theme/themeHooks'
import { ellipsizeAddress, formatLargeNumber } from '@utils/accountUtils'
import { removeDashAndCapitalize } from '@utils/hotspotNftsUtils'
import { Explorer } from '@utils/walletApiV2'
@@ -41,10 +41,10 @@ import { useTranslation } from 'react-i18next'
import { Alert, AlertButton, Linking } from 'react-native'
import { SvgUri } from 'react-native-svg'
import SafeAreaBox from '@components/SafeAreaBox'
-import { useSolana } from '../../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { CompressedNFT } from '../../types/solana'
import { IOT_CONFIG_KEY, MOBILE_CONFIG_KEY, Mints } from '../../utils/constants'
-import { CollectableNavigationProp } from './collectablesTypes'
+import { CollectableNavigationProp } from '../collectables/collectablesTypes'
const IotMapDetails = ({
maker,
diff --git a/src/features/collectables/HotspotMapLegend.tsx b/src/features/hotspots/HotspotMapLegend.tsx
similarity index 97%
rename from src/features/collectables/HotspotMapLegend.tsx
rename to src/features/hotspots/HotspotMapLegend.tsx
index ca5153009..70a4a2440 100644
--- a/src/features/collectables/HotspotMapLegend.tsx
+++ b/src/features/hotspots/HotspotMapLegend.tsx
@@ -1,7 +1,7 @@
-import Hex from '@assets/images/hex.svg'
+import Hex from '@assets/svgs/hex.svg'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import React from 'react'
export const HotspotMapLegend = ({
diff --git a/src/features/collectables/HotspotMapScreen.tsx b/src/features/hotspots/HotspotMapScreen.tsx
similarity index 65%
rename from src/features/collectables/HotspotMapScreen.tsx
rename to src/features/hotspots/HotspotMapScreen.tsx
index c8033b0b5..4200b77c2 100644
--- a/src/features/collectables/HotspotMapScreen.tsx
+++ b/src/features/hotspots/HotspotMapScreen.tsx
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable no-restricted-properties */
-import BackArrow from '@assets/images/backArrow.svg'
-import Hex from '@assets/images/hex.svg'
+import BackArrow from '@assets/svgs/backArrow.svg'
+import Hex from '@assets/svgs/hex.svg'
import { ReAnimatedBlurBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import CircleLoader from '@components/CircleLoader'
@@ -9,8 +9,6 @@ import FabButton from '@components/FabButton'
import { DelayedFadeIn } from '@components/FadeInOut'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import Map from '@components/map/Map'
-import { INITIAL_MAP_VIEW_STATE, MAX_MAP_ZOOM } from '@components/map/utils'
import {
BottomSheetModal,
BottomSheetModalProvider,
@@ -27,36 +25,31 @@ import { chunks, truthy } from '@helium/spl-utils'
import useHotspots from '@hooks/useHotspots'
import { IotHotspotInfoV0 } from '@hooks/useIotInfo'
import { MobileHotspotInfoV0 } from '@hooks/useMobileInfo'
-import MapLibreGL, { OnPressEvent } from '@maplibre/maplibre-react-native'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useBackgroundStyle, useColors } from '@theme/themeHooks'
-import { Polygon, feature, featureCollection } from '@turf/helpers'
+import { useBackgroundStyle, useColors } from '@config/theme/themeHooks'
import { IOT_CONFIG_KEY, MOBILE_CONFIG_KEY } from '@utils/constants'
-import { parseH3BNLocation } from '@utils/h3'
import {
getCachedIotInfos,
getCachedKeyToAssets,
getCachedMobileInfos,
toAsset,
} from '@utils/solanaUtils'
-import { BN } from 'bn.js'
-import { cellToBoundary, latLngToCell } from 'h3-js'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
-import { Alert } from 'react-native'
-import { useSolana } from '../../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { HotspotWithPendingRewards } from '../../types/solana'
import { HotspotMapHotspotDetails } from './HotspotMapHotspotDetails'
import { HotspotMapLegend } from './HotspotMapLegend'
import {
CollectableNavigationProp,
CollectableStackParamList,
-} from './collectablesTypes'
+} from '../collectables/collectablesTypes'
type Route = RouteProp
const DEFAULT_HEX = '631210968843200500' // used for when a hotspot has no iotInfo or mobileInfo
+
const HotspotMapScreen = () => {
const { t } = useTranslation()
const { anchorProvider } = useSolana()
@@ -64,12 +57,11 @@ const HotspotMapScreen = () => {
const bottomSheetStyle = useBackgroundStyle('bg.tertiary')
const navigation = useNavigation()
const colors = useColors()
- const mapRef = useRef(null)
- const cameraRef = useRef(null)
+ // const mapRef = useRef(null)
+ // const cameraRef = useRef(null)
const bottomSheetRef = useRef(null)
- const [bottomSheetHeight, setBottomSheetHeight] = useState(0)
const [bottomSheetSnapIndex, setBottomSheetSnapIndex] = useState(-1)
- const [zoomLevel, setZoomLevel] = useState(INITIAL_MAP_VIEW_STATE.zoomLevel)
+ // const [zoomLevel, setZoomLevel] = useState(INITIAL_MAP_VIEW_STATE.zoomLevel)
const [hotspot, setHotspot] = useState(route.params?.hotspot)
const [networkType, setNetworkType] = useState<'IOT' | 'MOBILE'>(
route.params?.network || 'IOT',
@@ -82,41 +74,41 @@ const HotspotMapScreen = () => {
const [activeHotspotIndex, setActiveHotspotIndex] = useState(0)
const [legendVisible, setLegendVisible] = useState(false)
const { hotspots, fetchAll, loading, onEndReached } = useHotspots()
- const [initialUserLocation, setInitialUserLocation] = useState()
- const [initialCenterSet, setInitalCenter] = useState(false)
- const [userLocation, setUserLocation] = useState()
- const onUserLocationUpdate = useCallback(
- (loc: MapLibreGL.Location) => {
- setUserLocation(loc)
- },
- [setUserLocation],
- )
-
- useEffect(() => {
- const coords = userLocation?.coords
- if (!initialUserLocation && coords) {
- setInitialUserLocation([coords.longitude, coords.latitude])
- }
- }, [initialUserLocation, setInitialUserLocation, userLocation?.coords])
-
- const initialCenter = useMemo(() => {
- return initialUserLocation || INITIAL_MAP_VIEW_STATE.centerCoordinate
- }, [initialUserLocation])
-
- useEffect(() => {
- if (
- initialCenter &&
- JSON.stringify(initialCenter) !==
- JSON.stringify(INITIAL_MAP_VIEW_STATE.centerCoordinate) &&
- !initialCenterSet
- ) {
- setInitalCenter(true)
- cameraRef.current?.setCamera({
- centerCoordinate: initialCenter,
- animationDuration: 0,
- })
- }
- }, [initialCenter, cameraRef, initialCenterSet, setInitalCenter])
+ // const [initialUserLocation, setInitialUserLocation] = useState()
+ // const [initialCenterSet, setInitalCenter] = useState(false)
+ // const [userLocation, setUserLocation] = useState()
+ // const onUserLocationUpdate = useCallback(
+ // (loc: MapLibreGL.Location) => {
+ // setUserLocation(loc)
+ // },
+ // [setUserLocation],
+ // )
+
+ // useEffect(() => {
+ // const coords = userLocation?.coords
+ // if (!initialUserLocation && coords) {
+ // setInitialUserLocation([coords.longitude, coords.latitude])
+ // }
+ // }, [initialUserLocation, setInitialUserLocation, userLocation?.coords])
+
+ // const initialCenter = useMemo(() => {
+ // return initialUserLocation || INITIAL_MAP_VIEW_STATE.centerCoordinate
+ // }, [initialUserLocation])
+
+ // useEffect(() => {
+ // if (
+ // initialCenter &&
+ // JSON.stringify(initialCenter) !==
+ // JSON.stringify(INITIAL_MAP_VIEW_STATE.centerCoordinate) &&
+ // !initialCenterSet
+ // ) {
+ // setInitalCenter(true)
+ // cameraRef.current?.setCamera({
+ // centerCoordinate: initialCenter,
+ // animationDuration: 0,
+ // })
+ // }
+ // }, [initialCenter, cameraRef, initialCenterSet, setInitalCenter])
// - fetch all hotspots
useEffect(() => {
@@ -233,82 +225,82 @@ const HotspotMapScreen = () => {
}, [loadingInfos, activeHex, hotspot, legendVisible, bottomSheetRef])
// - center the map on the active hex
- useAsync(async () => {
- if (
- activeHex &&
- activeHex !== DEFAULT_HEX &&
- mapRef?.current &&
- bottomSheetHeight
- ) {
- const cords = parseH3BNLocation(new BN(activeHex)).reverse()
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- const mapHeight = mapRef.current.state.height
-
- if (mapHeight - bottomSheetHeight > 0) {
- // eslint-disable-next-line @typescript-eslint/no-shadow
- const zoomLevel = await mapRef.current.getZoom()
-
- // Define the shift needed to adjust the map's center. This is set to a quarter of the bottom sheet's height.
- // This means the hexagon will be centered in the upper 3/4 of the map's viewable area.
- const centeringShift = bottomSheetHeight / 4
-
- // Convert the latitude to radians for more accurate calculations
- const latitudeRadians = (cords[1] * Math.PI) / 180
-
- // Calculate the number of meters per pixel at the current latitude and zoom level. This uses the Earth's
- // radius in meters and accounts for the zoom level to approximate how much geographic space each pixel covers.
- const metersPerPixel =
- (Math.cos(latitudeRadians) * 2 * Math.PI * 6378137) /
- (256 * 2 ** zoomLevel)
-
- // Calculate the shift in pixels needed to adjust the map's center based on the bottom sheet's height
- const pixelShift = centeringShift
-
- // Convert the pixel shift into a latitude degree shift, using the average meter per degree at the equator.
- const degreeShift = (pixelShift * metersPerPixel) / 111319.9
-
- // Adjust the map's center coordinate by subtracting the degree shift from the latitude. This effectively
- // moves the map's center up to account for the bottom sheet, ensuring the hexagon is centered in the
- // viewable area above the bottom sheet.
- cameraRef.current?.setCamera({
- centerCoordinate: [cords[0], cords[1] - degreeShift],
- animationDuration: 200,
- })
- }
- }
- }, [activeHex, mapRef, bottomSheetHeight, cameraRef])
-
- const iconSize = useMemo(() => 0.17 * (zoomLevel / MAX_MAP_ZOOM), [zoomLevel])
-
- const hexsFeature = useMemo(
- () =>
- featureCollection(
- Object.keys(hexInfoBuckets).map((h) => {
- const center = parseH3BNLocation(new BN(h))
- return feature(
- {
- type: 'Polygon',
- coordinates: [
- cellToBoundary(
- latLngToCell(
- center[0],
- center[1],
- networkType === 'MOBILE' ? (zoomLevel > 16 ? 12 : 10) : 8,
- ),
- ).map((p) => p.reverse()),
- ],
- } as Polygon,
- {
- id: h,
- color: networkType === 'MOBILE' ? '#009EF8' : '#26ED75',
- opacity: h === activeHex ? 1 : 0.3,
- },
- )
- }),
- ),
- [activeHex, hexInfoBuckets, networkType, zoomLevel],
- )
+ // useAsync(async () => {
+ // if (
+ // activeHex &&
+ // activeHex !== DEFAULT_HEX &&
+ // mapRef?.current &&
+ // bottomSheetHeight
+ // ) {
+ // const cords = parseH3BNLocation(new BN(activeHex)).reverse()
+ // // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // // @ts-ignore
+ // const mapHeight = mapRef.current.state.height
+
+ // if (mapHeight - bottomSheetHeight > 0) {
+ // // eslint-disable-next-line @typescript-eslint/no-shadow
+ // const zoomLevel = await mapRef.current.getZoom()
+
+ // // Define the shift needed to adjust the map's center. This is set to a quarter of the bottom sheet's height.
+ // // This means the hexagon will be centered in the upper 3/4 of the map's viewable area.
+ // const centeringShift = bottomSheetHeight / 4
+
+ // // Convert the latitude to radians for more accurate calculations
+ // const latitudeRadians = (cords[1] * Math.PI) / 180
+
+ // // Calculate the number of meters per pixel at the current latitude and zoom level. This uses the Earth's
+ // // radius in meters and accounts for the zoom level to approximate how much geographic space each pixel covers.
+ // const metersPerPixel =
+ // (Math.cos(latitudeRadians) * 2 * Math.PI * 6378137) /
+ // (256 * 2 ** zoomLevel)
+
+ // // Calculate the shift in pixels needed to adjust the map's center based on the bottom sheet's height
+ // const pixelShift = centeringShift
+
+ // // Convert the pixel shift into a latitude degree shift, using the average meter per degree at the equator.
+ // const degreeShift = (pixelShift * metersPerPixel) / 111319.9
+
+ // // Adjust the map's center coordinate by subtracting the degree shift from the latitude. This effectively
+ // // moves the map's center up to account for the bottom sheet, ensuring the hexagon is centered in the
+ // // viewable area above the bottom sheet.
+ // cameraRef.current?.setCamera({
+ // centerCoordinate: [cords[0], cords[1] - degreeShift],
+ // animationDuration: 200,
+ // })
+ // }
+ // }
+ // }, [activeHex, mapRef, bottomSheetHeight, cameraRef])
+
+ // const iconSize = useMemo(() => 0.17 * (zoomLevel / MAX_MAP_ZOOM), [zoomLevel])
+
+ // const hexsFeature = useMemo(
+ // () =>
+ // featureCollection(
+ // Object.keys(hexInfoBuckets).map((h) => {
+ // const center = parseH3BNLocation(new BN(h))
+ // return feature(
+ // {
+ // type: 'Polygon',
+ // coordinates: [
+ // cellToBoundary(
+ // latLngToCell(
+ // center[0],
+ // center[1],
+ // networkType === 'MOBILE' ? (zoomLevel > 16 ? 12 : 10) : 8,
+ // ),
+ // ).map((p) => p.reverse()),
+ // ],
+ // } as Polygon,
+ // {
+ // id: h,
+ // color: networkType === 'MOBILE' ? '#009EF8' : '#26ED75',
+ // opacity: h === activeHex ? 1 : 0.3,
+ // },
+ // )
+ // }),
+ // ),
+ // [activeHex, hexInfoBuckets, networkType, zoomLevel],
+ // )
const activeHexItem = useMemo(() => {
if (!loadingInfos && activeHex) {
@@ -343,24 +335,24 @@ const HotspotMapScreen = () => {
[loading, onEndReached, loadingInfos],
)
- const handleUserLocationPress = useCallback(() => {
- if (cameraRef?.current && userLocation?.coords) {
- cameraRef.current.setCamera({
- animationDuration: 500,
- zoomLevel: MAX_MAP_ZOOM,
- centerCoordinate: userLocation.coords,
- })
- }
- }, [userLocation, cameraRef])
-
- const handleRegionChanged = useCallback(async () => {
- if (mapRef?.current) {
- const zoom = await mapRef.current.getZoom()
- if (zoomLevel !== zoom) {
- setZoomLevel(zoom)
- }
- }
- }, [mapRef, zoomLevel, setZoomLevel])
+ // const handleUserLocationPress = useCallback(() => {
+ // if (cameraRef?.current && userLocation?.coords) {
+ // cameraRef.current.setCamera({
+ // animationDuration: 500,
+ // zoomLevel: MAX_MAP_ZOOM,
+ // centerCoordinate: userLocation.coords,
+ // })
+ // }
+ // }, [userLocation, cameraRef])
+
+ // const handleRegionChanged = useCallback(async () => {
+ // if (mapRef?.current) {
+ // const zoom = await mapRef.current.getZoom()
+ // if (zoomLevel !== zoom) {
+ // setZoomLevel(zoom)
+ // }
+ // }
+ // }, [mapRef, zoomLevel, setZoomLevel])
const handleLegendPress = useCallback(() => {
setLegendVisible(true)
@@ -371,28 +363,28 @@ const HotspotMapScreen = () => {
setHotspot(undefined)
}, [networkType, setNetworkType])
- const handleHexClick = useCallback(
- (event: OnPressEvent) => {
- const hex = event.features[0]
- setLegendVisible(false)
- const id = hex.properties?.id
- setActiveHex(id)
- if (id && (hexInfoBuckets[id]?.length || 0) > 1) {
- Alert.alert(
- t('collectablesScreen.hotspots.selectActive.title'),
- t('collectablesScreen.hotspots.selectActive.which'),
- hexInfoBuckets[id].map((info, index) => ({
- text: hotspots.find((h) => h.id === info.asset.toBase58())?.content
- ?.metadata?.name,
- onPress: () => {
- setActiveHotspotIndex(index)
- },
- })),
- )
- }
- },
- [hexInfoBuckets, hotspots, t],
- )
+ // const handleHexClick = useCallback(
+ // (event: OnPressEvent) => {
+ // const hex = event.features[0]
+ // setLegendVisible(false)
+ // const id = hex.properties?.id
+ // setActiveHex(id)
+ // if (id && (hexInfoBuckets[id]?.length || 0) > 1) {
+ // Alert.alert(
+ // t('collectablesScreen.hotspots.selectActive.title'),
+ // t('collectablesScreen.hotspots.selectActive.which'),
+ // hexInfoBuckets[id].map((info, index) => ({
+ // text: hotspots.find((h) => h.id === info.asset.toBase58())?.content
+ // ?.metadata?.name,
+ // onPress: () => {
+ // setActiveHotspotIndex(index)
+ // },
+ // })),
+ // )
+ // }
+ // },
+ // [hexInfoBuckets, hotspots, t],
+ // )
return (
@@ -417,9 +409,9 @@ const HotspotMapScreen = () => {
-
+ */}
+ {/* */}
{
width={36}
height={36}
justifyContent="center"
- onPress={handleUserLocationPress}
+ // onPress={handleUserLocationPress}
/>
@@ -564,11 +556,7 @@ const HotspotMapScreen = () => {
onChange={(idx) => setBottomSheetSnapIndex(idx)}
>
-
- setBottomSheetHeight(e.nativeEvent.layout.height)
- }
- >
+
{legendVisible && }
{activeHexItem && (
{
+ const {
+ hotspotsWithMeta,
+ loading: loadingHotspots,
+ refresh,
+ fetchMore,
+ fetchingMore,
+ onEndReached,
+ } = useHotspots()
+
+ const isFocused = useIsFocused()
+ const colors = useColors()
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
+ const navigation = useNavigation()
+ const [filterText, setFilterText] = useState('')
+ const [userLocation, setUserLocation] = useState()
+ const [filter, setFilter] = useState<'distance' | 'earnings'>('distance')
+ const route = useRoute<{
+ params: {
+ newHotspot?: HotspotWithPendingRewards | undefined
+ }
+ key: string
+ name: string
+ }>()
+
+ const newHotspot = useMemo(() => route?.params?.newHotspot, [route])
+
+ const onUserLocationUpdate = useCallback((location: Location) => {
+ setUserLocation(location)
+ }, [])
+
+ const onItemSelected = useCallback((value: number) => {
+ setFilter(value === 0 ? 'distance' : 'earnings')
+ }, [])
+
+ const options = useMemo(
+ () => [
+ {
+ label: t('HotspotPage.byDistance'),
+ value: 'distance',
+ },
+ {
+ label: t('HotspotPage.byEarnings'),
+ value: 'earnings',
+ },
+ ],
+ [t],
+ )
+
+ const onHotspotDetails = useCallback(
+ (hotspot: HotspotWithPendingRewards) => () => {
+ navigation.navigate('HotspotDetails', { hotspot })
+ },
+ [navigation],
+ )
+
+ const hotspotsWithDistance = useMemo(() => {
+ let hotspots = hotspotsWithMeta
+
+ if (newHotspot) {
+ // we push the new hotspot to the top of the list and remove it from the array
+ hotspots = [
+ newHotspot,
+ ...hotspots.filter((hotspot) => hotspot.id !== newHotspot.id),
+ ]
+ }
+
+ return hotspots.map((hotspot) => {
+ const subDao = hotspot?.content?.metadata?.hotspot_infos?.iot?.device_type
+ ? 'iot'
+ : 'mobile'
+ const { long, lat } = hotspot.content.metadata.hotspot_infos[subDao]
+
+ if (!long || !lat)
+ return {
+ ...hotspot,
+ distance: undefined,
+ }
+
+ const distance = userLocation
+ ? getDistance(
+ {
+ latitude: userLocation?.coords.latitude,
+ longitude: userLocation?.coords.longitude,
+ },
+ {
+ latitude: toNumber(lat),
+ longitude: toNumber(long),
+ },
+ )
+ : undefined
+
+ return {
+ ...hotspot,
+ distance,
+ }
+ })
+ }, [hotspotsWithMeta, userLocation, newHotspot])
+
+ const filteredHotspots = useMemo(() => {
+ const sortedHotspots = hotspotsWithDistance.sort((a, b) => {
+ if (filter === 'distance') {
+ // if distance is undefined, sort it to the end
+ return (a?.distance ?? Infinity) - (b?.distance ?? Infinity)
+ }
+ return (
+ (heliumToNumber(
+ new BN(b?.pendingRewards?.[MOBILE_MINT?.toBase58()] ?? 0),
+ 6,
+ ) ?? 0) -
+ (heliumToNumber(
+ new BN(a?.pendingRewards?.[MOBILE_MINT?.toBase58()] ?? 0),
+ 6,
+ ) ?? 0)
+ )
+ })
+
+ if (!filterText || filterText === '') {
+ return sortedHotspots as (HotspotWithPendingRewards & {
+ distance: number
+ })[]
+ }
+
+ return sortedHotspots.filter((hotspot) => {
+ return hotspot.content.metadata.name
+ .toLowerCase()
+ .includes(filterText.toLowerCase())
+ }) as (HotspotWithPendingRewards & { distance: number })[]
+ }, [hotspotsWithDistance, filterText, filter])
+
+ const renderHeader = useCallback(() => {
+ return (
+
+
+ {hotspotsWithMeta.map((hotspot) => {
+ const subDao = hotspot?.content?.metadata?.hotspot_infos?.iot
+ ?.device_type
+ ? 'iot'
+ : 'mobile'
+ const { long, lat } = hotspot.content.metadata.hotspot_infos[subDao]
+
+ if (!long || !lat) return null
+
+ return (
+
+
+
+ )
+ })}
+
+
+ {t('HotspotPage.amountOfHotspots', {
+ amount: hotspotsWithMeta?.length,
+ })}
+
+
+
+
+
+
+ )
+ }, [onUserLocationUpdate, hotspotsWithMeta, t, options, onItemSelected])
+
+ const renderItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item }: { item: HotspotWithPendingRewards & { distance: number } }) => {
+ const isFirst = item.id === filteredHotspots[0].id
+ const isLast =
+ item.id === filteredHotspots[filteredHotspots.length - 1].id
+ const borderTopStartRadius = isFirst ? '3xl' : undefined
+ const borderTopEndRadius = isFirst ? '3xl' : undefined
+ const borderBottomStartRadius = isLast ? '3xl' : undefined
+ const borderBottomEndRadius = isLast ? '3xl' : undefined
+
+ const { name } = item.content.metadata
+
+ const isActive = item?.content?.metadata?.hotspot_infos?.iot?.is_active
+
+ const isNewHotspot = item.id === newHotspot?.id
+
+ const distance = item?.distance
+
+ // if distance is less than 5 meters, show 'Nearby'
+ let distanceText = t('HotspotPage.distanceNotAvailable')
+
+ if (distance && distance < 5) {
+ distanceText = t('HotspotPage.nearby')
+ } else if (distance) {
+ distanceText = t('HotspotPage.metersAway', {
+ meters: distance,
+ })
+ }
+
+ return (
+
+
+
+
+
+ {name}
+
+
+
+ {distanceText}
+
+
+
+ {isNewHotspot && (
+
+
+ {t('HotspotPage.new')}
+
+
+ )}
+
+
+
+ )
+ },
+ [filteredHotspots, onHotspotDetails, newHotspot, t, colors],
+ )
+
+ const pageAmount = 20
+ const handleOnEndReached = useCallback(() => {
+ if (!fetchingMore && isFocused && !onEndReached) {
+ fetchMore(pageAmount)
+ }
+ }, [fetchingMore, isFocused, fetchMore, pageAmount, onEndReached])
+
+ const handleRefresh = useCallback(() => {
+ refresh(pageAmount)
+ }, [pageAmount, refresh])
+
+ const keyExtractor = useCallback(
+ (item: HotspotWithPendingRewards & { distance: number }) => {
+ return item.id
+ },
+ [],
+ )
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ paddingHorizontal: spacing['2xl'],
+ paddingBottom: bottom + NavBarHeight + spacing.xl,
+ }
+ }, [spacing, bottom])
+
+ return (
+ <>
+ {hotspotsWithMeta.length === 0 ? : null}
+
+
+ }
+ >
+
+
+ >
+ )
+}
+
+export default HotspotPage
diff --git a/src/features/hotspots/ModifyWifiScreen.tsx b/src/features/hotspots/ModifyWifiScreen.tsx
new file mode 100644
index 000000000..d1abc1be6
--- /dev/null
+++ b/src/features/hotspots/ModifyWifiScreen.tsx
@@ -0,0 +1,750 @@
+import BackScreen from '@components/BackScreen'
+import Box from '@components/Box'
+import { useSpacing, useColors } from '@config/theme/themeHooks'
+import { BleError, Device, useHotspotBle } from '@helium/react-native-sdk'
+import { wp } from '@utils/layout'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import Carousel from 'react-native-snap-carousel'
+import { useTranslation } from 'react-i18next'
+import TouchableContainer from '@components/TouchableContainer'
+import Text from '@components/Text'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import {
+ Alert,
+ FlatList,
+ PermissionsAndroid,
+ Platform,
+ RefreshControl,
+ StyleProp,
+ ViewStyle,
+} from 'react-native'
+import ScrollBox from '@components/ScrollBox'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import RightArrow from '@assets/svgs/rightArrow.svg'
+import {
+ check,
+ PERMISSIONS,
+ request,
+ RESULTS,
+ PermissionStatus,
+} from 'react-native-permissions'
+import * as Logger from '@utils/logger'
+import { useAsyncCallback } from 'react-async-hook'
+import { ButtonPressable, ImageBox, TextInput } from '@components/index'
+import Visibility from '@assets/svgs/visibility.svg'
+import VisibilityOff from '@assets/svgs/visibilityOff.svg'
+import { useNavigation } from '@react-navigation/native'
+import Config from 'react-native-config'
+import Checkmark from '@assets/svgs/checkmark.svg'
+
+const MOCK = Config.MOCK_IOT === 'true'
+const MOCK_DEVICES = [
+ { id: '1', name: 'RAK-78908' },
+ { id: '2', name: 'Helium-Hotspot-775' },
+] as Device[]
+
+type CarouselItem = {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ Screen: (ScreenProps) => React.JSX.Element
+}
+
+const ModifyWifiScreen = () => {
+ const carouselRef = useRef>(null)
+ const [network, setNetwork] = useState(undefined)
+
+ const slides = useMemo(() => {
+ return [
+ {
+ Screen: ScanHotspots,
+ },
+ {
+ Screen: WifiSettings,
+ },
+ {
+ Screen: WifiSetup,
+ },
+ ]
+ }, [])
+
+ const renderCarouselItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item }: { item: CarouselItem }) => {
+ return (
+
+ )
+ },
+ [network],
+ )
+
+ return (
+
+
+
+ )
+}
+
+const ScanHotspots = ({
+ carouselRef,
+}: {
+ carouselRef: React.RefObject>
+}) => {
+ const { startScan, stopScan, connect, scannedDevices } = useHotspotBle()
+ const [scanning, setScanning] = useState(false)
+ const colors = useColors()
+ const [canScan, setCanScan] = useState(undefined)
+ const spacing = useSpacing()
+ const { t } = useTranslation()
+ const [error, setError] = useState(undefined)
+
+ const bluetoothDevices = useMemo(() => {
+ if (MOCK) {
+ return MOCK_DEVICES
+ }
+ return scannedDevices
+ }, [scannedDevices])
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const showError = (e: any) => {
+ Logger.error(e)
+ setError(e.toString())
+ }
+
+ const updateCanScan = useCallback((result: PermissionStatus) => {
+ switch (result) {
+ case RESULTS.UNAVAILABLE:
+ case RESULTS.BLOCKED:
+ case RESULTS.DENIED:
+ case RESULTS.LIMITED:
+ setCanScan(false)
+ break
+ case RESULTS.GRANTED:
+ setCanScan(true)
+ break
+ }
+ }, [])
+
+ useEffect(() => {
+ if (Platform.OS === 'ios') {
+ setCanScan(true)
+ return
+ }
+
+ check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
+ .then(updateCanScan)
+ .catch(showError)
+ }, [updateCanScan])
+
+ useEffect(() => {
+ if (canScan !== false) return
+
+ request(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
+ .then(updateCanScan)
+ .catch(showError)
+ }, [canScan, updateCanScan])
+
+ const checkPermission = async () => {
+ if (Platform.OS === 'ios') {
+ return true
+ }
+
+ const perms = [
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
+ ]
+
+ const results = await Promise.all(
+ perms.map((p) => PermissionsAndroid.check(p)),
+ )
+
+ if (results.findIndex((r) => r === false) === -1) {
+ return true
+ }
+
+ const granted = await PermissionsAndroid.requestMultiple([
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
+ ])
+
+ perms.forEach((p) => {
+ if (!granted[p]) {
+ return false
+ }
+ })
+
+ return true
+ }
+
+ const navNext = useCallback(
+ () => carouselRef?.current?.snapToNext(),
+ [carouselRef],
+ )
+
+ const handleScanPress = useCallback(async () => {
+ const shouldScan = !scanning
+ setScanning(shouldScan)
+ await checkPermission()
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ let timeout: any | undefined
+ if (shouldScan) {
+ setError(undefined)
+ timeout = setTimeout(() => {
+ stopScan()
+ setScanning(false)
+ if (scannedDevices.length === 0) {
+ setError(
+ 'No hotspots found. Please ensure bluetooth pairing is enabled',
+ )
+ }
+ }, 30 * 1000)
+ }
+
+ if (shouldScan) {
+ startScan((e) => {
+ if (e) {
+ showError(e)
+ }
+ })
+ } else {
+ stopScan()
+ }
+ return () => {
+ if (timeout) {
+ clearTimeout(timeout)
+ stopScan()
+ }
+ }
+ }, [scannedDevices, scanning, startScan, stopScan])
+
+ const [connecting, setConnecting] = useState(false)
+ const connectDevice = useCallback(
+ (d: Device) => async () => {
+ if (MOCK) {
+ navNext()
+ return
+ }
+
+ try {
+ setConnecting(true)
+ await connect(d)
+ if (scanning) {
+ stopScan()
+ setScanning(false)
+ }
+ setConnecting(false)
+ navNext()
+ } catch (e) {
+ showError(e)
+ } finally {
+ setConnecting(false)
+ }
+ },
+ [connect, navNext, scanning, stopScan],
+ )
+
+ const renderItem = React.useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item }: { item: Device }) => {
+ const first = item.id === bluetoothDevices[0].id
+ const last = item.id === bluetoothDevices[bluetoothDevices.length - 1].id
+ const borderTopStartRadius = first ? '2xl' : 'none'
+ const borderTopEndRadius = first ? '2xl' : 'none'
+ const borderBottomStartRadius = last ? '2xl' : 'none'
+ const borderBottomEndRadius = last ? '2xl' : 'none'
+
+ return (
+
+
+ {item.name}
+
+
+
+ )
+ },
+ [connectDevice, connecting, bluetoothDevices, colors],
+ )
+
+ const renderHeader = useCallback(() => {
+ return (
+
+
+ {t('hotspotOnboarding.scan.title')}
+
+ {bluetoothDevices.length > 0 && (
+
+ {t('hotspotOnboarding.scan.hotspotsFound', {
+ count: bluetoothDevices.length,
+ })}
+
+ )}
+ {error && (
+
+ {error}
+
+ )}
+
+ )
+ }, [t, bluetoothDevices, error])
+
+ const renderFooter = useCallback(() => {
+ return (
+
+
+ {canScan
+ ? scanning
+ ? t('hotspotOnboarding.scan.stop')
+ : t('hotspotOnboarding.scan.start')
+ : t('hotspotOnboarding.scan.notEnabled')}
+
+
+
+ )
+ }, [canScan, handleScanPress, scanning, t, colors])
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ const keyExtractor = React.useCallback(({ id }: Device) => id, [])
+
+ return (
+
+ }
+ contentContainerStyle={{
+ flex: 1,
+ }}
+ >
+ }
+ ListHeaderComponent={renderHeader}
+ data={bluetoothDevices}
+ renderItem={renderItem}
+ keyExtractor={keyExtractor}
+ ListFooterComponent={renderFooter}
+ />
+
+ )
+}
+
+const WifiSettings = ({
+ carouselRef,
+ onNetworkSelected,
+}: {
+ carouselRef: React.RefObject>
+ onNetworkSelected: (network: string) => void
+}) => {
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const [networks, setNetworks] = useState()
+ const [configuredNetworks, setConfiguredNetworks] = useState()
+ const [connected, setConnected] = useState(false)
+
+ const { isConnected, readWifiNetworks, removeConfiguredWifi } =
+ useHotspotBle()
+
+ useEffect(() => {
+ isConnected().then(setConnected)
+ }, [isConnected])
+
+ const {
+ execute: handleRefresh,
+ loading: refreshing,
+ error,
+ } = useAsyncCallback(async () => {
+ if (MOCK) {
+ setConfiguredNetworks(['Solana-House-5678'])
+ setNetworks(['Helium-House-1234'])
+ return
+ }
+
+ if (!connected) return
+
+ const configured = await readWifiNetworks(true)
+ setConfiguredNetworks(configured)
+ const available = await readWifiNetworks(false)
+ setNetworks(available)
+ })
+
+ // Refresh on network change or on load
+ useEffect(() => {
+ handleRefresh()
+ }, [handleRefresh, connected])
+
+ const handleNetworkSelected = useCallback(
+ ({
+ network,
+ type,
+ }: {
+ network: string
+ type: 'configured' | 'available'
+ }) =>
+ async () => {
+ if (type === 'available') {
+ onNetworkSelected(network)
+ carouselRef?.current?.snapToNext()
+ } else {
+ Alert.alert(
+ t('hotspotOnboarding.wifiSettings.title'),
+ t('hotspotOnboarding.wifiSettings.remove', { network }),
+ [
+ {
+ text: t('generic.cancel'),
+ style: 'default',
+ },
+ {
+ text: t('generic.remove'),
+ style: 'destructive',
+ onPress: async () => {
+ setConfiguredNetworks(
+ configuredNetworks?.filter((n) => n !== network),
+ )
+ await removeConfiguredWifi(network)
+ readWifiNetworks(true).then(setConfiguredNetworks)
+ readWifiNetworks(false).then(setNetworks)
+ },
+ },
+ ],
+ )
+ }
+ },
+ [
+ onNetworkSelected,
+ carouselRef,
+ t,
+ configuredNetworks,
+ removeConfiguredWifi,
+ readWifiNetworks,
+ ],
+ )
+
+ const data = useMemo(
+ () => [...(configuredNetworks || []), ...(networks || [])],
+ [configuredNetworks, networks],
+ )
+
+ const renderItem = useCallback(
+ ({
+ item: network,
+ }: {
+ // eslint-disable-next-line react/no-unused-prop-types
+ item: string
+ // eslint-disable-next-line react/no-unused-prop-types
+ }) => {
+ const first = data[0] === network
+ const last = data[data.length - 1] === network
+ const borderTopStartRadius = first ? '2xl' : 'none'
+ const borderBottomStartRadius = last ? '2xl' : 'none'
+ const borderBottomEndRadius = last ? '2xl' : 'none'
+ const borderTopEndRadius = first ? '2xl' : 'none'
+
+ const isConfigured = configuredNetworks?.includes(network)
+
+ return (
+
+
+ {network}
+
+ {!isConfigured && (
+
+ )}
+ {isConfigured && }
+
+ )
+ },
+ [handleNetworkSelected, data, colors, configuredNetworks],
+ )
+
+ const keyExtractor = useCallback((name: string) => name, [])
+
+ const renderHeader = useCallback(
+ () => (
+
+
+ {t('hotspotOnboarding.wifiSettings.title')}
+
+
+ {t('hotspotOnboarding.wifiSettings.subtitle')}
+
+ {error && (
+
+ {error.message ? error.message.toString() : error.toString()}
+
+ )}
+
+ ),
+ [error, t],
+ )
+
+ const renderFooter = useCallback(
+ () => (
+
+
+ {refreshing
+ ? t('hotspotOnboarding.scan.stop')
+ : t('hotspotOnboarding.scan.start')}
+
+
+
+ ),
+ [colors, handleRefresh, refreshing, t],
+ )
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ }),
+ [spacing],
+ )
+
+ const flatListContentContainerStyle = useMemo(
+ () => ({
+ padding: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ return (
+
+ }
+ >
+
+ }
+ />
+
+ )
+}
+
+const WifiSetup = ({ network }: { network: string }) => {
+ const [secureTextEntry, setSecureTextEntry] = useState(true)
+ const [error, setError] = useState('')
+ const [loading, setLoading] = useState(false)
+ const [password, setPassword] = useState('')
+ const { setWifi } = useHotspotBle()
+ const { t } = useTranslation()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const navigation = useNavigation()
+
+ const toggleSecureEntry = useCallback(() => {
+ setSecureTextEntry(!secureTextEntry)
+ }, [secureTextEntry])
+
+ const handleSetWifi = useCallback(async () => {
+ setLoading(true)
+ try {
+ await setWifi(network, password)
+ navigation.goBack()
+ } catch (e) {
+ if (typeof e === 'string') {
+ setError(e)
+ } else {
+ setError((e as BleError).toString())
+ }
+ }
+ setLoading(false)
+ }, [password, setWifi, network, navigation])
+
+ const contentContainer = useMemo(
+ () => ({
+ paddingHorizontal: spacing['2xl'],
+ flex: 1,
+ justifyContent: 'center',
+ }),
+ [spacing],
+ )
+
+ return (
+ }>
+
+
+
+ {t('hotspotOnboarding.wifiSetup.title')}
+
+
+ {t('hotspotOnboarding.wifiSetup.subtitle', { network })}
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+ {secureTextEntry ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ )
+}
+
+export default ModifyWifiScreen
diff --git a/src/features/collectables/SettingUpAntennaScreen.tsx b/src/features/hotspots/SettingUpAntennaScreen.tsx
similarity index 96%
rename from src/features/collectables/SettingUpAntennaScreen.tsx
rename to src/features/hotspots/SettingUpAntennaScreen.tsx
index e2a33de88..82844980d 100644
--- a/src/features/collectables/SettingUpAntennaScreen.tsx
+++ b/src/features/hotspots/SettingUpAntennaScreen.tsx
@@ -1,11 +1,11 @@
import React, { memo, useCallback } from 'react'
import Box from '@components/Box'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { useNavigation } from '@react-navigation/native'
-import { TabBarNavigationProp } from 'src/navigation/rootTypes'
+import { TabBarNavigationProp } from 'src/app/rootTypes'
import { ReAnimatedBox } from '@components/AnimatedBox'
import { DelayedFadeIn } from '@components/FadeInOut'
-import BackArrow from '@assets/images/backArrow.svg'
+import BackArrow from '@assets/svgs/backArrow.svg'
import AccountIcon from '@components/AccountIcon'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useTranslation } from 'react-i18next'
diff --git a/src/features/collectables/animations/iot-mobile-tokens.json b/src/features/hotspots/animations/iot-mobile-tokens.json
similarity index 100%
rename from src/features/collectables/animations/iot-mobile-tokens.json
rename to src/features/hotspots/animations/iot-mobile-tokens.json
diff --git a/src/features/collectables/animations/iot-tokens.json b/src/features/hotspots/animations/iot-tokens.json
similarity index 100%
rename from src/features/collectables/animations/iot-tokens.json
rename to src/features/hotspots/animations/iot-tokens.json
diff --git a/src/features/collectables/animations/mobile-tokens.json b/src/features/hotspots/animations/mobile-tokens.json
similarity index 100%
rename from src/features/collectables/animations/mobile-tokens.json
rename to src/features/hotspots/animations/mobile-tokens.json
diff --git a/src/features/hotspots/hotspotTypes.ts b/src/features/hotspots/hotspotTypes.ts
new file mode 100644
index 000000000..0c379b575
--- /dev/null
+++ b/src/features/hotspots/hotspotTypes.ts
@@ -0,0 +1,60 @@
+import { StackNavigationProp } from '@react-navigation/stack'
+import {
+ Collectable,
+ CompressedNFT,
+ HotspotWithPendingRewards,
+} from '../../types/solana'
+
+export type PaymentRouteParam = {
+ collectable?: CompressedNFT
+}
+
+export type CollectableStackParamList = {
+ HotspotList: undefined
+ HotspotMapScreen:
+ | undefined
+ | {
+ hotspot?: HotspotWithPendingRewards
+ network?: 'IOT' | 'MOBILE'
+ }
+ AssertLocationScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ AntennaSetupScreen: {
+ collectable: HotspotWithPendingRewards
+ }
+ SettingUpAntennaScreen: undefined
+ PaymentScreen: undefined | PaymentRouteParam
+ ClaimRewardsScreen: {
+ hotspot: HotspotWithPendingRewards
+ }
+ ClaimAllRewardsScreen: undefined
+ ClaimingRewardsScreen: undefined
+ ChangeRewardsRecipientScreen: {
+ hotspot: HotspotWithPendingRewards
+ }
+ CollectionScreen: {
+ collection: Collectable[]
+ }
+ NftDetailsScreen: {
+ collectable: Collectable
+ }
+ NftMetadataScreen: {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ metadata: any
+ }
+ TransferCollectableScreen: {
+ collectable: CompressedNFT | Collectable
+ }
+ TransferCompleteScreen: {
+ collectable: CompressedNFT | Collectable
+ }
+ AddNewContact: undefined
+ PaymentQrScanner: undefined
+ AddressBookNavigator: undefined
+ ScanAddress: undefined
+ OnboardingNavigator: undefined
+}
+
+export type CollectableNavigationProp =
+ StackNavigationProp
diff --git a/src/features/keystone/ConnectKeystoneStartScreen.tsx b/src/features/keystone/ConnectKeystoneStartScreen.tsx
index 12012f174..687c74bdc 100644
--- a/src/features/keystone/ConnectKeystoneStartScreen.tsx
+++ b/src/features/keystone/ConnectKeystoneStartScreen.tsx
@@ -4,7 +4,7 @@ import ButtonPressable from '@components/ButtonPressable'
import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import { useNavigation } from '@react-navigation/native'
-import WarningKeystone from '@assets/images/warningKeystone.svg'
+import WarningKeystone from '@assets/svgs/warningKeystone.svg'
import React, {
forwardRef,
ReactNode,
@@ -16,11 +16,11 @@ import React, {
} from 'react'
import useCamera from '@hooks/useCamera'
import { BottomSheetBackdrop, BottomSheetModal } from '@gorhom/bottom-sheet'
-import { useOpacity, useSpacing } from '@theme/themeHooks'
+import { useOpacity, useSpacing } from '@config/theme/themeHooks'
import useBackHandler from '@hooks/useBackHandler'
import { useTheme } from '@shopify/restyle'
import { t } from 'i18next'
-import { RootNavigationProp } from 'src/navigation/rootTypes'
+import { RootNavigationProp } from 'src/app/rootTypes'
import { Image, Linking, Platform } from 'react-native'
type CameraPermissionBottomSheetAlertRef = {
diff --git a/src/features/keystone/KeystoneAccountAssignScreen.tsx b/src/features/keystone/KeystoneAccountAssignScreen.tsx
index 79c0ae8c9..6ae394992 100644
--- a/src/features/keystone/KeystoneAccountAssignScreen.tsx
+++ b/src/features/keystone/KeystoneAccountAssignScreen.tsx
@@ -7,20 +7,20 @@ import Text from '@components/Text'
import TextInput from '@components/TextInput'
import CheckBox from '@react-native-community/checkbox'
import { useNavigation } from '@react-navigation/native'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import React, { memo, useCallback, useMemo, useState } from 'react'
import { useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform, StyleSheet } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import base58 from 'bs58'
-import { CSAccountVersion } from '@storage/cloudStorage'
+import { CSAccountVersion } from '@config/storage/cloudStorage'
import { hex } from '@coral-xyz/anchor/dist/cjs/utils/bytes'
import { PublicKey } from '@solana/web3.js'
import Address from '@helium/address'
import { ED25519_KEY_TYPE } from '@helium/address/build/KeyTypes'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { RootNavigationProp } from '../../app/rootTypes'
import { ImportAccountNavigationProp } from '../onboarding/import/importAccountNavTypes'
import { CreateAccountNavigationProp } from '../onboarding/create/createAccountNavTypes'
import { useKeystoneOnboarding } from './KeystoneOnboardingProvider'
diff --git a/src/features/keystone/KeystoneModal.tsx b/src/features/keystone/KeystoneModal.tsx
index 0236523d2..b3ba7864d 100644
--- a/src/features/keystone/KeystoneModal.tsx
+++ b/src/features/keystone/KeystoneModal.tsx
@@ -6,7 +6,7 @@ import {
} from '@gorhom/bottom-sheet'
import useBackHandler from '@hooks/useBackHandler'
import { useTheme } from '@shopify/restyle'
-import { useOpacity, useSpacing } from '@theme/themeHooks'
+import { useOpacity, useSpacing } from '@config/theme/themeHooks'
import React, {
ReactNode,
Ref,
@@ -19,7 +19,7 @@ import React, {
useState,
} from 'react'
import EventEmitter from 'events'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { KeystoneSolanaSDK } from '@keystonehq/keystone-sdk'
import { uuid } from '@keystonehq/keystone-sdk/dist/utils'
import SignTxModal from './SignTx/SignTxModal'
diff --git a/src/features/keystone/ScanQrCodeScreen.tsx b/src/features/keystone/ScanQrCodeScreen.tsx
index c51e51cf7..1295e8900 100644
--- a/src/features/keystone/ScanQrCodeScreen.tsx
+++ b/src/features/keystone/ScanQrCodeScreen.tsx
@@ -3,7 +3,7 @@ import DynamicQrScanner from '@components/DynamicQrScanner'
import SafeAreaBox from '@components/SafeAreaBox'
import { URDecoder } from '@ngraveio/bc-ur'
import KeystoneSDK, { MultiAccounts, UR } from '@keystonehq/keystone-sdk'
-import { RootNavigationProp } from 'src/navigation/rootTypes'
+import { RootNavigationProp } from 'src/app/rootTypes'
import { useNavigation } from '@react-navigation/native'
import { Alert } from 'react-native'
import { useTranslation } from 'react-i18next'
diff --git a/src/features/keystone/SelectKeystoneAccountsScreen.tsx b/src/features/keystone/SelectKeystoneAccountsScreen.tsx
index 1de99393e..5cc09a8fd 100644
--- a/src/features/keystone/SelectKeystoneAccountsScreen.tsx
+++ b/src/features/keystone/SelectKeystoneAccountsScreen.tsx
@@ -6,23 +6,19 @@ import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
import { FlatList, RefreshControl } from 'react-native'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import CheckBox from '@react-native-community/checkbox'
import TouchableContainer from '@components/TouchableContainer'
import { humanReadable } from '@helium/spl-utils'
import BN from 'bn.js'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import {
- RootNavigationProp,
- RootStackParamList,
-} from 'src/navigation/rootTypes'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { RootNavigationProp, RootStackParamList } from 'src/app/rootTypes'
import { ellipsizeAddress } from '@utils/accountUtils'
import base58 from 'bs58'
import { retryWithBackoff } from '@utils/retryWithBackoff'
import { PublicKey } from '@solana/web3.js'
import { useTranslation } from 'react-i18next'
-import { useSolana } from '../../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { useKeystoneOnboarding } from './KeystoneOnboardingProvider'
export type KeystoneAccountType = {
@@ -42,7 +38,6 @@ const SelectKeystoneAccountsScreen = () => {
const colors = useColors()
const route = useRoute()
const { setKeystoneOnboardingData } = useKeystoneOnboarding()
- const { hasAccounts } = useAccountStorage()
const { derivationAccounts } = route.params
const [selected, setSelected] = React.useState>(
new Set(derivationAccounts.map((item) => item.path)),
diff --git a/src/features/keystone/SignTx/SignTxModal.tsx b/src/features/keystone/SignTx/SignTxModal.tsx
index 97dc4bb2a..47e194f4c 100644
--- a/src/features/keystone/SignTx/SignTxModal.tsx
+++ b/src/features/keystone/SignTx/SignTxModal.tsx
@@ -1,6 +1,6 @@
import SafeAreaBox from '@components/SafeAreaBox'
import React, { useEffect, useMemo, useState } from 'react'
-import Keystone from '@assets/images/keystoneLogo.svg'
+import Keystone from '@assets/svgs/keystoneLogo.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
@@ -19,7 +19,7 @@ import { useAsync } from 'react-async-hook'
import EventEmitter from 'events'
import CloseButton from '@components/CloseButton'
-import { useHitSlop } from '@theme/themeHooks'
+import { useHitSlop } from '@config/theme/themeHooks'
import { CameraScannerLayout } from '../../../components/CameraScannerLayout'
import { KeystoneSolSignRequest } from '../types/keystoneSolanaTxType'
diff --git a/src/features/ledger/DeviceChooseType.tsx b/src/features/ledger/DeviceChooseType.tsx
index 49508e121..792b9e013 100644
--- a/src/features/ledger/DeviceChooseType.tsx
+++ b/src/features/ledger/DeviceChooseType.tsx
@@ -1,11 +1,11 @@
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigation } from '@react-navigation/native'
-import Ledger from '@assets/images/ledger.svg'
+import Ledger from '@assets/svgs/ledger.svg'
import Text from '@components/Text'
import Box from '@components/Box'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import SafeAreaBox from '@components/SafeAreaBox'
import { LedgerNavigatorNavigationProp } from './ledgerNavigatorTypes'
diff --git a/src/features/ledger/DeviceScan.tsx b/src/features/ledger/DeviceScan.tsx
index 270861023..2e44b9728 100644
--- a/src/features/ledger/DeviceScan.tsx
+++ b/src/features/ledger/DeviceScan.tsx
@@ -3,9 +3,9 @@ import { useTranslation } from 'react-i18next'
import { FlatList, LayoutChangeEvent } from 'react-native'
import { Device } from 'react-native-ble-plx'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import CarotRight from '@assets/images/carot-right.svg'
-import LedgerCircle from '@assets/images/ledger-circle.svg'
-import Ledger from '@assets/images/ledger.svg'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import LedgerCircle from '@assets/svgs/ledger-circle.svg'
+import Ledger from '@assets/svgs/ledger.svg'
import {
BottomSheetBackdrop,
BottomSheetModal,
@@ -16,7 +16,7 @@ import BackButton from '@components/BackButton'
import Text from '@components/Text'
import Box from '@components/Box'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors, useOpacity } from '@theme/themeHooks'
+import { useColors, useOpacity } from '@config/theme/themeHooks'
import useBackHandler from '@hooks/useBackHandler'
import useLedgerDeviceScan from '@hooks/useLedgerDeviceScan'
import LedgerConnectSteps from './LedgerConnectSteps'
diff --git a/src/features/ledger/DeviceScanUsb.tsx b/src/features/ledger/DeviceScanUsb.tsx
index d82f509a1..0bd2ab1a3 100644
--- a/src/features/ledger/DeviceScanUsb.tsx
+++ b/src/features/ledger/DeviceScanUsb.tsx
@@ -3,13 +3,13 @@ import TransportHID from '@ledgerhq/react-native-hid'
import { useTranslation } from 'react-i18next'
import { FlatList } from 'react-native'
import { useNavigation } from '@react-navigation/native'
-import CarotRight from '@assets/images/carot-right.svg'
-import LedgerCircle from '@assets/images/ledger-circle.svg'
-import Ledger from '@assets/images/ledger.svg'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import LedgerCircle from '@assets/svgs/ledger-circle.svg'
+import Ledger from '@assets/svgs/ledger.svg'
import Text from '@components/Text'
import Box from '@components/Box'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import SafeAreaBox from '@components/SafeAreaBox'
import { LedgerNavigatorNavigationProp } from './ledgerNavigatorTypes'
diff --git a/src/features/ledger/DeviceShow.tsx b/src/features/ledger/DeviceShow.tsx
index a97621679..865e71e4f 100644
--- a/src/features/ledger/DeviceShow.tsx
+++ b/src/features/ledger/DeviceShow.tsx
@@ -3,25 +3,25 @@ import { ActivityIndicator, Image, SectionList } from 'react-native'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { useTranslation } from 'react-i18next'
import { useAsync } from 'react-async-hook'
-import Ledger from '@assets/images/ledger.svg'
-import ArrowRight from '@assets/images/arrowRight.svg'
+import Ledger from '@assets/svgs/ledger.svg'
+import ArrowRight from '@assets/svgs/arrowRight.svg'
import { TouchableOpacity } from 'react-native-gesture-handler'
import Box from '@components/Box'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import BackButton from '@components/BackButton'
-import { CSAccountVersion, CSAccounts } from '@storage/cloudStorage'
+import { CSAccountVersion, CSAccounts } from '@config/storage/cloudStorage'
import useLedger, { LedgerAccount } from '@hooks/useLedger'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import {
+ useAccountStorage,
+ MAX_ACCOUNTS,
+} from '@config/storage/AccountStorageProvider'
import {
LedgerNavigatorNavigationProp,
LedgerNavigatorStackParamList,
} from './ledgerNavigatorTypes'
-import {
- useAccountStorage,
- MAX_ACCOUNTS,
-} from '../../storage/AccountStorageProvider'
import LedgerAccountListItem, { Section } from './LedgerAccountListItem'
type Route = RouteProp
diff --git a/src/features/ledger/LedgerAccountListItem.tsx b/src/features/ledger/LedgerAccountListItem.tsx
index 47b7dbce7..d4489f2e3 100644
--- a/src/features/ledger/LedgerAccountListItem.tsx
+++ b/src/features/ledger/LedgerAccountListItem.tsx
@@ -5,7 +5,7 @@ import Text from '@components/Text'
import { toBN } from '@helium/spl-utils'
import { LedgerAccount } from '@hooks/useLedger'
import CheckBox from '@react-native-community/checkbox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { humanReadable } from '@utils/solanaUtils'
import React, { memo, useCallback, useMemo } from 'react'
import { ellipsizeAddress } from '../../utils/accountUtils'
diff --git a/src/features/ledger/LedgerConnectSteps.tsx b/src/features/ledger/LedgerConnectSteps.tsx
index 6ece8dd74..55526d5d8 100644
--- a/src/features/ledger/LedgerConnectSteps.tsx
+++ b/src/features/ledger/LedgerConnectSteps.tsx
@@ -1,11 +1,11 @@
import React, { memo } from 'react'
import { useTranslation } from 'react-i18next'
-import Check from '@assets/images/checkmark.svg'
+import Check from '@assets/svgs/checkmark.svg'
import { LayoutChangeEvent } from 'react-native'
-import InfoError from '@assets/images/infoError.svg'
+import InfoError from '@assets/svgs/infoError.svg'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
type Props = {
diff --git a/src/features/ledger/LedgerModal.tsx b/src/features/ledger/LedgerModal.tsx
index c89b42f4a..7d2cf9a9c 100644
--- a/src/features/ledger/LedgerModal.tsx
+++ b/src/features/ledger/LedgerModal.tsx
@@ -13,9 +13,9 @@ import useBackHandler from '@hooks/useBackHandler'
import useLedger from '@hooks/useLedger'
import { DeviceModelId } from '@ledgerhq/types-devices'
import { BoxProps } from '@shopify/restyle'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { Theme } from '@theme/theme'
-import { useColors, useOpacity } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { Theme } from '@config/theme/theme'
+import { useColors, useOpacity } from '@config/theme/themeHooks'
import { signLedgerMessage, signLedgerTransaction } from '@utils/heliumLedger'
import React, {
ReactNode,
@@ -29,7 +29,6 @@ import React, {
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
-import { useSharedValue } from 'react-native-reanimated'
import Animation from './Animation'
import LedgerConnectSteps from './LedgerConnectSteps'
import { getDeviceAnimation } from './getDeviceAnimation'
@@ -71,8 +70,6 @@ const LedgerModal = forwardRef(
| 'enableBlindSign'
>('loading')
- const animatedContentHeight = useSharedValue(0)
-
const openAppAndSign = useCallback(
async ({
transactionBuffer: tBuffer,
@@ -341,7 +338,6 @@ const LedgerModal = forwardRef(
backgroundStyle={backgroundStyle}
backdropComponent={renderBackdrop}
handleIndicatorStyle={handleIndicatorStyle}
- contentHeight={animatedContentHeight}
enableDynamicSizing
>
diff --git a/src/features/ledger/PairStart.tsx b/src/features/ledger/PairStart.tsx
index b52a77b57..a3b41249f 100644
--- a/src/features/ledger/PairStart.tsx
+++ b/src/features/ledger/PairStart.tsx
@@ -1,13 +1,13 @@
import React, { memo, useCallback } from 'react'
-import Ledger from '@assets/images/ledger.svg'
+import Ledger from '@assets/svgs/ledger.svg'
import { useTranslation } from 'react-i18next'
import { useNavigation } from '@react-navigation/native'
import Box from '@components/Box'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import Text from '@components/Text'
import SafeAreaBox from '@components/SafeAreaBox'
import ButtonPressable from '@components/ButtonPressable'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { AddNewAccountNavigationProp } from '../home/addNewAccount/addNewAccountTypes'
const PairStart = () => {
diff --git a/src/features/ledger/PairSuccess.tsx b/src/features/ledger/PairSuccess.tsx
index 41a3251c3..d8b0848a4 100644
--- a/src/features/ledger/PairSuccess.tsx
+++ b/src/features/ledger/PairSuccess.tsx
@@ -1,14 +1,14 @@
import { useNavigation } from '@react-navigation/native'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
-import Ledger from '@assets/images/ledger.svg'
+import Ledger from '@assets/svgs/ledger.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { LedgerNavigatorNavigationProp } from './ledgerNavigatorTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { RootNavigationProp } from '../../navigation/rootTypes'
+import { RootNavigationProp } from '../../app/rootTypes'
const PairSuccess = () => {
const { t } = useTranslation()
diff --git a/src/features/ledger/ledgerNavigatorTypes.tsx b/src/features/ledger/ledgerNavigatorTypes.tsx
index 070bdbaf0..6146bad3b 100644
--- a/src/features/ledger/ledgerNavigatorTypes.tsx
+++ b/src/features/ledger/ledgerNavigatorTypes.tsx
@@ -1,5 +1,5 @@
import { StackNavigationProp } from '@react-navigation/stack'
-import { LedgerDevice } from '../../storage/cloudStorage'
+import { LedgerDevice } from '@config/storage/cloudStorage'
export type LedgerNavigatorStackParamList = {
DeviceChooseType: undefined
diff --git a/src/features/lock/LockScreen.tsx b/src/features/lock/LockScreen.tsx
index 9cb4252df..8ae0284f5 100644
--- a/src/features/lock/LockScreen.tsx
+++ b/src/features/lock/LockScreen.tsx
@@ -9,14 +9,14 @@ import { useTranslation } from 'react-i18next'
import useAppState from 'react-native-appstate-hook'
import { FadeIn, FadeOutDown } from 'react-native-reanimated'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { darkTheme } from '@config/theme/theme'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import {
deleteSecureItem,
getSecureItem,
storeSecureItem,
-} from '../../storage/secureStorage'
+} from '@config/storage/secureStorage'
type Props = { children: React.ReactNode }
const LockScreen = ({ children }: Props) => {
diff --git a/src/features/migration/SolanaMigration.tsx b/src/features/migration/SolanaMigration.tsx
index ec01119d8..bf9ef4aeb 100644
--- a/src/features/migration/SolanaMigration.tsx
+++ b/src/features/migration/SolanaMigration.tsx
@@ -15,15 +15,15 @@ import IndeterminateProgressBar from '@components/IndeterminateProgressBar'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
import BackScreen from '@components/BackScreen'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Config from 'react-native-config'
import SafeAreaBox from '@components/SafeAreaBox'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import * as Logger from '../../utils/logger'
import { useAppDispatch } from '../../store/store'
import { fetchHotspots } from '../../store/slices/hotspotsSlice'
-import { useSolana } from '../../solana/SolanaProvider'
async function migrateWallet(
provider: Provider,
diff --git a/src/features/modals/InsufficientSolConversionModal.tsx b/src/features/modals/InsufficientSolConversionModal.tsx
index b52132aa9..572ab4599 100644
--- a/src/features/modals/InsufficientSolConversionModal.tsx
+++ b/src/features/modals/InsufficientSolConversionModal.tsx
@@ -17,9 +17,9 @@ import {
import { useEcosystemTokenSolConvert } from '@hooks/useEcosystemTokensSolConvert'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { PublicKey } from '@solana/web3.js'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import { useModal } from '@storage/ModalsProvider'
-import { useVisibleTokens } from '@storage/TokensProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useModal } from '@config/storage/ModalsProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
import BN from 'bn.js'
import React, {
FC,
@@ -32,8 +32,8 @@ import React, {
import { useTranslation } from 'react-i18next'
import { Switch } from 'react-native-gesture-handler'
import { Edge } from 'react-native-safe-area-context'
-import { useSolana } from '../../solana/SolanaProvider'
-import * as Logger from '../../utils/logger'
+import { useSolana } from '@features/solana/SolanaProvider'
+import * as Logger from '@utils/logger'
const InsufficientSolConversionModal: FC = () => {
const { t } = useTranslation()
diff --git a/src/features/notifications/AccountSlider.tsx b/src/features/notifications/AccountSlider.tsx
index aed7118a0..01cb5c9e1 100644
--- a/src/features/notifications/AccountSlider.tsx
+++ b/src/features/notifications/AccountSlider.tsx
@@ -1,15 +1,15 @@
import React, { memo, useCallback, useMemo, useRef } from 'react'
-import WalletUpdate from '@assets/images/walletUpdateIcon.svg'
-import HeliumUpdate from '@assets/images/heliumUpdateIcon.svg'
+import WalletUpdate from '@assets/svgs/walletUpdateIcon.svg'
+import HeliumUpdate from '@assets/svgs/heliumUpdateIcon.svg'
import { Carousel } from 'react-native-snap-carousel'
import { StyleSheet } from 'react-native'
import { useAsync } from 'react-async-hook'
import AccountIcon from '@components/AccountIcon'
import Box from '@components/Box'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
import { wp } from '../../utils/layout'
import AccountSliderIcon from './AccountSliderIcon'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
import { HELIUM_UPDATES_ITEM, WALLET_UPDATES_ITEM } from './notificationTypes'
import { isValidAccountHash } from '../../utils/accountUtils'
diff --git a/src/features/notifications/AccountSliderIcon.tsx b/src/features/notifications/AccountSliderIcon.tsx
index 3a7bd7f5b..7066a4210 100644
--- a/src/features/notifications/AccountSliderIcon.tsx
+++ b/src/features/notifications/AccountSliderIcon.tsx
@@ -2,7 +2,7 @@ import React, { memo, useCallback, useMemo } from 'react'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import Box from '@components/Box'
import { heliumAddressToSolAddress } from '@helium/spl-utils'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
type Props = {
icon: React.ReactNode
diff --git a/src/features/notifications/NotificationDetailBanner.tsx b/src/features/notifications/NotificationDetailBanner.tsx
index bfc2d1a22..4bef3de12 100644
--- a/src/features/notifications/NotificationDetailBanner.tsx
+++ b/src/features/notifications/NotificationDetailBanner.tsx
@@ -1,7 +1,7 @@
import React, { memo, useMemo } from 'react'
import { Image } from 'react-native'
import Box from '@components/Box'
-import { useSpacing } from '@theme/themeHooks'
+import { useSpacing } from '@config/theme/themeHooks'
import { ww } from '../../utils/layout'
const NotificationDetailBanner = ({ icon }: { icon: string }) => {
diff --git a/src/features/notifications/NotificationDetails.tsx b/src/features/notifications/NotificationDetails.tsx
index 9136e0369..1b715bd8e 100644
--- a/src/features/notifications/NotificationDetails.tsx
+++ b/src/features/notifications/NotificationDetails.tsx
@@ -8,14 +8,14 @@ import BackButton from '@components/BackButton'
import usePrevious from '@hooks/usePrevious'
import useMount from '@hooks/useMount'
import { DelayedFadeIn } from '@components/FadeInOut'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { NotificationsListStackParamList } from './notificationTypes'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
import NotificationDetailBanner from './NotificationDetailBanner'
import parseMarkup from '../../utils/parseMarkup'
import { useAppDispatch } from '../../store/store'
import { markNotificationRead } from '../../store/slices/notificationsSlice'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
type Route = RouteProp
diff --git a/src/features/notifications/NotificationsList.tsx b/src/features/notifications/NotificationsList.tsx
index 5a747b2a5..c39506083 100644
--- a/src/features/notifications/NotificationsList.tsx
+++ b/src/features/notifications/NotificationsList.tsx
@@ -4,12 +4,12 @@ import { useTranslation } from 'react-i18next'
import { SectionList } from 'react-native'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useSpacing } from '@theme/themeHooks'
+import { useSpacing } from '@config/theme/themeHooks'
import FadeInOut from '@components/FadeInOut'
import useHaptic from '@hooks/useHaptic'
import ScrollBox from '@components/ScrollBox'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
import { NotificationsListNavigationProp } from './notificationTypes'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
import NotificationListItem from './NotificationListItem'
import { Notification } from '../../utils/walletApiV2'
diff --git a/src/features/notifications/NotificationsNavigator.tsx b/src/features/notifications/NotificationsNavigator.tsx
index f36b62db3..f0bce4d62 100644
--- a/src/features/notifications/NotificationsNavigator.tsx
+++ b/src/features/notifications/NotificationsNavigator.tsx
@@ -1,6 +1,6 @@
import React, { memo } from 'react'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { useOpacity } from '@theme/themeHooks'
+import { useOpacity } from '@config/theme/themeHooks'
import NotificationsScreen from './NotificationsScreen'
import NotificationDetails from './NotificationDetails'
diff --git a/src/features/notifications/NotificationsScreen.tsx b/src/features/notifications/NotificationsScreen.tsx
index 15f9574da..2273a3dd3 100644
--- a/src/features/notifications/NotificationsScreen.tsx
+++ b/src/features/notifications/NotificationsScreen.tsx
@@ -5,8 +5,8 @@ import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import { DelayedFadeIn } from '@components/FadeInOut'
import { ReAnimatedBox } from '@components/AnimatedBox'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
import AccountSlider from './AccountSlider'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
import NotificationsList from './NotificationsList'
const NotificationsScreen = () => {
diff --git a/src/features/onboarding/AccountAssignScreen.tsx b/src/features/onboarding/AccountAssignScreen.tsx
index aee04fc8e..61f13c29b 100644
--- a/src/features/onboarding/AccountAssignScreen.tsx
+++ b/src/features/onboarding/AccountAssignScreen.tsx
@@ -10,9 +10,12 @@ import { heliumAddressFromSolAddress } from '@helium/spl-utils'
import CheckBox from '@react-native-community/checkbox'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { Keypair } from '@solana/web3.js'
-import { CSAccountVersion } from '@storage/cloudStorage'
-import { storeSecureAccount, toSecureAccount } from '@storage/secureStorage'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { CSAccountVersion } from '@config/storage/cloudStorage'
+import {
+ storeSecureAccount,
+ toSecureAccount,
+} from '@config/storage/secureStorage'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import { createHash } from 'crypto'
import React, { memo, useCallback, useMemo, useState } from 'react'
import { useAsyncCallback } from 'react-async-hook'
@@ -21,10 +24,10 @@ import { KeyboardAvoidingView, Platform, StyleSheet } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { accountNetType } from '@utils/accountUtils'
import { ResolvedPath } from '@hooks/useDerivationAccounts'
-import { AccountsServiceStackParamList } from '@services/AccountsService'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { AccountsServiceStackParamList } from 'src/app/services/AccountsService'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { RootNavigationProp } from '../../app/rootTypes'
import { CreateAccountNavigationProp } from './create/createAccountNavTypes'
import { ImportAccountNavigationProp } from './import/importAccountNavTypes'
import { useOnboarding } from './OnboardingProvider'
diff --git a/src/features/onboarding/AccountConfirmPinScreen.tsx b/src/features/onboarding/AccountConfirmPinScreen.tsx
index b5a9a7887..9710f2579 100644
--- a/src/features/onboarding/AccountConfirmPinScreen.tsx
+++ b/src/features/onboarding/AccountConfirmPinScreen.tsx
@@ -2,14 +2,14 @@ import ConfirmPinView from '@components/ConfirmPinView'
import { heliumAddressFromSolAddress } from '@helium/spl-utils'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { Keypair } from '@solana/web3.js'
-import { toSecureAccount } from '@storage/secureStorage'
+import { toSecureAccount } from '@config/storage/secureStorage'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { darkTheme } from '@config/theme/theme'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { RootNavigationProp } from '../../app/rootTypes'
import { useOnboarding } from './OnboardingProvider'
import { CreateAccountStackParamList } from './create/createAccountNavTypes'
import { ImportAccountStackParamList } from './import/importAccountNavTypes'
diff --git a/src/features/onboarding/AccountCreatePinScreen.tsx b/src/features/onboarding/AccountCreatePinScreen.tsx
index 14bb19d8c..75c218902 100644
--- a/src/features/onboarding/AccountCreatePinScreen.tsx
+++ b/src/features/onboarding/AccountCreatePinScreen.tsx
@@ -7,7 +7,7 @@ import Keypad from '@components/Keypad'
import Box from '@components/Box'
import { KeypadInput } from '@components/KeypadButton'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
+import { darkTheme } from '@config/theme/theme'
import {
CreateAccountNavigationProp,
CreateAccountStackParamList,
diff --git a/src/features/onboarding/CreateImportAccountScreen.tsx b/src/features/onboarding/CreateImportAccountScreen.tsx
index 824a7ba07..337a46349 100644
--- a/src/features/onboarding/CreateImportAccountScreen.tsx
+++ b/src/features/onboarding/CreateImportAccountScreen.tsx
@@ -1,15 +1,15 @@
import { useNavigation } from '@react-navigation/native'
import React, { memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
-import Plus from '@assets/images/plus.svg'
-import DownArrow from '@assets/images/importIcon.svg'
-import Ledger from '@assets/images/ledger.svg'
-import Keystone from '@assets/images/keystoneLogo.svg'
+import Plus from '@assets/svgs/plus.svg'
+import DownArrow from '@assets/svgs/importIcon.svg'
+import Ledger from '@assets/svgs/ledger.svg'
+import Keystone from '@assets/svgs/keystoneLogo.svg'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import Box from '@components/Box'
import Text from '@components/Text'
import SafeAreaBox from '@components/SafeAreaBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import BackgroundFill from '@components/BackgroundFill'
import FinePrint from '@components/FinePrint'
diff --git a/src/features/onboarding/NetTypeSegment.tsx b/src/features/onboarding/NetTypeSegment.tsx
index 82d62c75b..b59aac73f 100644
--- a/src/features/onboarding/NetTypeSegment.tsx
+++ b/src/features/onboarding/NetTypeSegment.tsx
@@ -5,13 +5,13 @@ import { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { NetTypes as NetType } from '@helium/address'
import { Platform, Switch } from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import Text from '@components/Text'
import Box from '@components/Box'
-import { useColors, useHitSlop, useSpacing } from '@theme/themeHooks'
+import { useColors, useHitSlop, useSpacing } from '@config/theme/themeHooks'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { useOnboarding } from './OnboardingProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
type Props = BoxProps
const NetTypeSegment = (boxProps: Props) => {
diff --git a/src/features/onboarding/OnboardingNavigator.tsx b/src/features/onboarding/OnboardingNavigator.tsx
index b2f1ffef8..aaef1b935 100644
--- a/src/features/onboarding/OnboardingNavigator.tsx
+++ b/src/features/onboarding/OnboardingNavigator.tsx
@@ -5,7 +5,7 @@ import {
} from '@react-navigation/stack'
import React, { memo, useMemo } from 'react'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
+import { darkTheme } from '@config/theme/theme'
import LedgerNavigator from '../ledger/LedgerNavigator'
import CreateImportAccountScreen from './CreateImportAccountScreen'
import CreateAccountNavigator from './create/CreateAccountNavigator'
diff --git a/src/features/onboarding/OnboardingProvider.tsx b/src/features/onboarding/OnboardingProvider.tsx
index 0afe6caea..822239f11 100644
--- a/src/features/onboarding/OnboardingProvider.tsx
+++ b/src/features/onboarding/OnboardingProvider.tsx
@@ -10,7 +10,7 @@ import React, {
useMemo,
useState,
} from 'react'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
type OnboardingData = {
account?: CSAccount
diff --git a/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx b/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx
index 7b69b17c7..fd379fabb 100644
--- a/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx
+++ b/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx
@@ -2,7 +2,7 @@ import React, { useCallback, useMemo } from 'react'
import { useNavigation } from '@react-navigation/native'
import { Edge } from 'react-native-safe-area-context'
import { useTranslation } from 'react-i18next'
-import Terminal from '@assets/images/terminal.svg'
+import Terminal from '@assets/svgs/terminal.svg'
import Text from '@components/Text'
import SafeAreaBox from '@components/SafeAreaBox'
import ButtonPressable from '@components/ButtonPressable'
diff --git a/src/features/onboarding/cli-import/CLIAccountNavigator.tsx b/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
index 089c2905a..525f78c8a 100644
--- a/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
+++ b/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import { createStackNavigator } from '@react-navigation/stack'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import CLIAccountImportStartScreen from './CLIAccountImportStartScreen'
import CLIPasswordScreen from './CLIPasswordScreen'
import CLIQrScanner from './CLIQrScanner'
diff --git a/src/features/onboarding/cli-import/CLIPasswordScreen.tsx b/src/features/onboarding/cli-import/CLIPasswordScreen.tsx
index 409231ee6..c2fb5886a 100644
--- a/src/features/onboarding/cli-import/CLIPasswordScreen.tsx
+++ b/src/features/onboarding/cli-import/CLIPasswordScreen.tsx
@@ -1,4 +1,4 @@
-import Terminal from '@assets/images/terminal.svg'
+import Terminal from '@assets/svgs/terminal.svg'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import CloseButton from '@components/CloseButton'
@@ -8,7 +8,7 @@ import TextInput from '@components/TextInput'
import useAlert from '@hooks/useAlert'
import { HELIUM_DERIVATION } from '@hooks/useDerivationAccounts'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { createKeypair } from '@storage/secureStorage'
+import { createKeypair } from '@config/storage/secureStorage'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { TextStyle } from 'react-native'
diff --git a/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx b/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx
index 3bd07809e..d589b79a4 100644
--- a/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx
+++ b/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx
@@ -1,14 +1,17 @@
-import Close from '@assets/images/close.svg'
-import InfoError from '@assets/images/infoError.svg'
+import Close from '@assets/svgs/close.svg'
+import InfoError from '@assets/svgs/infoError.svg'
import Box from '@components/Box'
import CircleLoader from '@components/CircleLoader'
import RevealWords from '@components/RevealWords'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useNavigation } from '@react-navigation/native'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { DEFAULT_DERIVATION_PATH, createKeypair } from '@storage/secureStorage'
-import { useColors } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import {
+ DEFAULT_DERIVATION_PATH,
+ createKeypair,
+} from '@config/storage/secureStorage'
+import { useColors } from '@config/theme/themeHooks'
import React, { memo, useCallback, useMemo } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
diff --git a/src/features/onboarding/create/AccountCreateStart.tsx b/src/features/onboarding/create/AccountCreateStart.tsx
index 044f9ac6e..62f90355b 100644
--- a/src/features/onboarding/create/AccountCreateStart.tsx
+++ b/src/features/onboarding/create/AccountCreateStart.tsx
@@ -1,14 +1,14 @@
import React, { memo, useCallback } from 'react'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { useTranslation } from 'react-i18next'
-import CreateAccount from '@assets/images/createAccount.svg'
+import CreateAccount from '@assets/svgs/createAccount.svg'
import { useNavigation } from '@react-navigation/native'
import Box from '@components/Box'
import Text from '@components/Text'
import ButtonPressable from '@components/ButtonPressable'
import CloseButton from '@components/CloseButton'
import SafeAreaBox from '@components/SafeAreaBox'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { CreateAccountNavigationProp } from './createAccountNavTypes'
type Props = { onCreate: () => void; inline?: boolean }
diff --git a/src/features/onboarding/create/ConfirmWordsScreen.tsx b/src/features/onboarding/create/ConfirmWordsScreen.tsx
index 1307ce173..1a868eb28 100644
--- a/src/features/onboarding/create/ConfirmWordsScreen.tsx
+++ b/src/features/onboarding/create/ConfirmWordsScreen.tsx
@@ -6,8 +6,8 @@ import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import CloseButton from '@components/CloseButton'
-import { Color } from '@theme/theme'
-import { useColors, usePaddingStyle } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors, usePaddingStyle } from '@config/theme/themeHooks'
import { upperCase } from 'lodash'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import useHaptic from '@hooks/useHaptic'
diff --git a/src/features/onboarding/create/CreateAccountNavigator.tsx b/src/features/onboarding/create/CreateAccountNavigator.tsx
index 215c34ccb..cfeeec13d 100644
--- a/src/features/onboarding/create/CreateAccountNavigator.tsx
+++ b/src/features/onboarding/create/CreateAccountNavigator.tsx
@@ -4,13 +4,13 @@ import {
StackNavigationOptions,
} from '@react-navigation/stack'
import { memo } from 'react'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import AccountCreatePassphraseScreen from './AccountCreatePassphraseScreen'
import AccountEnterPassphraseScreen from './AccountEnterPassphraseScreen'
import { CreateAccountStackParamList } from './createAccountNavTypes'
import AccountAssignScreen from '../AccountAssignScreen'
import AccountCreatePinScreen from '../AccountCreatePinScreen'
import AccountConfirmPinScreen from '../AccountConfirmPinScreen'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
import AccountCreateStartScreen from './AccountCreateStartScreen'
const CreateAccountStack = createStackNavigator()
diff --git a/src/features/onboarding/create/PhraseChip.tsx b/src/features/onboarding/create/PhraseChip.tsx
index 4718e6b35..f99ba8987 100644
--- a/src/features/onboarding/create/PhraseChip.tsx
+++ b/src/features/onboarding/create/PhraseChip.tsx
@@ -1,15 +1,15 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useState, memo, useCallback } from 'react'
import { upperCase } from 'lodash'
-import CheckMark from '@assets/images/checkmark.svg'
-import Fail from '@assets/images/fail.svg'
+import CheckMark from '@assets/svgs/checkmark.svg'
+import Fail from '@assets/svgs/fail.svg'
import Text from '@components/Text'
import TouchableHighlightBox, {
TouchableHighlightBoxProps,
} from '@components/TouchableHighlightBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import Box from '@components/Box'
-import { Color } from '@theme/theme'
+import { Color } from '@config/theme/theme'
type Props = Omit & {
title: string
diff --git a/src/features/onboarding/import/AccountImportScreen.tsx b/src/features/onboarding/import/AccountImportScreen.tsx
index dd2dee383..61b06008a 100644
--- a/src/features/onboarding/import/AccountImportScreen.tsx
+++ b/src/features/onboarding/import/AccountImportScreen.tsx
@@ -1,11 +1,11 @@
-import Close from '@assets/images/close.svg'
+import Close from '@assets/svgs/close.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import useAlert from '@hooks/useAlert'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { Color } from '@theme/theme'
-import { useColors, usePaddingStyle } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors, usePaddingStyle } from '@config/theme/themeHooks'
import { upperCase } from 'lodash'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -13,9 +13,9 @@ import { FlatList } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import { MAIN_DERIVATION_PATHS } from '@hooks/useDerivationAccounts'
import { Keypair } from '@solana/web3.js'
-import { CSAccount } from '@storage/cloudStorage'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
-import { createKeypair, toSecureAccount } from '../../../storage/secureStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { createKeypair, toSecureAccount } from '@config/storage/secureStorage'
import { useOnboarding } from '../OnboardingProvider'
import { OnboardingNavigationProp } from '../onboardingTypes'
import PassphraseAutocomplete from './PassphraseAutocomplete'
diff --git a/src/features/onboarding/import/AccountImportStartScreen.tsx b/src/features/onboarding/import/AccountImportStartScreen.tsx
index c573c9d71..a8abb4eee 100644
--- a/src/features/onboarding/import/AccountImportStartScreen.tsx
+++ b/src/features/onboarding/import/AccountImportStartScreen.tsx
@@ -9,12 +9,12 @@ import ButtonPressable from '@components/ButtonPressable'
import TextTransform from '@components/TextTransform'
import SafeAreaBox from '@components/SafeAreaBox'
import CloseButton from '@components/CloseButton'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { ImportAccountNavigationProp } from './importAccountNavTypes'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
import { useOnboarding } from '../OnboardingProvider'
import { MultiAccountStackParamList } from '../multiAccount/MultiAccountNavigatorTypes'
import { AddNewAccountNavigationProp } from '../../home/addNewAccount/addNewAccountTypes'
-import { RootNavigationProp } from '../../../navigation/rootTypes'
+import { RootNavigationProp } from '../../../app/rootTypes'
type Route = RouteProp
diff --git a/src/features/onboarding/import/ImportAccountNavigator.tsx b/src/features/onboarding/import/ImportAccountNavigator.tsx
index bcb0e4c47..5328d66b1 100644
--- a/src/features/onboarding/import/ImportAccountNavigator.tsx
+++ b/src/features/onboarding/import/ImportAccountNavigator.tsx
@@ -3,13 +3,13 @@ import {
createStackNavigator,
StackNavigationOptions,
} from '@react-navigation/stack'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { ImportAccountStackParamList } from './importAccountNavTypes'
import AccountImportStartScreen from './AccountImportStartScreen'
import AccountImportScreen from './AccountImportScreen'
import AccountAssignScreen from '../AccountAssignScreen'
import AccountCreatePinScreen from '../AccountCreatePinScreen'
import AccountConfirmPinScreen from '../AccountConfirmPinScreen'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
import CLIAccountNavigator from '../cli-import/CLIAccountNavigator'
import ImportSubAccountsScreen from './ImportSubAccountsScreen'
diff --git a/src/features/onboarding/import/ImportPrivateKey.tsx b/src/features/onboarding/import/ImportPrivateKey.tsx
index bd50c5bd9..c831151a0 100644
--- a/src/features/onboarding/import/ImportPrivateKey.tsx
+++ b/src/features/onboarding/import/ImportPrivateKey.tsx
@@ -14,12 +14,12 @@ import React, { memo, useCallback, useState } from 'react'
import { useAsync, useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import RNSodium from 'react-native-sodium'
-import { RootNavigationProp } from '../../../navigation/rootTypes'
-import { useAccountStorage } from '../../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import {
DEFAULT_DERIVATION_PATH,
createKeypair,
-} from '../../../storage/secureStorage'
+} from '@config/storage/secureStorage'
+import { RootNavigationProp } from '../../../app/rootTypes'
import * as Logger from '../../../utils/logger'
import { useOnboarding } from '../OnboardingProvider'
import { OnboardingStackParamList } from '../onboardingTypes'
diff --git a/src/features/onboarding/import/ImportReplaceWordModal.tsx b/src/features/onboarding/import/ImportReplaceWordModal.tsx
index ef1594041..35ef755a3 100644
--- a/src/features/onboarding/import/ImportReplaceWordModal.tsx
+++ b/src/features/onboarding/import/ImportReplaceWordModal.tsx
@@ -1,13 +1,13 @@
import React, { useCallback, useEffect, useState } from 'react'
import { Modal } from 'react-native'
import { useTranslation } from 'react-i18next'
-import Close from '@assets/images/close.svg'
-import wordlist from '@constants/wordlists/english.json'
+import Close from '@assets/svgs/close.svg'
+import wordlist from '@utils/constants/wordlists/english.json'
import TextInput from '@components/TextInput'
import Box from '@components/Box'
import SafeAreaBox from '@components/SafeAreaBox'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import ScrollBox from '@components/ScrollBox'
import MatchingWord from './MatchingWord'
diff --git a/src/features/onboarding/import/ImportSubAccountsScreen.tsx b/src/features/onboarding/import/ImportSubAccountsScreen.tsx
index 0dcacc49e..6deb91fe7 100644
--- a/src/features/onboarding/import/ImportSubAccountsScreen.tsx
+++ b/src/features/onboarding/import/ImportSubAccountsScreen.tsx
@@ -9,17 +9,17 @@ import {
} from '@hooks/useDerivationAccounts'
import CheckBox from '@react-native-community/checkbox'
import { useNavigation } from '@react-navigation/native'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { DEFAULT_DERIVATION_PATH } from '@storage/secureStorage'
-import { useColors } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { DEFAULT_DERIVATION_PATH } from '@config/storage/secureStorage'
+import { useColors } from '@config/theme/themeHooks'
import { ellipsizeAddress } from '@utils/accountUtils'
import { humanReadable } from '@utils/formatting'
import BN from 'bn.js'
import React, { useCallback, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, RefreshControl } from 'react-native'
-import { RootNavigationProp } from 'src/navigation/rootTypes'
-import { AccountsServiceNavigationProp } from '@services/AccountsService/accountServiceTypes'
+import { RootNavigationProp } from 'src/app/rootTypes'
+import { AccountsServiceNavigationProp } from 'src/app/services/AccountsService/accountServiceTypes'
import ScrollBox from '@components/ScrollBox'
import { useOnboarding } from '../OnboardingProvider'
diff --git a/src/features/onboarding/import/PassphraseAutocomplete.tsx b/src/features/onboarding/import/PassphraseAutocomplete.tsx
index 5677f1aa4..52d83b595 100644
--- a/src/features/onboarding/import/PassphraseAutocomplete.tsx
+++ b/src/features/onboarding/import/PassphraseAutocomplete.tsx
@@ -1,12 +1,12 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { upperCase } from 'lodash'
-import wordlist from '@constants/wordlists/english.json'
+import wordlist from '@utils/constants/wordlists/english.json'
import TextInput from '@components/TextInput'
import Box from '@components/Box'
import FabButton from '@components/FabButton'
import usePrevious from '@hooks/usePrevious'
-import { Color } from '@theme/theme'
+import { Color } from '@config/theme/theme'
import Clipboard from '@react-native-community/clipboard'
import ScrollBox from '@components/ScrollBox'
import { ScrollView } from 'react-native-gesture-handler'
diff --git a/src/features/payment/PaymentCard.tsx b/src/features/payment/PaymentCard.tsx
index e5e515f4e..ecdf01e3d 100644
--- a/src/features/payment/PaymentCard.tsx
+++ b/src/features/payment/PaymentCard.tsx
@@ -5,8 +5,8 @@ import BN from 'bn.js'
import React, { memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import ButtonPressable from '@components/ButtonPressable'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { checkSecureAccount } from '../../storage/secureStorage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { checkSecureAccount } from '@config/storage/secureStorage'
import { SendDetails } from '../../utils/linking'
import PaymentSummary from './PaymentSummary'
diff --git a/src/features/payment/PaymentError.tsx b/src/features/payment/PaymentError.tsx
index 04d4badfe..c4010c487 100644
--- a/src/features/payment/PaymentError.tsx
+++ b/src/features/payment/PaymentError.tsx
@@ -1,4 +1,4 @@
-import FailureIcon from '@assets/images/paymentFailure.svg'
+import FailureIcon from '@assets/svgs/paymentFailure.svg'
import BackgroundFill from '@components/BackgroundFill'
import Box from '@components/Box'
import Text from '@components/Text'
diff --git a/src/features/payment/PaymentItem.tsx b/src/features/payment/PaymentItem.tsx
index 8b6ec1753..7bcdce2ba 100644
--- a/src/features/payment/PaymentItem.tsx
+++ b/src/features/payment/PaymentItem.tsx
@@ -1,5 +1,5 @@
-import AddressIcon from '@assets/images/addressIcon.svg'
-import Remove from '@assets/images/remove.svg'
+import AddressIcon from '@assets/svgs/addressIcon.svg'
+import Remove from '@assets/svgs/remove.svg'
import Box from '@components/Box'
import MemoInput from '@components/MemoInput'
import Text from '@components/Text'
@@ -8,8 +8,8 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useMint } from '@helium/helium-react-hooks'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import { humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
import { toUpper } from 'lodash'
@@ -22,7 +22,7 @@ import {
} from 'react-native'
import { useDebounce } from 'use-debounce'
import { shortenAddress } from '@utils/formatting'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { useBalance } from '../../utils/Balance'
import {
accountNetType,
diff --git a/src/features/payment/PaymentQrScanner.tsx b/src/features/payment/PaymentQrScanner.tsx
index 6b8e938eb..74c69fd57 100644
--- a/src/features/payment/PaymentQrScanner.tsx
+++ b/src/features/payment/PaymentQrScanner.tsx
@@ -4,8 +4,8 @@ import { useNavigation } from '@react-navigation/native'
import useHaptic from '@hooks/useHaptic'
import useAlert from '@hooks/useAlert'
import QrScanner from '@components/QrScanner'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { SendNavigationProp } from '@services/WalletService/pages/SendPage/SentPageNavigator'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { SendNavigationProp } from '@services/WalletService/pages/SendPage'
import { parseBurn, parseDelegate, parsePaymentLink } from '../../utils/linking'
const PaymentQrScanner = () => {
diff --git a/src/features/payment/PaymentScreen.tsx b/src/features/payment/PaymentScreen.tsx
index 2cac0e449..fadc09edc 100644
--- a/src/features/payment/PaymentScreen.tsx
+++ b/src/features/payment/PaymentScreen.tsx
@@ -19,7 +19,7 @@ import { usePublicKey } from '@hooks/usePublicKey'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { NATIVE_MINT } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
-import { useVisibleTokens } from '@storage/TokensProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
import { Mints } from '@utils/constants'
import { fetchDomainOwner } from '@utils/getDomainOwner'
import {
@@ -43,19 +43,19 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
import Toast from 'react-native-simple-toast'
import { useSelector } from 'react-redux'
import { NavBarHeight } from '@components/ServiceNavBar'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { PaymentRouteParam } from '@services/WalletService'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
import ScrollBox from '@components/ScrollBox'
import {
SendNavigationProp,
SendStackParamList,
-} from '@services/WalletService/pages/SendPage/SentPageNavigator'
+} from '@services/WalletService/pages/SendPage'
import { useAsyncCallback } from 'react-async-hook'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { RootNavigationProp } from '../../app/rootTypes'
import useSubmitTxn from '../../hooks/useSubmitTxn'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { CSAccount } from '../../storage/cloudStorage'
import { RootState } from '../../store/rootReducer'
import { solanaSlice } from '../../store/slices/solanaSlice'
import { useAppDispatch } from '../../store/store'
diff --git a/src/features/payment/PaymentSubmit.tsx b/src/features/payment/PaymentSubmit.tsx
index 3edd1e90c..7cadcc784 100644
--- a/src/features/payment/PaymentSubmit.tsx
+++ b/src/features/payment/PaymentSubmit.tsx
@@ -2,7 +2,7 @@ import Box from '@components/Box'
import FadeInOut from '@components/FadeInOut'
import { SerializedError } from '@reduxjs/toolkit'
import { PublicKey } from '@solana/web3.js'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
import BN from 'bn.js'
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { StyleSheet } from 'react-native'
diff --git a/src/features/payment/PaymentSubmitLoading.tsx b/src/features/payment/PaymentSubmitLoading.tsx
index 00d91c528..9645285d3 100644
--- a/src/features/payment/PaymentSubmitLoading.tsx
+++ b/src/features/payment/PaymentSubmitLoading.tsx
@@ -7,7 +7,7 @@ import Text from '@components/Text'
import Box from '@components/Box'
import ActivityIndicator from '@components/ActivityIndicator'
import FadeInOut from '@components/FadeInOut'
-import globalStyles from '@theme/globalStyles'
+import globalStyles from '@config/theme/globalStyles'
type Props = {
onVideoEnd: () => void
diff --git a/src/features/payment/PaymentSuccess.tsx b/src/features/payment/PaymentSuccess.tsx
index 3abf025ef..ef81c5df9 100644
--- a/src/features/payment/PaymentSuccess.tsx
+++ b/src/features/payment/PaymentSuccess.tsx
@@ -1,4 +1,4 @@
-import SuccessIcon from '@assets/images/paymentSuccess.svg'
+import SuccessIcon from '@assets/svgs/paymentSuccess.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
diff --git a/src/features/payment/usePaymentsReducer.ts b/src/features/payment/usePaymentsReducer.ts
index 847bced9d..4d6d02c5e 100644
--- a/src/features/payment/usePaymentsReducer.ts
+++ b/src/features/payment/usePaymentsReducer.ts
@@ -3,7 +3,7 @@ import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
import { useReducer } from 'react'
import { NATIVE_MINT } from '@solana/spl-token'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { TXN_FEE_IN_LAMPORTS } from '../../utils/solanaUtils'
import { Payment } from './PaymentItem'
diff --git a/src/features/settings/AutoGasManager.tsx b/src/features/settings/AutoGasManager.tsx
index 26fbb8bd9..8be765507 100644
--- a/src/features/settings/AutoGasManager.tsx
+++ b/src/features/settings/AutoGasManager.tsx
@@ -6,8 +6,8 @@ import TokenPill from '@components/TokenPill'
import { HNT_MINT, IOT_MINT, MOBILE_MINT } from '@helium/spl-utils'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import { useVisibleTokens } from '@storage/TokensProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
import React, { FC, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Switch } from 'react-native'
diff --git a/src/features/settings/ConfirmSignoutScreen.tsx b/src/features/settings/ConfirmSignoutScreen.tsx
index 1769375fe..26c93b4ff 100644
--- a/src/features/settings/ConfirmSignoutScreen.tsx
+++ b/src/features/settings/ConfirmSignoutScreen.tsx
@@ -4,15 +4,15 @@ import { useNavigation } from '@react-navigation/native'
import { ActivityIndicator, Alert, Platform } from 'react-native'
import { useAsync } from 'react-async-hook'
import useAlert from '@hooks/useAlert'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import Box from '@components/Box'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import ConfirmWordsScreen from '../onboarding/create/ConfirmWordsScreen'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { getSecureAccount } from '@config/storage/secureStorage'
import { SettingsNavigationProp } from './settingsTypes'
-import { getSecureAccount } from '../../storage/secureStorage'
-import { RootNavigationProp } from '../../navigation/rootTypes'
+import ConfirmWordsScreen from '../onboarding/create/ConfirmWordsScreen'
+import { RootNavigationProp } from '../../app/rootTypes'
const ConfirmSignoutScreen = () => {
const { t } = useTranslation()
diff --git a/src/features/settings/RevealPrivateKeyScreen.tsx b/src/features/settings/RevealPrivateKeyScreen.tsx
index 22e2178c3..2f81d040a 100644
--- a/src/features/settings/RevealPrivateKeyScreen.tsx
+++ b/src/features/settings/RevealPrivateKeyScreen.tsx
@@ -9,8 +9,8 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import CopyAddress from '@components/CopyAddress'
import useAlert from '@hooks/useAlert'
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes'
-import { getSecureAccount } from '../../storage/secureStorage'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { getSecureAccount } from '@config/storage/secureStorage'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
const RevealPrivateKeyScreen = () => {
const { currentAccount } = useAccountStorage()
diff --git a/src/features/settings/RevealWordsScreen.tsx b/src/features/settings/RevealWordsScreen.tsx
index c6cb9b69c..ed436a114 100644
--- a/src/features/settings/RevealWordsScreen.tsx
+++ b/src/features/settings/RevealWordsScreen.tsx
@@ -2,11 +2,11 @@ import React, { memo, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useAsync } from 'react-async-hook'
import { useNavigation } from '@react-navigation/native'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import Box from '@components/Box'
import BackScreen from '@components/BackScreen'
import TextTransform from '@components/TextTransform'
-import { getSecureAccount } from '@storage/secureStorage'
+import { getSecureAccount } from '@config/storage/secureStorage'
import RevealWords from '@components/RevealWords'
import ScrollBox from '@components/ScrollBox'
diff --git a/src/features/settings/Settings.tsx b/src/features/settings/Settings.tsx
index 3e091be71..4f8b8d721 100644
--- a/src/features/settings/Settings.tsx
+++ b/src/features/settings/Settings.tsx
@@ -7,25 +7,25 @@ import { useAppVersion } from '@hooks/useDevice'
import { useExplorer } from '@hooks/useExplorer'
import { useNavigation } from '@react-navigation/native'
import { Cluster } from '@solana/web3.js'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import React, { ReactText, memo, useCallback, useMemo } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { Alert, Linking, Platform, SectionList } from 'react-native'
import deviceInfo from 'react-native-device-info'
import { SvgUri } from 'react-native-svg'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
import ScrollBox from '@components/ScrollBox'
-import { PRIVACY_POLICY, TERMS_OF_SERVICE } from '../../constants/urls'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
-import { useLanguageStorage } from '../../storage/LanguageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useLanguageStorage } from '@config/storage/LanguageProvider'
import {
checkSecureAccount,
getSecureAccount,
-} from '../../storage/secureStorage'
+} from '@config/storage/secureStorage'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { RootNavigationProp } from '../../app/rootTypes'
+import { PRIVACY_POLICY, TERMS_OF_SERVICE } from '../../utils/constants/urls'
import { persistor } from '../../store/persistence'
import { SUPPORTED_LANGUAGUES } from '../../utils/i18n'
import SUPPORTED_CURRENCIES from '../../utils/supportedCurrencies'
diff --git a/src/features/settings/SettingsConfirmPinScreen.tsx b/src/features/settings/SettingsConfirmPinScreen.tsx
index 5e8f1ffbc..f243b1ba3 100644
--- a/src/features/settings/SettingsConfirmPinScreen.tsx
+++ b/src/features/settings/SettingsConfirmPinScreen.tsx
@@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next'
import { RouteProp, useRoute, useNavigation } from '@react-navigation/native'
import ConfirmPinView from '@components/ConfirmPinView'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { darkTheme } from '@config/theme/theme'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { SettingsNavigationProp, SettingsStackParamList } from './settingsTypes'
type Route = RouteProp
diff --git a/src/features/settings/SettingsCreatePinScreen.tsx b/src/features/settings/SettingsCreatePinScreen.tsx
index 1ced39c85..2e6b9e5e0 100644
--- a/src/features/settings/SettingsCreatePinScreen.tsx
+++ b/src/features/settings/SettingsCreatePinScreen.tsx
@@ -7,7 +7,7 @@ import Keypad from '@components/Keypad'
import Box from '@components/Box'
import { KeypadInput } from '@components/KeypadButton'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
+import { darkTheme } from '@config/theme/theme'
import { SettingsNavigationProp } from './settingsTypes'
const SettingsCreatePinScreen = () => {
diff --git a/src/features/settings/SettingsListItem.tsx b/src/features/settings/SettingsListItem.tsx
index ec82f5647..e2acec530 100644
--- a/src/features/settings/SettingsListItem.tsx
+++ b/src/features/settings/SettingsListItem.tsx
@@ -1,16 +1,16 @@
import React, { memo, ReactText, useCallback, useMemo, useRef } from 'react'
import { Linking, Platform, Switch } from 'react-native'
-import CarotRight from '@assets/images/carot-right.svg'
-import LinkImg from '@assets/images/link.svg'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import LinkImg from '@assets/svgs/link.svg'
import { HeliumActionSheetItemType } from '@components/HeliumActionSheetItem'
import Text, { TextProps } from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { Color } from '@theme/theme'
+import { Color } from '@config/theme/theme'
import HeliumActionSheet, {
HeliumActionSheetRef,
} from '@components/HeliumActionSheet'
import Box from '@components/Box'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { hp } from '@utils/layout'
import sleep from '@utils/sleep'
diff --git a/src/features/settings/SettingsNavigator.tsx b/src/features/settings/SettingsNavigator.tsx
index 2769deff6..c4d2fff8e 100644
--- a/src/features/settings/SettingsNavigator.tsx
+++ b/src/features/settings/SettingsNavigator.tsx
@@ -1,5 +1,5 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { useOpacity } from '@theme/themeHooks'
+import { useOpacity } from '@config/theme/themeHooks'
import React, { memo } from 'react'
import SecretKeyWarningScreen from '@components/SecretKeyWarningScreen'
import SolanaMigration from '../migration/SolanaMigration'
diff --git a/src/features/settings/ShareAddressScreen.tsx b/src/features/settings/ShareAddressScreen.tsx
index 759c5ce6c..326b9c859 100644
--- a/src/features/settings/ShareAddressScreen.tsx
+++ b/src/features/settings/ShareAddressScreen.tsx
@@ -1,4 +1,4 @@
-import ShareAddress from '@assets/images/shareAddress.svg'
+import ShareAddress from '@assets/svgs/shareAddress.svg'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
import CopyAddress from '@components/CopyAddress'
@@ -6,9 +6,9 @@ import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import useCopyText from '@hooks/useCopyText'
import useHaptic from '@hooks/useHaptic'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { Spacing } from '@theme/theme'
-import { useSpacing } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { Spacing } from '@config/theme/theme'
+import { useSpacing } from '@config/theme/themeHooks'
import { ellipsizeAddress } from '@utils/accountUtils'
import React, { memo, useCallback, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
diff --git a/src/features/settings/UpdateAliasScreen.tsx b/src/features/settings/UpdateAliasScreen.tsx
index 236a4b611..4702cd9d1 100644
--- a/src/features/settings/UpdateAliasScreen.tsx
+++ b/src/features/settings/UpdateAliasScreen.tsx
@@ -5,9 +5,9 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useTranslation } from 'react-i18next'
import Box from '@components/Box'
import TextInput from '@components/TextInput'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import FabButton from '@components/FabButton'
-import { useSpacing } from '@theme/themeHooks'
+import { useSpacing } from '@config/theme/themeHooks'
import AccountIcon from '@components/AccountIcon'
import BackScreen from '@components/BackScreen'
import { SettingsNavigationProp } from './settingsTypes'
diff --git a/src/solana/AsyncAccountCache.ts b/src/features/solana/AsyncAccountCache.ts
similarity index 100%
rename from src/solana/AsyncAccountCache.ts
rename to src/features/solana/AsyncAccountCache.ts
diff --git a/src/solana/CollapsibleWritableAccountPreview.tsx b/src/features/solana/CollapsibleWritableAccountPreview.tsx
similarity index 94%
rename from src/solana/CollapsibleWritableAccountPreview.tsx
rename to src/features/solana/CollapsibleWritableAccountPreview.tsx
index 9210ae123..f6f10f002 100644
--- a/src/solana/CollapsibleWritableAccountPreview.tsx
+++ b/src/features/solana/CollapsibleWritableAccountPreview.tsx
@@ -1,9 +1,9 @@
-import Receive from '@assets/images/receive.svg'
-import ChevronDown from '@assets/images/remixChevronDown.svg'
-import ChevronUp from '@assets/images/remixChevronUp.svg'
-import Send from '@assets/images/send.svg'
-import UnknownAccount from '@assets/images/unknownAccount.svg'
-import AnchorAccount from '@assets/images/anchorAccount.svg'
+import Receive from '@assets/svgs/receive.svg'
+import ChevronDown from '@assets/svgs/remixChevronDown.svg'
+import ChevronUp from '@assets/svgs/remixChevronUp.svg'
+import Send from '@assets/svgs/send.svg'
+import UnknownAccount from '@assets/svgs/unknownAccount.svg'
+import AnchorAccount from '@assets/svgs/anchorAccount.svg'
import Box from '@components/Box'
import { Pill } from '@components/Pill'
import Text from '@components/Text'
@@ -18,7 +18,7 @@ import {
import { getMetadata, useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { NATIVE_MINT } from '@solana/spl-token'
import { AccountInfo } from '@solana/web3.js'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { shortenAddress } from '@utils/formatting'
import { humanReadable } from '@utils/solanaUtils'
import { BN } from 'bn.js'
diff --git a/src/solana/CollectablePreview.tsx b/src/features/solana/CollectablePreview.tsx
similarity index 97%
rename from src/solana/CollectablePreview.tsx
rename to src/features/solana/CollectablePreview.tsx
index a63baf0e5..8b3a3c5c3 100644
--- a/src/solana/CollectablePreview.tsx
+++ b/src/features/solana/CollectablePreview.tsx
@@ -1,11 +1,11 @@
-import Send from '@assets/images/send.svg'
+import Send from '@assets/svgs/send.svg'
import Box from '@components/Box'
import { Pill } from '@components/Pill'
import Text from '@components/Text'
import React, { useMemo } from 'react'
import ImageBox from '@components/ImageBox'
import { ellipsizeAddress } from '@utils/accountUtils'
-import { Collectable, CompressedNFT, isCompressedNFT } from '../types/solana'
+import { Collectable, CompressedNFT, isCompressedNFT } from '../../types/solana'
interface ICollectablePreviewProps {
collectable: CompressedNFT | Collectable
diff --git a/src/solana/MessagePreview.tsx b/src/features/solana/MessagePreview.tsx
similarity index 100%
rename from src/solana/MessagePreview.tsx
rename to src/features/solana/MessagePreview.tsx
diff --git a/src/solana/PaymentPreview.tsx b/src/features/solana/PaymentPreview.tsx
similarity index 97%
rename from src/solana/PaymentPreview.tsx
rename to src/features/solana/PaymentPreview.tsx
index eb188caea..f0ac307ca 100644
--- a/src/solana/PaymentPreview.tsx
+++ b/src/features/solana/PaymentPreview.tsx
@@ -1,4 +1,4 @@
-import Send from '@assets/images/send.svg'
+import Send from '@assets/svgs/send.svg'
import Box from '@components/Box'
import { Pill } from '@components/Pill'
import Text from '@components/Text'
diff --git a/src/solana/SolanaProvider.tsx b/src/features/solana/SolanaProvider.tsx
similarity index 95%
rename from src/solana/SolanaProvider.tsx
rename to src/features/solana/SolanaProvider.tsx
index e296cd168..059425daa 100644
--- a/src/solana/SolanaProvider.tsx
+++ b/src/features/solana/SolanaProvider.tsx
@@ -30,14 +30,14 @@ import { useSelector } from 'react-redux'
import nacl from 'tweetnacl'
import KeystoneModal, {
KeystoneModalRef,
-} from '../features/keystone/KeystoneModal'
-import LedgerModal, { LedgerModalRef } from '../features/ledger/LedgerModal'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
-import { getSessionKey, getSolanaKeypair } from '../storage/secureStorage'
-import { RootState } from '../store/rootReducer'
-import { appSlice } from '../store/slices/appSlice'
-import { useAppDispatch } from '../store/store'
-import { getConnection, isVersionedTransaction } from '../utils/solanaUtils'
+} from '@features/keystone/KeystoneModal'
+import LedgerModal, { LedgerModalRef } from '@features/ledger/LedgerModal'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { getSessionKey, getSolanaKeypair } from '@config/storage/secureStorage'
+import { RootState } from '@store/rootReducer'
+import { appSlice } from '@store/slices/appSlice'
+import { useAppDispatch } from '@store/store'
+import { getConnection, isVersionedTransaction } from '@utils/solanaUtils'
import { AsyncAccountCache } from './AsyncAccountCache'
const useSolanaHook = () => {
diff --git a/src/solana/SwapPreview.tsx b/src/features/solana/SwapPreview.tsx
similarity index 95%
rename from src/solana/SwapPreview.tsx
rename to src/features/solana/SwapPreview.tsx
index 774c86e18..53caf576b 100644
--- a/src/solana/SwapPreview.tsx
+++ b/src/features/solana/SwapPreview.tsx
@@ -1,5 +1,5 @@
-import Send from '@assets/images/send.svg'
-import Receive from '@assets/images/receive.svg'
+import Send from '@assets/svgs/send.svg'
+import Receive from '@assets/svgs/receive.svg'
import Box from '@components/Box'
import CircleLoader from '@components/CircleLoader'
import { Pill } from '@components/Pill'
@@ -9,7 +9,7 @@ import { useMint } from '@helium/helium-react-hooks'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { PublicKey } from '@solana/web3.js'
import React from 'react'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
interface ISwapPreviewProps {
inputMint: PublicKey
diff --git a/src/solana/WalletSIgnBottomSheetSimulated.tsx b/src/features/solana/WalletSIgnBottomSheetSimulated.tsx
similarity index 97%
rename from src/solana/WalletSIgnBottomSheetSimulated.tsx
rename to src/features/solana/WalletSIgnBottomSheetSimulated.tsx
index 9242f5ba2..b0494e4cf 100644
--- a/src/solana/WalletSIgnBottomSheetSimulated.tsx
+++ b/src/features/solana/WalletSIgnBottomSheetSimulated.tsx
@@ -1,9 +1,9 @@
-import Checkmark from '@assets/images/checkmark.svg'
-import IndentArrow from '@assets/images/indentArrow.svg'
-import InfoIcon from '@assets/images/info.svg'
-import CancelIcon from '@assets/images/remixCancel.svg'
-import ChevronDown from '@assets/images/remixChevronDown.svg'
-import ChevronUp from '@assets/images/remixChevronUp.svg'
+import Checkmark from '@assets/svgs/checkmark.svg'
+import IndentArrow from '@assets/svgs/indentArrow.svg'
+import InfoIcon from '@assets/svgs/info.svg'
+import CancelIcon from '@assets/svgs/remixCancel.svg'
+import ChevronDown from '@assets/svgs/remixChevronDown.svg'
+import ChevronUp from '@assets/svgs/remixChevronUp.svg'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
@@ -26,7 +26,7 @@ import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
import SafeAreaBox from '@components/SafeAreaBox'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { useSolana } from './SolanaProvider'
import WalletSignBottomSheetTransaction from './WalletSignBottomSheetTransaction'
import {
diff --git a/src/solana/WalletSignBottomSheet.tsx b/src/features/solana/WalletSignBottomSheet.tsx
similarity index 95%
rename from src/solana/WalletSignBottomSheet.tsx
rename to src/features/solana/WalletSignBottomSheet.tsx
index 7fa6489d1..654ac5207 100644
--- a/src/solana/WalletSignBottomSheet.tsx
+++ b/src/features/solana/WalletSignBottomSheet.tsx
@@ -5,7 +5,7 @@ import {
BottomSheetModalProvider,
BottomSheetScrollView,
} from '@gorhom/bottom-sheet'
-import { useBorderRadii } from '@theme/themeHooks'
+import { useBorderRadii } from '@config/theme/themeHooks'
import React, {
Ref,
forwardRef,
@@ -16,9 +16,8 @@ import React, {
useRef,
useState,
} from 'react'
-import { useSharedValue } from 'react-native-reanimated'
import { ThemeProvider } from '@shopify/restyle'
-import { darkTheme } from '@theme/theme'
+import { darkTheme } from '@config/theme/theme'
import { StyleProp, ViewStyle } from 'react-native'
import {
WalletSignBottomSheetProps,
@@ -38,7 +37,6 @@ const WalletSignBottomSheet = forwardRef(
((value: boolean | PromiseLike) => void) | null
>(null)
useImperativeHandle(ref, () => ({ show, hide }))
- const animatedContentHeight = useSharedValue(0)
const borderRadii = useBorderRadii()
const bottomSheetModalRef = useRef(null)
const [simulated, setSimulated] = useState(false)
@@ -146,7 +144,6 @@ const WalletSignBottomSheet = forwardRef(
elevation: 24,
}}
enableDynamicSizing
- contentHeight={animatedContentHeight}
>
diff --git a/src/solana/WalletSignBottomSheetCompact.tsx b/src/features/solana/WalletSignBottomSheetCompact.tsx
similarity index 100%
rename from src/solana/WalletSignBottomSheetCompact.tsx
rename to src/features/solana/WalletSignBottomSheetCompact.tsx
diff --git a/src/solana/WalletSignBottomSheetTransaction.tsx b/src/features/solana/WalletSignBottomSheetTransaction.tsx
similarity index 97%
rename from src/solana/WalletSignBottomSheetTransaction.tsx
rename to src/features/solana/WalletSignBottomSheetTransaction.tsx
index 8b58e84bb..df97a24d5 100644
--- a/src/solana/WalletSignBottomSheetTransaction.tsx
+++ b/src/features/solana/WalletSignBottomSheetTransaction.tsx
@@ -1,8 +1,8 @@
-import Alert from '@assets/images/alert.svg'
-import ExternalLink from '@assets/images/externalLink.svg'
-import ChevronDown from '@assets/images/remixChevronDown.svg'
-import ChevronUp from '@assets/images/remixChevronUp.svg'
-import UnknownAccount from '@assets/images/unknownAccount.svg'
+import Alert from '@assets/svgs/alert.svg'
+import ExternalLink from '@assets/svgs/externalLink.svg'
+import ChevronDown from '@assets/svgs/remixChevronDown.svg'
+import ChevronUp from '@assets/svgs/remixChevronUp.svg'
+import UnknownAccount from '@assets/svgs/unknownAccount.svg'
import Box from '@components/Box'
import { Pill } from '@components/Pill'
import Text from '@components/Text'
diff --git a/src/solana/WalletSignProvider.tsx b/src/features/solana/WalletSignProvider.tsx
similarity index 100%
rename from src/solana/WalletSignProvider.tsx
rename to src/features/solana/WalletSignProvider.tsx
diff --git a/src/solana/WarningBox.tsx b/src/features/solana/WarningBox.tsx
similarity index 94%
rename from src/solana/WarningBox.tsx
rename to src/features/solana/WarningBox.tsx
index f95e239af..342c98ff5 100644
--- a/src/solana/WarningBox.tsx
+++ b/src/features/solana/WarningBox.tsx
@@ -1,7 +1,7 @@
import Box from '@components/Box'
import Text from '@components/Text'
import React from 'react'
-import Alert from '@assets/images/alert.svg'
+import Alert from '@assets/svgs/alert.svg'
export const WarningBox = ({
header,
diff --git a/src/solana/WritableAccountPreview.tsx b/src/features/solana/WritableAccountPreview.tsx
similarity index 99%
rename from src/solana/WritableAccountPreview.tsx
rename to src/features/solana/WritableAccountPreview.tsx
index 226e36092..469409d62 100644
--- a/src/solana/WritableAccountPreview.tsx
+++ b/src/features/solana/WritableAccountPreview.tsx
@@ -1,4 +1,4 @@
-import ArrowRight from '@assets/images/remixArrowRight.svg'
+import ArrowRight from '@assets/svgs/remixArrowRight.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import {
diff --git a/src/solana/walletSignBottomSheetTypes.tsx b/src/features/solana/walletSignBottomSheetTypes.tsx
similarity index 100%
rename from src/solana/walletSignBottomSheetTypes.tsx
rename to src/features/solana/walletSignBottomSheetTypes.tsx
diff --git a/src/features/swaps/SwapItem.tsx b/src/features/swaps/SwapItem.tsx
index 33f7e04a6..481296fc7 100644
--- a/src/features/swaps/SwapItem.tsx
+++ b/src/features/swaps/SwapItem.tsx
@@ -4,8 +4,8 @@ import TokenPill from '@components/TokenPill'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
-import { useCreateOpacity } from '@theme/themeHooks'
+import { Theme } from '@config/theme/theme'
+import { useCreateOpacity } from '@config/theme/themeHooks'
import React, { memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { GestureResponderEvent, Pressable } from 'react-native'
diff --git a/src/features/swaps/SwapNavigator.tsx b/src/features/swaps/SwapNavigator.tsx
index e23e95856..219a8f35e 100644
--- a/src/features/swaps/SwapNavigator.tsx
+++ b/src/features/swaps/SwapNavigator.tsx
@@ -2,7 +2,7 @@ import {
createNativeStackNavigator,
NativeStackNavigationOptions,
} from '@react-navigation/native-stack'
-import { JupiterProvider } from '@storage/JupiterProvider'
+import { JupiterProvider } from '@config/storage/JupiterProvider'
import React, { memo, useMemo } from 'react'
import SwappingScreen from './SwappingScreen'
import SwapScreen from './SwapScreen'
diff --git a/src/features/swaps/SwapScreen.tsx b/src/features/swaps/SwapScreen.tsx
index 2b595f275..a696a4949 100644
--- a/src/features/swaps/SwapScreen.tsx
+++ b/src/features/swaps/SwapScreen.tsx
@@ -1,5 +1,5 @@
-import Menu from '@assets/images/menu.svg'
-import Plus from '@assets/images/plus.svg'
+import Menu from '@assets/svgs/menu.svg'
+import Plus from '@assets/svgs/plus.svg'
import AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
@@ -37,11 +37,11 @@ import { useTreasuryPrice } from '@hooks/useTreasuryPrice'
import { useNavigation } from '@react-navigation/native'
import { NATIVE_MINT } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useJupiter } from '@storage/JupiterProvider'
-import { useVisibleTokens } from '@storage/TokensProvider'
-import { CSAccount } from '@storage/cloudStorage'
-import { useColors, useHitSlop, useSpacing } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useJupiter } from '@config/storage/JupiterProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { useColors, useHitSlop, useSpacing } from '@config/theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { MIN_BALANCE_THRESHOLD } from '@utils/constants'
import {
@@ -73,7 +73,7 @@ import SegmentedControl from '@components/SegmentedControl'
import { Portal } from '@gorhom/portal'
import ScrollBox from '@components/ScrollBox'
import changeNavigationBarColor from 'react-native-navigation-bar-color'
-import { useSolana } from '../../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { solAddressIsValid } from '../../utils/accountUtils'
import SwapItem from './SwapItem'
import { SwapNavigationProp } from './swapTypes'
diff --git a/src/features/swaps/SwappingScreen.tsx b/src/features/swaps/SwappingScreen.tsx
index 52f291011..a17b0baaf 100644
--- a/src/features/swaps/SwappingScreen.tsx
+++ b/src/features/swaps/SwappingScreen.tsx
@@ -19,9 +19,9 @@ import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
import { Edge } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import 'text-encoding-polyfill'
-import ArrowRight from '../../assets/images/arrowRight.svg'
-import BackArrow from '../../assets/images/backArrow.svg'
-import { TabBarNavigationProp } from '../../navigation/rootTypes'
+import ArrowRight from '../../assets/svgs/arrowRight.svg'
+import BackArrow from '../../assets/svgs/backArrow.svg'
+import { TabBarNavigationProp } from '../../app/rootTypes'
import { RootState } from '../../store/rootReducer'
import { SwapStackParamList } from './swapTypes'
diff --git a/src/features/txnDelegation/LinkWallet.tsx b/src/features/txnDelegation/LinkWallet.tsx
index 3f4de13dc..2f86b6632 100644
--- a/src/features/txnDelegation/LinkWallet.tsx
+++ b/src/features/txnDelegation/LinkWallet.tsx
@@ -18,14 +18,11 @@ import AccountSelector, {
} from '@components/AccountSelector'
import AccountButton from '@components/AccountButton'
import useAlert from '@hooks/useAlert'
-import { ServiceSheetNavigationProp } from '@services/serviceSheetTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { ServiceSheetNavigationProp } from 'src/app/services/serviceSheetTypes'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { checkSecureAccount, getKeypair } from '@config/storage/secureStorage'
import { formatAccountAlias } from '../../utils/accountUtils'
-import { checkSecureAccount, getKeypair } from '../../storage/secureStorage'
-import {
- RootNavigationProp,
- RootStackParamList,
-} from '../../navigation/rootTypes'
+import { RootNavigationProp, RootStackParamList } from '../../app/rootTypes'
import sleep from '../../utils/sleep'
type Route = RouteProp
diff --git a/src/features/txnDelegation/SignHotspot.tsx b/src/features/txnDelegation/SignHotspot.tsx
index 0121c7e3d..e6da5d58a 100644
--- a/src/features/txnDelegation/SignHotspot.tsx
+++ b/src/features/txnDelegation/SignHotspot.tsx
@@ -14,7 +14,7 @@ import {
verifyWalletLinkToken,
} from '@helium/wallet-link'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import animalHash from 'angry-purple-tiger'
import BN from 'bn.js'
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'
@@ -23,13 +23,10 @@ import { useTranslation } from 'react-i18next'
import { ActivityIndicator, Linking } from 'react-native'
import Config from 'react-native-config'
import Toast from 'react-native-simple-toast'
-import { ServiceSheetNavigationProp } from '@services/serviceSheetTypes'
-import {
- RootNavigationProp,
- RootStackParamList,
-} from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { getKeypair } from '../../storage/secureStorage'
+import { ServiceSheetNavigationProp } from 'src/app/services/serviceSheetTypes'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { getKeypair } from '@config/storage/secureStorage'
+import { RootNavigationProp, RootStackParamList } from '../../app/rootTypes'
import { formatAccountAlias } from '../../utils/accountUtils'
import * as Logger from '../../utils/logger'
import useSolTxns from './useSolTxns'
diff --git a/src/features/txnDelegation/useSolTxns.ts b/src/features/txnDelegation/useSolTxns.ts
index e14c1a2e9..b75b1ac64 100644
--- a/src/features/txnDelegation/useSolTxns.ts
+++ b/src/features/txnDelegation/useSolTxns.ts
@@ -21,8 +21,8 @@ import { useCallback, useMemo, useRef, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { HeliumEntityManager } from '@helium/idls/lib/types/helium_entity_manager'
import { IdlInstruction } from '@coral-xyz/anchor/dist/cjs/idl'
-import { useSolana } from '../../solana/SolanaProvider'
-import { getKeypair, getSolanaKeypair } from '../../storage/secureStorage'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { getKeypair, getSolanaKeypair } from '@config/storage/secureStorage'
import { submitSolana } from '../../utils/solanaUtils'
const ValidTxnKeys = [
diff --git a/src/features/account/AccountActionBar.tsx b/src/features/wallet/AccountActionBar.tsx
similarity index 96%
rename from src/features/account/AccountActionBar.tsx
rename to src/features/wallet/AccountActionBar.tsx
index 4f211d126..43d43fb31 100644
--- a/src/features/account/AccountActionBar.tsx
+++ b/src/features/wallet/AccountActionBar.tsx
@@ -6,9 +6,9 @@ import { PublicKey } from '@solana/web3.js'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { LayoutChangeEvent } from 'react-native'
-import { WalletServiceNavigationProp } from '@services/WalletService'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { WalletServiceNavigationProp } from 'src/app/services/WalletService'
+import { WalletNavigationProp } from 'src/app/services/WalletService/pages/WalletPage'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
export type Action =
| 'send'
diff --git a/src/features/account/AccountActivityFilter.tsx b/src/features/wallet/AccountActivityFilter.tsx
similarity index 100%
rename from src/features/account/AccountActivityFilter.tsx
rename to src/features/wallet/AccountActivityFilter.tsx
diff --git a/src/features/account/AccountBalanceChart.tsx b/src/features/wallet/AccountBalanceChart.tsx
similarity index 98%
rename from src/features/account/AccountBalanceChart.tsx
rename to src/features/wallet/AccountBalanceChart.tsx
index 69f73f51f..f4849b4ae 100644
--- a/src/features/account/AccountBalanceChart.tsx
+++ b/src/features/wallet/AccountBalanceChart.tsx
@@ -10,7 +10,7 @@ import { Platform, processColor, ViewStyle } from 'react-native'
import { ChartSelectEvent, LineChart } from 'react-native-charts-wrapper'
import { ScrollView } from 'react-native-gesture-handler'
import FadeInOut from '@components/FadeInOut'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import useHaptic from '@hooks/useHaptic'
import usePrevious from '@hooks/usePrevious'
import { AccountBalance } from '../../types/balance'
diff --git a/src/features/account/AccountManageTokenListScreen.tsx b/src/features/wallet/AccountManageTokenListScreen.tsx
similarity index 95%
rename from src/features/account/AccountManageTokenListScreen.tsx
rename to src/features/wallet/AccountManageTokenListScreen.tsx
index 227315c5c..2fc9f2178 100644
--- a/src/features/account/AccountManageTokenListScreen.tsx
+++ b/src/features/wallet/AccountManageTokenListScreen.tsx
@@ -9,9 +9,9 @@ import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { usePublicKey } from '@hooks/usePublicKey'
import CheckBox from '@react-native-community/checkbox'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useVisibleTokens } from '@storage/TokensProvider'
-import { useColors } from '@theme/themeHooks'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
+import { useColors } from '@config/theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { getSortValue, humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
@@ -22,9 +22,9 @@ import { FlatList } from 'react-native-gesture-handler'
import BackScreen from '@components/BackScreen'
import ScrollBox from '@components/ScrollBox'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { NavBarHeight } from '@components/ServiceNavBar'
-import { useSolana } from '../../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { syncTokenAccounts } from '../../store/slices/balancesSlice'
import { useAppDispatch } from '../../store/store'
import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
diff --git a/src/features/account/AccountTokenBalance.tsx b/src/features/wallet/AccountTokenBalance.tsx
similarity index 96%
rename from src/features/account/AccountTokenBalance.tsx
rename to src/features/wallet/AccountTokenBalance.tsx
index 2aa378445..bef45dac2 100644
--- a/src/features/account/AccountTokenBalance.tsx
+++ b/src/features/wallet/AccountTokenBalance.tsx
@@ -7,8 +7,8 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { TextVariant, Theme } from '@theme/theme'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { TextVariant, Theme } from '@config/theme/theme'
import { IOT_SUB_DAO_KEY, MOBILE_SUB_DAO_KEY } from '@utils/constants'
import { getEscrowTokenAccount, humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
diff --git a/src/features/account/AccountTokenCurrencyBalance.tsx b/src/features/wallet/AccountTokenCurrencyBalance.tsx
similarity index 100%
rename from src/features/account/AccountTokenCurrencyBalance.tsx
rename to src/features/wallet/AccountTokenCurrencyBalance.tsx
diff --git a/src/features/account/AccountTokenScreen.tsx b/src/features/wallet/AccountTokenScreen.tsx
similarity index 96%
rename from src/features/account/AccountTokenScreen.tsx
rename to src/features/wallet/AccountTokenScreen.tsx
index 98f3b05dd..cfa6c51c5 100644
--- a/src/features/account/AccountTokenScreen.tsx
+++ b/src/features/wallet/AccountTokenScreen.tsx
@@ -13,18 +13,18 @@ import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { usePublicKey } from '@hooks/usePublicKey'
import { RouteProp, useRoute } from '@react-navigation/native'
import { NATIVE_MINT } from '@solana/spl-token'
-import { useModal } from '@storage/ModalsProvider'
-import { useColors } from '@theme/themeHooks'
+import { useModal } from '@config/storage/ModalsProvider'
+import { useColors } from '@config/theme/themeHooks'
import { GovMints, MIN_BALANCE_THRESHOLD } from '@utils/constants'
import React, { useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
-import { WalletStackParamList } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
import { PublicKey } from '@solana/web3.js'
import ScrollBox from '@components/ScrollBox'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { WalletStackParamList } from 'src/app/services/WalletService/pages/WalletPage'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { Activity } from '../../types/activity'
import AccountActionBar from './AccountActionBar'
import { useActivityFilter } from './AccountActivityFilter'
diff --git a/src/features/account/AccountView.tsx b/src/features/wallet/AccountView.tsx
similarity index 97%
rename from src/features/account/AccountView.tsx
rename to src/features/wallet/AccountView.tsx
index 3fd3a3d7c..da66a4cde 100644
--- a/src/features/account/AccountView.tsx
+++ b/src/features/wallet/AccountView.tsx
@@ -4,12 +4,12 @@ import FadeInOut from '@components/FadeInOut'
import Text from '@components/Text'
import useLayoutHeight from '@hooks/useLayoutHeight'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { useLanguage } from '@utils/i18n'
import { addMinutes } from 'date-fns'
import React, { memo, useEffect, useState } from 'react'
import { GestureResponderEvent } from 'react-native'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { AccountBalance } from '../../types/balance'
import { numberFormat, useBalance } from '../../utils/Balance'
import DateModule from '../../utils/DateModule'
diff --git a/src/features/account/AirdropScreen.tsx b/src/features/wallet/AirdropScreen.tsx
similarity index 95%
rename from src/features/account/AirdropScreen.tsx
rename to src/features/wallet/AirdropScreen.tsx
index 5308fe844..bc011d2e0 100644
--- a/src/features/account/AirdropScreen.tsx
+++ b/src/features/wallet/AirdropScreen.tsx
@@ -1,4 +1,4 @@
-import DripLogo from '@assets/images/dripLogo.svg'
+import DripLogo from '@assets/svgs/dripLogo.svg'
import { ReAnimatedBox } from '@components/AnimatedBox'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
@@ -8,7 +8,7 @@ import Text from '@components/Text'
import { usePublicKey } from '@hooks/usePublicKey'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { NATIVE_MINT } from '@solana/spl-token'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import * as logger from '@utils/logger'
import * as solUtils from '@utils/solanaUtils'
import axios from 'axios'
@@ -25,14 +25,14 @@ import {
} from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import ScrollBox from '@components/ScrollBox'
-import HNT from '@assets/images/hnt.svg'
+import HNT from '@assets/svgs/hnt.svg'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { NavBarHeight } from '@components/ServiceNavBar'
import {
WalletNavigationProp,
WalletStackParamList,
-} from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { useSolana } from '../../solana/SolanaProvider'
+} from 'src/app/services/WalletService/pages/WalletPage'
+import { useSolana } from '@features/solana/SolanaProvider'
const DROP_HEIGHT = 79
diff --git a/src/features/account/TokenListItem.tsx b/src/features/wallet/TokenListItem.tsx
similarity index 97%
rename from src/features/account/TokenListItem.tsx
rename to src/features/wallet/TokenListItem.tsx
index d636e37e1..6a13e0cf6 100644
--- a/src/features/account/TokenListItem.tsx
+++ b/src/features/wallet/TokenListItem.tsx
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-shadow */
-import Arrow from '@assets/images/listItemRight.svg'
-import Lock from '@assets/images/lockClosed.svg'
+import Arrow from '@assets/svgs/listItemRight.svg'
+import Lock from '@assets/svgs/lockClosed.svg'
import Box from '@components/Box'
import FadeInOut from '@components/FadeInOut'
import Text from '@components/Text'
@@ -19,18 +19,18 @@ import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import usePrevious from '@hooks/usePrevious'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
import React, { useCallback, useMemo } from 'react'
import { useAsync } from 'react-async-hook'
-import { ServiceSheetNavigationProp } from '@services/serviceSheetTypes'
-import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
+import { ServiceSheetNavigationProp } from 'src/app/services/serviceSheetTypes'
+import { WalletNavigationProp } from 'src/app/services/WalletService/pages/WalletPage'
import useAmountLocked from '@hooks/useAmountLocked'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
+import { useSolana } from '@features/solana/SolanaProvider'
import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
-import { useSolana } from '../../solana/SolanaProvider'
export const ITEM_HEIGHT = 72
type Props = {
diff --git a/src/services/WalletService/pages/WalletPage/TokensScreen.tsx b/src/features/wallet/TokensScreen.tsx
similarity index 91%
rename from src/services/WalletService/pages/WalletPage/TokensScreen.tsx
rename to src/features/wallet/TokensScreen.tsx
index 37b31229d..430d31018 100644
--- a/src/services/WalletService/pages/WalletPage/TokensScreen.tsx
+++ b/src/features/wallet/TokensScreen.tsx
@@ -4,20 +4,23 @@ import TotalFiatBalance from '@components/TotalFiatBalance'
import { AppState, FlatList, Platform, RefreshControl } from 'react-native'
import { useBalance } from '@utils/Balance'
import { DC_MINT, truthy } from '@helium/spl-utils'
-import { DEFAULT_TOKENS, useVisibleTokens } from '@storage/TokensProvider'
+import {
+ DEFAULT_TOKENS,
+ useVisibleTokens,
+} from '@config/storage/TokensProvider'
import { PublicKey } from '@solana/web3.js'
import {
HeliumTokenListItem,
TokenListItem,
TokenSkeleton,
-} from '@features/account/TokenListItem'
+} from '@features/wallet/TokenListItem'
import { GovMints } from '@utils/constants'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import WalletAlertBanner from '@components/WalletAlertBanner'
import { NavBarHeight } from '@components/ServiceNavBar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useAsync, useAsyncCallback } from 'react-async-hook'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { useAppDispatch } from '@store/store'
import { syncTokenAccounts } from '@store/slices/balancesSlice'
import { useAccountFetchCache } from '@helium/account-fetch-cache-hooks'
@@ -25,20 +28,20 @@ import { getAssociatedTokenAddressSync } from '@solana/spl-token'
import { times } from 'lodash'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useNavigation } from '@react-navigation/native'
-import Config from '@assets/images/config.svg'
+import Config from '@assets/svgs/config.svg'
import Text from '@components/Text'
import { useTranslation } from 'react-i18next'
import { getSortValue } from '@utils/solanaUtils'
-import { checkSecureAccount } from '@storage/secureStorage'
+import { checkSecureAccount } from '@config/storage/secureStorage'
import ScrollBox from '@components/ScrollBox'
import SharedGroupPreferences from 'react-native-shared-group-preferences'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import { CSAccount } from '@storage/cloudStorage'
-import { RootNavigationProp } from 'src/navigation/rootTypes'
-import { useNotificationStorage } from '@storage/NotificationStorageProvider'
-import { ServiceSheetNavigationProp } from '@services/serviceSheetTypes'
-import { WalletNavigationProp } from './WalletPageNavigator'
-import { useSolana } from '../../../../solana/SolanaProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { RootNavigationProp } from 'src/app/rootTypes'
+import { useNotificationStorage } from '@config/storage/NotificationStorageProvider'
+import { ServiceSheetNavigationProp } from 'src/app/services/serviceSheetTypes'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
const TokensScreen = () => {
const widgetGroup = 'group.com.helium.mobile.wallet.widget'
diff --git a/src/services/WalletService/pages/WalletPage/TokensTabs.tsx b/src/features/wallet/TokensTabs.tsx
similarity index 93%
rename from src/services/WalletService/pages/WalletPage/TokensTabs.tsx
rename to src/features/wallet/TokensTabs.tsx
index 4a507fe84..37109821c 100644
--- a/src/services/WalletService/pages/WalletPage/TokensTabs.tsx
+++ b/src/features/wallet/TokensTabs.tsx
@@ -2,15 +2,15 @@ import SegmentedControl, {
SegmentedControlRef,
} from '@components/SegmentedControl'
import React, { useCallback, useMemo, useRef } from 'react'
-import Tokens from '@assets/images/tokens.svg'
-import Collectables from '@assets/images/collectables.svg'
+import Tokens from '@assets/svgs/tokens.svg'
+import Collectables from '@assets/svgs/collectables.svg'
import {
MaterialTopTabNavigationOptions,
createMaterialTopTabNavigator,
} from '@react-navigation/material-top-tabs'
import { StackNavigationProp } from '@react-navigation/stack'
import NftList from '@features/collectables/NftList'
-import { useColors } from '@theme/themeHooks'
+import { useColors } from '@config/theme/themeHooks'
import { useNavigation } from '@react-navigation/native'
import TokensScreen from './TokensScreen'
diff --git a/src/features/account/TransactionDetail.tsx b/src/features/wallet/TransactionDetail.tsx
similarity index 98%
rename from src/features/account/TransactionDetail.tsx
rename to src/features/wallet/TransactionDetail.tsx
index 1d6170069..e741918ea 100644
--- a/src/features/account/TransactionDetail.tsx
+++ b/src/features/wallet/TransactionDetail.tsx
@@ -23,9 +23,9 @@ import { useTranslation } from 'react-i18next'
import { LayoutChangeEvent } from 'react-native'
import { Edge } from 'react-native-safe-area-context'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { Portal } from '@gorhom/portal'
-import { useCreateExplorerUrl } from '../../constants/urls'
+import { useCreateExplorerUrl } from '../../utils/constants/urls'
import { Activity } from '../../types/activity'
import TransactionLineItem from './TransactionLineItem'
import { useTxnDetails } from './useTxn'
diff --git a/src/features/account/TransactionLineItem.tsx b/src/features/wallet/TransactionLineItem.tsx
similarity index 95%
rename from src/features/account/TransactionLineItem.tsx
rename to src/features/wallet/TransactionLineItem.tsx
index da2cca679..d49630f79 100644
--- a/src/features/account/TransactionLineItem.tsx
+++ b/src/features/wallet/TransactionLineItem.tsx
@@ -1,4 +1,4 @@
-import DetailArrow from '@assets/images/detailArrow.svg'
+import DetailArrow from '@assets/svgs/detailArrow.svg'
import AccountIcon from '@components/AccountIcon'
import Box from '@components/Box'
import Text from '@components/Text'
@@ -6,12 +6,16 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import useAlert from '@hooks/useAlert'
import useCopyText from '@hooks/useCopyText'
import { useNavigation } from '@react-navigation/native'
-import { Color } from '@theme/theme'
-import { useColors, useHitSlop, useVerticalHitSlop } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import {
+ useColors,
+ useHitSlop,
+ useVerticalHitSlop,
+} from '@config/theme/themeHooks'
import React, { memo, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Linking } from 'react-native'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { ellipsizeAddress } from '../../utils/accountUtils'
import { locale } from '../../utils/i18n'
import { AddressBookNavigationProp } from '../addressBook/addressBookTypes'
diff --git a/src/features/account/TxnListItem.tsx b/src/features/wallet/TxnListItem.tsx
similarity index 95%
rename from src/features/account/TxnListItem.tsx
rename to src/features/wallet/TxnListItem.tsx
index c7dc47a19..00041ca66 100644
--- a/src/features/account/TxnListItem.tsx
+++ b/src/features/wallet/TxnListItem.tsx
@@ -1,11 +1,11 @@
-import Pending from '@assets/images/pending.svg'
+import Pending from '@assets/svgs/pending.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { PublicKey } from '@solana/web3.js'
import React, { memo, useCallback, useMemo } from 'react'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { Activity } from '../../types/activity'
import useTxn from './useTxn'
diff --git a/src/features/account/useSolanaActivityList.tsx b/src/features/wallet/useSolanaActivityList.tsx
similarity index 96%
rename from src/features/account/useSolanaActivityList.tsx
rename to src/features/wallet/useSolanaActivityList.tsx
index 5c74b53ba..2c2e6038d 100644
--- a/src/features/account/useSolanaActivityList.tsx
+++ b/src/features/wallet/useSolanaActivityList.tsx
@@ -3,8 +3,8 @@ import { PublicKey } from '@solana/web3.js'
import { onLogs, removeAccountChangeListener } from '@utils/solanaUtils'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useSelector } from 'react-redux'
-import { useSolana } from '../../solana/SolanaProvider'
-import { CSAccount } from '../../storage/cloudStorage'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { CSAccount } from '@config/storage/cloudStorage'
import { RootState } from '../../store/rootReducer'
import { getTxns } from '../../store/slices/solanaSlice'
import { useAppDispatch } from '../../store/store'
diff --git a/src/features/account/useTxn.tsx b/src/features/wallet/useTxn.tsx
similarity index 97%
rename from src/features/account/useTxn.tsx
rename to src/features/wallet/useTxn.tsx
index f6d1999f6..758dc3d14 100644
--- a/src/features/account/useTxn.tsx
+++ b/src/features/wallet/useTxn.tsx
@@ -1,5 +1,5 @@
-import TxnReceive from '@assets/images/txnReceive.svg'
-import TxnSend from '@assets/images/txnSend.svg'
+import TxnReceive from '@assets/svgs/txnReceive.svg'
+import TxnSend from '@assets/svgs/txnSend.svg'
import { useAccounts } from '@helium/account-fetch-cache-hooks'
import { truthy } from '@helium/spl-utils'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
@@ -11,8 +11,8 @@ import {
import { usePublicKey } from '@hooks/usePublicKey'
import { Mint, unpackMint } from '@solana/spl-token'
import { AccountInfo, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'
-import { Color } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
+import { Color } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import BN from 'bn.js'
import {
addMinutes,
diff --git a/src/hooks/useAmountLocked.ts b/src/hooks/useAmountLocked.ts
index bb2b45fd8..382c4daa3 100644
--- a/src/hooks/useAmountLocked.ts
+++ b/src/hooks/useAmountLocked.ts
@@ -7,8 +7,8 @@ import {
usePositions,
} from '@helium/voter-stake-registry-hooks'
import { BN } from 'bn.js'
+import { useSolana } from '@features/solana/SolanaProvider'
import { useCurrentWallet } from './useCurrentWallet'
-import { useSolana } from '../solana/SolanaProvider'
const useAmountLocked = (mint: PublicKey) => {
const wallet = useCurrentWallet()
diff --git a/src/hooks/useBrowser.ts b/src/hooks/useBrowser.ts
index 607e98278..da3d2531d 100644
--- a/src/hooks/useBrowser.ts
+++ b/src/hooks/useBrowser.ts
@@ -1,7 +1,7 @@
import { useSelector } from 'react-redux'
import { useCallback } from 'react'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { RootState } from '../store/rootReducer'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
import { BrowserDetails, browserSlice } from '../store/slices/browserSlice'
import { useAppDispatch } from '../store/store'
diff --git a/src/hooks/useCollectables.ts b/src/hooks/useCollectables.ts
index 968211d54..5474a96e7 100644
--- a/src/hooks/useCollectables.ts
+++ b/src/hooks/useCollectables.ts
@@ -1,8 +1,9 @@
import { useCallback, useEffect, useRef } from 'react'
import { useSelector } from 'react-redux'
import { WrappedConnection } from '@utils/WrappedConnection'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { CompressedNFT } from '../types/solana'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
import { RootState } from '../store/rootReducer'
import {
fetchCollectables,
@@ -16,7 +17,6 @@ import {
onLogs,
removeAccountChangeListener,
} from '../utils/solanaUtils'
-import { useSolana } from '../solana/SolanaProvider'
const useCollectables = (): WalletCollectables & {
refresh: () => void
diff --git a/src/hooks/useCurrentWallet.ts b/src/hooks/useCurrentWallet.ts
index 40ec0bd97..966ffd118 100644
--- a/src/hooks/useCurrentWallet.ts
+++ b/src/hooks/useCurrentWallet.ts
@@ -1,5 +1,5 @@
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { usePublicKey } from './usePublicKey'
export function useCurrentWallet(): PublicKey | undefined {
diff --git a/src/hooks/useDerivationAccounts.ts b/src/hooks/useDerivationAccounts.ts
index d5d7c1966..35e402a3c 100644
--- a/src/hooks/useDerivationAccounts.ts
+++ b/src/hooks/useDerivationAccounts.ts
@@ -13,7 +13,7 @@ import * as ed25519 from 'ed25519-hd-key'
import { useEffect, useMemo, useState } from 'react'
import Config from 'react-native-config'
import { retryWithBackoff } from '@utils/retryWithBackoff'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
export const solanaDerivation = (account = -1, change: number | undefined) => {
if (account === -1) {
diff --git a/src/hooks/useEcosystemTokensSolConvert.ts b/src/hooks/useEcosystemTokensSolConvert.ts
index e6200a6a3..a978be381 100644
--- a/src/hooks/useEcosystemTokensSolConvert.ts
+++ b/src/hooks/useEcosystemTokensSolConvert.ts
@@ -6,7 +6,7 @@ import BN from 'bn.js'
import { useMemo } from 'react'
import { useAsync } from 'react-async-hook'
import { Config } from 'react-native-config'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import * as logger from '../utils/logger'
import { useBN } from './useBN'
import { useCurrentWallet } from './useCurrentWallet'
diff --git a/src/hooks/useEnrichedTransactions.ts b/src/hooks/useEnrichedTransactions.ts
index a9675eb65..e617fd23a 100644
--- a/src/hooks/useEnrichedTransactions.ts
+++ b/src/hooks/useEnrichedTransactions.ts
@@ -1,8 +1,8 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { ConfirmedSignatureInfo } from '@solana/web3.js'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import { useSolana } from '../solana/SolanaProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { useAppDispatch } from '../store/store'
import { EnrichedTransaction } from '../types/solana'
import {
diff --git a/src/hooks/useExplorer.ts b/src/hooks/useExplorer.ts
index 3cea70f58..3e3d0f41e 100644
--- a/src/hooks/useExplorer.ts
+++ b/src/hooks/useExplorer.ts
@@ -1,4 +1,4 @@
-import { useAppStorage } from '@storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { getExplorers, Explorer } from '@utils/walletApiV2'
import { useMemo } from 'react'
import { useAsync } from 'react-async-hook'
diff --git a/src/hooks/useHaptic.ts b/src/hooks/useHaptic.ts
index a4ec95f54..e491fe7aa 100644
--- a/src/hooks/useHaptic.ts
+++ b/src/hooks/useHaptic.ts
@@ -1,4 +1,4 @@
-import { useAppStorage } from '@storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import * as Haptics from 'expo-haptics'
export type FeedbackStyle = 'light' | 'medium' | 'heavy'
diff --git a/src/hooks/useHeading.ts b/src/hooks/useHeading.ts
new file mode 100644
index 000000000..b86df7e31
--- /dev/null
+++ b/src/hooks/useHeading.ts
@@ -0,0 +1,22 @@
+import { useState, useEffect } from 'react'
+import CompassHeading from 'react-native-compass-heading'
+
+const useHeading = () => {
+ const [heading, setHeading] = useState(0)
+
+ useEffect(() => {
+ const degreeUpdateRate = 3
+
+ CompassHeading.start(degreeUpdateRate, ({ heading: newHeading }) => {
+ setHeading(newHeading)
+ })
+
+ return () => {
+ CompassHeading.stop()
+ }
+ }, [])
+
+ return { heading }
+}
+
+export default useHeading
diff --git a/src/hooks/useHotspot.tsx b/src/hooks/useHotspot.tsx
index 5a4a2564d..6491fe2b8 100644
--- a/src/hooks/useHotspot.tsx
+++ b/src/hooks/useHotspot.tsx
@@ -3,7 +3,7 @@ import { init } from '@helium/lazy-distributor-sdk'
import { PublicKey, VersionedTransaction } from '@solana/web3.js'
import { useEffect, useState } from 'react'
import { useAsyncCallback } from 'react-async-hook'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { IOT_LAZY_KEY, MOBILE_LAZY_KEY } from '../utils/constants'
import * as Logger from '../utils/logger'
diff --git a/src/hooks/useHotspotWithMeta.ts b/src/hooks/useHotspotWithMeta.ts
index e1395342b..7e0fe80e2 100644
--- a/src/hooks/useHotspotWithMeta.ts
+++ b/src/hooks/useHotspotWithMeta.ts
@@ -1,7 +1,7 @@
import { PublicKey } from '@solana/web3.js'
import { getHotspotWithRewards } from '@utils/solanaUtils'
import { useAsync } from 'react-async-hook'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { CompressedNFT } from '../types/solana'
export const useHotspotWithMetaAndRewards = (hotspot: CompressedNFT) => {
diff --git a/src/hooks/useHotspots.ts b/src/hooks/useHotspots.ts
index 64bc97cd4..c606a4ac5 100644
--- a/src/hooks/useHotspots.ts
+++ b/src/hooks/useHotspots.ts
@@ -1,8 +1,8 @@
import BN from 'bn.js'
import { useCallback, useEffect, useMemo } from 'react'
import { useSelector } from 'react-redux'
-import { useSolana } from '../solana/SolanaProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { RootState } from '../store/rootReducer'
import {
fetchAllHotspots,
diff --git a/src/hooks/useImplicitBurn.ts b/src/hooks/useImplicitBurn.ts
index 251c6d7ab..3fdde9bb1 100644
--- a/src/hooks/useImplicitBurn.ts
+++ b/src/hooks/useImplicitBurn.ts
@@ -14,9 +14,9 @@ import BN from 'bn.js'
import { Buffer } from 'buffer'
import { useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
-import { useSolana } from '../solana/SolanaProvider'
-import { useWalletSign } from '../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../solana/walletSignBottomSheetTypes'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
export function useImplicitBurn(): {
implicitBurn: (requiredDc: number) => void
diff --git a/src/hooks/useLedger.ts b/src/hooks/useLedger.ts
index 290477ae5..35150b276 100644
--- a/src/hooks/useLedger.ts
+++ b/src/hooks/useLedger.ts
@@ -8,8 +8,8 @@ import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes'
import { solAddressToHelium } from '@utils/accountUtils'
import base58 from 'bs58'
import { PublicKey } from '@solana/web3.js'
-import { useSolana } from '../solana/SolanaProvider'
-import { LedgerDevice } from '../storage/cloudStorage'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { LedgerDevice } from '@config/storage/cloudStorage'
import { runDerivationScheme } from '../utils/heliumLedger'
export type LedgerAccount = {
diff --git a/src/hooks/useMetaplexMetadata.tsx b/src/hooks/useMetaplexMetadata.tsx
index 0a8417df4..ffda9e3dc 100644
--- a/src/hooks/useMetaplexMetadata.tsx
+++ b/src/hooks/useMetaplexMetadata.tsx
@@ -106,17 +106,20 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): {
const { result: json, loading: jsonLoading } = useAsync(async () => {
if (!mint) return
- const meta = await getMetadata(metadataAcc?.data.uri.trim())
+ let meta
+ try {
+ meta = await getMetadata(metadataAcc?.data.uri.trim())
+ } catch {}
dispatch(
tokensSlice.actions.setToken({
mint: mint.toBase58(),
- name: meta?.name,
- symbol: meta?.symbol,
+ name: metadataAcc?.data?.name || meta?.name,
+ symbol: metadataAcc?.data?.symbol || meta?.symbol,
img: meta?.image,
}),
)
- return meta
+ return meta || metadataAcc
}, [mint, dispatch, metadataAcc])
if (mint?.equals(NATIVE_MINT)) {
@@ -151,7 +154,7 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): {
if (cachedToken) {
return {
- metadata: undefined,
+ metadata: metadataAcc,
loading: false,
json: {
name: cachedToken.name,
diff --git a/src/hooks/useNetworkColor.tsx b/src/hooks/useNetworkColor.tsx
index 88cb8383c..d0ab6217d 100644
--- a/src/hooks/useNetworkColor.tsx
+++ b/src/hooks/useNetworkColor.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
import { NetTypes } from '@helium/address'
-import { Color } from '@theme/theme'
+import { Color } from '@config/theme/theme'
export default ({
defaultColor,
diff --git a/src/hooks/useProposalStatus.ts b/src/hooks/useProposalStatus.ts
index 0db5228e1..f34cfcbb9 100644
--- a/src/hooks/useProposalStatus.ts
+++ b/src/hooks/useProposalStatus.ts
@@ -7,7 +7,7 @@ import { PublicKey } from '@solana/web3.js'
import { getDerivedProposalState } from '@utils/governanceUtils'
import BN from 'bn.js'
import { useMemo } from 'react'
-import { ProposalV0 } from '../features/governance/governanceTypes'
+import { ProposalV0 } from '@features/governance/governanceTypes'
function usePublicKey(
key: string | PublicKey | undefined,
diff --git a/src/hooks/useRentExempt.ts b/src/hooks/useRentExempt.ts
index 052ab6609..659d82882 100644
--- a/src/hooks/useRentExempt.ts
+++ b/src/hooks/useRentExempt.ts
@@ -1,6 +1,6 @@
import { useAsync } from 'react-async-hook'
import { LAMPORTS_PER_SOL } from '@solana/web3.js'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import * as logger from '../utils/logger'
export function useRentExempt(dataLength = 0) {
diff --git a/src/hooks/useSolanaHealth.ts b/src/hooks/useSolanaHealth.ts
index 49f9490ba..e7d1f93cf 100644
--- a/src/hooks/useSolanaHealth.ts
+++ b/src/hooks/useSolanaHealth.ts
@@ -2,7 +2,7 @@ import { WrappedConnection } from '@utils/WrappedConnection'
import { useMemo, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { getCurrentTPS } from '../utils/solanaUtils'
let lastUpdated = 0
diff --git a/src/hooks/useSubmitTxn.tsx b/src/hooks/useSubmitTxn.tsx
index 8652fcc71..47b7b7b5d 100644
--- a/src/hooks/useSubmitTxn.tsx
+++ b/src/hooks/useSubmitTxn.tsx
@@ -8,19 +8,19 @@ import {
toVersionedTx,
} from '@helium/spl-utils'
import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import i18n from '@utils/i18n'
import * as solUtils from '@utils/solanaUtils'
import BN from 'bn.js'
import React, { useCallback } from 'react'
import { ellipsizeAddress } from '@utils/accountUtils'
-import { SwapPreview } from '../solana/SwapPreview'
-import { CollectablePreview } from '../solana/CollectablePreview'
-import { MessagePreview } from '../solana/MessagePreview'
-import { PaymentPreivew } from '../solana/PaymentPreview'
-import { useSolana } from '../solana/SolanaProvider'
-import { useWalletSign } from '../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../solana/walletSignBottomSheetTypes'
+import { SwapPreview } from '@features/solana/SwapPreview'
+import { CollectablePreview } from '@features/solana/CollectablePreview'
+import { MessagePreview } from '@features/solana/MessagePreview'
+import { PaymentPreivew } from '@features/solana/PaymentPreview'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import {
claimAllRewards,
claimRewards,
diff --git a/src/services/HotspotService/index.tsx b/src/services/HotspotService/index.tsx
deleted file mode 100644
index 39cf9fe6b..000000000
--- a/src/services/HotspotService/index.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { useMemo } from 'react'
-import Hotspot from '@assets/images/hotspot.svg'
-import ServiceSheetPage, {
- ServiceNavBarOption,
-} from '@components/ServiceSheetPage'
-import CollectablesNavigator from '@features/collectables/CollectablesNavigator'
-import { StackNavigationProp } from '@react-navigation/stack'
-
-export type HotspotServiceStackParamList = {
- Hotspot: undefined
-}
-
-export type HotspotServiceNavigationProp =
- StackNavigationProp
-
-const HotspotService = () => {
- const options = useMemo((): Array => {
- return [
- { name: 'Hotspot', Icon: Hotspot, component: CollectablesNavigator },
- ]
- }, [])
-
- return
-}
-
-export default HotspotService
diff --git a/src/services/WalletService/pages/SendPage/index.tsx b/src/services/WalletService/pages/SendPage/index.tsx
deleted file mode 100644
index dea286d75..000000000
--- a/src/services/WalletService/pages/SendPage/index.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-import { ReAnimatedBox } from '@components/AnimatedBox'
-import { FadeIn } from 'react-native-reanimated'
-import SendPageNavigator from './SentPageNavigator'
-
-const SendPage = () => {
- return (
-
-
-
- )
-}
-
-export default SendPage
diff --git a/src/services/WalletService/pages/WalletPage/index.tsx b/src/services/WalletService/pages/WalletPage/index.tsx
deleted file mode 100644
index 6eb2c8c24..000000000
--- a/src/services/WalletService/pages/WalletPage/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import WalletPageNavigator from './WalletPageNavigator'
-
-const WalletPage = () => {
- return
-}
-
-export default WalletPage
diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts
index c2923b09e..743ffaa1e 100644
--- a/src/store/rootReducer.ts
+++ b/src/store/rootReducer.ts
@@ -29,6 +29,12 @@ const solanaConfig = {
blacklist: ['payment'],
}
+const appConfig = {
+ key: appSliceName,
+ storage: AsyncStorage,
+ blacklist: ['rootSheetPosition'],
+}
+
const notificationsConfig = {
key: notificationsSliceName,
storage: AsyncStorage,
@@ -57,7 +63,7 @@ const reducer = combineReducers({
notificationsReducer,
),
[authSliceName]: authReducer,
- [appSliceName]: appReducer,
+ [appSliceName]: persistReducer(appConfig, appReducer),
[hotspotSliceName]: hotspotReducer,
[browserSliceName]: browserReducer,
[tokensSliceName]: persistReducer(tokensConfig, tokensReducer),
diff --git a/src/store/slices/appSlice.ts b/src/store/slices/appSlice.ts
index f8f438a3c..b9e12e419 100644
--- a/src/store/slices/appSlice.ts
+++ b/src/store/slices/appSlice.ts
@@ -4,6 +4,7 @@ import { Cluster } from '@solana/web3.js'
export type AppState = {
showBanner: boolean
cluster?: Cluster
+ rootSheetPosition?: number
}
const initialState: AppState = {
@@ -20,6 +21,12 @@ const appSlice = createSlice({
setShowBanner: (state, action: PayloadAction) => {
state.showBanner = action.payload
},
+ setRootSheetPosition: (
+ state,
+ action: PayloadAction,
+ ) => {
+ state.rootSheetPosition = action.payload
+ },
},
})
diff --git a/src/store/slices/balancesSlice.ts b/src/store/slices/balancesSlice.ts
index db6a9fcef..7e5711193 100644
--- a/src/store/slices/balancesSlice.ts
+++ b/src/store/slices/balancesSlice.ts
@@ -3,7 +3,7 @@ import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { AccountLayout, TOKEN_PROGRAM_ID, getMint } from '@solana/spl-token'
import { Cluster, PublicKey } from '@solana/web3.js'
import { PURGE } from 'redux-persist'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { AccountBalance, Prices, TokenAccount } from '../../types/balance'
import { getBalanceHistory, getTokenPrices } from '../../utils/walletApiV2'
diff --git a/src/store/slices/browserSlice.ts b/src/store/slices/browserSlice.ts
index 0d562d5d0..0b789a719 100644
--- a/src/store/slices/browserSlice.ts
+++ b/src/store/slices/browserSlice.ts
@@ -1,5 +1,5 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
export type BrowserDetails = {
favorites: string[]
diff --git a/src/store/slices/collectablesSlice.ts b/src/store/slices/collectablesSlice.ts
index aab9260c8..4a7a4d16f 100644
--- a/src/store/slices/collectablesSlice.ts
+++ b/src/store/slices/collectablesSlice.ts
@@ -2,7 +2,7 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
import { Cluster, Connection, PublicKey } from '@solana/web3.js'
import { WrappedConnection } from '@utils/WrappedConnection'
import { PURGE } from 'redux-persist'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { CompressedNFT } from '../../types/solana'
import * as solUtils from '../../utils/solanaUtils'
diff --git a/src/store/slices/hotspotsSlice.ts b/src/store/slices/hotspotsSlice.ts
index e5b566c95..50c1cdf41 100644
--- a/src/store/slices/hotspotsSlice.ts
+++ b/src/store/slices/hotspotsSlice.ts
@@ -4,10 +4,11 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
import { Cluster, PublicKey } from '@solana/web3.js'
import { PURGE } from 'redux-persist'
import { CompressedNFT } from 'src/types/solana'
-import { DEFAULT_PAGE_AMOUNT } from '../../features/collectables/HotspotList'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import * as solUtils from '../../utils/solanaUtils'
+const DEFAULT_PAGE_AMOUNT = 20
+
export type WalletHotspots = {
loading: boolean
fetchingMore: boolean
diff --git a/src/store/slices/notificationsSlice.ts b/src/store/slices/notificationsSlice.ts
index 264ef01d2..8eba9822e 100644
--- a/src/store/slices/notificationsSlice.ts
+++ b/src/store/slices/notificationsSlice.ts
@@ -1,6 +1,6 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { PURGE } from 'redux-persist'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import * as WalletApi from '../../utils/walletApiV2'
type NotificationsByResource = Record
diff --git a/src/store/slices/solanaSlice.ts b/src/store/slices/solanaSlice.ts
index bc9004977..c779a3551 100644
--- a/src/store/slices/solanaSlice.ts
+++ b/src/store/slices/solanaSlice.ts
@@ -39,7 +39,7 @@ import { first, last } from 'lodash'
import { PURGE } from 'redux-persist'
import { LazyDistributor } from '@helium/idls/lib/types/lazy_distributor'
import { HeliumEntityManager } from '@helium/idls/lib/types/helium_entity_manager'
-import { CSAccount } from '../../storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { Activity } from '../../types/activity'
import { CompressedNFT, HotspotWithPendingRewards } from '../../types/solana'
import * as Logger from '../../utils/logger'
diff --git a/src/store/store.ts b/src/store/store.ts
index 99d9fd8e6..101ed96a6 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -8,6 +8,7 @@ import { solanaStatusApi } from './slices/solanaStatusApi'
import { name as solanaSliceName } from './slices/solanaSlice'
import { name as balancesSliceName } from './slices/balancesSlice'
import { name as notificationsSliceName } from './slices/notificationsSlice'
+import { name as appSliceName } from './slices/appSlice'
import Reactotron from '../../ReactotronConfig'
const enhancers: StoreEnhancer[] = []
@@ -24,6 +25,7 @@ const persistConfig = {
solanaSliceName,
balancesSliceName,
notificationsSliceName,
+ appSliceName,
],
}
diff --git a/src/utils/Balance.tsx b/src/utils/Balance.tsx
index 6e3863ac3..0a6302c6e 100644
--- a/src/utils/Balance.tsx
+++ b/src/utils/Balance.tsx
@@ -8,7 +8,7 @@ import {
toNumber,
} from '@helium/spl-utils'
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'
-import { useVisibleTokens } from '@storage/TokensProvider'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
import BN from 'bn.js'
import React, {
ReactNode,
@@ -21,10 +21,10 @@ import React, {
} from 'react'
import { useAsync } from 'react-async-hook'
import { useSelector } from 'react-redux'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import usePrevious from '../hooks/usePrevious'
-import { useSolana } from '../solana/SolanaProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
-import { useAppStorage } from '../storage/AppStorageProvider'
import { RootState } from '../store/rootReducer'
import { syncTokenAccounts } from '../store/slices/balancesSlice'
import { useAppDispatch } from '../store/store'
diff --git a/src/utils/StoreAtaBalance.ts b/src/utils/StoreAtaBalance.ts
index 2e3717dca..04cc8f9b2 100644
--- a/src/utils/StoreAtaBalance.ts
+++ b/src/utils/StoreAtaBalance.ts
@@ -2,8 +2,8 @@ import { useTokenAccount } from '@helium/helium-react-hooks'
import { usePublicKey } from '@hooks/usePublicKey'
import { AccountLayout } from '@solana/spl-token'
import { useEffect } from 'react'
-import { useSolana } from '../solana/SolanaProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { balancesSlice } from '../store/slices/balancesSlice'
import { useAppDispatch } from '../store/store'
diff --git a/src/utils/StoreSolBalance.ts b/src/utils/StoreSolBalance.ts
index 92cf74464..44aad4af7 100644
--- a/src/utils/StoreSolBalance.ts
+++ b/src/utils/StoreSolBalance.ts
@@ -1,7 +1,7 @@
import { useSolOwnedAmount } from '@helium/helium-react-hooks'
import { usePublicKey } from '@hooks/usePublicKey'
import { useEffect } from 'react'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { balancesSlice } from '../store/slices/balancesSlice'
import { useAppDispatch } from '../store/store'
diff --git a/src/utils/StoreTokenBalance.ts b/src/utils/StoreTokenBalance.ts
index 25d29f74d..399aabf2c 100644
--- a/src/utils/StoreTokenBalance.ts
+++ b/src/utils/StoreTokenBalance.ts
@@ -2,8 +2,8 @@ import { useTokenAccount } from '@helium/helium-react-hooks'
import { AccountLayout } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
import { useEffect } from 'react'
-import { useSolana } from '../solana/SolanaProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { balancesSlice } from '../store/slices/balancesSlice'
import { useAppDispatch } from '../store/store'
diff --git a/src/utils/axios.ts b/src/utils/axios.ts
new file mode 100644
index 000000000..4ff523936
--- /dev/null
+++ b/src/utils/axios.ts
@@ -0,0 +1,24 @@
+import axios, { AxiosError } from 'axios'
+
+export const handleAxiosError = (e: unknown, verbose = true) => {
+ if (axios.isAxiosError(e)) {
+ const axiosError = e as AxiosError
+ const data = JSON.stringify(axiosError.response?.data, null, 2)
+ const status = axiosError.response?.status || axiosError.status
+ const { message } = axiosError
+ const url = axiosError.config?.url
+
+ let errMessage = message
+ if (verbose) {
+ errMessage = `Request ${url} failed: \nData: ${data}\nStatus: ${status}\nMessage: ${message}`
+ }
+ // logger.breadcrumb(errMessage)
+
+ // eslint-disable-next-line no-console
+ console.error(axiosError.request)
+ return errMessage
+ }
+ const msg = (e as Error).message || 'Unknown error'
+ // logger.breadcrumb(msg)
+ return msg
+}
diff --git a/src/utils/camera.ts b/src/utils/camera.ts
new file mode 100644
index 000000000..09d781f12
--- /dev/null
+++ b/src/utils/camera.ts
@@ -0,0 +1,32 @@
+import { Platform } from 'react-native'
+import {
+ check,
+ request,
+ PERMISSIONS,
+ PermissionStatus,
+} from 'react-native-permissions'
+
+export const getCameraPermissionStatus =
+ async (): Promise => {
+ try {
+ if (Platform.OS === 'android') {
+ return await check(PERMISSIONS.ANDROID.CAMERA)
+ }
+
+ return await check(PERMISSIONS.IOS.CAMERA)
+ } catch {
+ return 'unavailable'
+ }
+ }
+
+export const requestCameraPermission = async (): Promise => {
+ try {
+ if (Platform.OS === 'android') {
+ return await request(PERMISSIONS.ANDROID.CAMERA)
+ }
+
+ return await request(PERMISSIONS.IOS.CAMERA)
+ } catch {
+ return 'unavailable'
+ }
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 2aeff32b7..2c7b46c95 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -42,3 +42,9 @@ export const MIN_BALANCE_THRESHOLD = 0.02 * LAMPORTS_PER_SOL
// Make a smaller batch for the sake of ledger.
export const MAX_TRANSACTIONS_PER_SIGNATURE_BATCH = 5
+
+export const HELIUM_WORLD_POI =
+ 'mapbox://styles/petermain/cm2lwnp6k00b701qhepzz65no'
+
+export const HELIUM_WORLD_NO_LABELS =
+ 'mapbox://styles/petermain/cm2lwmt9k000a01nt3l29dhhu'
diff --git a/src/constants/urls.ts b/src/utils/constants/urls.ts
similarity index 90%
rename from src/constants/urls.ts
rename to src/utils/constants/urls.ts
index 0e5904e8c..82f8fe92e 100644
--- a/src/constants/urls.ts
+++ b/src/utils/constants/urls.ts
@@ -1,5 +1,5 @@
import { useCallback } from 'react'
-import { useSolana } from '../solana/SolanaProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
export const EXPLORER_MAINNET_BASE_URL = 'https://explorer.helium.com'
export const EXPLORER_TESTNET_BASE_URL = 'https://testnet-explorer.helium.com/'
@@ -11,6 +11,8 @@ export const PUBLIC_API_TEST_URL = 'https://testnet-api.helium.wtf/v1'
export const PRIVACY_POLICY = 'https://wallet.helium.com/privacy-policy'
export const TERMS_OF_SERVICE = 'https://wallet.helium.com/terms-of-service'
+export const HOTSPOT_HELP = 'https://hardware.hellohelium.com/en/'
+
type UrlType = 'block' | 'txn' | 'account' | 'validator' | 'hotspot'
const useCreateExplorerUrl = () => {
diff --git a/src/constants/wordlists/english.json b/src/utils/constants/wordlists/english.json
similarity index 100%
rename from src/constants/wordlists/english.json
rename to src/utils/constants/wordlists/english.json
diff --git a/src/utils/degree.ts b/src/utils/degree.ts
new file mode 100644
index 000000000..2bdf94b77
--- /dev/null
+++ b/src/utils/degree.ts
@@ -0,0 +1,22 @@
+export const degToCompass = (num: number) => {
+ const val = Math.floor(num / 22.5 + 0.5)
+ const arr = [
+ 'N',
+ 'NNE',
+ 'NE',
+ 'ENE',
+ 'E',
+ 'ESE',
+ 'SE',
+ 'SSE',
+ 'S',
+ 'SSW',
+ 'SW',
+ 'WSW',
+ 'W',
+ 'WNW',
+ 'NW',
+ 'NNW',
+ ]
+ return arr[val % 16]
+}
diff --git a/src/utils/i18n.tsx b/src/utils/i18n.tsx
index 5f8ae1aa8..f7a48db38 100644
--- a/src/utils/i18n.tsx
+++ b/src/utils/i18n.tsx
@@ -4,7 +4,7 @@ import * as RNLocalize from 'react-native-localize'
import { useCallback, useState } from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { useAsync } from 'react-async-hook'
-import en from '../locales/en'
+import en from '@config/locales/en'
const locales = RNLocalize.getLocales()
diff --git a/src/utils/linking.ts b/src/utils/linking.ts
index 2b4a59828..5b6586001 100644
--- a/src/utils/linking.ts
+++ b/src/utils/linking.ts
@@ -5,10 +5,10 @@ import BN from 'bn.js'
import * as Linking from 'expo-linking'
import qs from 'qs'
import queryString from 'query-string'
-import { BurnRouteParam } from '@services/WalletService/pages/WalletPage/WalletPageNavigator'
-import { PaymentRouteParam } from '@services/WalletService'
-import { RootStackParamList } from '../navigation/rootTypes'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { BurnRouteParam } from '@services/WalletService/pages/WalletPage'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { RootStackParamList } from '../app/rootTypes'
import { solAddressIsValid } from './accountUtils'
export const APP_LINK_SCHEME = Linking.createURL('')
diff --git a/src/utils/location.ts b/src/utils/location.ts
new file mode 100644
index 000000000..5132a61b4
--- /dev/null
+++ b/src/utils/location.ts
@@ -0,0 +1,44 @@
+import Config from 'react-native-config'
+import Geocoder from 'react-native-geocoding'
+
+export const getAddressFromLatLng = async (
+ latitude: number,
+ longitude: number,
+) => {
+ Geocoder.init(Config.GOOGLE_MAPS_API_KEY || '')
+ const geocode = await Geocoder.from({
+ latitude,
+ longitude,
+ })
+ const postalCode = geocode.results[0].address_components.find((c) =>
+ c.types.includes('postal_code'),
+ )?.short_name
+ const country = geocode.results[0].address_components.find((c) =>
+ c.types.includes('country'),
+ )?.short_name
+ let city = geocode.results[0].address_components.find(
+ (c) =>
+ c.types.includes('locality') || c.types.includes('sublocality_level_1'),
+ )?.long_name
+
+ const state = geocode.results[0].address_components.find((c) =>
+ c.types.includes('administrative_area_level_1'),
+ )?.short_name
+
+ const street = geocode.results[0].address_components.find((c) =>
+ c.types.includes('route'),
+ )?.long_name
+
+ if (!city) {
+ // if city is still not defined, and address components has a neighborhood, use that
+ // e.g. liverpool, NY
+ const neighborhood = geocode.results[0].address_components.find((c) =>
+ c.types.includes('neighborhood'),
+ )
+ if (neighborhood) {
+ city = neighborhood.long_name
+ }
+ }
+
+ return { city, postalCode, country, street, state }
+}
diff --git a/src/utils/makeApiToken.ts b/src/utils/makeApiToken.ts
index 60656c88a..d7358d801 100644
--- a/src/utils/makeApiToken.ts
+++ b/src/utils/makeApiToken.ts
@@ -1,4 +1,4 @@
-import { getKeypair } from '../storage/secureStorage'
+import { getKeypair } from '@config/storage/secureStorage'
const makeSignature = async (token: { address: string; time: number }) => {
const stringifiedToken = JSON.stringify(token)
diff --git a/src/components/map/utils.ts b/src/utils/mapUtils.ts
similarity index 81%
rename from src/components/map/utils.ts
rename to src/utils/mapUtils.ts
index 83e3568f4..3f0f5144d 100644
--- a/src/components/map/utils.ts
+++ b/src/utils/mapUtils.ts
@@ -1,6 +1,5 @@
+import { CameraPadding, CameraStop } from '@rnmapbox/maps'
import { ViewProps } from 'react-native'
-import { CameraStop } from '@maplibre/maplibre-react-native/javascript/components/Camera'
-import { CameraPadding } from '@maplibre/maplibre-react-native'
export const MIN_MAP_ZOOM = 2
export const MAX_MAP_ZOOM = 18
@@ -13,6 +12,10 @@ type CameraBounds = CameraPadding & {
const WORLD_BOUNDS: CameraBounds = {
ne: [-134.827109, 57.785781],
sw: [129.767893, -30.955724],
+ paddingLeft: 0,
+ paddingRight: 0,
+ paddingTop: 0,
+ paddingBottom: 0,
}
export const INITIAL_MAP_VIEW_STATE: {
@@ -24,7 +27,7 @@ export const INITIAL_MAP_VIEW_STATE: {
} = {
centerCoordinate: [-122.419418, 37.774929],
bounds: WORLD_BOUNDS,
- zoomLevel: 12,
+ zoomLevel: 17,
animationDuration: 500,
}
diff --git a/src/utils/reverseGeocode.ts b/src/utils/reverseGeocode.ts
new file mode 100644
index 000000000..a699ae071
--- /dev/null
+++ b/src/utils/reverseGeocode.ts
@@ -0,0 +1,66 @@
+import { useAsync } from 'react-async-hook'
+import Config from 'react-native-config'
+
+const reverseGeocode = async ({
+ token,
+ lat,
+ lng,
+}: {
+ token: string
+ lat: number
+ lng: number
+}) => {
+ if (!lat || !lng) return
+
+ const endpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${lng},${lat}.json?access_token=${token}`
+ const response = await fetch(endpoint)
+ const results = (await response.json()) as { features: Feature[] }
+ const features = (results?.features || []) as Feature[]
+ if (!features.length) return
+
+ return features[0]
+}
+
+export const useReverseGeo = (lat?: number, lng?: number) => {
+ return useAsync(async () => {
+ if (!Config.MAPBOX_ACCESS_TOKEN || !lat || !lng) return
+ return reverseGeocode({ token: Config.MAPBOX_ACCESS_TOKEN, lat, lng })
+ }, [lat, lng])
+}
+
+export default reverseGeocode
+
+export interface Feature {
+ id: string
+ type: string
+ place_type: string[]
+ relevance: number
+ properties: Properties
+ text: string
+ place_name: string
+ center: number[]
+ geometry: Geometry
+ address?: string
+ context?: Context[]
+ bbox?: number[]
+}
+
+export interface Properties {
+ accuracy?: string
+ mapbox_id?: string
+ wikidata?: string
+ short_code?: string
+}
+
+export interface Geometry {
+ type: string
+ coordinates: number[]
+}
+
+export interface Context {
+ id: string
+ mapbox_id?: string
+ text: string
+ wikidata?: string
+ short_code?: string
+}
diff --git a/src/utils/solanaUtils.ts b/src/utils/solanaUtils.ts
index b97593e1a..88cb94a30 100644
--- a/src/utils/solanaUtils.ts
+++ b/src/utils/solanaUtils.ts
@@ -117,7 +117,7 @@ import {
token,
walletAdapterIdentity,
} from '@metaplex-foundation/js'
-import { getSessionKey } from '../storage/secureStorage'
+import { getSessionKey } from '@config/storage/secureStorage'
import { Activity, Payment } from '../types/activity'
import {
Collectable,
@@ -931,7 +931,8 @@ export const getNFTs = async (
page,
'',
'',
- { showFungible: true },
+ // TODO: Update helium-program-library to support new options
+ { showFungible: true, showCollectionMetadata: true } as any,
)
return items
diff --git a/src/utils/useBalanceHistory.tsx b/src/utils/useBalanceHistory.tsx
index 029708902..8887c3f0d 100644
--- a/src/utils/useBalanceHistory.tsx
+++ b/src/utils/useBalanceHistory.tsx
@@ -1,12 +1,12 @@
import { useEffect, useRef } from 'react'
import { AppState } from 'react-native'
import { useSelector } from 'react-redux'
-import { useAppStorage } from '../storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
import { RootState } from '../store/rootReducer'
import { useAppDispatch } from '../store/store'
import { readBalanceHistory } from '../store/slices/balancesSlice'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
-import { useSolana } from '../solana/SolanaProvider'
export const useBalanceHistory = () => {
const { currentAccount } = useAccountStorage()
diff --git a/src/utils/usePollTokenPrices.tsx b/src/utils/usePollTokenPrices.tsx
index bb0a099c2..8e56e3200 100644
--- a/src/utils/usePollTokenPrices.tsx
+++ b/src/utils/usePollTokenPrices.tsx
@@ -1,6 +1,6 @@
import { useCallback, useEffect } from 'react'
import { useSelector } from 'react-redux'
-import { useAppStorage } from '../storage/AppStorageProvider'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { RootState } from '../store/rootReducer'
import { useAppDispatch } from '../store/store'
import { readTokenPrices } from '../store/slices/balancesSlice'
diff --git a/src/utils/walletApiV2.ts b/src/utils/walletApiV2.ts
index 42423a534..f5b631c86 100644
--- a/src/utils/walletApiV2.ts
+++ b/src/utils/walletApiV2.ts
@@ -2,10 +2,10 @@ import axios from 'axios'
import Config from 'react-native-config'
import { Cluster } from '@solana/web3.js'
import { heliumAddressFromSolAddress } from '@helium/spl-utils'
-import { getSecureItem } from '../storage/secureStorage'
+import { getSecureItem } from '@config/storage/secureStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { AccountBalance, Prices } from '../types/balance'
import makeApiToken from './makeApiToken'
-import { CSAccount } from '../storage/cloudStorage'
export type Notification = {
title: string
diff --git a/tsconfig.json b/tsconfig.json
index ce20e39d7..98139a039 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -42,16 +42,15 @@
"@helium/crypto": ["./node_modules/@helium/crypto-react-native"],
"@assets": ["./src/assets"],
"@components/*": ["./src/components/*"],
- "@constants/*": ["./src/constants/*"],
"@components": ["src/components/index"],
"@hooks/*": ["./src/hooks/*"],
- "@theme/*": ["./src/theme/*"],
"@utils/*": ["./src/utils/*"],
- "@storage/*": ["./src/storage/*"],
+ "@config/*": ["./src/config/*"],
"@types/*": ["./src/types/*"],
"@features/*": ["./src/features/*"],
- "@services/*": ["./src/services/*"],
- "@store/*": ["./src/store/*"]
+ "@services/*": ["src/app/services/*"],
+ "@store/*": ["./src/store/*"],
+ "@app/*": ["./src/app/*"]
}
},
"exclude": [
diff --git a/yarn.lock b/yarn.lock
index 2fae13c8c..4831d31e1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -34,6 +34,44 @@ __metadata:
languageName: node
linkType: hard
+"@ardatan/relay-compiler@npm:12.0.0":
+ version: 12.0.0
+ resolution: "@ardatan/relay-compiler@npm:12.0.0"
+ dependencies:
+ "@babel/core": ^7.14.0
+ "@babel/generator": ^7.14.0
+ "@babel/parser": ^7.14.0
+ "@babel/runtime": ^7.0.0
+ "@babel/traverse": ^7.14.0
+ "@babel/types": ^7.0.0
+ babel-preset-fbjs: ^3.4.0
+ chalk: ^4.0.0
+ fb-watchman: ^2.0.0
+ fbjs: ^3.0.0
+ glob: ^7.1.1
+ immutable: ~3.7.6
+ invariant: ^2.2.4
+ nullthrows: ^1.1.1
+ relay-runtime: 12.0.0
+ signedsource: ^1.0.0
+ yargs: ^15.3.1
+ peerDependencies:
+ graphql: "*"
+ bin:
+ relay-compiler: bin/relay-compiler
+ checksum: f0cec120d02961ee8652e0dde72d9e425bc97cad5d0f767d8764cfd30952294eb2838432f33e4da8bb6999d0c13dcd1df128280666bfea373294d98aa8033ae7
+ languageName: node
+ linkType: hard
+
+"@ardatan/sync-fetch@npm:^0.0.1":
+ version: 0.0.1
+ resolution: "@ardatan/sync-fetch@npm:0.0.1"
+ dependencies:
+ node-fetch: ^2.6.1
+ checksum: af39bdfb4c2b35bd2c6acc540a5e302730dae17e73d3a18cd1a4aa50c1c741cb1869dffdef1379c491da5ad2e3cfa2bf3a8064e6046c12b46c6a97f54f100a8d
+ languageName: node
+ linkType: hard
+
"@azure/core-asynciterator-polyfill@npm:^1.0.2":
version: 1.0.2
resolution: "@azure/core-asynciterator-polyfill@npm:1.0.2"
@@ -69,6 +107,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0":
+ version: 7.26.2
+ resolution: "@babel/code-frame@npm:7.26.2"
+ dependencies:
+ "@babel/helper-validator-identifier": ^7.25.9
+ js-tokens: ^4.0.0
+ picocolors: ^1.0.0
+ checksum: db13f5c42d54b76c1480916485e6900748bbcb0014a8aca87f50a091f70ff4e0d0a6db63cade75eb41fcc3d2b6ba0a7f89e343def4f96f00269b41b8ab8dd7b8
+ languageName: node
+ linkType: hard
+
"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.1, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/compat-data@npm:7.25.2"
@@ -76,6 +125,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/compat-data@npm:^7.25.9":
+ version: 7.26.2
+ resolution: "@babel/compat-data@npm:7.26.2"
+ checksum: d52fae9b0dc59b409d6005ae6b172e89329f46d68136130065ebe923a156fc633e0f1c8600b3e319b9e0f99fd948f64991a5419e2e9431d00d9d235d5f7a7618
+ languageName: node
+ linkType: hard
+
"@babel/core@npm:7.20.12":
version: 7.20.12
resolution: "@babel/core@npm:7.20.12"
@@ -122,6 +178,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/core@npm:^7.14.0, @babel/core@npm:^7.22.9":
+ version: 7.26.0
+ resolution: "@babel/core@npm:7.26.0"
+ dependencies:
+ "@ampproject/remapping": ^2.2.0
+ "@babel/code-frame": ^7.26.0
+ "@babel/generator": ^7.26.0
+ "@babel/helper-compilation-targets": ^7.25.9
+ "@babel/helper-module-transforms": ^7.26.0
+ "@babel/helpers": ^7.26.0
+ "@babel/parser": ^7.26.0
+ "@babel/template": ^7.25.9
+ "@babel/traverse": ^7.25.9
+ "@babel/types": ^7.26.0
+ convert-source-map: ^2.0.0
+ debug: ^4.1.0
+ gensync: ^1.0.0-beta.2
+ json5: ^2.2.3
+ semver: ^6.3.1
+ checksum: b296084cfd818bed8079526af93b5dfa0ba70282532d2132caf71d4060ab190ba26d3184832a45accd82c3c54016985a4109ab9118674347a7e5e9bc464894e6
+ languageName: node
+ linkType: hard
+
"@babel/eslint-parser@npm:^7.20.0":
version: 7.25.1
resolution: "@babel/eslint-parser@npm:7.25.1"
@@ -136,6 +215,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0":
+ version: 7.26.2
+ resolution: "@babel/generator@npm:7.26.2"
+ dependencies:
+ "@babel/parser": ^7.26.2
+ "@babel/types": ^7.26.0
+ "@jridgewell/gen-mapping": ^0.3.5
+ "@jridgewell/trace-mapping": ^0.3.25
+ jsesc: ^3.0.2
+ checksum: 6ff850b7d6082619f8c2f518d993cf7254cfbaa20b026282cbef5c9b2197686d076a432b18e36c4d1a42721c016df4f77a8f62c67600775d9683621d534b91b4
+ languageName: node
+ linkType: hard
+
"@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.20.5, @babel/generator@npm:^7.20.7, @babel/generator@npm:^7.22.15, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.7.2":
version: 7.25.0
resolution: "@babel/generator@npm:7.25.0"
@@ -179,6 +271,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-compilation-targets@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-compilation-targets@npm:7.25.9"
+ dependencies:
+ "@babel/compat-data": ^7.25.9
+ "@babel/helper-validator-option": ^7.25.9
+ browserslist: ^4.24.0
+ lru-cache: ^5.1.1
+ semver: ^6.3.1
+ checksum: 3af536e2db358b38f968abdf7d512d425d1018fef2f485d6f131a57a7bcaed32c606b4e148bb230e1508fa42b5b2ac281855a68eb78270f54698c48a83201b9b
+ languageName: node
+ linkType: hard
+
"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.22.5, @babel/helper-create-class-features-plugin@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-create-class-features-plugin@npm:7.25.0"
@@ -286,6 +391,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-imports@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-module-imports@npm:7.25.9"
+ dependencies:
+ "@babel/traverse": ^7.25.9
+ "@babel/types": ^7.25.9
+ checksum: 1b411ce4ca825422ef7065dffae7d8acef52023e51ad096351e3e2c05837e9bf9fca2af9ca7f28dc26d596a588863d0fedd40711a88e350b736c619a80e704e6
+ languageName: node
+ linkType: hard
+
"@babel/helper-module-transforms@npm:^7.20.11, @babel/helper-module-transforms@npm:^7.22.20, @babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9, @babel/helper-module-transforms@npm:^7.24.8":
version: 7.25.2
resolution: "@babel/helper-module-transforms@npm:7.25.2"
@@ -300,6 +415,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-transforms@npm:^7.26.0":
+ version: 7.26.0
+ resolution: "@babel/helper-module-transforms@npm:7.26.0"
+ dependencies:
+ "@babel/helper-module-imports": ^7.25.9
+ "@babel/helper-validator-identifier": ^7.25.9
+ "@babel/traverse": ^7.25.9
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 942eee3adf2b387443c247a2c190c17c4fd45ba92a23087abab4c804f40541790d51ad5277e4b5b1ed8d5ba5b62de73857446b7742f835c18ebd350384e63917
+ languageName: node
+ linkType: hard
+
"@babel/helper-optimise-call-expression@npm:^7.22.5, @babel/helper-optimise-call-expression@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-optimise-call-expression@npm:7.24.7"
@@ -378,6 +506,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-string-parser@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-string-parser@npm:7.25.9"
+ checksum: 6435ee0849e101681c1849868278b5aee82686ba2c1e27280e5e8aca6233af6810d39f8e4e693d2f2a44a3728a6ccfd66f72d71826a94105b86b731697cdfa99
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-validator-identifier@npm:7.24.7"
@@ -385,6 +520,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-identifier@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-validator-identifier@npm:7.25.9"
+ checksum: 5b85918cb1a92a7f3f508ea02699e8d2422fe17ea8e82acd445006c0ef7520fbf48e3dbcdaf7b0a1d571fc3a2715a29719e5226636cb6042e15fe6ed2a590944
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.21.0, @babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-validator-option@npm:7.24.8"
@@ -392,6 +534,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-option@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-validator-option@npm:7.25.9"
+ checksum: 9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d
+ languageName: node
+ linkType: hard
+
"@babel/helper-wrap-function@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-wrap-function@npm:7.25.0"
@@ -414,6 +563,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helpers@npm:^7.26.0":
+ version: 7.26.0
+ resolution: "@babel/helpers@npm:7.26.0"
+ dependencies:
+ "@babel/template": ^7.25.9
+ "@babel/types": ^7.26.0
+ checksum: d77fe8d45033d6007eadfa440355c1355eed57902d5a302f450827ad3d530343430a21210584d32eef2f216ae463d4591184c6fc60cf205bbf3a884561469200
+ languageName: node
+ linkType: hard
+
"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/highlight@npm:7.24.7"
@@ -437,6 +596,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/parser@npm:^7.14.0, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2":
+ version: 7.26.2
+ resolution: "@babel/parser@npm:7.26.2"
+ dependencies:
+ "@babel/types": ^7.26.0
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: c88b5ea0adf357ef909cdc2c31e284a154943edc59f63f6e8a4c20bf773a1b2f3d8c2205e59c09ca7cdad91e7466300114548876529277a80651b6436a48d5d9
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6":
version: 7.22.15
resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15"
@@ -1717,6 +1887,32 @@ __metadata:
languageName: node
linkType: hard
+"@babel/template@npm:^7.18.10, @babel/template@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/template@npm:7.25.9"
+ dependencies:
+ "@babel/code-frame": ^7.25.9
+ "@babel/parser": ^7.25.9
+ "@babel/types": ^7.25.9
+ checksum: 103641fea19c7f4e82dc913aa6b6ac157112a96d7c724d513288f538b84bae04fb87b1f1e495ac1736367b1bc30e10f058b30208fb25f66038e1f1eb4e426472
+ languageName: node
+ linkType: hard
+
+"@babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/traverse@npm:7.25.9"
+ dependencies:
+ "@babel/code-frame": ^7.25.9
+ "@babel/generator": ^7.25.9
+ "@babel/parser": ^7.25.9
+ "@babel/template": ^7.25.9
+ "@babel/types": ^7.25.9
+ debug: ^4.3.1
+ globals: ^11.1.0
+ checksum: 901d325662ff1dd9bc51de00862e01055fa6bc374f5297d7e3731f2f0e268bbb1d2141f53fa82860aa308ee44afdcf186a948f16c83153927925804b95a9594d
+ languageName: node
+ linkType: hard
+
"@babel/traverse@npm:^7.20.0, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.22.15, @babel/traverse@npm:^7.22.20, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.2":
version: 7.25.3
resolution: "@babel/traverse@npm:7.25.3"
@@ -1743,6 +1939,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0":
+ version: 7.26.0
+ resolution: "@babel/types@npm:7.26.0"
+ dependencies:
+ "@babel/helper-string-parser": ^7.25.9
+ "@babel/helper-validator-identifier": ^7.25.9
+ checksum: a3dd37dabac693018872da96edb8c1843a605c1bfacde6c3f504fba79b972426a6f24df70aa646356c0c1b19bdd2c722c623c684a996c002381071680602280d
+ languageName: node
+ linkType: hard
+
"@bcoe/v8-coverage@npm:^0.2.3":
version: 0.2.3
resolution: "@bcoe/v8-coverage@npm:0.2.3"
@@ -2486,36 +2692,6 @@ __metadata:
languageName: node
linkType: hard
-"@expo/config-plugins@npm:^4.0.3":
- version: 4.1.5
- resolution: "@expo/config-plugins@npm:4.1.5"
- dependencies:
- "@expo/config-types": ^45.0.0
- "@expo/json-file": 8.2.36
- "@expo/plist": 0.0.18
- "@expo/sdk-runtime-versions": ^1.0.0
- "@react-native/normalize-color": ^2.0.0
- chalk: ^4.1.2
- debug: ^4.3.1
- find-up: ~5.0.0
- getenv: ^1.0.0
- glob: 7.1.6
- resolve-from: ^5.0.0
- semver: ^7.3.5
- slash: ^3.0.0
- xcode: ^3.0.1
- xml2js: 0.4.23
- checksum: f631217251281b1e25949adbec175ef1362dd08d837ce676ed8350c1401b5764091ba100f76f42adb623e4cdcde5b270be77ad6606f978d419c07fd8c81b701c
- languageName: node
- linkType: hard
-
-"@expo/config-types@npm:^45.0.0":
- version: 45.0.0
- resolution: "@expo/config-types@npm:45.0.0"
- checksum: 9b4866540654da61af0985ebfc975b3cb690625acf7742443a7e56263bf134b261e22719720982223407f8957d08a3646178c79f482861218882f0956d804021
- languageName: node
- linkType: hard
-
"@expo/config-types@npm:^51.0.0-unreleased":
version: 51.0.2
resolution: "@expo/config-types@npm:51.0.2"
@@ -2594,17 +2770,6 @@ __metadata:
languageName: node
linkType: hard
-"@expo/json-file@npm:8.2.36":
- version: 8.2.36
- resolution: "@expo/json-file@npm:8.2.36"
- dependencies:
- "@babel/code-frame": ~7.10.4
- json5: ^1.0.1
- write-file-atomic: ^2.3.0
- checksum: 37ce80b3472fef2a56136ebff5993d98ab4fbd45c4d7791ff47be80438dbeabd84bc699a401da0c314357ef65d8fff87a5a1241b3119db2d575878f9321bd1e7
- languageName: node
- linkType: hard
-
"@expo/json-file@npm:^8.3.0, @expo/json-file@npm:~8.3.0":
version: 8.3.3
resolution: "@expo/json-file@npm:8.3.3"
@@ -2672,17 +2837,6 @@ __metadata:
languageName: node
linkType: hard
-"@expo/plist@npm:0.0.18":
- version: 0.0.18
- resolution: "@expo/plist@npm:0.0.18"
- dependencies:
- "@xmldom/xmldom": ~0.7.0
- base64-js: ^1.2.3
- xmlbuilder: ^14.0.0
- checksum: 42f5743fcd2a07b55a9f048d27cf0f273510ab35dde1f7030b22dc8c30ab2cfb65c6e68f8aa58fbcfa00177fdc7c9696d0004083c9a47c36fd4ac7fea27d6ccc
- languageName: node
- linkType: hard
-
"@expo/plist@npm:^0.1.0":
version: 0.1.3
resolution: "@expo/plist@npm:0.1.3"
@@ -2710,165 +2864,866 @@ __metadata:
semver: ^7.6.0
xml2js: 0.6.0
peerDependencies:
- expo-modules-autolinking: ">=0.8.1"
- checksum: 7210870c33b0fd78c4a1e758f801af3f47e16cf67a3a4a46a12bb10ad242e7925ec7f027dc348b6b4121c04ab76924630730f49debe086ccb95f72dc11c39c10
+ expo-modules-autolinking: ">=0.8.1"
+ checksum: 7210870c33b0fd78c4a1e758f801af3f47e16cf67a3a4a46a12bb10ad242e7925ec7f027dc348b6b4121c04ab76924630730f49debe086ccb95f72dc11c39c10
+ languageName: node
+ linkType: hard
+
+"@expo/prebuild-config@npm:7.0.8":
+ version: 7.0.8
+ resolution: "@expo/prebuild-config@npm:7.0.8"
+ dependencies:
+ "@expo/config": ~9.0.0-beta.0
+ "@expo/config-plugins": ~8.0.8
+ "@expo/config-types": ^51.0.0-unreleased
+ "@expo/image-utils": ^0.5.0
+ "@expo/json-file": ^8.3.0
+ "@react-native/normalize-colors": 0.74.85
+ debug: ^4.3.1
+ fs-extra: ^9.0.0
+ resolve-from: ^5.0.0
+ semver: ^7.6.0
+ xml2js: 0.6.0
+ peerDependencies:
+ expo-modules-autolinking: ">=0.8.1"
+ checksum: b3715b10aa5aa9e60e97802feaaa6ddca4330752ec566d9f272e23417d00e2a298b6cc2f0d33f8a46a3c907f10b862d2975b737ba10e194ac834eae48847923b
+ languageName: node
+ linkType: hard
+
+"@expo/rudder-sdk-node@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@expo/rudder-sdk-node@npm:1.1.1"
+ dependencies:
+ "@expo/bunyan": ^4.0.0
+ "@segment/loosely-validate-event": ^2.0.0
+ fetch-retry: ^4.1.1
+ md5: ^2.2.1
+ node-fetch: ^2.6.1
+ remove-trailing-slash: ^0.1.0
+ uuid: ^8.3.2
+ checksum: 5ce50c1a82f899b135600cb29cddf3fab601938700c8203f16a1394d2ffbf9e2cdd246b92ff635f8415121072d99a7b4a370f715b78f6680594b5a630e8d78c6
+ languageName: node
+ linkType: hard
+
+"@expo/sdk-runtime-versions@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "@expo/sdk-runtime-versions@npm:1.0.0"
+ checksum: 0942d5a356f590e8dc795761456cc48b3e2d6a38ad2a02d6774efcdc5a70424e05623b4e3e5d2fec0cdc30f40dde05c14391c781607eed3971bf8676518bfd9d
+ languageName: node
+ linkType: hard
+
+"@expo/spawn-async@npm:^1.5.0, @expo/spawn-async@npm:^1.7.2":
+ version: 1.7.2
+ resolution: "@expo/spawn-async@npm:1.7.2"
+ dependencies:
+ cross-spawn: ^7.0.3
+ checksum: d99e5ff6d303ec9b0105f97c4fa6c65bca526c7d4d0987997c35cc745fa8224adf009942d01808192ebb9fa30619a53316641958631e85cf17b773d9eeda2597
+ languageName: node
+ linkType: hard
+
+"@expo/vector-icons@npm:^14.0.0":
+ version: 14.0.2
+ resolution: "@expo/vector-icons@npm:14.0.2"
+ dependencies:
+ prop-types: ^15.8.1
+ checksum: 49e27ff52eb138745313fa2c39863fb762230b0089b910d668d7f2c06b7e71a0249dc3a26bfc8725d07bdfaadab1dbcbce087b34dfc244b00a15fc02fe4866e2
+ languageName: node
+ linkType: hard
+
+"@expo/xcpretty@npm:^4.3.0":
+ version: 4.3.1
+ resolution: "@expo/xcpretty@npm:4.3.1"
+ dependencies:
+ "@babel/code-frame": 7.10.4
+ chalk: ^4.1.0
+ find-up: ^5.0.0
+ js-yaml: ^4.1.0
+ bin:
+ excpretty: build/cli.js
+ checksum: dbf3e2d7f501fbbd11baf0c0aa9057c8a87efe0993a82caafd30c66977ac430d03fa84e27b529e3d0b04fee8c6beec1bd135f0522229dca91220561b76309854
+ languageName: node
+ linkType: hard
+
+"@fastify/ajv-compiler@npm:^3.5.0":
+ version: 3.5.0
+ resolution: "@fastify/ajv-compiler@npm:3.5.0"
+ dependencies:
+ ajv: ^8.11.0
+ ajv-formats: ^2.1.1
+ fast-uri: ^2.0.0
+ checksum: 5e5b16469f8d586473d0b32e3a9cf38c0d86ef2a6fb7ea12ed7f3665642bd8eb2dde9adcc317814369cb5a58210bfdac35996fa87d1cc23e88bbc799f0b128b0
+ languageName: node
+ linkType: hard
+
+"@fastify/cors@npm:^8.1.1":
+ version: 8.4.0
+ resolution: "@fastify/cors@npm:8.4.0"
+ dependencies:
+ fastify-plugin: ^4.0.0
+ mnemonist: 0.39.5
+ checksum: 4fe99623918b9c58f6590dac00fe778f2755eacc47de726acf97b3a3305a414425b393422429efca1b261514100f4092a4ad41bc549c6f6edf60e83f9f5d3701
+ languageName: node
+ linkType: hard
+
+"@fastify/deepmerge@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "@fastify/deepmerge@npm:1.3.0"
+ checksum: 33ec927905dca320d7ae9535a1521909f7c82339706345324ab6287ad100589a799b8257c15b0e582c7bb74e2aa4883d82ba0228d7b116aa8789ada4f78d6974
+ languageName: node
+ linkType: hard
+
+"@fastify/error@npm:^3.2.0":
+ version: 3.3.0
+ resolution: "@fastify/error@npm:3.3.0"
+ checksum: 202507c8c7f49922cac2f5afc82802151b0bd9c583ca1c2850bf43d0f4cd97eedb3a3388b9016da74f8a01b517a5861d1f666c506dd64fd22995e559bc139264
+ languageName: node
+ linkType: hard
+
+"@fastify/fast-json-stringify-compiler@npm:^4.3.0":
+ version: 4.3.0
+ resolution: "@fastify/fast-json-stringify-compiler@npm:4.3.0"
+ dependencies:
+ fast-json-stringify: ^5.7.0
+ checksum: 2734afabe2539d3e15d2bd9f8dfee756d9cd969f7303dc085dd91c744ff61742bb0d3ebd3b561cf3c32be54567048a634b4962f943eb6bd9ed3fbd71cbf6a4fa
+ languageName: node
+ linkType: hard
+
+"@gorhom/bottom-sheet@npm:5.0.4":
+ version: 5.0.4
+ resolution: "@gorhom/bottom-sheet@npm:5.0.4"
+ dependencies:
+ "@gorhom/portal": 1.0.14
+ invariant: ^2.2.4
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-native": "*"
+ react: "*"
+ react-native: "*"
+ react-native-gesture-handler: ">=2.16.1"
+ react-native-reanimated: ">=3.10.1"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-native":
+ optional: true
+ checksum: 7ccfca84b0c9555efaa127ef17b6f2a16c15ec48f0db12bde146da9c86d599d126abb2cb8eecfb33811c26574a5ceddaee87d995d5e90ad7166770d6675c414b
+ languageName: node
+ linkType: hard
+
+"@gorhom/portal@npm:1.0.14":
+ version: 1.0.14
+ resolution: "@gorhom/portal@npm:1.0.14"
+ dependencies:
+ nanoid: ^3.3.1
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: 227bb96a2db854ab29bb9da8d4f3823c7f7448358de459709dd1b78522110da564c9a8734c6bc7d7153ed7c99320e0fb5d60b420c2ebb75ecaf2f0d757f410f9
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/add@npm:^5.0.3":
+ version: 5.0.3
+ resolution: "@graphql-codegen/add@npm:5.0.3"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.0.3
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 5196b6c64907f03dc1adc0ac4f98ed5fe69abe0eb87027a55dfc14b178cc1fee2bc47f68c8f5a68ce7aa4bc5a4f970f983d1d85b6d7a20489e50657baccd2ad0
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/cli@npm:^5.0.0":
+ version: 5.0.3
+ resolution: "@graphql-codegen/cli@npm:5.0.3"
+ dependencies:
+ "@babel/generator": ^7.18.13
+ "@babel/template": ^7.18.10
+ "@babel/types": ^7.18.13
+ "@graphql-codegen/client-preset": ^4.4.0
+ "@graphql-codegen/core": ^4.0.2
+ "@graphql-codegen/plugin-helpers": ^5.0.3
+ "@graphql-tools/apollo-engine-loader": ^8.0.0
+ "@graphql-tools/code-file-loader": ^8.0.0
+ "@graphql-tools/git-loader": ^8.0.0
+ "@graphql-tools/github-loader": ^8.0.0
+ "@graphql-tools/graphql-file-loader": ^8.0.0
+ "@graphql-tools/json-file-loader": ^8.0.0
+ "@graphql-tools/load": ^8.0.0
+ "@graphql-tools/prisma-loader": ^8.0.0
+ "@graphql-tools/url-loader": ^8.0.0
+ "@graphql-tools/utils": ^10.0.0
+ "@whatwg-node/fetch": ^0.9.20
+ chalk: ^4.1.0
+ cosmiconfig: ^8.1.3
+ debounce: ^1.2.0
+ detect-indent: ^6.0.0
+ graphql-config: ^5.1.1
+ inquirer: ^8.0.0
+ is-glob: ^4.0.1
+ jiti: ^1.17.1
+ json-to-pretty-yaml: ^1.2.2
+ listr2: ^4.0.5
+ log-symbols: ^4.0.0
+ micromatch: ^4.0.5
+ shell-quote: ^1.7.3
+ string-env-interpolation: ^1.0.1
+ ts-log: ^2.2.3
+ tslib: ^2.4.0
+ yaml: ^2.3.1
+ yargs: ^17.0.0
+ peerDependencies:
+ "@parcel/watcher": ^2.1.0
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ peerDependenciesMeta:
+ "@parcel/watcher":
+ optional: true
+ bin:
+ gql-gen: cjs/bin.js
+ graphql-code-generator: cjs/bin.js
+ graphql-codegen: cjs/bin.js
+ graphql-codegen-esm: esm/bin.js
+ checksum: 8a28419b25e73b4edf5006a93243a24ecdcc030b80d19dbf9153326c45382b2654b9275fa5b29035864652e3698196883e93ba593339cba43221c46cc20da697
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/client-preset@npm:^4.4.0":
+ version: 4.5.0
+ resolution: "@graphql-codegen/client-preset@npm:4.5.0"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.20.2
+ "@babel/template": ^7.20.7
+ "@graphql-codegen/add": ^5.0.3
+ "@graphql-codegen/gql-tag-operations": 4.0.11
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-codegen/typed-document-node": ^5.0.11
+ "@graphql-codegen/typescript": ^4.1.1
+ "@graphql-codegen/typescript-operations": ^4.3.1
+ "@graphql-codegen/visitor-plugin-common": ^5.5.0
+ "@graphql-tools/documents": ^1.0.0
+ "@graphql-tools/utils": ^10.0.0
+ "@graphql-typed-document-node/core": 3.2.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 8247074bdb5210c2822e1f3d9c6a37c21d642a4d2241424f1afefdd3a7a29a984da8b9efd250876d6b8f89e056661c70ed70cb96060e71d0f36d5339405f5ed9
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/core@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "@graphql-codegen/core@npm:4.0.2"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.0.3
+ "@graphql-tools/schema": ^10.0.0
+ "@graphql-tools/utils": ^10.0.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 5fda4e843174aacd4a481b73b4d259fa2df7ffe4200bd06e95ecd4b3f43aa5969deeaeb51f6cf15a542e99ee5756c3e02a29d9d2ff9891af40e234a8f68ead4d
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/gql-tag-operations@npm:4.0.11":
+ version: 4.0.11
+ resolution: "@graphql-codegen/gql-tag-operations@npm:4.0.11"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-codegen/visitor-plugin-common": 5.5.0
+ "@graphql-tools/utils": ^10.0.0
+ auto-bind: ~4.0.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 68d5eac31547b7012551a72a41caa2be532b85e08efe3efaf7744f27ea4b355a59f032a99f3394b1c2d0eea045d30e2216bf5d86379cbc0e926bf51cb12b4de2
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/plugin-helpers@npm:^2.7.2":
+ version: 2.7.2
+ resolution: "@graphql-codegen/plugin-helpers@npm:2.7.2"
+ dependencies:
+ "@graphql-tools/utils": ^8.8.0
+ change-case-all: 1.0.14
+ common-tags: 1.8.2
+ import-from: 4.0.0
+ lodash: ~4.17.0
+ tslib: ~2.4.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 66e0d507ad5db60b67092ebf7632d464d56ab446ac8fd87c293e00d9016944912d8cf9199e3e026b0a9247a50f50c4118a44f49e13675db64211652cd6259b05
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/plugin-helpers@npm:^3.0.0":
+ version: 3.1.2
+ resolution: "@graphql-codegen/plugin-helpers@npm:3.1.2"
+ dependencies:
+ "@graphql-tools/utils": ^9.0.0
+ change-case-all: 1.0.15
+ common-tags: 1.8.2
+ import-from: 4.0.0
+ lodash: ~4.17.0
+ tslib: ~2.4.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 4d0c615738570681b5ffd3c07305a35d6aa3e5fd87c9199c0a670b95529ab865b1df978ce584d5b415107a567ac484e56a48db129a6d1d2eb8a254fbd3260e39
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/plugin-helpers@npm:^5.0.3, @graphql-codegen/plugin-helpers@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "@graphql-codegen/plugin-helpers@npm:5.1.0"
+ dependencies:
+ "@graphql-tools/utils": ^10.0.0
+ change-case-all: 1.0.15
+ common-tags: 1.8.2
+ import-from: 4.0.0
+ lodash: ~4.17.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 235762e2e7a55898e71fb1d52ef3093c26787c16e7eb5a3df6e06a7b2003da641b9a9c96833091e9fb11f9cf72da9e7c5f19ce124074d5d7d33a419117d050a9
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/schema-ast@npm:^4.0.2":
+ version: 4.1.0
+ resolution: "@graphql-codegen/schema-ast@npm:4.1.0"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.0.3
+ "@graphql-tools/utils": ^10.0.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: cddec7723d708990ac8e33eb8935e72545b60ed7b772452ba45b60e577af950d23503de83f0919d1730f7d52dcb970900d3587d9a54202032164ba3c246d4c10
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/typed-document-node@npm:^5.0.11":
+ version: 5.0.11
+ resolution: "@graphql-codegen/typed-document-node@npm:5.0.11"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-codegen/visitor-plugin-common": 5.5.0
+ auto-bind: ~4.0.0
+ change-case-all: 1.0.15
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: c14b16c06910181355c4b3b0d01e023ca394889cf18c1262841280c84c2c00a27692359d8703d4545832183749f185ebf0d519b1ca6970043fce6fb8687aaa9c
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/typescript-operations@npm:^4.0.1, @graphql-codegen/typescript-operations@npm:^4.3.1":
+ version: 4.3.1
+ resolution: "@graphql-codegen/typescript-operations@npm:4.3.1"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-codegen/typescript": ^4.1.1
+ "@graphql-codegen/visitor-plugin-common": 5.5.0
+ auto-bind: ~4.0.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 9618fb8287d6f5d94942da67e48826ae85d9ed2df376a4da686f37438492a4870f209f0473356abd3140762d34021f4c8166a7c8cab63ace8be5f423a8e2f0d3
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/typescript-rtk-query@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "@graphql-codegen/typescript-rtk-query@npm:3.1.1"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^3.0.0
+ "@graphql-codegen/visitor-plugin-common": 2.13.1
+ auto-bind: ~4.0.0
+ change-case-all: 1.0.15
+ tslib: ~2.6.0
+ peerDependencies:
+ "@reduxjs/toolkit": ^1.6.0 || ^2.0.0
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ graphql-request: ^3.4.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
+ graphql-tag: ^2.0.0
+ peerDependenciesMeta:
+ graphql-request:
+ optional: true
+ checksum: 662fb0f3c647c0e09d566b69d21c5ec3f0856d3f33d9efac2c0ed3308a33a9a71ca6058f5a182b26366d5bf4dce077839bb6deb9cfbaa2283e2626cc6b81c68e
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/typescript@npm:^4.0.1, @graphql-codegen/typescript@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "@graphql-codegen/typescript@npm:4.1.1"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-codegen/schema-ast": ^4.0.2
+ "@graphql-codegen/visitor-plugin-common": 5.5.0
+ auto-bind: ~4.0.0
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 4256dbf935a6780c573864f346b9280271711ea1fe0c746146480faacd77c3b5578479b3daf584a987f3fd83ecfabf486f9cfc58b068460fabae32ee33fbc565
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/visitor-plugin-common@npm:2.13.1":
+ version: 2.13.1
+ resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.1"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^2.7.2
+ "@graphql-tools/optimize": ^1.3.0
+ "@graphql-tools/relay-operation-optimizer": ^6.5.0
+ "@graphql-tools/utils": ^8.8.0
+ auto-bind: ~4.0.0
+ change-case-all: 1.0.14
+ dependency-graph: ^0.11.0
+ graphql-tag: ^2.11.0
+ parse-filepath: ^1.0.2
+ tslib: ~2.4.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 0c329aa6e435602f2f6c1569ec2091b7850f58cc5dca7ac763c38c82588545ec1110c1de587f5f3949b11ff96f94401d1e63e329607d78424583b276fd08f1ae
+ languageName: node
+ linkType: hard
+
+"@graphql-codegen/visitor-plugin-common@npm:5.5.0, @graphql-codegen/visitor-plugin-common@npm:^5.5.0":
+ version: 5.5.0
+ resolution: "@graphql-codegen/visitor-plugin-common@npm:5.5.0"
+ dependencies:
+ "@graphql-codegen/plugin-helpers": ^5.1.0
+ "@graphql-tools/optimize": ^2.0.0
+ "@graphql-tools/relay-operation-optimizer": ^7.0.0
+ "@graphql-tools/utils": ^10.0.0
+ auto-bind: ~4.0.0
+ change-case-all: 1.0.15
+ dependency-graph: ^0.11.0
+ graphql-tag: ^2.11.0
+ parse-filepath: ^1.0.2
+ tslib: ~2.6.0
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 7d2727100be2acdb3a75292093013892bc819c5166905c0d6eab21c5c46561744a2fab252fb43f6b60d4afec8d565416ae7848c2abc413cda7924ef7a7fb6633
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/apollo-engine-loader@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "@graphql-tools/apollo-engine-loader@npm:8.0.3"
+ dependencies:
+ "@ardatan/sync-fetch": ^0.0.1
+ "@graphql-tools/utils": ^10.5.5
+ "@whatwg-node/fetch": ^0.10.0
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 2c88cf3a44274474cab1350e3e409d00733bf9daf1c828a77b59244bc064798c4e2c046f9e7d08a6f2a451e0bda9619e87a89cee4f7ab16f340da6586cf3bd98
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/batch-execute@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "@graphql-tools/batch-execute@npm:9.0.5"
+ dependencies:
+ "@graphql-tools/utils": ^10.5.5
+ dataloader: ^2.2.2
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 7ea4d6f59150304862fcafdab31e654b6e175666c6c5c084ce06cfc62936b0e2d02b867d4ce4de804b95b88d4a4575e4c02a5015f0d0a63b6d5eabbf49c36502
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/code-file-loader@npm:^8.0.0":
+ version: 8.1.4
+ resolution: "@graphql-tools/code-file-loader@npm:8.1.4"
+ dependencies:
+ "@graphql-tools/graphql-tag-pluck": 8.3.3
+ "@graphql-tools/utils": ^10.5.5
+ globby: ^11.0.3
+ tslib: ^2.4.0
+ unixify: ^1.0.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 08e78e7cbc60d9e2b03972c584d9c6f0224e7da14de35e917a1b1cca3b614cef3fd34a138ea766fe9e04c1aa38c0a6292e1907e451fed1aee1f8e53736a7f290
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/delegate@npm:^10.1.1":
+ version: 10.1.1
+ resolution: "@graphql-tools/delegate@npm:10.1.1"
+ dependencies:
+ "@graphql-tools/batch-execute": ^9.0.5
+ "@graphql-tools/executor": ^1.3.2
+ "@graphql-tools/schema": ^10.0.7
+ "@graphql-tools/utils": ^10.5.5
+ "@repeaterjs/repeater": ^3.0.6
+ dataloader: ^2.2.2
+ dset: ^3.1.2
+ tslib: ^2.5.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: d3814c1561eeff07ced69ce18aef861e8e339c7e8b2991d180763ab8eb2078b3bbe46700f363aa44a9b67b8e31b90a81f8bab274fcced9af539930d33f3602a1
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/documents@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "@graphql-tools/documents@npm:1.0.1"
+ dependencies:
+ lodash.sortby: ^4.7.0
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: c6ff859d2673dbf884f19d6319735afacc6bff2df6f8ea3dbf56839d01568f61210f256f0905156f123428cc24962ada26b37903263699fc8cd7efb8849a6508
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/executor-graphql-ws@npm:^1.3.1":
+ version: 1.3.1
+ resolution: "@graphql-tools/executor-graphql-ws@npm:1.3.1"
+ dependencies:
+ "@graphql-tools/utils": ^10.5.5
+ "@types/ws": ^8.0.0
+ graphql-ws: ^5.14.0
+ isomorphic-ws: ^5.0.0
+ tslib: ^2.4.0
+ ws: ^8.17.1
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 850cef03d4a517bd922a98a82f28e1cf5353f96e53e649403cbc394cb2ef6d3256438d1fe5bba9fb1b2e9bc4b92e4242d4ae4b8f25f393e1d43108dbbadf06b5
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/executor-http@npm:^1.1.8":
+ version: 1.1.8
+ resolution: "@graphql-tools/executor-http@npm:1.1.8"
+ dependencies:
+ "@graphql-tools/utils": ^10.5.5
+ "@repeaterjs/repeater": ^3.0.4
+ "@whatwg-node/fetch": ^0.10.0
+ extract-files: ^11.0.0
+ meros: ^1.2.1
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 1ec80c125da44547b20040f993cc4f893d0d68ca2b5b2e0471d16acced548c8c9dec53cabce1216c81841fe222bf2addd32f09f2c5fba99c6bb125c06845a492
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/executor-legacy-ws@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "@graphql-tools/executor-legacy-ws@npm:1.1.1"
+ dependencies:
+ "@graphql-tools/utils": ^10.5.5
+ "@types/ws": ^8.0.0
+ isomorphic-ws: ^5.0.0
+ tslib: ^2.4.0
+ ws: ^8.17.1
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 08538c986bc121a8c10168ca9a61d6d379f13b19e764b4487ce4166a54e264e2c9472b5c26e3c7b9ce3ea536af24c0bde4acfc4194bc4964b2981c531a367621
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/executor@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "@graphql-tools/executor@npm:1.3.2"
+ dependencies:
+ "@graphql-tools/utils": ^10.5.5
+ "@graphql-typed-document-node/core": 3.2.0
+ "@repeaterjs/repeater": ^3.0.4
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 1bc7c25f19e428bedf322d080f136d6edb113b64572dd1c8fa3f00611c957a64160057f99155715c59f6d39758090268be96b6d9a11b6921f48985d70cda862c
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/git-loader@npm:^8.0.0":
+ version: 8.0.8
+ resolution: "@graphql-tools/git-loader@npm:8.0.8"
+ dependencies:
+ "@graphql-tools/graphql-tag-pluck": 8.3.3
+ "@graphql-tools/utils": ^10.5.5
+ is-glob: 4.0.3
+ micromatch: ^4.0.8
+ tslib: ^2.4.0
+ unixify: ^1.0.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 19a9db2337500d99607bcde6e6aa70de4a7072edd5d221cec5d311475492f56749a775af7f9b0e8981b4d748c11b4926b851cff7c05296a9e509155c1c9bb3f6
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/github-loader@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "@graphql-tools/github-loader@npm:8.0.3"
+ dependencies:
+ "@ardatan/sync-fetch": ^0.0.1
+ "@graphql-tools/executor-http": ^1.1.8
+ "@graphql-tools/graphql-tag-pluck": ^8.3.3
+ "@graphql-tools/utils": ^10.5.5
+ "@whatwg-node/fetch": ^0.10.0
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: d9fdc88db3733bea4ef7783fd71cd192758201a999159b8286c826cd5b754b0332a090515c7940afc62f126c181c4fa35e62ce57c2acd2dce1472632031bfa53
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/graphql-file-loader@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "@graphql-tools/graphql-file-loader@npm:8.0.2"
+ dependencies:
+ "@graphql-tools/import": 7.0.2
+ "@graphql-tools/utils": ^10.5.5
+ globby: ^11.0.3
+ tslib: ^2.4.0
+ unixify: ^1.0.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: ab963352275aeeef5ea40d2759a2c3c4259c1392db4002146cba2d27a3a31299fb97495e891f3e5fa4fc8cd09d1442e2129b3821a70d79fcee437b736c6291ca
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/graphql-tag-pluck@npm:8.3.3, @graphql-tools/graphql-tag-pluck@npm:^8.3.3":
+ version: 8.3.3
+ resolution: "@graphql-tools/graphql-tag-pluck@npm:8.3.3"
+ dependencies:
+ "@babel/core": ^7.22.9
+ "@babel/parser": ^7.16.8
+ "@babel/plugin-syntax-import-assertions": ^7.20.0
+ "@babel/traverse": ^7.16.8
+ "@babel/types": ^7.16.8
+ "@graphql-tools/utils": ^10.5.5
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 9fc3278a0ae0e80114c3d65f550655acc867cc161531ea3ae6aacf400109036329dfa6afcf5b386880298e19ee0a790ebb1a1556d55e49e558b757a5b3beb5b0
languageName: node
linkType: hard
-"@expo/prebuild-config@npm:7.0.8":
- version: 7.0.8
- resolution: "@expo/prebuild-config@npm:7.0.8"
+"@graphql-tools/import@npm:7.0.2":
+ version: 7.0.2
+ resolution: "@graphql-tools/import@npm:7.0.2"
dependencies:
- "@expo/config": ~9.0.0-beta.0
- "@expo/config-plugins": ~8.0.8
- "@expo/config-types": ^51.0.0-unreleased
- "@expo/image-utils": ^0.5.0
- "@expo/json-file": ^8.3.0
- "@react-native/normalize-colors": 0.74.85
- debug: ^4.3.1
- fs-extra: ^9.0.0
- resolve-from: ^5.0.0
- semver: ^7.6.0
- xml2js: 0.6.0
+ "@graphql-tools/utils": ^10.5.5
+ resolve-from: 5.0.0
+ tslib: ^2.4.0
peerDependencies:
- expo-modules-autolinking: ">=0.8.1"
- checksum: b3715b10aa5aa9e60e97802feaaa6ddca4330752ec566d9f272e23417d00e2a298b6cc2f0d33f8a46a3c907f10b862d2975b737ba10e194ac834eae48847923b
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: b6ee488e3720bc41710f7ccf7b499ae5cda63f80a2ebd35d6e2c80b6f36d1ff8345450c6c21f79c5aed8b001c87589c63d6a122236deb7d73ff17582038806c4
languageName: node
linkType: hard
-"@expo/rudder-sdk-node@npm:1.1.1":
- version: 1.1.1
- resolution: "@expo/rudder-sdk-node@npm:1.1.1"
+"@graphql-tools/json-file-loader@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "@graphql-tools/json-file-loader@npm:8.0.2"
dependencies:
- "@expo/bunyan": ^4.0.0
- "@segment/loosely-validate-event": ^2.0.0
- fetch-retry: ^4.1.1
- md5: ^2.2.1
- node-fetch: ^2.6.1
- remove-trailing-slash: ^0.1.0
- uuid: ^8.3.2
- checksum: 5ce50c1a82f899b135600cb29cddf3fab601938700c8203f16a1394d2ffbf9e2cdd246b92ff635f8415121072d99a7b4a370f715b78f6680594b5a630e8d78c6
+ "@graphql-tools/utils": ^10.5.5
+ globby: ^11.0.3
+ tslib: ^2.4.0
+ unixify: ^1.0.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 56c53e22ac762ee2c668a33e1ab929cbea86b3ecb95a74290e085ac94385c22b2e7854b4d16094c8289cfaf76712c274bd99725d2f151ddad60d72edf1fdc412
languageName: node
linkType: hard
-"@expo/sdk-runtime-versions@npm:^1.0.0":
- version: 1.0.0
- resolution: "@expo/sdk-runtime-versions@npm:1.0.0"
- checksum: 0942d5a356f590e8dc795761456cc48b3e2d6a38ad2a02d6774efcdc5a70424e05623b4e3e5d2fec0cdc30f40dde05c14391c781607eed3971bf8676518bfd9d
+"@graphql-tools/load@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "@graphql-tools/load@npm:8.0.3"
+ dependencies:
+ "@graphql-tools/schema": ^10.0.7
+ "@graphql-tools/utils": ^10.5.5
+ p-limit: 3.1.0
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: f50df2d078bd4be008dc487c6c16ed8875f24bbebde677c9f64af444310c05fc2545681d3eafd351331ab4161907e1c86491835fce30656fc7ce50d0bb2b25c2
languageName: node
linkType: hard
-"@expo/spawn-async@npm:^1.5.0, @expo/spawn-async@npm:^1.7.2":
- version: 1.7.2
- resolution: "@expo/spawn-async@npm:1.7.2"
+"@graphql-tools/merge@npm:^9.0.0, @graphql-tools/merge@npm:^9.0.8":
+ version: 9.0.8
+ resolution: "@graphql-tools/merge@npm:9.0.8"
dependencies:
- cross-spawn: ^7.0.3
- checksum: d99e5ff6d303ec9b0105f97c4fa6c65bca526c7d4d0987997c35cc745fa8224adf009942d01808192ebb9fa30619a53316641958631e85cf17b773d9eeda2597
+ "@graphql-tools/utils": ^10.5.5
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: f1441595332068d7fe6c344da5ddd0bbc114fc64858f71a6ba6c766d658e68ef20f03cf387aaba7d5f9cf7e97cbf7ebd30f21c99438b742cdd0ecaf0ccbd5719
languageName: node
linkType: hard
-"@expo/vector-icons@npm:^14.0.0":
- version: 14.0.2
- resolution: "@expo/vector-icons@npm:14.0.2"
+"@graphql-tools/optimize@npm:^1.3.0":
+ version: 1.4.0
+ resolution: "@graphql-tools/optimize@npm:1.4.0"
dependencies:
- prop-types: ^15.8.1
- checksum: 49e27ff52eb138745313fa2c39863fb762230b0089b910d668d7f2c06b7e71a0249dc3a26bfc8725d07bdfaadab1dbcbce087b34dfc244b00a15fc02fe4866e2
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: bccbc596f2007ae706ee948e900f3174aa80ef043e8ae3467f735a10df0b31873bafdd20c0ef09b662171363a31e2d0859adb362bbf762da00245f8e9fd501b0
languageName: node
linkType: hard
-"@expo/xcpretty@npm:^4.3.0":
- version: 4.3.1
- resolution: "@expo/xcpretty@npm:4.3.1"
+"@graphql-tools/optimize@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "@graphql-tools/optimize@npm:2.0.0"
dependencies:
- "@babel/code-frame": 7.10.4
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 7f79c0e1852abc571308e887d27d613da5b797256c8c6eb6c5fe7ca77f09e61524778ae281cebc0b698c51d4fe1074e2b8e0d0627b8e2dcf505aa6ed09b49a2f
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/prisma-loader@npm:^8.0.0":
+ version: 8.0.16
+ resolution: "@graphql-tools/prisma-loader@npm:8.0.16"
+ dependencies:
+ "@graphql-tools/url-loader": ^8.0.14
+ "@graphql-tools/utils": ^10.5.5
+ "@types/js-yaml": ^4.0.0
+ "@whatwg-node/fetch": ^0.10.0
chalk: ^4.1.0
- find-up: ^5.0.0
- js-yaml: ^4.1.0
- bin:
- excpretty: build/cli.js
- checksum: dbf3e2d7f501fbbd11baf0c0aa9057c8a87efe0993a82caafd30c66977ac430d03fa84e27b529e3d0b04fee8c6beec1bd135f0522229dca91220561b76309854
+ debug: ^4.3.1
+ dotenv: ^16.0.0
+ graphql-request: ^6.0.0
+ http-proxy-agent: ^7.0.0
+ https-proxy-agent: ^7.0.0
+ jose: ^5.0.0
+ js-yaml: ^4.0.0
+ lodash: ^4.17.20
+ scuid: ^1.1.0
+ tslib: ^2.4.0
+ yaml-ast-parser: ^0.0.43
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 77ef0f507d488564753fab108ca70df6d4280ab92752ccba4119ee74c435df18815fa3565bec03f6a945611439e3dbe923cd995481b914bf6fa4b4893f214f37
languageName: node
linkType: hard
-"@fastify/ajv-compiler@npm:^3.5.0":
- version: 3.5.0
- resolution: "@fastify/ajv-compiler@npm:3.5.0"
+"@graphql-tools/relay-operation-optimizer@npm:^6.5.0":
+ version: 6.5.18
+ resolution: "@graphql-tools/relay-operation-optimizer@npm:6.5.18"
dependencies:
- ajv: ^8.11.0
- ajv-formats: ^2.1.1
- fast-uri: ^2.0.0
- checksum: 5e5b16469f8d586473d0b32e3a9cf38c0d86ef2a6fb7ea12ed7f3665642bd8eb2dde9adcc317814369cb5a58210bfdac35996fa87d1cc23e88bbc799f0b128b0
+ "@ardatan/relay-compiler": 12.0.0
+ "@graphql-tools/utils": ^9.2.1
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 56a8c7e6a0bf5fa4d5106276f69c08630a95659eb4300249b3dd28e2057ebb7e7815c51beadf98acdbf695cad5937988d16a3d01ca74fc120c76892968fbeb2b
languageName: node
linkType: hard
-"@fastify/cors@npm:^8.1.1":
- version: 8.4.0
- resolution: "@fastify/cors@npm:8.4.0"
+"@graphql-tools/relay-operation-optimizer@npm:^7.0.0":
+ version: 7.0.2
+ resolution: "@graphql-tools/relay-operation-optimizer@npm:7.0.2"
dependencies:
- fastify-plugin: ^4.0.0
- mnemonist: 0.39.5
- checksum: 4fe99623918b9c58f6590dac00fe778f2755eacc47de726acf97b3a3305a414425b393422429efca1b261514100f4092a4ad41bc549c6f6edf60e83f9f5d3701
+ "@ardatan/relay-compiler": 12.0.0
+ "@graphql-tools/utils": ^10.5.5
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 6eff45ec213d193d72bb1dc67d43ababba0909ddd4700360c26a82668d5e190cebf96940f6337c117a35350aed31b2bd7c9296f2dcd4df2687dbec30e6cdcebe
languageName: node
linkType: hard
-"@fastify/deepmerge@npm:^1.0.0":
- version: 1.3.0
- resolution: "@fastify/deepmerge@npm:1.3.0"
- checksum: 33ec927905dca320d7ae9535a1521909f7c82339706345324ab6287ad100589a799b8257c15b0e582c7bb74e2aa4883d82ba0228d7b116aa8789ada4f78d6974
+"@graphql-tools/schema@npm:^10.0.0, @graphql-tools/schema@npm:^10.0.7":
+ version: 10.0.7
+ resolution: "@graphql-tools/schema@npm:10.0.7"
+ dependencies:
+ "@graphql-tools/merge": ^9.0.8
+ "@graphql-tools/utils": ^10.5.5
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: d0cf9d286755d4d1ed7d7f33b51f1f1fcf9afdcbc3470078f5face1e49253948963b5a5e8cbdcf08fecc7b016aecbac794428c2269c6c9de91422e5b4375cec1
languageName: node
linkType: hard
-"@fastify/error@npm:^3.2.0":
- version: 3.3.0
- resolution: "@fastify/error@npm:3.3.0"
- checksum: 202507c8c7f49922cac2f5afc82802151b0bd9c583ca1c2850bf43d0f4cd97eedb3a3388b9016da74f8a01b517a5861d1f666c506dd64fd22995e559bc139264
+"@graphql-tools/url-loader@npm:^8.0.0, @graphql-tools/url-loader@npm:^8.0.14":
+ version: 8.0.14
+ resolution: "@graphql-tools/url-loader@npm:8.0.14"
+ dependencies:
+ "@ardatan/sync-fetch": ^0.0.1
+ "@graphql-tools/executor-graphql-ws": ^1.3.1
+ "@graphql-tools/executor-http": ^1.1.8
+ "@graphql-tools/executor-legacy-ws": ^1.1.1
+ "@graphql-tools/utils": ^10.5.5
+ "@graphql-tools/wrap": ^10.0.15
+ "@types/ws": ^8.0.0
+ "@whatwg-node/fetch": ^0.10.0
+ isomorphic-ws: ^5.0.0
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.11
+ ws: ^8.17.1
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: fb99bf71e2fbca6a9be35699acb4a9fa850e60e9afec079d89a8c48c4743175ace18de71351ca533957e7f5d0c66358a2c7dc81de4a9fea6b5d618a50bdcf564
languageName: node
linkType: hard
-"@fastify/fast-json-stringify-compiler@npm:^4.3.0":
- version: 4.3.0
- resolution: "@fastify/fast-json-stringify-compiler@npm:4.3.0"
+"@graphql-tools/utils@npm:^10.0.0, @graphql-tools/utils@npm:^10.5.5":
+ version: 10.5.5
+ resolution: "@graphql-tools/utils@npm:10.5.5"
dependencies:
- fast-json-stringify: ^5.7.0
- checksum: 2734afabe2539d3e15d2bd9f8dfee756d9cd969f7303dc085dd91c744ff61742bb0d3ebd3b561cf3c32be54567048a634b4962f943eb6bd9ed3fbd71cbf6a4fa
+ "@graphql-typed-document-node/core": ^3.1.1
+ cross-inspect: 1.0.1
+ dset: ^3.1.2
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: bbc5ea58c286e1a9f82876570f98b29079e224a8b3568ca8df4720de8c790e1cb8772182d1411af99d6ac749b9082810e02f21f0813dc43c4d0438ef9e04e885
languageName: node
linkType: hard
-"@gorhom/bottom-sheet@npm:4.6.4":
- version: 4.6.4
- resolution: "@gorhom/bottom-sheet@npm:4.6.4"
+"@graphql-tools/utils@npm:^8.8.0":
+ version: 8.13.1
+ resolution: "@graphql-tools/utils@npm:8.13.1"
dependencies:
- "@gorhom/portal": 1.0.14
- invariant: ^2.2.4
+ tslib: ^2.4.0
peerDependencies:
- "@types/react": "*"
- "@types/react-native": "*"
- react: "*"
- react-native: "*"
- react-native-gesture-handler: ">=1.10.1"
- react-native-reanimated: ">=2.2.0"
- peerDependenciesMeta:
- "@types/react":
- optional: true
- "@types/react-native":
- optional: true
- checksum: 2cea033c4f321b93fdbf61470b507b5efd51425a8ab927b49d7aaa1d9f0568cbcfb188e385311389dbffbafe47b941dbd3e60f74b1d663a1a2d73262e2719f85
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: ff04fdeb29e9ac596ea53386cd5b23cd741bb14c1997c6b0ba3c34ca165bd82b528a355e8c8e2ba726eb39e833ba9cbb0851ba0addb8c6d367089a1145bf9a49
languageName: node
linkType: hard
-"@gorhom/portal@npm:1.0.14":
- version: 1.0.14
- resolution: "@gorhom/portal@npm:1.0.14"
+"@graphql-tools/utils@npm:^9.0.0, @graphql-tools/utils@npm:^9.2.1":
+ version: 9.2.1
+ resolution: "@graphql-tools/utils@npm:9.2.1"
dependencies:
- nanoid: ^3.3.1
+ "@graphql-typed-document-node/core": ^3.1.1
+ tslib: ^2.4.0
peerDependencies:
- react: "*"
- react-native: "*"
- checksum: 227bb96a2db854ab29bb9da8d4f3823c7f7448358de459709dd1b78522110da564c9a8734c6bc7d7153ed7c99320e0fb5d60b420c2ebb75ecaf2f0d757f410f9
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 94ed12df5f49e5c338322ffd931236a687a3d5c443bf499f9baab5d4fcd9792234111142be8aa506a01ca2e82732996c4e1d8f6159ff9cc7fdc5c97f63e55226
+ languageName: node
+ linkType: hard
+
+"@graphql-tools/wrap@npm:^10.0.15":
+ version: 10.0.15
+ resolution: "@graphql-tools/wrap@npm:10.0.15"
+ dependencies:
+ "@graphql-tools/delegate": ^10.1.1
+ "@graphql-tools/schema": ^10.0.7
+ "@graphql-tools/utils": ^10.5.5
+ tslib: ^2.4.0
+ value-or-promise: ^1.0.12
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 0fdb6d440cdac8b2dd12f6e0f8c9bd88302c78370b7e33ef7cbacd1e7aa021bb9cc4a73465a81d1ead1f2a2a3f319b852ebcc051d58367b6aa553ed7304da00a
languageName: node
linkType: hard
-"@graphql-typed-document-node/core@npm:^3.1.0":
+"@graphql-typed-document-node/core@npm:3.2.0, @graphql-typed-document-node/core@npm:^3.1.0, @graphql-typed-document-node/core@npm:^3.1.1, @graphql-typed-document-node/core@npm:^3.2.0":
version: 3.2.0
resolution: "@graphql-typed-document-node/core@npm:3.2.0"
peerDependencies:
@@ -4260,6 +5115,13 @@ __metadata:
languageName: node
linkType: hard
+"@kamilkisiela/fast-url-parser@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "@kamilkisiela/fast-url-parser@npm:1.1.4"
+ checksum: 921d305eff1fce5c7c669aee5cfe39e50109968addb496c23f0a42253d030e3cd5865eb01b13245915923bee452db75ba8a8254e69b0d0575d3c168efce7091e
+ languageName: node
+ linkType: hard
+
"@keystonehq/alias-sampling@npm:^0.1.1":
version: 0.1.2
resolution: "@keystonehq/alias-sampling@npm:0.1.2"
@@ -4551,50 +5413,6 @@ __metadata:
languageName: node
linkType: hard
-"@mapbox/geo-viewport@npm:>= 0.4.0":
- version: 0.5.0
- resolution: "@mapbox/geo-viewport@npm:0.5.0"
- dependencies:
- "@mapbox/sphericalmercator": ^1.2.0
- checksum: 9cb990e177226acbdf7658f3367ed3158d8a77350afb0e1de71fa432e682a8aed4afe2f80d36872eb79666b54432fe6219797d50f2ab4152c51811235b7520a0
- languageName: node
- linkType: hard
-
-"@mapbox/sphericalmercator@npm:^1.2.0":
- version: 1.2.0
- resolution: "@mapbox/sphericalmercator@npm:1.2.0"
- bin:
- bbox: bin/bbox.js
- to4326: bin/to4326.js
- to900913: bin/to900913.js
- xyz: bin/xyz.js
- checksum: 515cd9fcadc6626d6352001f6d9dba073fcd10433ceee37d13d4be7fc9a48930b4163b79f53151b71ff9a4410da77bd11c5ff62e3b9d6119bce9031c4d7dabc1
- languageName: node
- linkType: hard
-
-"@maplibre/maplibre-react-native@npm:^9.1.0":
- version: 9.1.0
- resolution: "@maplibre/maplibre-react-native@npm:9.1.0"
- dependencies:
- "@expo/config-plugins": ^4.0.3
- "@mapbox/geo-viewport": ">= 0.4.0"
- "@turf/along": 6.5.0
- "@turf/distance": 6.5.0
- "@turf/helpers": 6.5.0
- "@turf/length": 6.5.0
- "@turf/nearest-point-on-line": 6.5.0
- "@types/geojson": ^7946.0.7
- "@types/node": ^18.11.18
- debounce: ^1.2.0
- deprecated-react-native-prop-types: ^4.1.0
- peerDependencies:
- prop-types: ^15.8.1
- react: ">=16.6.1"
- react-native: ">=0.59.9"
- checksum: 288e177f83cec2db2ee055911090dacdf42ce862387d8e9ea3cbcb412ae7df40d41743b09912cf95479094c83a9f268dc5fcc5ebd82d690e55e093007d7b1fe9
- languageName: node
- linkType: hard
-
"@metaplex-foundation/beet-solana@npm:0.4.0, @metaplex-foundation/beet-solana@npm:^0.4.0":
version: 0.4.0
resolution: "@metaplex-foundation/beet-solana@npm:0.4.0"
@@ -4930,10 +5748,10 @@ __metadata:
languageName: node
linkType: hard
-"@novalabsxyz/mobile-theme@npm:2.0.0-y.25":
- version: 2.0.0-y.25
- resolution: "@novalabsxyz/mobile-theme@npm:2.0.0-y.25"
- checksum: 54a01e1aef25c406fea2d7d4651dd0f94d62b884bc34dc3a5702e1cbab392969139b5ca9631adae95f8fff81822c34a0a08159cbcbd0a71c722f43d6704205b7
+"@novalabsxyz/mobile-theme@npm:2.0.0-y.26":
+ version: 2.0.0-y.26
+ resolution: "@novalabsxyz/mobile-theme@npm:2.0.0-y.26"
+ checksum: 48060226173468d998c55c5e75c15d0666a02e03893c94816acb72d514b6c18d0c9a7fd6d4f4f06ad62fc5cb9a7a823d025a6e797a93057716f23b1859b15ef9
languageName: node
linkType: hard
@@ -5353,6 +6171,16 @@ __metadata:
languageName: node
linkType: hard
+"@react-native-masked-view/masked-view@npm:^0.3.2":
+ version: 0.3.2
+ resolution: "@react-native-masked-view/masked-view@npm:0.3.2"
+ peerDependencies:
+ react: ">=16"
+ react-native: ">=0.57"
+ checksum: e35ab882148df3f9b71f04355d2fb1b24d6f2aaf29043f80758f398bdf905eed67734b36b072fa8b934923ff4e3d80ccb5e37d8376cb1825272078b96a21dadc
+ languageName: node
+ linkType: hard
+
"@react-native/assets-registry@npm:0.74.87":
version: 0.74.87
resolution: "@react-native/assets-registry@npm:0.74.87"
@@ -5665,7 +6493,7 @@ __metadata:
languageName: node
linkType: hard
-"@react-native/normalize-color@npm:*, @react-native/normalize-color@npm:^2.0.0":
+"@react-native/normalize-color@npm:*":
version: 2.1.0
resolution: "@react-native/normalize-color@npm:2.1.0"
checksum: 8ccbd40b3c7629f1dc97b3e9aadd95fd3507fcf2e37535a6299a70436ab891c34cbdc4240b07380553d6e85dd909e23d5773b5be1da2906b026312e0b0768838
@@ -5693,13 +6521,6 @@ __metadata:
languageName: node
linkType: hard
-"@react-native/normalize-colors@npm:<0.73.0":
- version: 0.72.0
- resolution: "@react-native/normalize-colors@npm:0.72.0"
- checksum: c8ec577663394a3390eb34c3cd531350521172bcfad7de309ab111e5f9e3d27c966d4a4387f00972302107be3d8cad584c5794ccfa30939aecc56162e4ddbe25
- languageName: node
- linkType: hard
-
"@react-native/typescript-config@npm:0.74.87":
version: 0.74.87
resolution: "@react-native/typescript-config@npm:0.74.87"
@@ -5875,6 +6696,41 @@ __metadata:
languageName: node
linkType: hard
+"@repeaterjs/repeater@npm:^3.0.4, @repeaterjs/repeater@npm:^3.0.6":
+ version: 3.0.6
+ resolution: "@repeaterjs/repeater@npm:3.0.6"
+ checksum: aae878b953162bec77c94b45f2236ddfc01a65308267c7cb30220fa2f8511654a302c0d32aad228c58241d685607d7bb35b6d528b2879355e6636ff08fddb266
+ languageName: node
+ linkType: hard
+
+"@rnmapbox/maps@npm:^10.1.31":
+ version: 10.1.31
+ resolution: "@rnmapbox/maps@npm:10.1.31"
+ dependencies:
+ "@turf/along": 6.5.0
+ "@turf/distance": 6.5.0
+ "@turf/helpers": 6.5.0
+ "@turf/length": 6.5.0
+ "@turf/nearest-point-on-line": 6.5.0
+ "@types/geojson": ^7946.0.7
+ debounce: ^1.2.0
+ peerDependencies:
+ expo: ">=47.0.0"
+ mapbox-gl: ^2.9.0
+ react: ">=16.6.1"
+ react-dom: ">= 17.0.0"
+ react-native: ">=0.59.9"
+ peerDependenciesMeta:
+ expo:
+ optional: true
+ mapbox-gl:
+ optional: true
+ react-dom:
+ optional: true
+ checksum: f4ac56f9dbc3128b2bfeedd3980668f2c05e92b965297a0be1556b0059fcf15e7c84d9127b32383d6608d65b6986e5e3ed6ef08499091f0a31a6fbb72c0819fb
+ languageName: node
+ linkType: hard
+
"@rnx-kit/chromium-edge-launcher@npm:^1.0.0":
version: 1.0.0
resolution: "@rnx-kit/chromium-edge-launcher@npm:1.0.0"
@@ -7139,6 +7995,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/js-yaml@npm:^4.0.0":
+ version: 4.0.9
+ resolution: "@types/js-yaml@npm:4.0.9"
+ checksum: e5e5e49b5789a29fdb1f7d204f82de11cb9e8f6cb24ab064c616da5d6e1b3ccfbf95aa5d1498a9fbd3b9e745564e69b4a20b6c530b5a8bbb2d4eb830cda9bc69
+ languageName: node
+ linkType: hard
+
"@types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.9":
version: 7.0.13
resolution: "@types/json-schema@npm:7.0.13"
@@ -7249,7 +8112,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:^18.0.0, @types/node@npm:^18.11.18":
+"@types/node@npm:^18.0.0":
version: 18.19.43
resolution: "@types/node@npm:18.19.43"
dependencies:
@@ -7440,6 +8303,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/ws@npm:^8.0.0":
+ version: 8.5.13
+ resolution: "@types/ws@npm:8.5.13"
+ dependencies:
+ "@types/node": "*"
+ checksum: f17023ce7b89c6124249c90211803a4aaa02886e12bc2d0d2cd47fa665eeb058db4d871ce4397d8e423f6beea97dd56835dd3fdbb921030fe4d887601e37d609
+ languageName: node
+ linkType: hard
+
"@types/ws@npm:^8.2.2":
version: 8.5.12
resolution: "@types/ws@npm:8.5.12"
@@ -8162,6 +9034,50 @@ __metadata:
languageName: node
linkType: hard
+"@whatwg-node/fetch@npm:^0.10.0":
+ version: 0.10.1
+ resolution: "@whatwg-node/fetch@npm:0.10.1"
+ dependencies:
+ "@whatwg-node/node-fetch": ^0.7.1
+ urlpattern-polyfill: ^10.0.0
+ checksum: 7b0c64476d1a8f7c3cd6d946dfda3f39c204049c903d6338a07f1579a1b2771f89e742f71057b7b7beef3ccf8bf8ecc2b019c072719f1fd64509386d7ca102ae
+ languageName: node
+ linkType: hard
+
+"@whatwg-node/fetch@npm:^0.9.20":
+ version: 0.9.23
+ resolution: "@whatwg-node/fetch@npm:0.9.23"
+ dependencies:
+ "@whatwg-node/node-fetch": ^0.6.0
+ urlpattern-polyfill: ^10.0.0
+ checksum: 16c99adecce7eac17220b24c9385f34a30b9c546a790ab8f03f602747746c34ebbd24cf22faa7c921b92463f2e1f6b1ce754da636b4eda1b920720b31f9c41b8
+ languageName: node
+ linkType: hard
+
+"@whatwg-node/node-fetch@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "@whatwg-node/node-fetch@npm:0.6.0"
+ dependencies:
+ "@kamilkisiela/fast-url-parser": ^1.1.4
+ busboy: ^1.6.0
+ fast-querystring: ^1.1.1
+ tslib: ^2.6.3
+ checksum: 78a80a3c0ada94ba5256a7d94be5d27a5527b4cdc071ed2c328ff0f434d8446ee1e0464019af79be06c2d032520065f47abb7e492b774a084ac4b13bd4a86c41
+ languageName: node
+ linkType: hard
+
+"@whatwg-node/node-fetch@npm:^0.7.1":
+ version: 0.7.2
+ resolution: "@whatwg-node/node-fetch@npm:0.7.2"
+ dependencies:
+ "@kamilkisiela/fast-url-parser": ^1.1.4
+ busboy: ^1.6.0
+ fast-querystring: ^1.1.1
+ tslib: ^2.6.3
+ checksum: 1bba3e512a0d69ae335c01dea0b8a246afc1ea9946ef53437ee632c54215fc044b798bd4aa1f76ed31937ccfb43624413f83dcd62282ab1fb54bd13ccaea2b14
+ languageName: node
+ linkType: hard
+
"@xmldom/xmldom@npm:^0.8.8":
version: 0.8.10
resolution: "@xmldom/xmldom@npm:0.8.10"
@@ -8169,7 +9085,7 @@ __metadata:
languageName: node
linkType: hard
-"@xmldom/xmldom@npm:~0.7.0, @xmldom/xmldom@npm:~0.7.7":
+"@xmldom/xmldom@npm:~0.7.7":
version: 0.7.13
resolution: "@xmldom/xmldom@npm:0.7.13"
checksum: b4054078530e5fa8ede9677425deff0fce6d965f4c477ca73f8490d8a089e60b8498a15560425a1335f5ff99ecb851ed2c734b0a9a879299a5694302f212f37a
@@ -8401,7 +9317,7 @@ __metadata:
languageName: node
linkType: hard
-"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.2":
+"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.0, ansi-escapes@npm:^4.3.2":
version: 4.3.2
resolution: "ansi-escapes@npm:4.3.2"
dependencies:
@@ -8881,6 +9797,13 @@ __metadata:
languageName: node
linkType: hard
+"auto-bind@npm:~4.0.0":
+ version: 4.0.0
+ resolution: "auto-bind@npm:4.0.0"
+ checksum: 00cad71cce5742faccb7dd65c1b55ebc4f45add4b0c9a1547b10b05bab22813230133b0c892c67ba3eb969a4524710c5e43cc45c72898ec84e56f3a596e7a04f
+ languageName: node
+ linkType: hard
+
"available-typed-arrays@npm:^1.0.7":
version: 1.0.7
resolution: "available-typed-arrays@npm:1.0.7"
@@ -9623,6 +10546,15 @@ __metadata:
languageName: node
linkType: hard
+"braces@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "braces@npm:3.0.3"
+ dependencies:
+ fill-range: ^7.1.1
+ checksum: b95aa0b3bd909f6cd1720ffcf031aeaf46154dd88b4da01f9a1d3f7ea866a79eba76a6d01cbc3c422b2ee5cdc39a4f02491058d5df0d7bf6e6a162a832df1f69
+ languageName: node
+ linkType: hard
+
"brorand@npm:^1.0.1, brorand@npm:^1.1.0":
version: 1.1.0
resolution: "brorand@npm:1.1.0"
@@ -9717,6 +10649,20 @@ __metadata:
languageName: node
linkType: hard
+"browserslist@npm:^4.24.0":
+ version: 4.24.2
+ resolution: "browserslist@npm:4.24.2"
+ dependencies:
+ caniuse-lite: ^1.0.30001669
+ electron-to-chromium: ^1.5.41
+ node-releases: ^2.0.18
+ update-browserslist-db: ^1.1.1
+ bin:
+ browserslist: cli.js
+ checksum: cf64085f12132d38638f38937a255edb82c7551b164a98577b055dd79719187a816112f7b97b9739e400c4954cd66479c0d7a843cb816e346f4795dc24fd5d97
+ languageName: node
+ linkType: hard
+
"bs58@npm:5.0.0, bs58@npm:^5.0.0":
version: 5.0.0
resolution: "bs58@npm:5.0.0"
@@ -9872,6 +10818,15 @@ __metadata:
languageName: node
linkType: hard
+"busboy@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "busboy@npm:1.6.0"
+ dependencies:
+ streamsearch: ^1.1.0
+ checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e
+ languageName: node
+ linkType: hard
+
"bytes@npm:3.0.0":
version: 3.0.0
resolution: "bytes@npm:3.0.0"
@@ -9961,6 +10916,16 @@ __metadata:
languageName: node
linkType: hard
+"camel-case@npm:^4.1.2":
+ version: 4.1.2
+ resolution: "camel-case@npm:4.1.2"
+ dependencies:
+ pascal-case: ^3.1.2
+ tslib: ^2.0.3
+ checksum: bcbd25cd253b3cbc69be3f535750137dbf2beb70f093bdc575f73f800acc8443d34fd52ab8f0a2413c34f1e8203139ffc88428d8863e4dfe530cfb257a379ad6
+ languageName: node
+ linkType: hard
+
"camelcase-keys@npm:7.0.2":
version: 7.0.2
resolution: "camelcase-keys@npm:7.0.2"
@@ -10012,6 +10977,13 @@ __metadata:
languageName: node
linkType: hard
+"caniuse-lite@npm:^1.0.30001669":
+ version: 1.0.30001680
+ resolution: "caniuse-lite@npm:1.0.30001680"
+ checksum: 2641d2b18c5ab0a6663cb350c5adc81e5ede1a7677d1c7518a8053ada87bf6f206419e1820a2608f76fa5e4f7bea327cbe47df423783e571569a88c0ea645270
+ languageName: node
+ linkType: hard
+
"capability@npm:^0.2.5":
version: 0.2.5
resolution: "capability@npm:0.2.5"
@@ -10019,6 +10991,17 @@ __metadata:
languageName: node
linkType: hard
+"capital-case@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "capital-case@npm:1.0.4"
+ dependencies:
+ no-case: ^3.0.4
+ tslib: ^2.0.3
+ upper-case-first: ^2.0.2
+ checksum: 41fa8fa87f6d24d0835a2b4a9341a3eaecb64ac29cd7c5391f35d6175a0fa98ab044e7f2602e1ec3afc886231462ed71b5b80c590b8b41af903ec2c15e5c5931
+ languageName: node
+ linkType: hard
+
"case-anything@npm:^2.1.13":
version: 2.1.13
resolution: "case-anything@npm:2.1.13"
@@ -10061,6 +11044,62 @@ __metadata:
languageName: node
linkType: hard
+"change-case-all@npm:1.0.14":
+ version: 1.0.14
+ resolution: "change-case-all@npm:1.0.14"
+ dependencies:
+ change-case: ^4.1.2
+ is-lower-case: ^2.0.2
+ is-upper-case: ^2.0.2
+ lower-case: ^2.0.2
+ lower-case-first: ^2.0.2
+ sponge-case: ^1.0.1
+ swap-case: ^2.0.2
+ title-case: ^3.0.3
+ upper-case: ^2.0.2
+ upper-case-first: ^2.0.2
+ checksum: 6ff893e005e1bf115cc2969cc5ca3610f7c6ece9e90b7927ed12c980c7d3ea9a565150d246c6dba0fee21aaacbd38d69b98a4670d96b892c76f66e46616506d3
+ languageName: node
+ linkType: hard
+
+"change-case-all@npm:1.0.15":
+ version: 1.0.15
+ resolution: "change-case-all@npm:1.0.15"
+ dependencies:
+ change-case: ^4.1.2
+ is-lower-case: ^2.0.2
+ is-upper-case: ^2.0.2
+ lower-case: ^2.0.2
+ lower-case-first: ^2.0.2
+ sponge-case: ^1.0.1
+ swap-case: ^2.0.2
+ title-case: ^3.0.3
+ upper-case: ^2.0.2
+ upper-case-first: ^2.0.2
+ checksum: e1dabdcd8447a3690f3faf15f92979dfbc113109b50916976e1d5e518e6cfdebee4f05f54d0ca24fb79a4bf835185b59ae25e967bb3dc10bd236a775b19ecc52
+ languageName: node
+ linkType: hard
+
+"change-case@npm:^4.1.2":
+ version: 4.1.2
+ resolution: "change-case@npm:4.1.2"
+ dependencies:
+ camel-case: ^4.1.2
+ capital-case: ^1.0.4
+ constant-case: ^3.0.4
+ dot-case: ^3.0.4
+ header-case: ^2.0.4
+ no-case: ^3.0.4
+ param-case: ^3.0.4
+ pascal-case: ^3.1.2
+ path-case: ^3.0.4
+ sentence-case: ^3.0.4
+ snake-case: ^3.0.4
+ tslib: ^2.0.3
+ checksum: e4bc4a093a1f7cce8b33896665cf9e456e3bc3cc0def2ad7691b1994cfca99b3188d0a513b16855b01a6bd20692fcde12a7d4d87a5615c4c515bbbf0e651f116
+ languageName: node
+ linkType: hard
+
"char-regex@npm:^1.0.2":
version: 1.0.2
resolution: "char-regex@npm:1.0.2"
@@ -10178,6 +11217,16 @@ __metadata:
languageName: node
linkType: hard
+"cli-truncate@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "cli-truncate@npm:2.1.0"
+ dependencies:
+ slice-ansi: ^3.0.0
+ string-width: ^4.2.0
+ checksum: bf1e4e6195392dc718bf9cd71f317b6300dc4a9191d052f31046b8773230ece4fa09458813bf0e3455a5e68c0690d2ea2c197d14a8b85a7b5e01c97f4b5feb5d
+ languageName: node
+ linkType: hard
+
"cli-width@npm:^3.0.0":
version: 3.0.0
resolution: "cli-width@npm:3.0.0"
@@ -10356,6 +11405,13 @@ __metadata:
languageName: node
linkType: hard
+"colorette@npm:^2.0.16":
+ version: 2.0.20
+ resolution: "colorette@npm:2.0.20"
+ checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d
+ languageName: node
+ linkType: hard
+
"colors@npm:^1.1.2":
version: 1.4.0
resolution: "colors@npm:1.4.0"
@@ -10421,6 +11477,13 @@ __metadata:
languageName: node
linkType: hard
+"common-tags@npm:1.8.2":
+ version: 1.8.2
+ resolution: "common-tags@npm:1.8.2"
+ checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff
+ languageName: node
+ linkType: hard
+
"commondir@npm:^1.0.1":
version: 1.0.1
resolution: "commondir@npm:1.0.1"
@@ -10518,6 +11581,17 @@ __metadata:
languageName: node
linkType: hard
+"constant-case@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "constant-case@npm:3.0.4"
+ dependencies:
+ no-case: ^3.0.4
+ tslib: ^2.0.3
+ upper-case: ^2.0.2
+ checksum: 6c3346d51afc28d9fae922e966c68eb77a19d94858dba230dd92d7b918b37d36db50f0311e9ecf6847e43e934b1c01406a0936973376ab17ec2c471fbcfb2cf3
+ languageName: node
+ linkType: hard
+
"constants-browserify@npm:1.0.0":
version: 1.0.0
resolution: "constants-browserify@npm:1.0.0"
@@ -10605,6 +11679,23 @@ __metadata:
languageName: node
linkType: hard
+"cosmiconfig@npm:^8.1.0, cosmiconfig@npm:^8.1.3":
+ version: 8.3.6
+ resolution: "cosmiconfig@npm:8.3.6"
+ dependencies:
+ import-fresh: ^3.3.0
+ js-yaml: ^4.1.0
+ parse-json: ^5.2.0
+ path-type: ^4.0.0
+ peerDependencies:
+ typescript: ">=4.9.5"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0
+ languageName: node
+ linkType: hard
+
"crc@npm:^3.8.0":
version: 3.8.0
resolution: "crc@npm:3.8.0"
@@ -10677,6 +11768,15 @@ __metadata:
languageName: node
linkType: hard
+"cross-inspect@npm:1.0.1":
+ version: 1.0.1
+ resolution: "cross-inspect@npm:1.0.1"
+ dependencies:
+ tslib: ^2.4.0
+ checksum: 7c1e02e0a9670b62416a3ea1df7ae880fdad3aa0a857de8932c4e5f8acd71298c7e3db9da8e9da603f5692cd1879938f5e72e34a9f5d1345987bef656d117fc1
+ languageName: node
+ linkType: hard
+
"cross-spawn@npm:^6.0.0":
version: 6.0.5
resolution: "cross-spawn@npm:6.0.5"
@@ -10930,6 +12030,13 @@ __metadata:
languageName: node
linkType: hard
+"dataloader@npm:^2.2.2":
+ version: 2.2.2
+ resolution: "dataloader@npm:2.2.2"
+ checksum: 4dabd247089c29f194e94d5434d504f99156c5c214a03463c20f3f17f40398d7e179edee69a27c16e315519ac8739042a810090087ae26449a0e685156a02c65
+ languageName: node
+ linkType: hard
+
"date-fns@npm:2.29.2":
version: 2.29.2
resolution: "date-fns@npm:2.29.2"
@@ -11194,6 +12301,13 @@ __metadata:
languageName: node
linkType: hard
+"dependency-graph@npm:^0.11.0":
+ version: 0.11.0
+ resolution: "dependency-graph@npm:0.11.0"
+ checksum: 477204beaa9be69e642bc31ffe7a8c383d0cf48fa27acbc91c5df01431ab913e65c154213d2ef83d034c98d77280743ec85e5da018a97a18dd43d3c0b78b28cd
+ languageName: node
+ linkType: hard
+
"deprecated-react-native-prop-types@npm:2.3.0, deprecated-react-native-prop-types@npm:^2.2.0, deprecated-react-native-prop-types@npm:^2.3.0":
version: 2.3.0
resolution: "deprecated-react-native-prop-types@npm:2.3.0"
@@ -11205,17 +12319,6 @@ __metadata:
languageName: node
linkType: hard
-"deprecated-react-native-prop-types@npm:^4.1.0":
- version: 4.2.3
- resolution: "deprecated-react-native-prop-types@npm:4.2.3"
- dependencies:
- "@react-native/normalize-colors": <0.73.0
- invariant: ^2.2.4
- prop-types: ^15.8.1
- checksum: 294752f9f15733b66473022d8258a14aac850e4a3db7e802ef189a09871236f5a110f8fe588468ae1df92f24641ae29de05943074dc54da02a5e4262935f913d
- languageName: node
- linkType: hard
-
"des.js@npm:^1.0.0":
version: 1.1.0
resolution: "des.js@npm:1.1.0"
@@ -11240,6 +12343,13 @@ __metadata:
languageName: node
linkType: hard
+"detect-indent@npm:^6.0.0":
+ version: 6.1.0
+ resolution: "detect-indent@npm:6.1.0"
+ checksum: ab953a73c72dbd4e8fc68e4ed4bfd92c97eb6c43734af3900add963fd3a9316f3bc0578b018b24198d4c31a358571eff5f0656e81a1f3b9ad5c547d58b2d093d
+ languageName: node
+ linkType: hard
+
"detect-libc@npm:^1.0.3":
version: 1.0.3
resolution: "detect-libc@npm:1.0.3"
@@ -11413,7 +12523,7 @@ __metadata:
languageName: node
linkType: hard
-"dotenv@npm:^16.0.3, dotenv@npm:^16.4.4, dotenv@npm:~16.4.5":
+"dotenv@npm:^16.0.0, dotenv@npm:^16.0.3, dotenv@npm:^16.4.4, dotenv@npm:~16.4.5":
version: 16.4.5
resolution: "dotenv@npm:16.4.5"
checksum: 301a12c3d44fd49888b74eb9ccf9f07a1f5df43f489e7fcb89647a2edcd84c42d6bc349dc8df099cd18f07c35c7b04685c1a4f3e6a6a9e6b30f8d48c15b7f49c
@@ -11436,6 +12546,13 @@ __metadata:
languageName: node
linkType: hard
+"dset@npm:^3.1.2":
+ version: 3.1.4
+ resolution: "dset@npm:3.1.4"
+ checksum: 9a7677e9ffd3c13ad850f7cf367aa94b39984006510e84c3c09b7b88bba0a5b3b7196d85a99d0c4cae4e47d67bdeca43dc1834a41d80f31bcdc86dd26121ecec
+ languageName: node
+ linkType: hard
+
"duplexify@npm:^4.1.2":
version: 4.1.2
resolution: "duplexify@npm:4.1.2"
@@ -11479,6 +12596,13 @@ __metadata:
languageName: node
linkType: hard
+"electron-to-chromium@npm:^1.5.41":
+ version: 1.5.56
+ resolution: "electron-to-chromium@npm:1.5.56"
+ checksum: ef8213e3531715d48ca7c61e4b70532d57616271b56642d212297c72ba984bf57621c32d04eb56c19bfb90cf17d421875e6f334deddd191edf28515bebfb9061
+ languageName: node
+ linkType: hard
+
"elliptic@npm:6.5.4, elliptic@npm:^6.5.3":
version: 6.5.4
resolution: "elliptic@npm:6.5.4"
@@ -11856,6 +12980,13 @@ __metadata:
languageName: node
linkType: hard
+"escalade@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "escalade@npm:3.2.0"
+ checksum: 47b029c83de01b0d17ad99ed766347b974b0d628e848de404018f3abee728e987da0d2d370ad4574aa3d5b5bfc368754fd085d69a30f8e75903486ec4b5b709e
+ languageName: node
+ linkType: hard
+
"escape-html@npm:~1.0.3":
version: 1.0.3
resolution: "escape-html@npm:1.0.3"
@@ -12651,6 +13782,15 @@ __metadata:
languageName: node
linkType: hard
+"expo-location@npm:^17.0.1":
+ version: 17.0.1
+ resolution: "expo-location@npm:17.0.1"
+ peerDependencies:
+ expo: "*"
+ checksum: 1bfadaf16851cff26c14276aae7507daf159b2e62fc0c1e45c0f2288bb83be6314d55b4d4726317beff08d6582735a4b2c06cfdd4969b594a19321c735acdd1d
+ languageName: node
+ linkType: hard
+
"expo-modules-autolinking@npm:1.11.1":
version: 1.11.1
resolution: "expo-modules-autolinking@npm:1.11.1"
@@ -12773,6 +13913,13 @@ __metadata:
languageName: node
linkType: hard
+"extract-files@npm:^11.0.0":
+ version: 11.0.0
+ resolution: "extract-files@npm:11.0.0"
+ checksum: 39ebd92772e9a1e30d1e3112fb7db85d353c8243640635668b615ac1d605ceb79fbb13d17829dd308993ef37bb189ad99817f79ab164ae95c9bb3df9f440bd16
+ languageName: node
+ linkType: hard
+
"eyes@npm:^0.1.8":
version: 0.1.8
resolution: "eyes@npm:0.1.8"
@@ -12856,7 +14003,7 @@ __metadata:
languageName: node
linkType: hard
-"fast-querystring@npm:^1.0.0":
+"fast-querystring@npm:^1.0.0, fast-querystring@npm:^1.1.1":
version: 1.1.2
resolution: "fast-querystring@npm:1.1.2"
dependencies:
@@ -13052,6 +14199,15 @@ __metadata:
languageName: node
linkType: hard
+"fill-range@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "fill-range@npm:7.1.1"
+ dependencies:
+ to-regex-range: ^5.0.1
+ checksum: b4abfbca3839a3d55e4ae5ec62e131e2e356bf4859ce8480c64c4876100f4df292a63e5bb1618e1d7460282ca2b305653064f01654474aa35c68000980f17798
+ languageName: node
+ linkType: hard
+
"filter-obj@npm:^1.1.0":
version: 1.1.0
resolution: "filter-obj@npm:1.1.0"
@@ -13477,6 +14633,13 @@ __metadata:
languageName: node
linkType: hard
+"geolib@npm:^3.3.4":
+ version: 3.3.4
+ resolution: "geolib@npm:3.3.4"
+ checksum: b5ca8090effd384fec168a957d89416577a92dcb63aedf361a60794e07051e6f2a98a3c2db64de2dd9114ac22c63fbf9ec67b2f61dbc300292040cbd4387942b
+ languageName: node
+ linkType: hard
+
"get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5":
version: 2.0.5
resolution: "get-caller-file@npm:2.0.5"
@@ -13694,7 +14857,44 @@ __metadata:
languageName: node
linkType: hard
-"graphql-tag@npm:^2.10.1":
+"graphql-config@npm:^5.1.1":
+ version: 5.1.3
+ resolution: "graphql-config@npm:5.1.3"
+ dependencies:
+ "@graphql-tools/graphql-file-loader": ^8.0.0
+ "@graphql-tools/json-file-loader": ^8.0.0
+ "@graphql-tools/load": ^8.0.0
+ "@graphql-tools/merge": ^9.0.0
+ "@graphql-tools/url-loader": ^8.0.0
+ "@graphql-tools/utils": ^10.0.0
+ cosmiconfig: ^8.1.0
+ jiti: ^2.0.0
+ minimatch: ^9.0.5
+ string-env-interpolation: ^1.0.1
+ tslib: ^2.4.0
+ peerDependencies:
+ cosmiconfig-toml-loader: ^1.0.0
+ graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ peerDependenciesMeta:
+ cosmiconfig-toml-loader:
+ optional: true
+ checksum: fde8aee849def42a5eaf02fbe3e404c91be94a53782c22ff58b29bfcfed7e9be2fba114fa94b4a97e12ea1e5970267ebaa119ba6915b2d4d9bb8f5ae9c5485c2
+ languageName: node
+ linkType: hard
+
+"graphql-request@npm:^6.0.0":
+ version: 6.1.0
+ resolution: "graphql-request@npm:6.1.0"
+ dependencies:
+ "@graphql-typed-document-node/core": ^3.2.0
+ cross-fetch: ^3.1.5
+ peerDependencies:
+ graphql: 14 - 16
+ checksum: 6d62630a0169574442320651c1f7626c0c602025c3c46b19e09417c9579bb209306ee63de9793a03be2e1701bb7f13971f8545d99bc6573e340f823af0ad35b2
+ languageName: node
+ linkType: hard
+
+"graphql-tag@npm:^2.10.1, graphql-tag@npm:^2.11.0":
version: 2.12.6
resolution: "graphql-tag@npm:2.12.6"
dependencies:
@@ -13705,6 +14905,15 @@ __metadata:
languageName: node
linkType: hard
+"graphql-ws@npm:^5.14.0":
+ version: 5.16.0
+ resolution: "graphql-ws@npm:5.16.0"
+ peerDependencies:
+ graphql: ">=0.11 <=16"
+ checksum: e3e077ec187a92be3fd5dfae49e23af11a82711d3537064384f6861c2b5ceb339f60dc1871d0026b47ff05e4ed3c941404812a8086347e454688e0e6ef0e69f3
+ languageName: node
+ linkType: hard
+
"graphql@npm:15.8.0":
version: 15.8.0
resolution: "graphql@npm:15.8.0"
@@ -13862,6 +15071,16 @@ __metadata:
languageName: node
linkType: hard
+"header-case@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "header-case@npm:2.0.4"
+ dependencies:
+ capital-case: ^1.0.4
+ tslib: ^2.0.3
+ checksum: 571c83eeb25e8130d172218712f807c0b96d62b020981400bccc1503a7cf14b09b8b10498a962d2739eccf231d950e3848ba7d420b58a6acd2f9283439546cd9
+ languageName: node
+ linkType: hard
+
"helium-wallet@workspace:.":
version: 0.0.0-use.local
resolution: "helium-wallet@workspace:."
@@ -13872,10 +15091,14 @@ __metadata:
"@babel/runtime": 7.20.13
"@bonfida/spl-name-service": ^1.1.1
"@coral-xyz/anchor": ^0.28.0
- "@gorhom/bottom-sheet": 4.6.4
+ "@gorhom/bottom-sheet": 5.0.4
"@gorhom/portal": 1.0.14
- "@helium/account-fetch-cache": 0.9.14
- "@helium/account-fetch-cache-hooks": 0.9.14
+ "@graphql-codegen/cli": ^5.0.0
+ "@graphql-codegen/typescript": ^4.0.1
+ "@graphql-codegen/typescript-operations": ^4.0.1
+ "@graphql-codegen/typescript-rtk-query": ^3.1.1
+ "@helium/account-fetch-cache": 0.9.7
+ "@helium/account-fetch-cache-hooks": 0.9.7
"@helium/address": 4.10.2
"@helium/circuit-breaker-sdk": ^0.9.14
"@helium/crypto-react-native": 4.8.0
@@ -13910,12 +15133,11 @@ __metadata:
"@ledgerhq/react-native-hid": 6.30.0
"@ledgerhq/react-native-hw-transport-ble": 6.29.5
"@ledgerhq/types-devices": ^6.22.4
- "@maplibre/maplibre-react-native": ^9.1.0
"@metaplex-foundation/js": ^0.19.5
"@metaplex-foundation/mpl-bubblegum": 0.6.0
"@metaplex-foundation/mpl-token-metadata": 2.10.0
"@ngraveio/bc-ur": ^1.1.13
- "@novalabsxyz/mobile-theme": 2.0.0-y.25
+ "@novalabsxyz/mobile-theme": 2.0.0-y.26
"@onsol/tldparser": ^0.5.3
"@react-native-async-storage/async-storage": 1.18.1
"@react-native-community/blur": 4.3.0
@@ -13924,6 +15146,7 @@ __metadata:
"@react-native-community/hooks": 2.8.1
"@react-native-community/netinfo": 9.3.7
"@react-native-community/slider": ^4.5.2
+ "@react-native-masked-view/masked-view": ^0.3.2
"@react-native/babel-preset": 0.74.87
"@react-native/eslint-config": 0.74.87
"@react-native/metro-config": 0.74.87
@@ -13934,6 +15157,7 @@ __metadata:
"@react-navigation/native-stack": 6.7.0
"@react-navigation/stack": 6.2.2
"@reduxjs/toolkit": 1.9.1
+ "@rnmapbox/maps": ^10.1.31
"@shopify/restyle": 2.4.2
"@solana/spl-account-compression": 0.1.4
"@solana/spl-memo": 0.2.3
@@ -14014,9 +15238,11 @@ __metadata:
expo-haptics: 13.0.1
expo-linking: 6.3.1
expo-local-authentication: 14.0.1
+ expo-location: ^17.0.1
expo-secure-store: 13.0.2
expo-splash-screen: 0.27.5
fuse.js: 6.6.2
+ geolib: ^3.3.4
h3-js: 4.1.0
https-browserify: 0.0.1
husky: 7.0.4
@@ -14049,10 +15275,13 @@ __metadata:
react-native-clean-project: ^4.0.3
react-native-cli-bump-version: 1.5.0
react-native-codegen: 0.0.7
+ react-native-compass-heading: ^1.5.0
+ react-native-confetti-cannon: ^1.5.2
react-native-config: 1.4.6
react-native-crypto: 2.2.0
react-native-device-info: 8.7.1
react-native-flash-message: 0.2.1
+ react-native-geocoding: ^0.5.0
react-native-gesture-handler: 2.18.1
react-native-get-random-values: 1.8.0
react-native-icloudstore: 0.9.0
@@ -14077,6 +15306,7 @@ __metadata:
react-native-share: 7.9.0
react-native-shared-group-preferences: 1.1.24
react-native-simple-toast: 1.1.4
+ react-native-skeleton-placeholder: ^5.2.4
react-native-snap-carousel: 4.0.0-beta.6
react-native-sodium: ^0.4.0
react-native-svg: 13.4.0
@@ -14088,6 +15318,7 @@ __metadata:
react-native-udp: 2.7.0
react-native-url-polyfill: ^2.0.0
react-native-video: 5.2.1
+ react-native-vision-camera: ^4.5.3
react-native-webview: 13.10.5
react-redux: 8.0.4
react-test-renderer: 17.0.2
@@ -14284,7 +15515,7 @@ __metadata:
languageName: node
linkType: hard
-"https-proxy-agent@npm:^7.0.1":
+"https-proxy-agent@npm:^7.0.0, https-proxy-agent@npm:^7.0.1":
version: 7.0.5
resolution: "https-proxy-agent@npm:7.0.5"
dependencies:
@@ -14392,6 +15623,13 @@ __metadata:
languageName: node
linkType: hard
+"immutable@npm:~3.7.6":
+ version: 3.7.6
+ resolution: "immutable@npm:3.7.6"
+ checksum: 8cccfb22d3ecf14fe0c474612e96d6bb5d117493e7639fe6642fb81e78c9ac4b698dd8a322c105001a709ad873ffc90e30bad7db5d9a3ef0b54a6e1db0258e8e
+ languageName: node
+ linkType: hard
+
"import-fresh@npm:^2.0.0":
version: 2.0.0
resolution: "import-fresh@npm:2.0.0"
@@ -14402,7 +15640,7 @@ __metadata:
languageName: node
linkType: hard
-"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1":
+"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0":
version: 3.3.0
resolution: "import-fresh@npm:3.3.0"
dependencies:
@@ -14412,6 +15650,13 @@ __metadata:
languageName: node
linkType: hard
+"import-from@npm:4.0.0":
+ version: 4.0.0
+ resolution: "import-from@npm:4.0.0"
+ checksum: 1fa29c05b048da18914e91d9a529e5d9b91774bebbfab10e53f59bcc1667917672b971cf102fee857f142e5e433ce69fa1f0a596e1c7d82f9947a5ec352694b9
+ languageName: node
+ linkType: hard
+
"import-local@npm:^3.0.2":
version: 3.1.0
resolution: "import-local@npm:3.1.0"
@@ -14490,7 +15735,7 @@ __metadata:
languageName: node
linkType: hard
-"inquirer@npm:^8.2.0":
+"inquirer@npm:^8.0.0, inquirer@npm:^8.2.0":
version: 8.2.6
resolution: "inquirer@npm:8.2.6"
dependencies:
@@ -14581,6 +15826,16 @@ __metadata:
languageName: node
linkType: hard
+"is-absolute@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "is-absolute@npm:1.0.0"
+ dependencies:
+ is-relative: ^1.0.0
+ is-windows: ^1.0.1
+ checksum: 9d16b2605eda3f3ce755410f1d423e327ad3a898bcb86c9354cf63970ed3f91ba85e9828aa56f5d6a952b9fae43d0477770f78d37409ae8ecc31e59ebc279b27
+ languageName: node
+ linkType: hard
+
"is-accessor-descriptor@npm:^0.1.6":
version: 0.1.6
resolution: "is-accessor-descriptor@npm:0.1.6"
@@ -14834,6 +16089,15 @@ __metadata:
languageName: node
linkType: hard
+"is-glob@npm:4.0.3, is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "is-glob@npm:4.0.3"
+ dependencies:
+ is-extglob: ^2.1.1
+ checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4
+ languageName: node
+ linkType: hard
+
"is-glob@npm:^2.0.0":
version: 2.0.1
resolution: "is-glob@npm:2.0.1"
@@ -14843,15 +16107,6 @@ __metadata:
languageName: node
linkType: hard
-"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3":
- version: 4.0.3
- resolution: "is-glob@npm:4.0.3"
- dependencies:
- is-extglob: ^2.1.1
- checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4
- languageName: node
- linkType: hard
-
"is-hex-prefixed@npm:1.0.0":
version: 1.0.0
resolution: "is-hex-prefixed@npm:1.0.0"
@@ -14882,6 +16137,15 @@ __metadata:
languageName: node
linkType: hard
+"is-lower-case@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "is-lower-case@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: ba57dd1201e15fd9b590654736afccf1b3b68e919f40c23ef13b00ebcc639b1d9c2f81fe86415bff3e8eccffec459786c9ac9dc8f3a19cfa4484206c411c1d7d
+ languageName: node
+ linkType: hard
+
"is-map@npm:^2.0.3":
version: 2.0.3
resolution: "is-map@npm:2.0.3"
@@ -14978,6 +16242,15 @@ __metadata:
languageName: node
linkType: hard
+"is-relative@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "is-relative@npm:1.0.0"
+ dependencies:
+ is-unc-path: ^1.0.0
+ checksum: 3271a0df109302ef5e14a29dcd5d23d9788e15ade91a40b942b035827ffbb59f7ce9ff82d036ea798541a52913cbf9d2d0b66456340887b51f3542d57b5a4c05
+ languageName: node
+ linkType: hard
+
"is-retry-allowed@npm:^2.2.0":
version: 2.2.0
resolution: "is-retry-allowed@npm:2.2.0"
@@ -15042,6 +16315,15 @@ __metadata:
languageName: node
linkType: hard
+"is-unc-path@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "is-unc-path@npm:1.0.0"
+ dependencies:
+ unc-path-regex: ^0.1.2
+ checksum: e8abfde203f7409f5b03a5f1f8636e3a41e78b983702ef49d9343eb608cdfe691429398e8815157519b987b739bcfbc73ae7cf4c8582b0ab66add5171088eab6
+ languageName: node
+ linkType: hard
+
"is-unicode-supported@npm:^0.1.0":
version: 0.1.0
resolution: "is-unicode-supported@npm:0.1.0"
@@ -15049,6 +16331,15 @@ __metadata:
languageName: node
linkType: hard
+"is-upper-case@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "is-upper-case@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: cf4fd43c00c2e72cd5cff911923070b89f0933b464941bd782e2315385f80b5a5acd772db3b796542e5e3cfed735f4dffd88c54d62db1ebfc5c3daa7b1af2bc6
+ languageName: node
+ linkType: hard
+
"is-valid-path@npm:^0.1.1":
version: 0.1.1
resolution: "is-valid-path@npm:0.1.1"
@@ -15084,7 +16375,7 @@ __metadata:
languageName: node
linkType: hard
-"is-windows@npm:^1.0.2":
+"is-windows@npm:^1.0.1, is-windows@npm:^1.0.2":
version: 1.0.2
resolution: "is-windows@npm:1.0.2"
checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7
@@ -15184,6 +16475,15 @@ __metadata:
languageName: node
linkType: hard
+"isomorphic-ws@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "isomorphic-ws@npm:5.0.0"
+ peerDependencies:
+ ws: "*"
+ checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
+ languageName: node
+ linkType: hard
+
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0":
version: 3.2.0
resolution: "istanbul-lib-coverage@npm:3.2.0"
@@ -15776,6 +17076,24 @@ __metadata:
languageName: node
linkType: hard
+"jiti@npm:^1.17.1":
+ version: 1.21.6
+ resolution: "jiti@npm:1.21.6"
+ bin:
+ jiti: bin/jiti.js
+ checksum: 9ea4a70a7bb950794824683ed1c632e2ede26949fbd348e2ba5ec8dc5efa54dc42022d85ae229cadaa60d4b95012e80ea07d625797199b688cc22ab0e8891d32
+ languageName: node
+ linkType: hard
+
+"jiti@npm:^2.0.0":
+ version: 2.4.0
+ resolution: "jiti@npm:2.4.0"
+ bin:
+ jiti: lib/jiti-cli.mjs
+ checksum: b7d8c441214e48f6c1be2952a83f40e2b1eb6e94fe81b1fd89370d11a7e322c61eb3fbd9a8d47029e14338414091ebbb575e1a92c645ab30fea6240c5c4957c7
+ languageName: node
+ linkType: hard
+
"jmespath@npm:0.16.0":
version: 0.16.0
resolution: "jmespath@npm:0.16.0"
@@ -15803,6 +17121,13 @@ __metadata:
languageName: node
linkType: hard
+"jose@npm:^5.0.0":
+ version: 5.9.6
+ resolution: "jose@npm:5.9.6"
+ checksum: 4b536da0201858ed4c4582e8bb479081f11e0c63dd0f5e473adde16fc539785e1f2f0409bc1fc7cbbb5b68026776c960b4952da3a06f6fdfff0b9764c9127ae0
+ languageName: node
+ linkType: hard
+
"js-base64@npm:^3.7.2":
version: 3.7.5
resolution: "js-base64@npm:3.7.5"
@@ -15850,7 +17175,7 @@ __metadata:
languageName: node
linkType: hard
-"js-yaml@npm:^4.1.0":
+"js-yaml@npm:^4.0.0, js-yaml@npm:^4.1.0":
version: 4.1.0
resolution: "js-yaml@npm:4.1.0"
dependencies:
@@ -15960,6 +17285,15 @@ __metadata:
languageName: node
linkType: hard
+"jsesc@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "jsesc@npm:3.0.2"
+ bin:
+ jsesc: bin/jsesc
+ checksum: a36d3ca40574a974d9c2063bf68c2b6141c20da8f2a36bd3279fc802563f35f0527a6c828801295bdfb2803952cf2cf387786c2c90ed564f88d5782475abfe3c
+ languageName: node
+ linkType: hard
+
"jsesc@npm:~0.5.0":
version: 0.5.0
resolution: "jsesc@npm:0.5.0"
@@ -16055,6 +17389,16 @@ __metadata:
languageName: node
linkType: hard
+"json-to-pretty-yaml@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "json-to-pretty-yaml@npm:1.2.2"
+ dependencies:
+ remedial: ^1.0.7
+ remove-trailing-spaces: ^1.0.6
+ checksum: 4b78480f426e176e5fdac073e05877683bb026f1175deb52d0941b992f9c91a58a812c020f00aa67ba1fc7cadb220539a264146f222e48a48c8bb2a0931cac9b
+ languageName: node
+ linkType: hard
+
"json5@npm:^0.5.1":
version: 0.5.1
resolution: "json5@npm:0.5.1"
@@ -16064,7 +17408,7 @@ __metadata:
languageName: node
linkType: hard
-"json5@npm:^1.0.1, json5@npm:^1.0.2":
+"json5@npm:^1.0.2":
version: 1.0.2
resolution: "json5@npm:1.0.2"
dependencies:
@@ -16518,6 +17862,27 @@ __metadata:
languageName: node
linkType: hard
+"listr2@npm:^4.0.5":
+ version: 4.0.5
+ resolution: "listr2@npm:4.0.5"
+ dependencies:
+ cli-truncate: ^2.1.0
+ colorette: ^2.0.16
+ log-update: ^4.0.0
+ p-map: ^4.0.0
+ rfdc: ^1.3.0
+ rxjs: ^7.5.5
+ through: ^2.3.8
+ wrap-ansi: ^7.0.0
+ peerDependencies:
+ enquirer: ">= 2.3.0 < 3"
+ peerDependenciesMeta:
+ enquirer:
+ optional: true
+ checksum: 7af31851abe25969ef0581c6db808117e36af15b131401795182427769d9824f451ba9e8aff6ccd25b6a4f6c8796f816292caf08e5f1f9b1775e8e9c313dc6c5
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^3.0.0":
version: 3.0.0
resolution: "locate-path@npm:3.0.0"
@@ -16574,6 +17939,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.sortby@npm:^4.7.0":
+ version: 4.7.0
+ resolution: "lodash.sortby@npm:4.7.0"
+ checksum: db170c9396d29d11fe9a9f25668c4993e0c1331bcb941ddbd48fb76f492e732add7f2a47cfdf8e9d740fa59ac41bbfaf931d268bc72aab3ab49e9f89354d718c
+ languageName: node
+ linkType: hard
+
"lodash.throttle@npm:^4.1.1":
version: 4.1.1
resolution: "lodash.throttle@npm:4.1.1"
@@ -16588,7 +17960,7 @@ __metadata:
languageName: node
linkType: hard
-"lodash@npm:4.17.21, lodash@npm:^4.17.13, lodash@npm:^4.17.21, lodash@npm:^4.17.4":
+"lodash@npm:4.17.21, lodash@npm:^4.17.13, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.0":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
@@ -16604,7 +17976,7 @@ __metadata:
languageName: node
linkType: hard
-"log-symbols@npm:^4.1.0":
+"log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0":
version: 4.1.0
resolution: "log-symbols@npm:4.1.0"
dependencies:
@@ -16614,6 +17986,18 @@ __metadata:
languageName: node
linkType: hard
+"log-update@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "log-update@npm:4.0.0"
+ dependencies:
+ ansi-escapes: ^4.3.0
+ cli-cursor: ^3.1.0
+ slice-ansi: ^4.0.0
+ wrap-ansi: ^6.2.0
+ checksum: ae2f85bbabc1906034154fb7d4c4477c79b3e703d22d78adee8b3862fa913942772e7fa11713e3d96fb46de4e3cabefbf5d0a544344f03b58d3c4bff52aa9eb2
+ languageName: node
+ linkType: hard
+
"logkitty@npm:^0.7.1":
version: 0.7.1
resolution: "logkitty@npm:0.7.1"
@@ -16686,6 +18070,15 @@ __metadata:
languageName: node
linkType: hard
+"lower-case-first@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "lower-case-first@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: 33e3da1098ddda219ce125d4ab7a78a944972c0ee8872e95b6ccc35df8ad405284ab233b0ba4d72315ad1a06fe2f0d418ee4cba9ec1ef1c386dea78899fc8958
+ languageName: node
+ linkType: hard
+
"lower-case@npm:^2.0.2":
version: 2.0.2
resolution: "lower-case@npm:2.0.2"
@@ -16768,7 +18161,7 @@ __metadata:
languageName: node
linkType: hard
-"map-cache@npm:^0.2.2":
+"map-cache@npm:^0.2.0, map-cache@npm:^0.2.2":
version: 0.2.2
resolution: "map-cache@npm:0.2.2"
checksum: 3067cea54285c43848bb4539f978a15dedc63c03022abeec6ef05c8cb6829f920f13b94bcaf04142fc6a088318e564c4785704072910d120d55dbc2e0c421969
@@ -16961,6 +18354,18 @@ __metadata:
languageName: node
linkType: hard
+"meros@npm:^1.2.1":
+ version: 1.3.0
+ resolution: "meros@npm:1.3.0"
+ peerDependencies:
+ "@types/node": ">=13"
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ checksum: ea86c83fe9357d3eb2f5bad20909e12642c7bc8c10340d9bd0968b48f69ec453de14f7e5032d138ad04cb10d79b8c9fb3c9601bb515e8fbdf9bec4eed62994ad
+ languageName: node
+ linkType: hard
+
"mersenne-twister@npm:^1.1.0":
version: 1.1.0
resolution: "mersenne-twister@npm:1.1.0"
@@ -17288,6 +18693,16 @@ __metadata:
languageName: node
linkType: hard
+"micromatch@npm:^4.0.5, micromatch@npm:^4.0.8":
+ version: 4.0.8
+ resolution: "micromatch@npm:4.0.8"
+ dependencies:
+ braces: ^3.0.3
+ picomatch: ^2.3.1
+ checksum: 79920eb634e6f400b464a954fcfa589c4e7c7143209488e44baf627f9affc8b1e306f41f4f0deedde97e69cb725920879462d3e750ab3bd3c1aed675bb3a8966
+ languageName: node
+ linkType: hard
+
"miller-rabin@npm:^4.0.0":
version: 4.0.1
resolution: "miller-rabin@npm:4.0.1"
@@ -17380,7 +18795,7 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^9.0.4":
+"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5":
version: 9.0.5
resolution: "minimatch@npm:9.0.5"
dependencies:
@@ -17896,6 +19311,15 @@ __metadata:
languageName: node
linkType: hard
+"normalize-path@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "normalize-path@npm:2.1.1"
+ dependencies:
+ remove-trailing-separator: ^1.0.1
+ checksum: 7e9cbdcf7f5b8da7aa191fbfe33daf290cdcd8c038f422faf1b8a83c972bf7a6d94c5be34c4326cb00fb63bc0fd97d9fbcfaf2e5d6142332c2cd36d2e1b86cea
+ languageName: node
+ linkType: hard
+
"normalize-path@npm:^3.0.0":
version: 3.0.0
resolution: "normalize-path@npm:3.0.0"
@@ -18310,6 +19734,15 @@ __metadata:
languageName: node
linkType: hard
+"p-limit@npm:3.1.0, p-limit@npm:^3.0.2, p-limit@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "p-limit@npm:3.1.0"
+ dependencies:
+ yocto-queue: ^0.1.0
+ checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360
+ languageName: node
+ linkType: hard
+
"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0":
version: 2.3.0
resolution: "p-limit@npm:2.3.0"
@@ -18319,15 +19752,6 @@ __metadata:
languageName: node
linkType: hard
-"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0":
- version: 3.1.0
- resolution: "p-limit@npm:3.1.0"
- dependencies:
- yocto-queue: ^0.1.0
- checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360
- languageName: node
- linkType: hard
-
"p-locate@npm:^3.0.0":
version: 3.0.0
resolution: "p-locate@npm:3.0.0"
@@ -18399,6 +19823,16 @@ __metadata:
languageName: node
linkType: hard
+"param-case@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "param-case@npm:3.0.4"
+ dependencies:
+ dot-case: ^3.0.4
+ tslib: ^2.0.3
+ checksum: b34227fd0f794e078776eb3aa6247442056cb47761e9cd2c4c881c86d84c64205f6a56ef0d70b41ee7d77da02c3f4ed2f88e3896a8fefe08bdfb4deca037c687
+ languageName: node
+ linkType: hard
+
"parent-module@npm:^1.0.0":
version: 1.0.1
resolution: "parent-module@npm:1.0.1"
@@ -18421,6 +19855,17 @@ __metadata:
languageName: node
linkType: hard
+"parse-filepath@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "parse-filepath@npm:1.0.2"
+ dependencies:
+ is-absolute: ^1.0.0
+ map-cache: ^0.2.0
+ path-root: ^0.1.1
+ checksum: 6794c3f38d3921f0f7cc63fb1fb0c4d04cd463356ad389c8ce6726d3c50793b9005971f4138975a6d7025526058d5e65e9bfe634d0765e84c4e2571152665a69
+ languageName: node
+ linkType: hard
+
"parse-json@npm:^4.0.0":
version: 4.0.0
resolution: "parse-json@npm:4.0.0"
@@ -18466,6 +19911,16 @@ __metadata:
languageName: node
linkType: hard
+"pascal-case@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "pascal-case@npm:3.1.2"
+ dependencies:
+ no-case: ^3.0.4
+ tslib: ^2.0.3
+ checksum: ba98bfd595fc91ef3d30f4243b1aee2f6ec41c53b4546bfa3039487c367abaa182471dcfc830a1f9e1a0df00c14a370514fa2b3a1aacc68b15a460c31116873e
+ languageName: node
+ linkType: hard
+
"pascalcase@npm:^0.1.1":
version: 0.1.1
resolution: "pascalcase@npm:0.1.1"
@@ -18515,6 +19970,16 @@ __metadata:
languageName: node
linkType: hard
+"path-case@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "path-case@npm:3.0.4"
+ dependencies:
+ dot-case: ^3.0.4
+ tslib: ^2.0.3
+ checksum: 61de0526222629f65038a66f63330dd22d5b54014ded6636283e1d15364da38b3cf29e4433aa3f9d8b0dba407ae2b059c23b0104a34ee789944b1bc1c5c7e06d
+ languageName: node
+ linkType: hard
+
"path-dirname@npm:^1.0.2":
version: 1.0.2
resolution: "path-dirname@npm:1.0.2"
@@ -18564,6 +20029,22 @@ __metadata:
languageName: node
linkType: hard
+"path-root-regex@npm:^0.1.0":
+ version: 0.1.2
+ resolution: "path-root-regex@npm:0.1.2"
+ checksum: dcd75d1f8e93faabe35a58e875b0f636839b3658ff2ad8c289463c40bc1a844debe0dab73c3398ef9dc8f6ec6c319720aff390cf4633763ddcf3cf4b1bbf7e8b
+ languageName: node
+ linkType: hard
+
+"path-root@npm:^0.1.1":
+ version: 0.1.1
+ resolution: "path-root@npm:0.1.1"
+ dependencies:
+ path-root-regex: ^0.1.0
+ checksum: ff88aebfc1c59ace510cc06703d67692a11530989920427625e52b66a303ca9b3d4059b0b7d0b2a73248d1ad29bcb342b8b786ec00592f3101d38a45fd3b2e08
+ languageName: node
+ linkType: hard
+
"path-scurry@npm:^1.11.1":
version: 1.11.1
resolution: "path-scurry@npm:1.11.1"
@@ -18703,6 +20184,13 @@ __metadata:
languageName: node
linkType: hard
+"picocolors@npm:^1.1.0":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045
+ languageName: node
+ linkType: hard
+
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1":
version: 2.3.1
resolution: "picomatch@npm:2.3.1"
@@ -19553,6 +21041,23 @@ __metadata:
languageName: node
linkType: hard
+"react-native-compass-heading@npm:^1.5.0":
+ version: 1.5.0
+ resolution: "react-native-compass-heading@npm:1.5.0"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: 09dfa531c8498937b0cfc4c809cdf049232c85d204e32c1f8923843a8fb00c09efbc9f75e28bd92d7265669e0ae40c9b0b12b567232f1dc080a23ecd8b16145e
+ languageName: node
+ linkType: hard
+
+"react-native-confetti-cannon@npm:^1.5.2":
+ version: 1.5.2
+ resolution: "react-native-confetti-cannon@npm:1.5.2"
+ checksum: 09026fd93304c0f3c3acfcf8dfc9b25003b30826031dffd81df6eea3b66dcee84f6ac4237719a84d3d71cb430f4fbf53d4c22b64ef17d439d5a3e5986c2ada83
+ languageName: node
+ linkType: hard
+
"react-native-config@npm:1.4.6":
version: 1.4.6
resolution: "react-native-config@npm:1.4.6"
@@ -19627,6 +21132,13 @@ __metadata:
languageName: node
linkType: hard
+"react-native-geocoding@npm:^0.5.0":
+ version: 0.5.0
+ resolution: "react-native-geocoding@npm:0.5.0"
+ checksum: a33e9dc87d104abe19206660e9fa0782090909ca8b58c70eae4690faa92194817724833086b29c57387500cdd9ecd0febd6ccbbd0f4eac0e11a93696429cf9d2
+ languageName: node
+ linkType: hard
+
"react-native-gesture-handler@npm:2.18.1":
version: 2.18.1
resolution: "react-native-gesture-handler@npm:2.18.1"
@@ -19903,6 +21415,18 @@ __metadata:
languageName: node
linkType: hard
+"react-native-skeleton-placeholder@npm:^5.2.4":
+ version: 5.2.4
+ resolution: "react-native-skeleton-placeholder@npm:5.2.4"
+ peerDependencies:
+ "@react-native-masked-view/masked-view": ^0.2.8
+ react: ">=0.14.8"
+ react-native: ">=0.50.1"
+ react-native-linear-gradient: ^2.5.6
+ checksum: c90176c55d0a8342724c38ed5af8baff8ed879b04feeff027574c3c405f3d1be193614bd65e30ddf46407cb951d412f6cc5e2aa4a8e179c589c865f83bdae39e
+ languageName: node
+ linkType: hard
+
"react-native-snap-carousel@npm:4.0.0-beta.6":
version: 4.0.0-beta.6
resolution: "react-native-snap-carousel@npm:4.0.0-beta.6"
@@ -20032,6 +21556,26 @@ __metadata:
languageName: node
linkType: hard
+"react-native-vision-camera@npm:^4.5.3":
+ version: 4.5.3
+ resolution: "react-native-vision-camera@npm:4.5.3"
+ peerDependencies:
+ "@shopify/react-native-skia": "*"
+ react: "*"
+ react-native: "*"
+ react-native-reanimated: "*"
+ react-native-worklets-core: "*"
+ peerDependenciesMeta:
+ "@shopify/react-native-skia":
+ optional: true
+ react-native-reanimated:
+ optional: true
+ react-native-worklets-core:
+ optional: true
+ checksum: 99d57a70f93134903ae25ef798947f79804ea00e3b58cbb21131115552e6f2950d2a3be9a6a237232ca6bab7b5031aa12d9ca2df659be39dc607d75997317abc
+ languageName: node
+ linkType: hard
+
"react-native-webview@npm:13.10.5":
version: 13.10.5
resolution: "react-native-webview@npm:13.10.5"
@@ -20468,6 +22012,31 @@ __metadata:
languageName: node
linkType: hard
+"relay-runtime@npm:12.0.0":
+ version: 12.0.0
+ resolution: "relay-runtime@npm:12.0.0"
+ dependencies:
+ "@babel/runtime": ^7.0.0
+ fbjs: ^3.0.0
+ invariant: ^2.2.4
+ checksum: 51cdc8a5e04188982452ae4e7c6ac7d6375ee769130d24ce8e8f9cdd45aa7e11ecd68670f56e30dcee1b4974585e88ecce19e69a9868b80cda0db7678c3b8f0a
+ languageName: node
+ linkType: hard
+
+"remedial@npm:^1.0.7":
+ version: 1.0.8
+ resolution: "remedial@npm:1.0.8"
+ checksum: 12df7c55eb92501d7f33cfe5f5ad12be13bb6ac0c53f494aaa9963d5a5155bb8be2143e8d5e17afa1a500ef5dc71d13642920d35350f2a31b65a9778afab6869
+ languageName: node
+ linkType: hard
+
+"remove-trailing-separator@npm:^1.0.1":
+ version: 1.1.0
+ resolution: "remove-trailing-separator@npm:1.1.0"
+ checksum: d3c20b5a2d987db13e1cca9385d56ecfa1641bae143b620835ac02a6b70ab88f68f117a0021838db826c57b31373d609d52e4f31aca75fc490c862732d595419
+ languageName: node
+ linkType: hard
+
"remove-trailing-slash@npm:^0.1.0":
version: 0.1.1
resolution: "remove-trailing-slash@npm:0.1.1"
@@ -20475,6 +22044,13 @@ __metadata:
languageName: node
linkType: hard
+"remove-trailing-spaces@npm:^1.0.6":
+ version: 1.0.8
+ resolution: "remove-trailing-spaces@npm:1.0.8"
+ checksum: 81f615c5cd8dd6a5e3017dcc9af598965575d176d42ef99cfd7b894529991f464e629fd68aba089f5c6bebf5bb8070a5eee56f3b621aba55e8ef524d6a4d4f69
+ languageName: node
+ linkType: hard
+
"repeat-element@npm:^1.1.2":
version: 1.1.4
resolution: "repeat-element@npm:1.1.4"
@@ -20537,6 +22113,13 @@ __metadata:
languageName: node
linkType: hard
+"resolve-from@npm:5.0.0, resolve-from@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "resolve-from@npm:5.0.0"
+ checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf
+ languageName: node
+ linkType: hard
+
"resolve-from@npm:^3.0.0":
version: 3.0.0
resolution: "resolve-from@npm:3.0.0"
@@ -20551,13 +22134,6 @@ __metadata:
languageName: node
linkType: hard
-"resolve-from@npm:^5.0.0":
- version: 5.0.0
- resolution: "resolve-from@npm:5.0.0"
- checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf
- languageName: node
- linkType: hard
-
"resolve-url@npm:^0.2.1":
version: 0.2.1
resolution: "resolve-url@npm:0.2.1"
@@ -21041,6 +22617,13 @@ __metadata:
languageName: node
linkType: hard
+"scuid@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "scuid@npm:1.1.0"
+ checksum: cd094ac3718b0070a222f9a499b280c698fdea10268cc163fa244421099544c1766dd893fdee0e2a8eba5d53ab9d0bcb11067bedff166665030fa6fda25a096b
+ languageName: node
+ linkType: hard
+
"secp256k1@npm:^4.0.0, secp256k1@npm:^4.0.2":
version: 4.0.3
resolution: "secp256k1@npm:4.0.3"
@@ -21138,6 +22721,17 @@ __metadata:
languageName: node
linkType: hard
+"sentence-case@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "sentence-case@npm:3.0.4"
+ dependencies:
+ no-case: ^3.0.4
+ tslib: ^2.0.3
+ upper-case-first: ^2.0.2
+ checksum: 3cfe6c0143e649132365695706702d7f729f484fa7b25f43435876efe7af2478243eefb052bacbcce10babf9319fd6b5b6bc59b94c80a1c819bcbb40651465d5
+ languageName: node
+ linkType: hard
+
"sequelize-pool@npm:^7.1.0":
version: 7.1.0
resolution: "sequelize-pool@npm:7.1.0"
@@ -21380,6 +22974,13 @@ __metadata:
languageName: node
linkType: hard
+"signedsource@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "signedsource@npm:1.0.0"
+ checksum: 64b2c8d7a48de9009cfd3aff62bb7c88abf3b8e0421f17ebb1d7f5ca9cc9c3ad10f5a1e3ae6cd804e4e6121c87b668202ae9057065f058ddfbf34ea65f63945d
+ languageName: node
+ linkType: hard
+
"simple-plist@npm:^1.1.0":
version: 1.3.1
resolution: "simple-plist@npm:1.3.1"
@@ -21439,6 +23040,17 @@ __metadata:
languageName: node
linkType: hard
+"slice-ansi@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "slice-ansi@npm:3.0.0"
+ dependencies:
+ ansi-styles: ^4.0.0
+ astral-regex: ^2.0.0
+ is-fullwidth-code-point: ^3.0.0
+ checksum: 5ec6d022d12e016347e9e3e98a7eb2a592213a43a65f1b61b74d2c78288da0aded781f665807a9f3876b9daa9ad94f64f77d7633a0458876c3a4fdc4eb223f24
+ languageName: node
+ linkType: hard
+
"slice-ansi@npm:^4.0.0":
version: 4.0.0
resolution: "slice-ansi@npm:4.0.0"
@@ -21671,6 +23283,15 @@ __metadata:
languageName: node
linkType: hard
+"sponge-case@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "sponge-case@npm:1.0.1"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: 64f53d930f63c5a9e59d4cae487c1ffa87d25eab682833b01d572cc885e7e3fdbad4f03409a41f03ecb27f1f8959432253eb48332c7007c3388efddb24ba2792
+ languageName: node
+ linkType: hard
+
"sprintf-js@npm:^1.1.3":
version: 1.1.3
resolution: "sprintf-js@npm:1.1.3"
@@ -21790,6 +23411,13 @@ __metadata:
languageName: node
linkType: hard
+"streamsearch@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "streamsearch@npm:1.1.0"
+ checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942
+ languageName: node
+ linkType: hard
+
"strict-uri-encode@npm:^2.0.0":
version: 2.0.0
resolution: "strict-uri-encode@npm:2.0.0"
@@ -21797,6 +23425,13 @@ __metadata:
languageName: node
linkType: hard
+"string-env-interpolation@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "string-env-interpolation@npm:1.0.1"
+ checksum: d126329587f635bee65300e4451e7352b9b67e03daeb62f006ca84244cac12a1f6e45176b018653ba0c3ec3b5d980f9ca59d2eeed99cf799501cdaa7f871dc6f
+ languageName: node
+ linkType: hard
+
"string-length@npm:^4.0.1":
version: 4.0.2
resolution: "string-length@npm:4.0.2"
@@ -22158,6 +23793,15 @@ __metadata:
languageName: node
linkType: hard
+"swap-case@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "swap-case@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: 6e21c9e1b3cd5735eb2af679a99ec3efc78a14e3d4d5e3fd594e254b91cfd37185b3d1c6e41b22f53a2cdf5d1b963ce30c0fe8b78337e3fd43d0137084670a5f
+ languageName: node
+ linkType: hard
+
"table@npm:^6.0.9":
version: 6.8.1
resolution: "table@npm:6.8.1"
@@ -22357,7 +24001,7 @@ __metadata:
languageName: node
linkType: hard
-"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.6":
+"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.6, through@npm:^2.3.8":
version: 2.3.8
resolution: "through@npm:2.3.8"
checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd
@@ -22380,6 +24024,15 @@ __metadata:
languageName: node
linkType: hard
+"title-case@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "title-case@npm:3.0.3"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: e8b7ea006b53cf3208d278455d9f1e22c409459d7f9878da324fa3b18cc0aef8560924c19c744e870394a5d9cddfdbe029ebae9875909ee7f4fc562e7cbfc53e
+ languageName: node
+ linkType: hard
+
"tmp-promise@npm:^3.0.2":
version: 3.0.3
resolution: "tmp-promise@npm:3.0.3"
@@ -22524,6 +24177,13 @@ __metadata:
languageName: node
linkType: hard
+"ts-log@npm:^2.2.3":
+ version: 2.2.7
+ resolution: "ts-log@npm:2.2.7"
+ checksum: c423a5eb54abb9471578902953814d3d0c88b3f237db016998f8998ecf982cb0f748bb8ebf93670eeba9b836ff0ce407d8065a340f3ab218ea7b9442c255b3d4
+ languageName: node
+ linkType: hard
+
"ts-poet@npm:^6.5.0":
version: 6.6.0
resolution: "ts-poet@npm:6.6.0"
@@ -22601,6 +24261,27 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:^2.5.0, tslib@npm:^2.6.3":
+ version: 2.8.1
+ resolution: "tslib@npm:2.8.1"
+ checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a
+ languageName: node
+ linkType: hard
+
+"tslib@npm:~2.4.0":
+ version: 2.4.1
+ resolution: "tslib@npm:2.4.1"
+ checksum: 19480d6e0313292bd6505d4efe096a6b31c70e21cf08b5febf4da62e95c265c8f571f7b36fcc3d1a17e068032f59c269fab3459d6cd3ed6949eafecf64315fca
+ languageName: node
+ linkType: hard
+
+"tslib@npm:~2.6.0":
+ version: 2.6.3
+ resolution: "tslib@npm:2.6.3"
+ checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5
+ languageName: node
+ linkType: hard
+
"tsutils@npm:^3.21.0":
version: 3.21.0
resolution: "tsutils@npm:3.21.0"
@@ -22835,6 +24516,13 @@ __metadata:
languageName: node
linkType: hard
+"unc-path-regex@npm:^0.1.2":
+ version: 0.1.2
+ resolution: "unc-path-regex@npm:0.1.2"
+ checksum: a05fa2006bf4606051c10fc7968f08ce7b28fa646befafa282813aeb1ac1a56f65cb1b577ca7851af2726198d59475bb49b11776036257b843eaacee2860a4ec
+ languageName: node
+ linkType: hard
+
"undici-types@npm:~5.26.4":
version: 5.26.5
resolution: "undici-types@npm:5.26.5"
@@ -22942,6 +24630,15 @@ __metadata:
languageName: node
linkType: hard
+"unixify@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "unixify@npm:1.0.0"
+ dependencies:
+ normalize-path: ^2.1.1
+ checksum: 3be30e48579fc6c7390bd59b4ab9e745fede0c164dfb7351cf710bd1dbef8484b1441186205af6bcb13b731c0c88caf9b33459f7bf8c89e79c046e656ae433f0
+ languageName: node
+ linkType: hard
+
"unpipe@npm:~1.0.0":
version: 1.0.0
resolution: "unpipe@npm:1.0.0"
@@ -22980,6 +24677,38 @@ __metadata:
languageName: node
linkType: hard
+"update-browserslist-db@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "update-browserslist-db@npm:1.1.1"
+ dependencies:
+ escalade: ^3.2.0
+ picocolors: ^1.1.0
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 2ea11bd2562122162c3e438d83a1f9125238c0844b6d16d366e3276d0c0acac6036822dc7df65fc5a89c699cdf9f174acf439c39bedf3f9a2f3983976e4b4c3e
+ languageName: node
+ linkType: hard
+
+"upper-case-first@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "upper-case-first@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: 4487db4701effe3b54ced4b3e4aa4d9ab06c548f97244d04aafb642eedf96a76d5a03cf5f38f10f415531d5792d1ac6e1b50f2a76984dc6964ad530f12876409
+ languageName: node
+ linkType: hard
+
+"upper-case@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "upper-case@npm:2.0.2"
+ dependencies:
+ tslib: ^2.0.3
+ checksum: 508723a2b03ab90cf1d6b7e0397513980fab821cbe79c87341d0e96cedefadf0d85f9d71eac24ab23f526a041d585a575cfca120a9f920e44eb4f8a7cf89121c
+ languageName: node
+ linkType: hard
+
"uri-js@npm:^4.2.2":
version: 4.4.1
resolution: "uri-js@npm:4.4.1"
@@ -23013,6 +24742,13 @@ __metadata:
languageName: node
linkType: hard
+"urlpattern-polyfill@npm:^10.0.0":
+ version: 10.0.0
+ resolution: "urlpattern-polyfill@npm:10.0.0"
+ checksum: 61d890f151ea4ecf34a3dcab32c65ad1f3cda857c9d154af198260c6e5b2ad96d024593409baaa6d4428dd1ab206c14799bf37fe011117ac93a6a44913ac5aa4
+ languageName: node
+ linkType: hard
+
"use-debounce@npm:7.0.1":
version: 7.0.1
resolution: "use-debounce@npm:7.0.1"
@@ -23207,6 +24943,13 @@ __metadata:
languageName: node
linkType: hard
+"value-or-promise@npm:^1.0.11, value-or-promise@npm:^1.0.12":
+ version: 1.0.12
+ resolution: "value-or-promise@npm:1.0.12"
+ checksum: f53a66c75b7447c90bbaf946a757ca09c094629cb80ba742f59c980ec3a69be0a385a0e75505dedb4e757862f1a994ca4beaf083a831f24d3ffb3d4bb18cd1e1
+ languageName: node
+ linkType: hard
+
"vary@npm:^1, vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"
@@ -23578,6 +25321,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:^8.17.1":
+ version: 8.18.0
+ resolution: "ws@npm:8.18.0"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975
+ languageName: node
+ linkType: hard
+
"xcode@npm:^3.0.1":
version: 3.0.1
resolution: "xcode@npm:3.0.1"
@@ -23588,16 +25346,6 @@ __metadata:
languageName: node
linkType: hard
-"xml2js@npm:0.4.23":
- version: 0.4.23
- resolution: "xml2js@npm:0.4.23"
- dependencies:
- sax: ">=0.6.0"
- xmlbuilder: ~11.0.0
- checksum: ca0cf2dfbf6deeaae878a891c8fbc0db6fd04398087084edf143cdc83d0509ad0fe199b890f62f39c4415cf60268a27a6aed0d343f0658f8779bd7add690fa98
- languageName: node
- linkType: hard
-
"xml2js@npm:0.5.0":
version: 0.5.0
resolution: "xml2js@npm:0.5.0"
@@ -23698,6 +25446,13 @@ __metadata:
languageName: node
linkType: hard
+"yaml-ast-parser@npm:^0.0.43":
+ version: 0.0.43
+ resolution: "yaml-ast-parser@npm:0.0.43"
+ checksum: fb5df4c067b6ccbd00953a46faf6ff27f0e290d623c712dc41f330251118f110e22cfd184bbff498bd969cbcda3cd27e0f9d0adb9e6d90eb60ccafc0d8e28077
+ languageName: node
+ linkType: hard
+
"yaml@npm:^2.2.1, yaml@npm:^2.2.2":
version: 2.5.0
resolution: "yaml@npm:2.5.0"
@@ -23707,6 +25462,15 @@ __metadata:
languageName: node
linkType: hard
+"yaml@npm:^2.3.1":
+ version: 2.6.0
+ resolution: "yaml@npm:2.6.0"
+ bin:
+ yaml: bin.mjs
+ checksum: e5e74fd75e01bde2c09333d529af9fbb5928c5f7f01bfdefdcb2bf753d4ef489a45cab4deac01c9448f55ca27e691612b81fe3c3a59bb8cb5b0069da0f92cf0b
+ languageName: node
+ linkType: hard
+
"yargs-parser@npm:^18.1.2":
version: 18.1.3
resolution: "yargs-parser@npm:18.1.3"
@@ -23743,7 +25507,7 @@ __metadata:
languageName: node
linkType: hard
-"yargs@npm:^17.3.1, yargs@npm:^17.6.2":
+"yargs@npm:^17.0.0, yargs@npm:^17.3.1, yargs@npm:^17.6.2":
version: 17.7.2
resolution: "yargs@npm:17.7.2"
dependencies: